NOT FUNCTIONAL CURRENTLY NEED TO FIX

Advanced Audio Alerts with EASY instructions and Functional Overlay

// ==UserScript==
// @name         NOT FUNCTIONAL CURRENTLY NEED TO FIX
// @namespace    https://www.iqrpg.com/
// @version      1.3.8
// @description  Advanced Audio Alerts with EASY instructions and Functional Overlay
// @Author       Oatmilk (Formerly Grogu2484)
// @match        http://iqrpg.com/game.html
// @match        https://iqrpg.com/game.html
// @match        http://www.iqrpg.com/game.html
// @match        https://www.iqrpg.com/game.html
// @require      http://code.jquery.com/jquery-latest.js
// @grant        none
// @license      MIT
// ==/UserScript==
 
/**************************************************************************************
*                                                                                     *
*        YOU MAY EDIT ANYTHING BELOW THIS LINE UNTIL NEXT BOX LIKE THIS !!!           *
*                                                                                     *
**************************************************************************************/
 
// QUICK ACCESS CONTROLS
// Quickly enable or disable specific game notification types
var NOTIFICATIONS_ENABLED = {
    auto: true,           // Auto timer notifications
    dungeon: true,        // Dungeon completion notifications
    boss: true,           // Boss fight notifications
    events: true,         // Skill events notifications
    whispers: true,       // Whisper notifications
    land: true,           // Land timer notifications
    mastery: true,        // Mastery milestone notifications
    effects: true,        // Effect expiration notifications
    clan: true,          // Clan-related notifications
    bonusExp: true        // Bonus EXP notifications
};
 
// SOUND PROFILE SELECTION
// Choose from: "default", "subtle", "game", "natural", "custom"
var SOUND_PROFILE = "default";
 
/*
    SOUND PROFILE DETAILS:
    ----------------------
    - default: Original game sounds (recommended)
    - subtle: Quieter, less intrusive notifications
    - game: Video game-style voice alerts
    - natural: Nature-themed sound effects
    - custom: Use your own sound URLs (configure below)
*/
 
// CUSTOM SOUND PROFILE CONFIGURATION
// ONLY USE IF ------> SOUND_PROFILE is set to "custom"
var CUSTOM_SOUND_URLS = {
    auto: 'https://www.example.com/auto-sound.wav',
    boss: 'https://www.example.com/boss-sound.wav',
    bossDefeated: 'https://www.example.com/boss-defeated-sound.wav',
    event: 'https://www.example.com/event-sound.wav',
    whisper: 'https://www.example.com/whisper-sound.wav',
    land: 'https://www.example.com/land-sound.wav',
    mastery: 'https://www.example.com/mastery-sound.wav',
    effect: 'https://www.example.com/effect-sound.wav',
    watchtower: 'https://www.example.com/watchtower-sound.wav',
    bonusExp: 'https://www.example.com/bonus-exp-sound.wav'
};
 
/*
    MAIN CONTROLS - QUICK TOGGLE
    Set to true --->ENABLES sounds, false<--- DISABLES sounds
    -----------------------------------------------
*/
 
// MASTER TOGGLE - Set to false to disable ALL AUDIO(SOUND) notifications
var MASTER_AUDIO_ENABLED = true;
 
// MASTER TOGGLE - Set to false to disable ALL DESKTOP(Image) notifications
var MASTER_DESKTOP_ENABLED = true;
 
// VISUAL OVERLAY - Set to false to disable startup overlay
var SHOW_STARTUP_OVERLAY = true;
 
// VISUAL OVERLAY DURATION - How long to show the startup overlay (in seconds)
var OVERLAY_DURATION = 5;
 
/*
    VOLUME CONTROL
    --------------
    Set the master volume for all sounds (Valid range: 0.0 to 1.0 (0 = silent, 1 = maximum volume))
*/
 
var MASTER_VOLUME = 0.5;
 
/*
    INDIVIDUAL NOTIFICATION SETTINGS
    -------------------------------
    EDIT ALL THE SETTINGS BELOW! EACH SECTION CONTROLS A DIFFERENT TYPE OF NOTIFICATION
    SET AUDIO ALERTS TO LOWERCASE true TO ENABLE SOUNDS, SET TO LOWERCASE false TO DISABLE AUDIO ALERTS
    SET DESKTOP ALERTS TO LOWERCASE true TO ENABLE DESTOP NOTIFICATIONS, SET TO LOWERCASE false to DISABLE DESKTOP NOTIFICATIONS
    DEBUG IS THE LAST EDITABLE SECTION. THERE IS A BIG PAGE BREAK SO YOU DO NOT EDIT BELOW THAT LINE OR IT WILL NOT WORK..
*/
 
// AUTO SECTION
var autoAudioAlert = true;              // Audio alert when autos are low
var autoAlertSoundURL = 'https://www.myinstants.com/media/sounds/notification.mp3';
var autoAlertRepeatInSeconds = 10;       // How often to repeat (1-60 seconds)
var autoAlertNumber = 100;               // Alert at this number of autos (1-100)
var autoMaxNumberOfAudioAlerts = 0;     // Maximum alerts (0 = unlimited)
var autoDesktopAlert = false;           // Desktop notification when autos are low
 
// DUNGEON SECTION
var dungeonAudioAlert = true;           // Audio alert when dungeon completes
var dungeonDesktopAlert = false;        // Desktop notification for dungeon
 
// BOSS SECTION
var bossAudioAlert = true;              // Audio alert for boss events
var bossAlertSoundURL = 'https://www.myinstants.com/media/sounds/alert.mp3';
var bossDefeatedSoundURL = 'https://www.myinstants.com/media/sounds/ff-victory.mp3';
var bossDesktopAlert = false;           // Desktop notification for boss events
 
// EVENT SECTION
var eventDesktopAlert = true;          // Desktop notification for events
var eventAlertSoundURL = 'https://www.myinstants.com/media/sounds/alert.mp3';
var eventAlert_Woodcutting = true;      // Alert for woodcutting events
var eventAlert_Quarrying = true;        // Alert for quarrying events
var eventAlert_Mining = true;           // Alert for mining events
var eventAudioAlert = true;             // Audio alert when events start
var eventAudioAlertFinished = false;    // Audio alert when events finish
 
// WHISPER SECTION
var whisperAudioAlert = true;           // Audio alert for whispers
var whisperAlertSoundURL = 'https://www.myinstants.com/media/sounds/ping.mp3';
var whisperAlertOnlyWhenTabIsInactive = false;  // Only alert when tab not active
var whisperDesktopAlert = false;        // Desktop notification for whispers
 
// LAND SECTION
var landAudioAlert = true;              // Audio alert when land timer completes
var landAlertSoundURL = 'https://www.myinstants.com/media/sounds/coins.mp3';
 
// MASTERY SECTION
var masteryAudioAlert = true;           // Audio alert for mastery milestones
var masteryEveryXLevels = 10;           // Alert every X levels (1-100)
var masteryAlertSoundURL = 'https://www.myinstants.com/media/sounds/ff-victory.mp3';
 
// EFFECT SECTION
var effectAudioAlert = true;            // Audio alert when effects expire
var effectAutoLeft = 5;                 // Alert at this many minutes (1-60)
var effectAlertSoundURL = 'https://www.myinstants.com/media/sounds/hammer.mp3';
 
// CLAN SECTION
var watchtowerAudioAlert = true;       // Audio alert for watchtower events
var watchtowerAlertSoundURL = 'https://www.myinstants.com/media/sounds/alert.mp3';
var watchtowerDesktopAlert = false;     // Desktop notification for watchtower
 
// BONUS EXP SECTION
var bonusExpAudioAlert = true;          // Audio alert for bonus exp
var bonusExpAlertSoundURL = 'https://www.myinstants.com/media/sounds/magic.mp3';
 
// DEBUG SECTION
var showDebugInfo = true;              // Show debug info in console
 
/**************************************************************************************
*                                                                                     *
*                  !! DO NOT EDIT ANYTHING BELOW THIS LINE !!                         *
*                                                                                     *
**************************************************************************************/
 
(function() {
    'use strict';
    
    // Additional configuration (managed by code)
    var NOTIFICATION_DURATION = 7;          // Notification display time in seconds
    var LOW_RESOURCE_MODE = false;          // Reduce CPU usage mode
    var autoProgressiveAlerts = true;       // Progressive auto alerts
    var dungeonTimerAlert = true;           // Dungeon timer alerts  
    var dungeonTimerMinutes = 5;            // Alert minutes for dungeon timer
    var bossDifferentSounds = true;         // Different sounds for boss types
    var eventReminderAlert = false;         // Reminder alert for events
    var eventUniqueSound = true;            // Unique sounds per event type
    var whisperUrgentMode = false;          // Priority for whisper notifications
    var whisperRepeatAlert = false;         // Repeat alerts for whispers
    var landTimerAlert = false;             // Land timer alerts
    var landTimerMinutes = 5;               // Alert minutes for land timer
    var masteryCelebrationMode = false;     // Special celebration for mastery
    var effectPriorityMode = false;         // Prioritize important effects
    var effectCustomPriority = [];          // Priority effect names
    var clanChatHighlight = false;          // Highlight clan chat messages
    var clanChatKeywords = [];              // Keywords to highlight
    var bonusExpBlinkingAlert = false;      // Blinking alert for bonus exp
    var enableVisualIndicators = true;     // Visual indicators toggle - CHANGED TO TRUE
    var visualAlertColor = "#ff5555";       // Visual alert color
    var visualAlertPulse = true;            // Pulse animation for alerts
    var visualAlertCorner = "top-right";    // Position of visual alerts
    var enableErrorLogging = true;         // Log errors to console - CHANGED TO TRUE
    var statsTracking = false;              // Track notification stats
    
    // State variables
    let alerting = false;
    let alertInterval = null;
    let currentAutoAlerts = 0;
    let canSendDesktopAlert = true;
    let desktopNotificationCooldown = false;
    let bonusExpActive = false;
    let soundProfile = {};
    let lastWhisperTime = 0;
    let visualAlertElement = null;
    let adaptedSelectors = {};
    let notificationStats = {
        total: 0,
        auto: 0,
        dungeon: 0,
        boss: 0,
        event: 0,
        whisper: 0,
        land: 0,
        mastery: 0,
        effect: 0,
        clan: 0,
        bonusExp: 0
    };

    // Debug function for testing sound playback
    function testSoundPlayback() {
        console.log("Testing sound playback...");
        try {
            const testSounds = [
                { name: "Auto", url: soundProfile.auto },
                { name: "Boss", url: soundProfile.boss },
                { name: "Event", url: soundProfile.event },
                { name: "Whisper", url: soundProfile.whisper }
            ];
            
            let delay = 0;
            testSounds.forEach(sound => {
                setTimeout(() => {
                    console.log(`Testing ${sound.name} sound: ${sound.url}`);
                    const audio = new Audio(sound.url);
                    audio.volume = 0.5; // Lower volume for testing
                    
                    // Add event listeners to diagnose issues
                    audio.addEventListener('play', () => {
                        console.log(`${sound.name} sound started playing`);
                    });
                    
                    audio.addEventListener('ended', () => {
                        console.log(`${sound.name} sound completed`);
                    });
                    
                    audio.addEventListener('error', (e) => {
                        console.error(`${sound.name} sound error:`, e);
                        showVisualAlert(`Sound Error: ${sound.name}`, 3000);
                    });
                    
                    // Play the sound
                    audio.play().catch(error => {
                        console.error(`${sound.name} sound playback failed:`, error);
                        showVisualAlert(`Failed to play ${sound.name} sound`, 3000);
                    });
                }, delay);
                delay += 2000; // Add 2 second delay between sounds
            });
        } catch (error) {
            console.error("Sound test failed:", error);
        }
    }
    
    // Pass the real volume setting to the internal variable
    var masterAudioLevel = MASTER_VOLUME;
 
    // Create and show startup overlay
    function showStartupOverlay() {
        if (!SHOW_STARTUP_OVERLAY) return;
        
        // Create overlay container
        const overlay = document.createElement('div');
        overlay.id = 'iqrpg-enhancer-overlay';
        
        // Style the overlay
        Object.assign(overlay.style, {
            position: 'fixed',
            top: '0',
            left: '0',
            width: '100%',
            height: '100%',
            backgroundColor: 'rgba(0, 0, 0, 0.8)',
            zIndex: '10000',
            display: 'flex',
            flexDirection: 'column',
            justifyContent: 'center',
            alignItems: 'center',
            transition: 'opacity 1s ease-in-out',
            opacity: '0'
        });
        
        // Create header
        const header = document.createElement('div');
        header.textContent = 'IQRPG AUDIO ENHANCER';
        Object.assign(header.style, {
            color: '#fff',
            fontSize: '28px',
            fontWeight: 'bold',
            textAlign: 'center',
            marginBottom: '20px',
            fontFamily: 'Arial, sans-serif',
            textShadow: '0 0 10px #00ccff, 0 0 20px #00ccff'
        });
        
        // Create status message
        const status = document.createElement('div');
        status.textContent = 'SUCCESSFULLY LOADED';
        Object.assign(status.style, {
            color: '#00ff00',
            fontSize: '22px',
            fontWeight: 'bold',
            textAlign: 'center',
            marginBottom: '30px',
            fontFamily: 'Arial, sans-serif'
        });
        
        // Create version info
        const version = document.createElement('div');
        version.textContent = 'Version 1.2.2 (Fixed)';
        Object.assign(version.style, {
            color: '#aaaaaa',
            fontSize: '16px',
            textAlign: 'center',
            marginBottom: '30px',
            fontFamily: 'Arial, sans-serif'
        });
        
        // Create active modules section
        const modules = document.createElement('div');
        Object.assign(modules.style, {
            display: 'flex',
            flexWrap: 'wrap',
            justifyContent: 'center',
            maxWidth: '600px',
            margin: '0 auto'
        });
        
        // Add module indicators
        const moduleList = [
            { name: 'Auto Alerts', enabled: NOTIFICATIONS_ENABLED.auto && autoAudioAlert },
            { name: 'Dungeon Alerts', enabled: NOTIFICATIONS_ENABLED.dungeon && dungeonAudioAlert },
            { name: 'Boss Alerts', enabled: NOTIFICATIONS_ENABLED.boss && bossAudioAlert },
            { name: 'Event Alerts', enabled: NOTIFICATIONS_ENABLED.events && eventAudioAlert },
            { name: 'Whisper Alerts', enabled: NOTIFICATIONS_ENABLED.whispers && whisperAudioAlert },
            { name: 'Land Timer', enabled: NOTIFICATIONS_ENABLED.land && landAudioAlert },
            { name: 'Mastery Alerts', enabled: NOTIFICATIONS_ENABLED.mastery && masteryAudioAlert },
            { name: 'Effect Alerts', enabled: NOTIFICATIONS_ENABLED.effects && effectAudioAlert },
            { name: 'Clan Alerts', enabled: NOTIFICATIONS_ENABLED.clan && watchtowerAudioAlert },
            { name: 'Bonus EXP', enabled: NOTIFICATIONS_ENABLED.bonusExp && bonusExpAudioAlert }
        ];
        
        moduleList.forEach(moduleInfo => {
            const module = document.createElement('div');
            module.textContent = moduleInfo.name;
            Object.assign(module.style, {
                padding: '8px 15px',
                margin: '5px',
                backgroundColor: moduleInfo.enabled ? 'rgba(0, 255, 0, 0.2)' : 'rgba(255, 0, 0, 0.2)',
                border: `1px solid ${moduleInfo.enabled ? '#00ff00' : '#ff0000'}`,
                borderRadius: '4px',
                color: moduleInfo.enabled ? '#00ff00' : '#ff0000',
                fontFamily: 'Arial, sans-serif',
                fontSize: '14px'
            });
            modules.appendChild(module);
        });
        
        // Create sound profile info
        const profileInfo = document.createElement('div');
        profileInfo.textContent = `Active Sound Profile: ${SOUND_PROFILE.toUpperCase()}`;
        Object.assign(profileInfo.style, {
            color: '#ffffff',
            fontSize: '16px',
            textAlign: 'center',
            marginTop: '30px',
            fontFamily: 'Arial, sans-serif'
        });
        
        // Create volume info
        const volumeInfo = document.createElement('div');
        volumeInfo.textContent = `Volume: ${Math.round(MASTER_VOLUME * 100)}%`;
        Object.assign(volumeInfo.style, {
            color: '#ffffff',
            fontSize: '16px',
            textAlign: 'center',
            marginTop: '10px',
            fontFamily: 'Arial, sans-serif'
        });
        
        // Add test sound button
        const testSoundButton = document.createElement('button');
        testSoundButton.textContent = 'Test Sounds';
        Object.assign(testSoundButton.style, {
            marginTop: '20px',
            padding: '8px 20px',
            backgroundColor: '#007bff',
            color: '#fff',
            border: 'none',
            borderRadius: '4px',
            cursor: 'pointer',
            fontSize: '14px',
            fontFamily: 'Arial, sans-serif',
            marginRight: '10px'
        });
        
        testSoundButton.addEventListener('mouseover', () => {
            testSoundButton.style.backgroundColor = '#0069d9';
        });
        
        testSoundButton.addEventListener('mouseout', () => {
            testSoundButton.style.backgroundColor = '#007bff';
        });
        
        testSoundButton.addEventListener('click', () => {
            testSoundPlayback();
        });
        
        // Create closing note
        const closingNote = document.createElement('div');
        closingNote.textContent = `This overlay will close in ${OVERLAY_DURATION} seconds...`;
        Object.assign(closingNote.style, {
            color: '#aaaaaa',
            fontSize: '14px',
            textAlign: 'center',
            marginTop: '40px',
            fontFamily: 'Arial, sans-serif'
        });
        
        // Add close button
        const closeButton = document.createElement('button');
        closeButton.textContent = 'Close';
        Object.assign(closeButton.style, {
            marginTop: '20px',
            padding: '8px 20px',
            backgroundColor: '#444',
            color: '#fff',
            border: 'none',
            borderRadius: '4px',
            cursor: 'pointer',
            fontSize: '14px',
            fontFamily: 'Arial, sans-serif'
        });
        
        closeButton.addEventListener('mouseover', () => {
            closeButton.style.backgroundColor = '#666';
        });
        
        closeButton.addEventListener('mouseout', () => {
            closeButton.style.backgroundColor = '#444';
        });
        
        closeButton.addEventListener('click', () => {
            hideStartupOverlay();
        });
        
        // Create button container
        const buttonContainer = document.createElement('div');
        Object.assign(buttonContainer.style, {
            display: 'flex',
            justifyContent: 'center',
            marginTop: '20px'
        });
        
        buttonContainer.appendChild(testSoundButton);
        buttonContainer.appendChild(closeButton);
        
        // Assemble overlay
        overlay.appendChild(header);
        overlay.appendChild(status);
        overlay.appendChild(version);
        overlay.appendChild(modules);
        overlay.appendChild(profileInfo);
        overlay.appendChild(volumeInfo);
        overlay.appendChild(buttonContainer);
        overlay.appendChild(closingNote);
        
        // Add overlay to document
        document.body.appendChild(overlay);
        
        // Fade in the overlay
        setTimeout(() => {
            overlay.style.opacity = '1';
        }, 100);
        
        // Set timeout to remove overlay
        setTimeout(() => {
            hideStartupOverlay();
        }, OVERLAY_DURATION * 1000);
    }
    
    // Hide and remove the startup overlay
    function hideStartupOverlay() {
        const overlay = document.getElementById('iqrpg-enhancer-overlay');
        if (!overlay) return;
        
        // Fade out
        overlay.style.opacity = '0';
        
        // Remove after fade
        setTimeout(() => {
            if (overlay.parentNode) {
                overlay.parentNode.removeChild(overlay);
            }
        }, 1000);
    }
// Initialize sound profiles based on selected profile
    function initSoundProfiles() {
        // Default profile (updated more reliable sounds)
        const defaultProfile = {
            auto: 'https://www.myinstants.com/media/sounds/notification.mp3',
            boss: 'https://www.myinstants.com/media/sounds/alert.mp3',
            bossDefeated: 'https://www.myinstants.com/media/sounds/ff-victory.mp3',
            event: 'https://www.myinstants.com/media/sounds/alert.mp3',
            whisper: 'https://www.myinstants.com/media/sounds/ping.mp3',
            land: 'https://www.myinstants.com/media/sounds/coins.mp3',
            mastery: 'https://www.myinstants.com/media/sounds/ff-victory.mp3',
            effect: 'https://www.myinstants.com/media/sounds/hammer.mp3',
            watchtower: 'https://www.myinstants.com/media/sounds/alert.mp3',
            bonusExp: 'https://www.myinstants.com/media/sounds/magic.mp3'
        };
        
        // Subtle profile (quieter, less intrusive sounds)
        const subtleProfile = {
            auto: 'https://www.myinstants.com/media/sounds/pristine-609.mp3',
            boss: 'https://www.myinstants.com/media/sounds/interface-124464.mp3',
            bossDefeated: 'https://www.myinstants.com/media/sounds/success-1-6297.mp3',
            event: 'https://www.myinstants.com/media/sounds/click-21156.mp3',
            whisper: 'https://www.myinstants.com/media/sounds/notification-sound-7062.mp3',
            land: 'https://www.myinstants.com/media/sounds/coins-497.mp3',
            mastery: 'https://www.myinstants.com/media/sounds/success-fanfare-trumpets-6185.mp3',
            effect: 'https://www.myinstants.com/media/sounds/beep-6-96243.mp3',
            watchtower: 'https://www.myinstants.com/media/sounds/click-for-my-website-345.mp3',
            bonusExp: 'https://www.myinstants.com/media/sounds/short-success-sound-glockenspiel-treasure-video-game-6346.mp3'
        };
        
        // Game profile (video game sounds)
        const gameProfile = {
            auto: 'https://www.myinstants.com/media/sounds/mario-coin-sound.mp3',
            boss: 'https://www.myinstants.com/media/sounds/zelda-secret.mp3',
            bossDefeated: 'https://www.myinstants.com/media/sounds/ff-victory.mp3',
            event: 'https://www.myinstants.com/media/sounds/zelda-secret.mp3',
            whisper: 'https://www.myinstants.com/media/sounds/notification_2.mp3',
            land: 'https://www.myinstants.com/media/sounds/chest-opening-sfx.mp3',
            mastery: 'https://www.myinstants.com/media/sounds/level-up-sound-effect.mp3',
            effect: 'https://www.myinstants.com/media/sounds/beep-7-88619.mp3',
            watchtower: 'https://www.myinstants.com/media/sounds/Metal-Gear-Solid-Alert.mp3',
            bonusExp: 'https://www.myinstants.com/media/sounds/enchant.mp3'
        };
        
        // Natural profile (nature sounds)
        const naturalProfile = {
            auto: 'https://www.myinstants.com/media/sounds/birds-singing-sound-effect.mp3',
            boss: 'https://www.myinstants.com/media/sounds/thunder-38516.mp3',
            bossDefeated: 'https://www.myinstants.com/media/sounds/birds-singing-sound-effect.mp3',
            event: 'https://www.myinstants.com/media/sounds/rain-and-thunder-nature-sounds-7803.mp3',
            whisper: 'https://www.myinstants.com/media/sounds/owl-hooting-sound-effect.mp3',
            land: 'https://www.myinstants.com/media/sounds/river-stream-nature-sounds-7782.mp3',
            mastery: 'https://www.myinstants.com/media/sounds/wind-sound-effect.mp3',
            effect: 'https://www.myinstants.com/media/sounds/forest-wind-bird-sounds.mp3',
            watchtower: 'https://www.myinstants.com/media/sounds/wolf-howl-sound-effect.mp3',
            bonusExp: 'https://www.myinstants.com/media/sounds/waterfall-nature-sounds-7825.mp3'
        };
        
        // Custom profile (user defined sounds)
        const customProfile = {
            auto: CUSTOM_SOUND_URLS.auto || defaultProfile.auto,
            boss: CUSTOM_SOUND_URLS.boss || defaultProfile.boss,
            bossDefeated: CUSTOM_SOUND_URLS.bossDefeated || defaultProfile.bossDefeated,
            event: CUSTOM_SOUND_URLS.event || defaultProfile.event,
            whisper: CUSTOM_SOUND_URLS.whisper || defaultProfile.whisper,
            land: CUSTOM_SOUND_URLS.land || defaultProfile.land,
            mastery: CUSTOM_SOUND_URLS.mastery || defaultProfile.mastery,
            effect: CUSTOM_SOUND_URLS.effect || defaultProfile.effect,
            watchtower: CUSTOM_SOUND_URLS.watchtower || defaultProfile.watchtower,
            bonusExp: CUSTOM_SOUND_URLS.bonusExp || defaultProfile.bonusExp
        };
        
        // Set active profile based on user selection
        switch (SOUND_PROFILE.toLowerCase()) {
            case "subtle":
                soundProfile = subtleProfile;
                break;
            case "game":
                soundProfile = gameProfile;
                break;
            case "natural":
                soundProfile = naturalProfile;
                break;
            case "custom":
                soundProfile = customProfile;
                break;
            default:
                soundProfile = defaultProfile;
        }
        
        // Log sound profile for debugging
        if (showDebugInfo) {
            console.log("Active sound profile:", SOUND_PROFILE);
            console.log("Sound URLs:", soundProfile);
        }
    }
 
    // Play audio alert with the specified sound URL
    function playAudioAlert(soundURL, volume = masterAudioLevel) {
        if (!MASTER_AUDIO_ENABLED) return;
        
        try {
            console.log("Attempting to play sound:", soundURL);
            
            // Preload the audio first
            const audio = new Audio();
            
            // Set up error handling
            audio.onerror = function(e) {
                console.error("Audio error:", e);
                showVisualAlert("Sound playback error", 2000);
            };
            
            // Set up success handling
            audio.oncanplaythrough = function() {
                console.log("Sound loaded and ready to play");
                
                // Set volume and play
                audio.volume = volume;
                
                // Try to play the sound
                const playPromise = audio.play();
                
                // Handle autoplay policy issues
                if (playPromise !== undefined) {
                    playPromise.then(() => {
                        console.log("Sound playing successfully");
                    }).catch(error => {
                        console.error("Sound play failed:", error);
                        showVisualAlert("Browser blocked autoplay", 2000);
                        
                        // Try an alternative approach for browsers with strict autoplay policies
                        document.addEventListener('click', function playOnClick() {
                            audio.play();
                            document.removeEventListener('click', playOnClick);
                        }, { once: true });
                    });
                }
            };
            
            // Set the source after attaching event handlers
            audio.src = soundURL;
            
            if (statsTracking) {
                notificationStats.total++;
            }
        } catch (error) {
            console.error('Error creating audio object:', error);
            showVisualAlert("Failed to create audio", 2000);
        }
    }
 
    // Send desktop notification
    function sendDesktopNotification(title, message, icon = null, duration = NOTIFICATION_DURATION * 1000) {
        if (!MASTER_DESKTOP_ENABLED || !canSendDesktopAlert || desktopNotificationCooldown) return;
        
        // Check if notifications are supported and permitted
        if (!("Notification" in window)) {
            if (showDebugInfo) {
                console.log('Desktop notifications not supported in this browser');
            }
            return;
        }
        
        if (Notification.permission === "denied") {
            if (showDebugInfo) {
                console.log('Desktop notifications permission denied');
            }
            return;
        }
        
        // Request permission if not granted
        if (Notification.permission !== "granted") {
            Notification.requestPermission().then(permission => {
                if (permission === "granted") {
                    // Try again after permission granted
                    sendDesktopNotification(title, message, icon, duration);
                }
            });
            return;
        }
        
        // Set notification cooldown
        desktopNotificationCooldown = true;
        
        // Create and show notification
        const options = {
            body: message,
            icon: icon || 'https://www.iqrpg.com/favicon.ico',
            silent: true // We handle audio separately
        };
        
        const notification = new Notification(title, options);
        
        // Close notification after duration
        setTimeout(() => {
            notification.close();
            desktopNotificationCooldown = false;
        }, duration);
    }
 
    // Display visual alert on screen
    function showVisualAlert(message, duration = 3000) {
        if (!enableVisualIndicators) return;
        
        console.log("Showing visual alert:", message);
        
        // Create alert element if it doesn't exist
        if (!visualAlertElement) {
            visualAlertElement = document.createElement('div');
            visualAlertElement.id = 'iqrpg-audio-enhancer-alert';
            
            // Apply styling based on user preferences
            const style = {
                position: 'fixed',
                padding: '10px 15px',
                backgroundColor: visualAlertColor,
                color: '#fff',
                fontWeight: 'bold',
                zIndex: '9999',
                borderRadius: '5px',
                boxShadow: '0 2px 10px rgba(0,0,0,0.2)',
                opacity: '0',
                transition: 'opacity 0.3s ease-in-out'
            };
            
            // Position based on user preference
            switch (visualAlertCorner) {
                case 'top-left':
                    style.top = '10px';
                    style.left = '10px';
                    break;
                case 'top-right':
                    style.top = '10px';
                    style.right = '10px';
                    break;
                case 'bottom-left':
                    style.bottom = '10px';
                    style.left = '10px';
                    break;
                case 'bottom-right':
                    style.bottom = '10px';
                    style.right = '10px';
                    break;
                default:
                    style.top = '10px';
                    style.right = '10px';
            }
            
            // Apply styles
            Object.assign(visualAlertElement.style, style);
            
            // Add pulse animation if enabled
            if (visualAlertPulse) {
                visualAlertElement.style.animation = 'iqrpg-pulse 1s infinite';
                
                // Add keyframes for pulse animation
                const styleSheet = document.createElement('style');
                styleSheet.textContent = `
                    @keyframes iqrpg-pulse {
                        0% { transform: scale(1); }
                        50% { transform: scale(1.05); }
                        100% { transform: scale(1); }
                    }
                `;
                document.head.appendChild(styleSheet);
            }
            
            document.body.appendChild(visualAlertElement);
        }
        
        // Update message and show alert
        visualAlertElement.textContent = message;
        visualAlertElement.style.opacity = '1';
        
        // Hide after duration
        setTimeout(() => {
            visualAlertElement.style.opacity = '0';
        }, duration);
    }
 
    // Handle title change (for whispers and other notifications)
    function handleTitleChange() {
        const title = document.title;
        
        if (showDebugInfo) {
            console.log("Title changed:", title);
        }
        
        // Check for whisper notifications
        if (NOTIFICATIONS_ENABLED.whispers && title.includes('Whisper')) {
            handleWhisperNotification();
        }
        
        // Check for event notifications
        if (NOTIFICATIONS_ENABLED.events && title.includes('Event')) {
            handleEventNotification();
        }
        
        // Check for bonus exp notifications
        if (NOTIFICATIONS_ENABLED.bonusExp && title.includes('Bonus EXP')) {
            handleBonusExpNotification();
        }
    }
 
    // Handle whisper notifications
    function handleWhisperNotification() {
        if (!whisperAudioAlert) return;
        
        console.log("Whisper notification triggered");
        
        // Don't alert if tab is active and setting requires inactive tab
        if (whisperAlertOnlyWhenTabIsInactive && document.visibilityState === 'visible') {
            console.log("Tab is active, skipping whisper alert");
            return;
        }
        
        // Check time since last whisper alert to prevent spam
        const now = Date.now();
        if (now - lastWhisperTime < 3000) { // 3 second cooldown
            console.log("Whisper alert on cooldown");
            return;
        }
        
        lastWhisperTime = now;
        
        // Play whisper sound
        playAudioAlert(soundProfile.whisper);
        
        // Update stats if enabled
        if (statsTracking) {
            notificationStats.whisper++;
        }
        
        // Send desktop notification if enabled
        if (whisperDesktopAlert) {
            sendDesktopNotification('IQRPG Whisper', 'You received a new whisper!');
        }
        
        // Show visual indicator if enabled
        if (enableVisualIndicators) {
            showVisualAlert('New Whisper');
        }
    }
 
    // Handle event notifications
    function handleEventNotification() {
        if (!eventAudioAlert) return;
        
        console.log("Event notification triggered");
        
        // Extract event type from title if possible
        const title = document.title;
        let eventType = 'unknown';
        
        if (title.includes('Woodcutting') && eventAlert_Woodcutting) {
            eventType = 'woodcutting';
        } else if (title.includes('Quarrying') && eventAlert_Quarrying) {
            eventType = 'quarrying';
        } else if (title.includes('Mining') && eventAlert_Mining) {
            eventType = 'mining';
        } else {
            // Unknown event type or disabled
            console.log("Unknown or disabled event type");
            return;
        }
        
        console.log(`Event type: ${eventType}`);
        
        // Play event sound
        playAudioAlert(soundProfile.event);
        
        // Update stats if enabled
        if (statsTracking) {
            notificationStats.event++;
        }
        
        // Send desktop notification if enabled
        if (eventDesktopAlert) {
            sendDesktopNotification('IQRPG Event', `A ${eventType} event has started!`);
        }
        
        // Show visual indicator if enabled
        if (enableVisualIndicators) {
            showVisualAlert(`${eventType.charAt(0).toUpperCase() + eventType.slice(1)} Event Started`);
        }
    }
 
    // Handle bonus exp notifications
    function handleBonusExpNotification() {
        if (!bonusExpAudioAlert || bonusExpActive) return;
        
        console.log("Bonus EXP notification triggered");
        bonusExpActive = true;
        
        // Play bonus exp sound
        playAudioAlert(soundProfile.bonusExp);
        
        // Update stats if enabled
        if (statsTracking) {
            notificationStats.bonusExp++;
        }
        
        // Add blinking indicator if enabled
        if (bonusExpBlinkingAlert) {
            const favicon = document.querySelector('link[rel="icon"]');
            if (favicon) {
                // Remember original favicon
                const originalFavicon = favicon.href;
                
                // Create alternate favicon (simple colored square)
                const canvas = document.createElement('canvas');
                canvas.width = 16;
                canvas.height = 16;
                const ctx = canvas.getContext('2d');
                ctx.fillStyle = '#ffcc00';
                ctx.fillRect(0, 0, 16, 16);
                const alternateFavicon = canvas.toDataURL();
                
                // Set up blinking interval
                let blinkState = false;
                const blinkInterval = setInterval(() => {
                    favicon.href = blinkState ? originalFavicon : alternateFavicon;
                    blinkState = !blinkState;
                }, 500);
                
                // Stop blinking after 10 seconds
                setTimeout(() => {
                    clearInterval(blinkInterval);
                    favicon.href = originalFavicon;
                    bonusExpActive = false;
                }, 10000);
            }
        } else {
            // Reset active state after delay
            setTimeout(() => {
                bonusExpActive = false;
            }, 10000);
        }
        
        // Show visual indicator if enabled
        if (enableVisualIndicators) {
            showVisualAlert('Bonus EXP Active!');
        }
    }
 
    // Handle dungeon completion notification
    function handleDungeonCompletion() {
        if (!NOTIFICATIONS_ENABLED.dungeon || !dungeonAudioAlert) return;
        
        console.log("Dungeon completion triggered");
        
        // Play dungeon completion sound
        playAudioAlert(soundProfile.boss);
        
        // Update stats if enabled
        if (statsTracking) {
            notificationStats.dungeon++;
        }
        
        // Send desktop notification if enabled
        if (dungeonDesktopAlert) {
            sendDesktopNotification('IQRPG Dungeon', 'Dungeon run has completed!');
        }
        
        // Show visual indicator if enabled
        if (enableVisualIndicators) {
            showVisualAlert('Dungeon Completed');
        }
    }
 
    // Handle boss notification
    function handleBossNotification(type = 'normal') {
        if (!NOTIFICATIONS_ENABLED.boss || !bossAudioAlert) return;
        
        console.log(`Boss notification triggered: ${type}`);
        
        // Determine which sound to play based on boss type
        let soundUrl = soundProfile.boss;
        if (type === 'defeated' && bossDifferentSounds) {
            soundUrl = soundProfile.bossDefeated;
        }
        
        // Play boss sound
        playAudioAlert(soundUrl);
        
        // Update stats if enabled
        if (statsTracking) {
            notificationStats.boss++;
        }
        
        // Send desktop notification if enabled
        if (bossDesktopAlert) {
            const message = type === 'defeated' ? 'Boss has been defeated!' : 'Boss fight in progress!';
            sendDesktopNotification('IQRPG Boss', message);
        }
        
        // Show visual indicator if enabled
        if (enableVisualIndicators) {
            const message = type === 'defeated' ? 'Boss Defeated!' : 'Boss Fight!';
            showVisualAlert(message);
        }
    }
 
    // Handle autos remaining change
    function handleAutosRemainingChange(count) {
        if (!NOTIFICATIONS_ENABLED.auto || !autoAudioAlert) return;
        
        // Convert to number if it's a string
        const autosRemaining = typeof count === 'string' ? parseInt(count, 10) : count;
        
        if (showDebugInfo) {
            console.log(`Autos remaining: ${autosRemaining}`);
        }
        
        // Check if we should alert
        if (isNaN(autosRemaining) || autosRemaining > autoAlertNumber) {
            // Reset alert count if autos are above threshold
            currentAutoAlerts = 0;
            
            // Clear alert interval if it exists
            if (alertInterval) {
                clearInterval(alertInterval);
                alertInterval = null;
                alerting = false;
            }
            
            return;
        }
        
        // Don't start a new alert if we're already alerting
        if (alerting) return;
        
        // Check if we've reached the maximum number of alerts
        if (autoMaxNumberOfAudioAlerts > 0 && currentAutoAlerts >= autoMaxNumberOfAudioAlerts) {
            return;
        }
        
        // Start alerting
        alerting = true;
        
        console.log(`Auto alert triggered: ${autosRemaining} autos remaining`);
        
        // Play auto alert sound
        playAudioAlert(soundProfile.auto);
        currentAutoAlerts++;
        
        // Update stats if enabled
        if (statsTracking) {
            notificationStats.auto++;
        }
        
        // Send desktop notification if enabled
        if (autoDesktopAlert) {
            sendDesktopNotification('IQRPG Auto Alert', `Only ${autosRemaining} autos remaining!`);
        }
        
        // Show visual indicator if enabled
        if (enableVisualIndicators) {
            showVisualAlert(`${autosRemaining} Autos Left`);
        }
        
        // Set up repeat alert if configured
        if (autoAlertRepeatInSeconds > 0) {
            alertInterval = setInterval(() => {
                // Check if we've reached the maximum number of alerts
                if (autoMaxNumberOfAudioAlerts > 0 && currentAutoAlerts >= autoMaxNumberOfAudioAlerts) {
                    clearInterval(alertInterval);
                    alertInterval = null;
                    alerting = false;
                    return;
                }
                
                // Play auto alert sound again
                playAudioAlert(soundProfile.auto);
                currentAutoAlerts++;
                
                // Update stats if enabled
                if (statsTracking) {
                    notificationStats.auto++;
                }
            }, autoAlertRepeatInSeconds * 1000);
        } else {
            alerting = false;
        }
    }
 
    // Handle mastery level change
    function handleMasteryLevelChange(level) {
        if (!NOTIFICATIONS_ENABLED.mastery || !masteryAudioAlert) return;
        
        // Convert to number if it's a string
        const masteryLevel = typeof level === 'string' ? parseInt(level, 10) : level;
        
        if (showDebugInfo) {
            console.log(`Mastery level: ${masteryLevel}`);
        }
        
        // Check if this level is a milestone
        if (isNaN(masteryLevel) || masteryLevel % masteryEveryXLevels !== 0) {
            return;
        }
        
        console.log(`Mastery milestone reached: ${masteryLevel}`);
        
        // Play mastery sound
        playAudioAlert(soundProfile.mastery);
        
        // Update stats if enabled
        if (statsTracking) {
            notificationStats.mastery++;
        }
        
        // Show visual indicator if enabled
        if (enableVisualIndicators) {
            showVisualAlert(`Mastery Level ${masteryLevel}!`);
        }
        
        // Special celebration if enabled
        if (masteryCelebrationMode) {
            // Create a temporary celebration overlay
            const overlay = document.createElement('div');
            overlay.style.position = 'fixed';
            overlay.style.top = '0';
            overlay.style.left = '0';
            overlay.style.width = '100%';
            overlay.style.height = '100%';
            overlay.style.backgroundColor = 'rgba(0,0,0,0.7)';
            overlay.style.zIndex = '10000';
            overlay.style.display = 'flex';
            overlay.style.justifyContent = 'center';
            overlay.style.alignItems = 'center';
            overlay.style.flexDirection = 'column';
            
            const message = document.createElement('div');
            message.style.color = '#ffcc00';
            message.style.fontSize = '32px';
            message.style.fontWeight = 'bold';
            message.style.textShadow = '0 0 10px rgba(255,204,0,0.7)';
            message.textContent = `MASTERY LEVEL ${masteryLevel}!`;
            
            overlay.appendChild(message);
            document.body.appendChild(overlay);
            
            // Remove overlay after a short delay
            setTimeout(() => {
                overlay.style.transition = 'opacity 1s ease-out';
                overlay.style.opacity = '0';
                setTimeout(() => {
                    document.body.removeChild(overlay);
                }, 1000);
            }, 2000);
        }
    }
 
    // Handle effect expiration
    function handleEffectExpiration(effectName, minutesLeft) {
        if (!NOTIFICATIONS_ENABLED.effects || !effectAudioAlert) return;
        
        if (showDebugInfo) {
            console.log(`Effect: ${effectName}, minutes left: ${minutesLeft}`);
        }
        
        // Check priority mode
        if (effectPriorityMode && effectCustomPriority.length > 0) {
            if (!effectCustomPriority.some(name => effectName.includes(name))) {
                return;
            }
        }
        
        // Convert to number if it's a string
        const minsLeft = typeof minutesLeft === 'string' ? parseInt(minutesLeft, 10) : minutesLeft;
        
        // Check if the effect is about to expire
        if (isNaN(minsLeft) || minsLeft > effectAutoLeft) {
            return;
        }
        
        console.log(`Effect expiring soon: ${effectName}, ${minsLeft} min remaining`);
        
        // Play effect expiration sound
        playAudioAlert(soundProfile.effect);
        
        // Update stats if enabled
        if (statsTracking) {
            notificationStats.effect++;
        }
        
        // Show visual indicator if enabled
        if (enableVisualIndicators) {
            showVisualAlert(`${effectName} expires in ${minsLeft} min`);
        }
    }
 
    // Handle land timer completion
    function handleLandTimerCompletion() {
        if (!NOTIFICATIONS_ENABLED.land || !landAudioAlert) return;
        
        console.log("Land timer completed");
        
        // Play land timer sound
        playAudioAlert(soundProfile.land);
        
        // Update stats if enabled
        if (statsTracking) {
            notificationStats.land++;
        }
        
        // Show visual indicator if enabled
        if (enableVisualIndicators) {
            showVisualAlert('Land Timer Completed');
        }
    }
 
    // Handle clan watchtower notification
    function handleWatchtowerNotification() {
        if (!NOTIFICATIONS_ENABLED.clan || !watchtowerAudioAlert) return;
        
        console.log("Watchtower notification triggered");
        
        // Play watchtower sound
        playAudioAlert(soundProfile.watchtower);
        
        // Update stats if enabled
        if (statsTracking) {
            notificationStats.clan++;
        }
        
        // Send desktop notification if enabled
        if (watchtowerDesktopAlert) {
            sendDesktopNotification('IQRPG Clan', 'Watchtower Alert!');
        }
        
        // Show visual indicator if enabled
        if (enableVisualIndicators) {
            showVisualAlert('Clan Watchtower Alert');
        }
    }
 
    // Find and process game elements
    function setupGameSelectors() {
        // Force enable debug logging during setup
        const originalDebugSetting = showDebugInfo;
        showDebugInfo = true;
        
        console.log("Setting up game selectors...");
        
        // Determine which version of the game UI is being used
        const isNewUI = document.querySelector('.game-panel-x') !== null;
        console.log("Detected UI version:", isNewUI ? "New" : "Classic");
        
        // Set up selectors based on UI version
        if (isNewUI) {
            // NEW UI SELECTORS
            adaptedSelectors = {
                autosRemaining: '.auto-label, .auto-counter, [class*="auto"]',
                dungeonComplete: '.dungeon-complete-indicator, .dungeon-result, [class*="dungeon"]',
                bossStatus: '.boss-status-indicator, .boss-result, [class*="boss"]',
                masteryLevel: '.mastery-level-display, .mastery-level, [class*="mastery"]',
                effectsContainer: '.active-effects-panel, .effects-list, [class*="effect"]',
                landTimer: '.land-timer-display, .land-timer, [class*="land"]',
                chatContainer: '.chat-container-x, .chat-area, [class*="chat"]'
            };
        } else {
            // CLASSIC UI SELECTORS
            adaptedSelectors = {
                autosRemaining: '#autosRemaining, .autoDisplay, [class*="auto"]',
                dungeonComplete: '.dungeon-complete, #dungeonComplete, [class*="dungeon"]',
                bossStatus: '.boss-status, #bossStatus, [class*="boss"]',
                masteryLevel: '#masteryLevel, .masteryLevel, [class*="mastery"]',
                effectsContainer: '.effects-container, #effectsContainer, [class*="effect"]',
                landTimer: '#landTimer, .landTimer, [class*="land"]',
                chatContainer: '.chat-container, #chatContainer, [class*="chat"]'
            };
        }
        
        // Log selectors for debugging
        console.log("Game selectors set up:", adaptedSelectors);
        
        // Add fallback selectors for common elements
        console.log("Adding fallback selectors");
        const fallbackSelectors = {
            autosRemaining: document.querySelectorAll('[data-id="autos"], [data-attribute="autos"], [id*="auto"], [class*="auto"]'),
            dungeonComplete: document.querySelectorAll('[data-id="dungeon"], [data-attribute="dungeon"], [id*="dungeon"], [class*="dungeon"]'),
            bossStatus: document.querySelectorAll('[data-id="boss"], [data-attribute="boss"], [id*="boss"], [class*="boss"]'),
            masteryLevel: document.querySelectorAll('[data-id="mastery"], [data-attribute="mastery"], [id*="mastery"], [class*="mastery"]'),
            effectsContainer: document.querySelectorAll('[data-id="effects"], [data-attribute="effects"], [id*="effect"], [class*="effect"]'),
            landTimer: document.querySelectorAll('[data-id="land"], [data-attribute="land"], [id*="land"], [class*="land"]'),
            chatContainer: document.querySelectorAll('[data-id="chat"], [data-attribute="chat"], [id*="chat"], [class*="chat"]')
        };
        
        // Log the number of elements found for each fallback selector
        for (const key in fallbackSelectors) {
            console.log(`Fallback ${key} elements found: ${fallbackSelectors[key].length}`);
        }
        
        // Restore original debug setting
        showDebugInfo = originalDebugSetting;
        
        return isNewUI;
    }
 
    // Observe changes to game elements
    function setupObservers() {
        // Initialize sound profiles
        initSoundProfiles();
        
        // Set up game selectors
        const isNewUI = setupGameSelectors();
        
        console.log("Setting up observers...");
        
        // Create a function to handle title changes
        const titleChangeHandler = () => {
            handleTitleChange();
        };
        
        // Set up title observer for title-based notifications
        const titleObserver = new MutationObserver(titleChangeHandler);
        
        // Observe title changes
        titleObserver.observe(document.querySelector('title') || document.head, {
            subtree: true,
            characterData: true,
            childList: true,
            attributes: true
        });
        
        console.log("Title observer set up");
        
        // Also listen for the visibilitychange event to handle tab focus changes
        document.addEventListener('visibilitychange', titleChangeHandler);
        
        // Helper function to safely find elements
        function safeQuerySelector(selector) {
            try {
                // First try with the exact selector
                let element = document.querySelector(selector);
                
                if (!element && selector.includes(',')) {
                    // If the selector contains multiple options, try them one by one
                    const selectors = selector.split(',').map(s => s.trim());
                    for (const s of selectors) {
                        element = document.querySelector(s);
                        if (element) {
                            console.log(`Found element using selector: ${s}`);
                            break;
                        }
                    }
                }
                
                if (!element) {
                    console.warn(`Element not found with selector ${selector}`);
                }
                
                return element;
            } catch (error) {
                console.error(`Error finding element with selector ${selector}:`, error);
                return null;
            }
        }
        
        // Helper function to safely create observers
        function safeObserve(element, callback, options = {}) {
            if (!element) {
                console.warn("Cannot observe null element");
                return null;
            }
            
            try {
                const observer = new MutationObserver(callback);
                observer.observe(element, {
                    subtree: true,
                    characterData: true,
                    childList: true,
                    attributes: true,
                    ...options
                });
                console.log("Observer set up for", element);
                return observer;
            } catch (error) {
                console.error('Error setting up observer:', error);
                return null;
            }
        }
        
        // Set up a global observer to watch for dynamically added elements
        const bodyObserver = new MutationObserver((mutations) => {
            // Check if we need to find game elements that weren't initially available
            for (const [key, selector] of Object.entries(adaptedSelectors)) {
                if (!document.querySelector(selector)) {
                    // Try to find the element again
                    const element = safeQuerySelector(selector);
                    if (element) {
                        console.log(`Found previously missing element for ${key}`);
                        
                        // Set up the appropriate observer based on the element type
                        switch (key) {
                            case 'autosRemaining':
                                setupAutoObserver(element);
                                break;
                            case 'dungeonComplete':
                                setupDungeonObserver(element);
                                break;
                            case 'bossStatus':
                                setupBossObserver(element);
                                break;
                            case 'masteryLevel':
                                setupMasteryObserver(element);
                                break;
                            case 'effectsContainer':
                                setupEffectsObserver(element);
                                break;
                            case 'landTimer':
                                setupLandObserver(element);
                                break;
                            case 'chatContainer':
                                setupChatObserver(element);
                                break;
                        }
                    }
                }
            }
        });
        
        // Start observing the body for changes
        bodyObserver.observe(document.body, {
            subtree: true,
            childList: true
        });
        
        console.log("Body observer set up");
        
        // Setup function for auto observer
        function setupAutoObserver(element) {
            safeObserve(element, mutations => {
                for (const mutation of mutations) {
                    if (mutation.type === 'characterData' || mutation.type === 'childList') {
                        // Extract number from text content
                        const text = element.textContent;
                        const match = text.match(/(\d+)/);
                        if (match) {
                            handleAutosRemainingChange(parseInt(match[1], 10));
                        }
                    }
                }
            });
        }
        
        // Setup function for dungeon observer
        function setupDungeonObserver(element) {
            safeObserve(element, mutations => {
                for (const mutation of mutations) {
                    if (mutation.type === 'attributes' || mutation.type === 'childList') {
                        // Check if dungeon complete indicator is visible
                        if ((element.style.display !== 'none' && element.classList.contains('active')) ||
                            element.textContent.toLowerCase().includes('complete') ||
                            element.textContent.toLowerCase().includes('finished')) {
                            handleDungeonCompletion();
                        }
                    }
                }
            });
        }
        
        // Setup function for boss observer
        function setupBossObserver(element) {
            safeObserve(element, mutations => {
                for (const mutation of mutations) {
                    if (mutation.type === 'attributes' || mutation.type === 'childList') {
                        // Check boss status text
                        const text = element.textContent.toLowerCase();
                        if (text.includes('defeated') || text.includes('victory')) {
                            handleBossNotification('defeated');
                        } else if (text.includes('fight') || text.includes('in progress') || text.includes('battle')) {
                            handleBossNotification('normal');
                        }
                    }
                }
            });
        }
        
        // Setup function for mastery observer
        function setupMasteryObserver(element) {
            safeObserve(element, mutations => {
                for (const mutation of mutations) {
                    if (mutation.type === 'characterData' || mutation.type === 'childList') {
                        // Extract level from text content
                        const text = element.textContent;
                        const match = text.match(/(\d+)/);
                        if (match) {
                            handleMasteryLevelChange(parseInt(match[1], 10));
                        }
                    }
                }
            });
        }
        
        // Setup function for effects observer
        function setupEffectsObserver(element) {
            safeObserve(element, mutations => {
                for (const mutation of mutations) {
                    if (mutation.type === 'childList') {
                        // Process each effect element
                        const effectElements = element.querySelectorAll('.effect, [class*="effect"]');
                        effectElements.forEach(effect => {
                            try {
                                const nameElement = effect.querySelector('.effect-name, [class*="name"]');
                                const timeElement = effect.querySelector('.effect-time, [class*="time"]');
                                
                                if (nameElement && timeElement) {
                                    const effectName = nameElement.textContent.trim();
                                    const timeText = timeElement.textContent.trim();
                                    
                                    // Extract minutes remaining
                                    const minutesMatch = timeText.match(/(\d+)m/);
                                    if (minutesMatch) {
                                        const minutes = parseInt(minutesMatch[1], 10);
                                        handleEffectExpiration(effectName, minutes);
                                    }
                                }
                            } catch (error) {
                                console.error('Error processing effect element:', error);
                            }
                        });
                    }
                }
            });
        }
        
        // Setup function for land observer
        function setupLandObserver(element) {
            safeObserve(element, mutations => {
                for (const mutation of mutations) {
                    if (mutation.type === 'characterData' || mutation.type === 'childList') {
                        // Check if timer is completed (displays "Ready")
                        const text = element.textContent.trim().toLowerCase();
if (text.includes('ready') || text.includes('0:00') || text.includes('completed')) {
                            handleLandTimerCompletion();
                        }
                    }
                }
            });
        }
        
        // Setup function for chat observer
        function setupChatObserver(element) {
            safeObserve(element, mutations => {
                for (const mutation of mutations) {
                    if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
                        // Process new chat messages
                        mutation.addedNodes.forEach(node => {
                            if (node.nodeType === Node.ELEMENT_NODE && node.classList) {
                                // Check for clan messages
                                if (NOTIFICATIONS_ENABLED.clan && 
                                    (node.classList.contains('clan-message') || 
                                     node.querySelector('.clan-tag, [class*="clan"]'))) {
                                    
                                    // Check for watchtower alerts
                                    const text = node.textContent.toLowerCase();
                                    if (text.includes('watchtower') || text.includes('attack')) {
                                        handleWatchtowerNotification();
                                    }
                                    
                                    // Highlight clan chat if enabled
                                    if (clanChatHighlight && clanChatKeywords.length > 0) {
                                        for (const keyword of clanChatKeywords) {
                                            if (text.includes(keyword.toLowerCase())) {
                                                node.style.backgroundColor = 'rgba(255, 255, 0, 0.2)';
                                                node.style.borderLeft = '3px solid #ffcc00';
                                                break;
                                            }
                                        }
                                    }
                                }
                                
                                // Check for whispers
                                if (NOTIFICATIONS_ENABLED.whispers && 
                                    (node.classList.contains('whisper') || 
                                     node.classList.contains('whisper-message') || 
                                     node.querySelector('.whisper-tag, [class*="whisper"]'))) {
                                    handleWhisperNotification();
                                }
                            }
                        });
                    }
                }
            });
        }
        
        // Try to set up observers for each element
        console.log("Setting up element-specific observers");
        
        // Observe autos remaining
        const autosElement = safeQuerySelector(adaptedSelectors.autosRemaining);
        if (autosElement) {
            setupAutoObserver(autosElement);
        }
        
        // Observe dungeon completion
        const dungeonElement = safeQuerySelector(adaptedSelectors.dungeonComplete);
        if (dungeonElement) {
            setupDungeonObserver(dungeonElement);
        }
        
        // Observe boss status
        const bossElement = safeQuerySelector(adaptedSelectors.bossStatus);
        if (bossElement) {
            setupBossObserver(bossElement);
        }
        
        // Observe mastery level
        const masteryElement = safeQuerySelector(adaptedSelectors.masteryLevel);
        if (masteryElement) {
            setupMasteryObserver(masteryElement);
        }
        
        // Observe active effects
        const effectsElement = safeQuerySelector(adaptedSelectors.effectsContainer);
        if (effectsElement) {
            setupEffectsObserver(effectsElement);
        }
        
        // Observe land timer
        const landElement = safeQuerySelector(adaptedSelectors.landTimer);
        if (landElement) {
            setupLandObserver(landElement);
        }
        
        // Observe chat for clan notifications
        const chatElement = safeQuerySelector(adaptedSelectors.chatContainer);
        if (chatElement) {
            setupChatObserver(chatElement);
        }
        
        console.log("Observers setup complete");
        
        // Try triggering some artificial alerts to test if everything works
        setTimeout(() => {
            console.log("Testing alerts...");
            showVisualAlert("Script loaded successfully!", 3000);
        }, 3000);
    }
 
    // Add settings button to game UI
    function addSettingsButton() {
        try {
            console.log("Adding settings button...");
            
            // Create settings button
            const settingsButton = document.createElement('div');
            settingsButton.id = 'iqrpg-audio-enhancer-settings';
            settingsButton.title = 'Audio Enhancer Settings';
            
            // Style the button
            Object.assign(settingsButton.style, {
                position: 'fixed',
                top: '10px',
                right: '10px',
                width: '24px',
                height: '24px',
                backgroundColor: '#333',
                borderRadius: '50%',
                cursor: 'pointer',
                zIndex: '9999',
                display: 'flex',
                justifyContent: 'center',
                alignItems: 'center',
                boxShadow: '0 2px 5px rgba(0,0,0,0.2)',
                border: '2px solid #555'
            });
            
            // Add speaker icon
            settingsButton.innerHTML = `
                <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2">
                    <polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"></polygon>
                    <path d="M19.07 4.93a10 10 0 0 1 0 14.14M15.54 8.46a5 5 0 0 1 0 7.07"></path>
                </svg>
            `;
            
            // Toggle mute on click
            settingsButton.addEventListener('click', function() {
                MASTER_AUDIO_ENABLED = !MASTER_AUDIO_ENABLED;
                
                // Update button appearance
                if (!MASTER_AUDIO_ENABLED) {
                    this.innerHTML = `
                        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#ff5555" stroke-width="2">
                            <polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"></polygon>
                            <line x1="23" y1="9" x2="17" y2="15"></line>
                            <line x1="17" y1="9" x2="23" y2="15"></line>
                        </svg>
                    `;
                    this.style.borderColor = '#ff5555';
                    
                    // Show notification
                    showVisualAlert('Audio Alerts Disabled', 2000);
                } else {
                    this.innerHTML = `
                        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2">
                            <polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"></polygon>
                            <path d="M19.07 4.93a10 10 0 0 1 0 14.14M15.54 8.46a5 5 0 0 1 0 7.07"></path>
                        </svg>
                    `;
                    this.style.borderColor = '#555';
                    
                    // Play test sound and show notification
                    playAudioAlert(soundProfile.auto, 0.5);
                    showVisualAlert('Audio Alerts Enabled', 2000);
                }
                
                // Log state change
                console.log('Audio alerts:', MASTER_AUDIO_ENABLED ? 'enabled' : 'disabled');
            });
            
            // Add button to document
            document.body.appendChild(settingsButton);
            
            console.log('Settings button added');
        } catch (error) {
            console.error('Error adding settings button:', error);
        }
    }
 
    // Check game version and compatibility
    function checkGameVersion() {
        try {
            // Look for version indicator
            const versionElement = document.querySelector('.version, [class*="version"]');
            
            if (versionElement) {
                const gameVersion = versionElement.textContent.trim();
                
                console.log('Detected IQRPG version:', gameVersion);
                
                // Check if we need to adapt to a new version
                if (gameVersion.includes('beta') || parseFloat(gameVersion) >= 0.5) {
                    // Re-setup observers with updated selectors
                    setupGameSelectors();
                    setupObservers();
                    
                    console.log('Adapted to new game version');
                }
            } else {
                console.log('Game version element not found, using default selectors');
            }
        } catch (error) {
            console.error('Error checking game version:', error);
        }
    }
 
    // Initialization on document ready
    $(document).ready(function() {
        try {
            console.log("IQRPG Audio Enhancer starting...");
            
            // Use appropriate delay based on resource mode
            const initDelay = LOW_RESOURCE_MODE ? 1000 : 500;
            
            setTimeout(() => {
                // Self-healing mechanism - detect script startup failures
                try {
                    setupObservers();
                    addSettingsButton();
                    
                    // Show startup overlay to confirm script is loaded
                    showStartupOverlay();
                    
                    // Show initialization message in console
                    console.log('IQRPG Audio Enhancer initialized!');
                    
                    // Log active sound profile
                    console.log('Active sound profile:', SOUND_PROFILE);
                    console.log('Master volume:', MASTER_VOLUME);
                    console.log('Adapted selectors:', adaptedSelectors);
                    
                    // Initial visual alert if enabled
                    if (enableVisualIndicators) {
                        showVisualAlert('IQRPG Audio Enhancer activated!', 3000);
                    }
                    
                    // Add version check mechanism
                    checkGameVersion();
                    
                    // Add browser interaction event to help with autoplay restrictions
                    document.addEventListener('click', function triggerUserInteraction() {
                        console.log("User interaction detected - audio should now work");
                        // Play a silent sound to unlock audio
                        const silentSound = new Audio("data:audio/mp3;base64,SUQzBAAAAAABEVRYWFgAAAAtAAADY29tbWVudABCaWdTb3VuZEJhbmsuY29tIC8gTGFTb25vdGhlcXVlLm9yZwBURU5DAAAAHQAAA1N3aXRjaCBQbHVzIMKpIE5DSCBTb2Z0d2FyZQBUSVQyAAAABgAAAzIyMzUAVFNTRQAAAA8AAANMYXZmNTcuODMuMTAwAAAAAAAAAAAAAAD/80DEAAAAA0gAAAAATEFNRTMuMTAwVVVVVVVVVVVVVUxBTUUzLjEwMFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/zQsRbAAADSAAAAABVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/zQMSkAAADSAAAAABVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV");
                        silentSound.play().catch(e => console.log("Silent sound playback failed:", e));
                        
                        // Remove the event listener after first click
                        document.removeEventListener('click', triggerUserInteraction);
                    });
                    
                } catch (error) {
                    console.error('IQRPG Audio Enhancer initialization error:', error);
                    
                    // Recovery attempt
                    setTimeout(() => {
                        console.log('Attempting recovery after initialization error...');
                        setupObservers();
                    }, 10000); // Try again after 10 seconds
                }
            }, initDelay);
        } catch (outerError) {
            console.error('Critical startup error:', outerError);
        }
// Enhanced whisper message listener with fixed audio handling
function setupEnhancedWhisperListener() {
    let lastMessageCount = 0;
    // Less aggressive interval to reduce system load
    const CHECK_INTERVAL = 300;
    // Tracking last notification time to prevent spam
    let lastNotificationTime = 0;
    
    function scanForWhispers() {
        const possibleContainers = [
            '#messages', 
            '.messages', 
            '[id*="message"]', 
            '[class*="message"]',
            '#chat',
            '.chat',
            '[id*="chat"]',
            '[class*="chat"]'
        ];
        
        for (const selector of possibleContainers) {
            const container = document.querySelector(selector);
            if (!container) continue;
            
            // Only check for new messages to reduce processing
            const messages = container.querySelectorAll('div, p, li, span');
            if (messages.length <= lastMessageCount) continue;
            
            // Only scan new messages
            const newMessages = Array.from(messages).slice(lastMessageCount);
            
            for (const message of newMessages) {
                const messageText = message.textContent.toLowerCase();
                
                // Whisper detection via class
                const hasWhisperClass = message.classList && (
                    message.classList.contains('whisper') || 
                    message.classList.contains('private') ||
                    message.classList.contains('pm')
                );
                
                // Simpler content matching to reduce false positives
                const hasWhisperContent = 
                    messageText.includes('whisper') || 
                    messageText.includes('whispers') || 
                    messageText.includes('pm:') || 
                    messageText.includes('from:') ||
                    messageText.match(/\[from .*\]/i);
                
                if (hasWhisperClass || hasWhisperContent) {
                    const now = Date.now();
                    // Prevent notification spam with 3-second cooldown
                    if (now - lastNotificationTime > 3000) {
                        console.log("Whisper detected:", messageText);
                        lastNotificationTime = now;
                        
                        // Use the original notification system instead of duplicating it
                        handleWhisperNotification();
                        showVisualAlert("Whisper Message Received", 5000);
                    }
                }
            }
            
            // Update message count
            lastMessageCount = messages.length;
            break; // Only check one container
        }
    }
    
    // Run checks at a reasonable interval
    setInterval(scanForWhispers, CHECK_INTERVAL);
    
    // Simple title check
    const originalTitle = document.title;
    setInterval(() => {
        if (document.title !== originalTitle && 
            document.title.toLowerCase().includes('whisper')) {
            // Use existing handler
            handleWhisperNotification();
        }
    }, CHECK_INTERVAL);
    
    console.log("Enhanced whisper detection activated - fixed version");
}

// Call setup but don't start multiple interval timers
setupEnhancedWhisperListener();
    }); // Close document.ready
})(); // Close and invoke IIFE