//=============================================================================
// MinimapZoom.js
//=============================================================================

/*:
 * @plugindesc Adds a minimap/zoom-out feature with exit labels, zoom and pan controls.
 * @author Dazed Translations
 *
 * @param Toggle Key
 * @desc The key to toggle minimap (keycode: M = 79)
 * @default 79
 *
 * @help
 * Press the M key while on the map to toggle a zoomed-out minimap view.
 * Shows the entire map scaled to fit the screen.
 * Character sprites are hidden, and a marker shows your position.
 * 
 * Controls:
 * - M: Close minimap
 * - Mouse Wheel / Shift / Ctrl: Zoom in/out
 * - Arrow Keys / Mouse Drag: Pan the map
 * - R: Reset zoom and pan
 * 
 * Features:
 * - Exit locations are numbered and show destination names in a legend
 * - Nearby exits to the same location are grouped together
 * - Zoom and pan for easier viewing of large maps
 * - Fog of War: Only explored areas are revealed on the minimap
 * - Exit Discovery: Exits are only shown after the player uses them
 * 
 * Settings (Options Menu):
 * - "Minimap Mod (M)": Enable/disable the minimap feature entirely
 * - "Fog of War": Dark overlay hiding unexplored map areas
 * - "Hide Exits": Hide exits/locations until discovered by the player
 * 
 * Combinations:
 * - Both ON: Full exploration mode (dark fog + hidden exits)
 * - Fog OFF, Exits ON: See full map but exits hidden until used
 * - Fog ON, Exits OFF: Dark fog but all exits visible
 * - Both OFF: See everything immediately
 */

(function() {
    'use strict';
    
    // Plugin parameters
    const pluginName = 'MinimapZoom';
    const parameters = PluginManager.parameters(pluginName);
    const toggleKeyCode = Number(parameters['Toggle Key'] || 79); // M key
    
    // Track minimap state
    let minimapActive = false;
    
    // Zoom and pan state
    let minimapZoom = 1.0;
    let minimapPanX = 0;
    let minimapPanY = 0;
    const MIN_ZOOM = 0.5;
    const MAX_ZOOM = 3.0;
    const ZOOM_STEP = 0.1;
    const PAN_SPEED = 15;
    
    // Mouse drag state
    let isDragging = false;
    let dragStartX = 0;
    let dragStartY = 0;
    let dragStartPanX = 0;
    let dragStartPanY = 0;
    
    // Exit location data
    let exitLocations = [];
    
    // Fog of war - exploration tracking
    const EXPLORE_RADIUS = 5;  // Tiles revealed around player
    
    // Export minimap state for other plugins/systems to check
    window.isMinimapActive = function() {
        return minimapActive;
    };
    
    // Function to close minimap from anywhere (used by event start)
    window.closeMinimapIfActive = function() {
        if (minimapActive && SceneManager._scene && SceneManager._scene.hideMinimap) {
            minimapActive = false;
            SceneManager._scene.hideMinimap();
            SoundManager.playCancel();
        }
    };
    
    //=========================================================================
    // ConfigManager - Add minimap enabled setting
    //=========================================================================
    
    // Default values (enabled by default)
    ConfigManager.minimapEnabled = true;
    ConfigManager.minimapFogOfWar = true;  // Fog of war (dark overlay) enabled by default
    ConfigManager.minimapRevealAll = false; // Reveal all destinations OFF by default (exploration mode)
    
    // Hook into makeData to save the settings
    const _ConfigManager_makeData = ConfigManager.makeData;
    ConfigManager.makeData = function() {
        const config = _ConfigManager_makeData.call(this);
        config.minimapEnabled = this.minimapEnabled;
        config.minimapFogOfWar = this.minimapFogOfWar;
        config.minimapRevealAll = this.minimapRevealAll;
        return config;
    };
    
    // Hook into applyData to load the settings
    const _ConfigManager_applyData = ConfigManager.applyData;
    ConfigManager.applyData = function(config) {
        _ConfigManager_applyData.call(this, config);
        this.minimapEnabled = this.readFlag(config, "minimapEnabled", true);
        this.minimapFogOfWar = this.readFlag(config, "minimapFogOfWar", true);
        this.minimapRevealAll = this.readFlag(config, "minimapRevealAll", false);
    };
    
    //=========================================================================
    // Window_Options - Add minimap toggle option
    //=========================================================================
    
    const _Window_Options_makeCommandList = Window_Options.prototype.makeCommandList;
    Window_Options.prototype.makeCommandList = function() {
        _Window_Options_makeCommandList.call(this);
        this.addCommand("Minimap Mod (M)", "minimapEnabled");
        this.addCommand("  Fog of War", "minimapFogOfWar");
        this.addCommand("  Reveal Destinations", "minimapRevealAll");
    };
    
    //=========================================================================
    // Input - Add minimap key and zoom/pan keys
    //=========================================================================
    
    Input.keyMapper[toggleKeyCode] = 'minimap';
    Input.keyMapper[82] = 'minimapReset';  // R key
    // Note: Shift (16) and Ctrl (17) are checked directly in updateMinimapZoomPan
    // to avoid interfering with game controls when minimap is not active
    
    //=========================================================================
    // Auto-close minimap when any event starts
    //=========================================================================
    
    // When any event starts, auto-close the minimap
    const _Game_Event_start = Game_Event.prototype.start;
    Game_Event.prototype.start = function() {
        // Close minimap if it's open when an event tries to start
        window.closeMinimapIfActive();
        _Game_Event_start.call(this);
    };
    
    //=========================================================================
    // Exploration Tracking - Fog of War System
    //=========================================================================
    
    // Initialize exploration data on Game_System
    const _Game_System_initialize = Game_System.prototype.initialize;
    Game_System.prototype.initialize = function() {
        _Game_System_initialize.call(this);
        this._exploredMaps = {};
        this._activatedExits = {};  // Track which exits have been used
    };
    
    // Get explored tiles for current map
    Game_System.prototype.getExploredTiles = function(mapId) {
        if (!this._exploredMaps) {
            this._exploredMaps = {};
        }
        if (!this._exploredMaps[mapId]) {
            this._exploredMaps[mapId] = {};
        }
        return this._exploredMaps[mapId];
    };
    
    // Mark a tile as explored
    Game_System.prototype.exploreTile = function(mapId, x, y) {
        const explored = this.getExploredTiles(mapId);
        const key = x + ',' + y;
        explored[key] = true;
    };
    
    // Check if a tile is explored
    Game_System.prototype.isTileExplored = function(mapId, x, y) {
        const explored = this.getExploredTiles(mapId);
        const key = x + ',' + y;
        return explored[key] === true;
    };
    
    // Mark an exit as activated (used by player)
    Game_System.prototype.activateExit = function(fromMapId, toMapId, x, y) {
        if (!this._activatedExits) {
            this._activatedExits = {};
        }
        if (!this._activatedExits[fromMapId]) {
            this._activatedExits[fromMapId] = {};
        }
        // Key by destination map and approximate position (to handle grouped exits)
        const key = toMapId + '_' + Math.floor(x / 4) + '_' + Math.floor(y / 4);
        this._activatedExits[fromMapId][key] = true;
        
        // Also store exact position for precise matching
        const exactKey = toMapId + '_' + x + '_' + y;
        this._activatedExits[fromMapId][exactKey] = true;
    };
    
    // Check if an exit has been activated
    Game_System.prototype.isExitActivated = function(fromMapId, toMapId, x, y) {
        if (!this._activatedExits) {
            this._activatedExits = {};
        }
        if (!this._activatedExits[fromMapId]) {
            return false;
        }
        // Check exact position first
        const exactKey = toMapId + '_' + x + '_' + y;
        if (this._activatedExits[fromMapId][exactKey]) {
            return true;
        }
        // Check grouped position
        const key = toMapId + '_' + Math.floor(x / 4) + '_' + Math.floor(y / 4);
        return this._activatedExits[fromMapId][key] === true;
    };
    
    // Reveal tiles around a position
    Game_System.prototype.revealAroundPosition = function(mapId, centerX, centerY, radius) {
        for (let dx = -radius; dx <= radius; dx++) {
            for (let dy = -radius; dy <= radius; dy++) {
                // Use circular radius
                if (dx * dx + dy * dy <= radius * radius) {
                    const x = centerX + dx;
                    const y = centerY + dy;
                    if (x >= 0 && y >= 0 && x < $gameMap.width() && y < $gameMap.height()) {
                        this.exploreTile(mapId, x, y);
                    }
                }
            }
        }
    };
    
    // Track when player uses a transfer command
    const _Game_Interpreter_command201 = Game_Interpreter.prototype.command201;
    Game_Interpreter.prototype.command201 = function(params) {
        // params[0]: 0 = direct, 1 = variable designation
        // params[1]: map ID (or variable ID)
        // params[2]: x (or variable ID)
        // params[3]: y (or variable ID)
        
        // Get actual values (handle both direct and variable designation)
        let toMapId, toX, toY;
        if (params[0] === 0) {
            toMapId = params[1];
            toX = params[2];
            toY = params[3];
        } else {
            toMapId = $gameVariables.value(params[1]);
            toX = $gameVariables.value(params[2]);
            toY = $gameVariables.value(params[3]);
        }
        
        const fromMapId = $gameMap.mapId();
        
        // Use the event's position as the exit location
        const event = $gameMap.event(this._eventId);
        if (event) {
            $gameSystem.activateExit(fromMapId, toMapId, event.x, event.y);
        }
        // Also record the arrival exit (where player comes out on destination map)
        $gameSystem.activateExit(toMapId, fromMapId, toX, toY);
        
        // Store info about where we came from so we can reveal the return exit
        $gameSystem._pendingEntryReveal = {
            destinationMapId: toMapId,
            sourceMapId: fromMapId,
            landingX: toX,
            landingY: toY
        };
        
        return _Game_Interpreter_command201.call(this, params);
    };
    
    // Find nearby exit events and activate them (so they show on minimap)
    Game_System.prototype.activateNearbyExits = function(mapId, targetMapId, nearX, nearY) {
        for (const event of $gameMap.events()) {
            if (!event) continue;
            
            // Only check events within reasonable distance
            const dx = Math.abs(event.x - nearX);
            const dy = Math.abs(event.y - nearY);
            if (dx > 15 || dy > 15) continue;
            
            const eventData = event.event();
            if (!eventData) continue;
            
            // Check all pages for Transfer Player command leading to target map
            for (const page of eventData.pages) {
                if (!page || !page.list) continue;
                
                for (const cmd of page.list) {
                    if (cmd.code === 201) {  // Transfer Player command
                        const params = cmd.parameters;
                        let cmdTargetMapId = params[0] === 0 ? params[1] : $gameVariables.value(params[1]);
                        
                        if (cmdTargetMapId === targetMapId) {
                            // Reveal and activate this exit
                            this.revealAroundPosition(mapId, event.x, event.y, EXPLORE_RADIUS);
                            this.activateExit(mapId, targetMapId, event.x, event.y);
                        }
                        break;
                    }
                }
            }
        }
    };
    
    // Track player movement to reveal tiles
    const _Game_Player_moveStraight = Game_Player.prototype.moveStraight;
    Game_Player.prototype.moveStraight = function(d) {
        _Game_Player_moveStraight.call(this, d);
        if (this.isMovementSucceeded()) {
            $gameSystem.revealAroundPosition($gameMap.mapId(), this.x, this.y, EXPLORE_RADIUS);
        }
    };
    
    // Also reveal on map setup (when entering a new map or loading)
    const _Game_Player_performTransfer = Game_Player.prototype.performTransfer;
    Game_Player.prototype.performTransfer = function() {
        _Game_Player_performTransfer.call(this);
        if ($gameMap.mapId() > 0) {
            // Reveal around player's new position
            $gameSystem.revealAroundPosition($gameMap.mapId(), this.x, this.y, EXPLORE_RADIUS);
            // Note: Exit reveal is handled in Scene_Map.start after map is fully loaded
        }
    };
    
    // Reveal on game load as well - and handle pending entry reveals
    const _Scene_Map_start = Scene_Map.prototype.start;
    Scene_Map.prototype.start = function() {
        _Scene_Map_start.call(this);
        if ($gameMap.mapId() > 0) {
            $gameSystem.revealAroundPosition($gameMap.mapId(), $gamePlayer.x, $gamePlayer.y, EXPLORE_RADIUS);
            
            // Check for pending entry reveal - find and activate nearby exits leading back
            if ($gameSystem._pendingEntryReveal && 
                $gameSystem._pendingEntryReveal.destinationMapId === $gameMap.mapId()) {
                const entry = $gameSystem._pendingEntryReveal;
                $gameSystem.activateNearbyExits(
                    $gameMap.mapId(), 
                    entry.sourceMapId, 
                    entry.landingX, 
                    entry.landingY
                );
                $gameSystem._pendingEntryReveal = null;
            }
        }
    };
    
    //=========================================================================
    // Scene_Map - Handle minimap toggle
    //=========================================================================
    
    const _Scene_Map_update = Scene_Map.prototype.update;
    Scene_Map.prototype.update = function() {
        _Scene_Map_update.call(this);
        this.updateMinimapToggle();
    };
    
    Scene_Map.prototype.updateMinimapToggle = function() {
        // Check if minimap is enabled in options
        if (!ConfigManager.minimapEnabled) {
            // If minimap is currently active but disabled, close it
            if (minimapActive) {
                minimapActive = false;
                this.hideMinimap();
            }
            return;  // Don't process minimap inputs when disabled
        }
        
        // Allow closing minimap anytime (even during events/messages), but only open when not busy
        if (Input.isTriggered('minimap')) {
            if (minimapActive) {
                // Always allow closing
                this.toggleMinimap();
            } else if (!$gameMessage.isBusy() && !$gameMap.isEventRunning()) {
                // Only open when not busy
                this.toggleMinimap();
            }
        }
        
        // Auto-close minimap if an event starts running or message appears
        if (minimapActive && ($gameMap.isEventRunning() || $gameMessage.isBusy())) {
            minimapActive = false;
            this.hideMinimap();
            SoundManager.playCancel();
        }
        
        // Update player marker position and atmospheric effects if minimap is active
        if (minimapActive) {
            // Handle zoom and pan controls
            this.updateMinimapZoomPan();
            
            if (this._minimapPlayerMarker) {
                this.updateMinimapPlayerMarker();
            }
            this.updateMinimapAtmosphere();
        }
    };
    
    Scene_Map.prototype.collectExitLocations = function() {
        exitLocations = [];
        const rawExits = [];
        const mapId = $gameMap.mapId();
        
        // Collect all transfer events (show all if revealAll is ON, otherwise filter by exploration)
        const revealAll = ConfigManager.minimapRevealAll;
        for (const event of $gameMap.events()) {
            if (!event) continue;
            
            // Only include exits in explored areas (unless revealAll is enabled)
            if (!revealAll && !$gameSystem.isTileExplored(mapId, event.x, event.y)) {
                continue;
            }
            
            const eventData = event.event();
            if (!eventData) continue;
            
            // Check all pages for Transfer Player command
            for (const page of eventData.pages) {
                if (!page || !page.list) continue;
                
                for (const cmd of page.list) {
                    if (cmd.code === 201) {  // Transfer Player command
                        const params = cmd.parameters;
                        if (params[0] === 0) {  // Direct designation (not variable)
                            const targetMapId = params[1];
                            
                            // Only show exits that have been activated (used by player) - unless revealAll is enabled
                            if (!revealAll && !$gameSystem.isExitActivated(mapId, targetMapId, event.x, event.y)) {
                                continue;
                            }
                            
                            const mapName = this.getMapName(targetMapId);
                            
                            rawExits.push({
                                x: event.x,
                                y: event.y,
                                mapId: targetMapId,
                                mapName: mapName
                            });
                        }
                        break;  // Only need first transfer per page
                    }
                }
            }
        }
        
        // Group nearby exits going to the same destination
        const GROUPING_DISTANCE = 3;  // Tiles within this distance get grouped
        const grouped = [];
        const used = new Set();
        
        for (let i = 0; i < rawExits.length; i++) {
            if (used.has(i)) continue;
            
            const exit = rawExits[i];
            const group = {
                positions: [{x: exit.x, y: exit.y}],
                mapId: exit.mapId,
                mapName: exit.mapName
            };
            used.add(i);
            
            // Find nearby exits to same destination
            for (let j = i + 1; j < rawExits.length; j++) {
                if (used.has(j)) continue;
                const other = rawExits[j];
                
                if (other.mapId === exit.mapId) {
                    // Check if any position in group is close enough
                    let isNearby = false;
                    for (const pos of group.positions) {
                        const dx = Math.abs(other.x - pos.x);
                        const dy = Math.abs(other.y - pos.y);
                        if (dx <= GROUPING_DISTANCE && dy <= GROUPING_DISTANCE) {
                            isNearby = true;
                            break;
                        }
                    }
                    
                    if (isNearby) {
                        group.positions.push({x: other.x, y: other.y});
                        used.add(j);
                    }
                }
            }
            
            // Calculate center position for the group
            let sumX = 0, sumY = 0;
            for (const pos of group.positions) {
                sumX += pos.x;
                sumY += pos.y;
            }
            group.centerX = sumX / group.positions.length;
            group.centerY = sumY / group.positions.length;
            
            grouped.push(group);
        }
        
        // Assign numbers to grouped exits
        let exitNumber = 1;
        for (const group of grouped) {
            group.number = exitNumber++;
            exitLocations.push(group);
        }
    };
    
    Scene_Map.prototype.getMapName = function(mapId) {
        // Try to get map name from $dataMapInfos
        if ($dataMapInfos && $dataMapInfos[mapId]) {
            return $dataMapInfos[mapId].name || 'Unknown';
        }
        return 'Map ' + mapId;
    };
    
    Scene_Map.prototype.updateMinimapZoomPan = function() {
        let zoomChanged = false;
        let panChanged = false;
        
        // Zoom controls - check raw key state directly only when minimap is active
        // This prevents Shift/Ctrl from being captured when minimap is closed
        const shiftPressed = Input._currentState['shift'];
        const ctrlPressed = Input._currentState['control'];
        
        if (shiftPressed) {
            minimapZoom = Math.min(MAX_ZOOM, minimapZoom + ZOOM_STEP);
            zoomChanged = true;
        }
        if (ctrlPressed) {
            minimapZoom = Math.max(MIN_ZOOM, minimapZoom - ZOOM_STEP);
            zoomChanged = true;
        }
        
        // Pan controls (arrow keys)
        if (Input.isPressed('up')) {
            minimapPanY += PAN_SPEED;
            panChanged = true;
        }
        if (Input.isPressed('down')) {
            minimapPanY -= PAN_SPEED;
            panChanged = true;
        }
        if (Input.isPressed('left')) {
            minimapPanX += PAN_SPEED;
            panChanged = true;
        }
        if (Input.isPressed('right')) {
            minimapPanX -= PAN_SPEED;
            panChanged = true;
        }
        
        // Reset controls
        if (Input.isTriggered('minimapReset')) {
            minimapZoom = 1.0;
            minimapPanX = 0;
            minimapPanY = 0;
            zoomChanged = true;
            panChanged = true;
            SoundManager.playCursor();
        }
        
        // Mouse wheel zoom
        if (this._minimapContent) {
            const wheelY = TouchInput.wheelY;
            if (wheelY !== 0) {
                if (wheelY < 0) {
                    minimapZoom = Math.min(MAX_ZOOM, minimapZoom + ZOOM_STEP);
                } else {
                    minimapZoom = Math.max(MIN_ZOOM, minimapZoom - ZOOM_STEP);
                }
                zoomChanged = true;
            }
        }
        
        // Mouse drag pan
        if (TouchInput.isPressed()) {
            if (!isDragging) {
                isDragging = true;
                dragStartX = TouchInput.x;
                dragStartY = TouchInput.y;
                dragStartPanX = minimapPanX;
                dragStartPanY = minimapPanY;
            } else {
                minimapPanX = dragStartPanX + (TouchInput.x - dragStartX);
                minimapPanY = dragStartPanY + (TouchInput.y - dragStartY);
                panChanged = true;
            }
        } else {
            isDragging = false;
        }
        
        // Apply zoom and pan to content
        if ((zoomChanged || panChanged) && this._minimapContent) {
            this.applyMinimapTransform();
        }
    };
    
    Scene_Map.prototype.applyMinimapTransform = function() {
        if (!this._minimapContent) return;
        
        // Calculate the center point for zooming
        const centerX = Graphics.width / 2;
        const centerY = Graphics.height / 2;
        
        // Apply scale
        this._minimapContent.scale.x = this._minimapScale * minimapZoom;
        this._minimapContent.scale.y = this._minimapScale * minimapZoom;
        
        // Calculate new offset to keep centered
        const mapWidth = $gameMap.width() * this._minimapTileWidth;
        const mapHeight = $gameMap.height() * this._minimapTileHeight;
        const scaledWidth = mapWidth * this._minimapScale * minimapZoom;
        const scaledHeight = mapHeight * this._minimapScale * minimapZoom;
        
        const baseOffsetX = (Graphics.width - scaledWidth) / 2;
        const baseOffsetY = (Graphics.height - scaledHeight) / 2;
        
        this._minimapContent.x = baseOffsetX + minimapPanX;
        this._minimapContent.y = baseOffsetY + minimapPanY;
        
        // Update border to match content
        if (this._minimapBorder) {
            this._minimapBorder.scale.x = this._minimapScale * minimapZoom;
            this._minimapBorder.scale.y = this._minimapScale * minimapZoom;
            this._minimapBorder.x = baseOffsetX + minimapPanX - this._borderPadding * this._minimapScale * minimapZoom;
            this._minimapBorder.y = baseOffsetY + minimapPanY - this._borderPadding * this._minimapScale * minimapZoom;
        }
        
        // Update exit destinations panel to stay next to map (right side)
        if (this._exitDestinationsPanel) {
            this._exitDestinationsPanel.scale.x = minimapZoom;
            this._exitDestinationsPanel.scale.y = minimapZoom;
            this._exitDestinationsPanel.x = baseOffsetX + minimapPanX + scaledWidth + this._exitPanelOffset * minimapZoom;
            this._exitDestinationsPanel.y = baseOffsetY + minimapPanY;
        }
        
        // Update legend panel to stay next to map (left side)
        if (this._legendPanel) {
            this._legendPanel.scale.x = minimapZoom;
            this._legendPanel.scale.y = minimapZoom;
            const legendWidth = 120 * minimapZoom;
            this._legendPanel.x = baseOffsetX + minimapPanX - legendWidth - this._legendPanelOffset * minimapZoom;
            this._legendPanel.y = baseOffsetY + minimapPanY;
        }
        
        // Update title panel to stay above map (centered)
        if (this._titlePanel) {
            this._titlePanel.scale.x = minimapZoom;
            this._titlePanel.scale.y = minimapZoom;
            this._titlePanel.x = baseOffsetX + minimapPanX + scaledWidth / 2;
            this._titlePanel.y = baseOffsetY + minimapPanY - this._titlePanelOffset * minimapZoom;
        }
        
        // Update controls panel to stay below map (centered)
        if (this._controlsPanel) {
            this._controlsPanel.scale.x = minimapZoom;
            this._controlsPanel.scale.y = minimapZoom;
            this._controlsPanel.x = baseOffsetX + minimapPanX + scaledWidth / 2;
            this._controlsPanel.y = baseOffsetY + minimapPanY + scaledHeight + this._controlsPanelOffset * minimapZoom;
        }
        
        // Store current offsets for marker positioning
        this._currentOffsetX = this._minimapContent.x;
        this._currentOffsetY = this._minimapContent.y;
        this._currentScale = this._minimapScale * minimapZoom;
        
        // Update exit markers positions
        if (this._exitMarkers) {
            this.updateExitMarkerPositions();
        }
    };
    
    Scene_Map.prototype.updateMinimapAtmosphere = function() {
        // Subtle flicker effect on the map content to simulate candlelight
        if (this._minimapContent) {
            const flicker = 0.92 + Math.sin(Graphics.frameCount * 0.05) * 0.03 + 
                           Math.sin(Graphics.frameCount * 0.13) * 0.02;
            this._minimapContent.opacity = Math.floor(255 * flicker);
        }
    };
    
    Scene_Map.prototype.toggleMinimap = function() {
        minimapActive = !minimapActive;
        
        if (minimapActive) {
            this.showMinimap();
            SoundManager.playCursor();
        } else {
            this.hideMinimap();
            SoundManager.playCancel();
        }
    };
    
    Scene_Map.prototype.showMinimap = function() {
        if (!this._spriteset) return;
        
        // Reset zoom and pan when opening
        minimapZoom = 1.0;
        minimapPanX = 0;
        minimapPanY = 0;
        isDragging = false;
        
        // Collect exit location data
        this.collectExitLocations();
        
        // Hide the normal spriteset
        this._spriteset.visible = false;
        
        // Create minimap overlay
        this.createMinimapOverlay();
    };
    
    Scene_Map.prototype.hideMinimap = function() {
        if (!this._spriteset) return;
        
        // Show the normal spriteset
        this._spriteset.visible = true;
        
        // Remove minimap overlay
        this.removeMinimapOverlay();
    };
    
    Scene_Map.prototype.createMinimapOverlay = function() {
        if (this._minimapOverlay) return;
        
        // Create container for minimap
        this._minimapOverlay = new Sprite();
        this._minimapOverlay.bitmap = new Bitmap(Graphics.width, Graphics.height);
        
        // Draw dark atmospheric background with vignette
        this.drawAtmosphericBackground();
        
        // Get map dimensions
        const mapWidth = $gameMap.width();
        const mapHeight = $gameMap.height();
        const tileWidth = $gameMap.tileWidth();
        const tileHeight = $gameMap.tileHeight();
        
        // Calculate scale to fit entire map on screen with padding
        const padding = 70;
        const availableWidth = Graphics.width - padding * 2;
        const availableHeight = Graphics.height - padding * 2;
        
        const mapPixelWidth = mapWidth * tileWidth;
        const mapPixelHeight = mapHeight * tileHeight;
        
        const scaleX = availableWidth / mapPixelWidth;
        const scaleY = availableHeight / mapPixelHeight;
        const scale = Math.min(scaleX, scaleY, 1); // Don't zoom in past 1x
        
        const scaledWidth = mapPixelWidth * scale;
        const scaledHeight = mapPixelHeight * scale;
        
        // Center the map
        const offsetX = (Graphics.width - scaledWidth) / 2;
        const offsetY = (Graphics.height - scaledHeight) / 2;
        
        // Store for marker positioning
        this._minimapScale = scale;
        this._minimapOffsetX = offsetX;
        this._minimapOffsetY = offsetY;
        this._minimapTileWidth = tileWidth;
        this._minimapTileHeight = tileHeight;
        
        // Create the map snapshot sprite
        this._minimapContent = new Sprite();
        this._minimapContent.x = offsetX;
        this._minimapContent.y = offsetY;
        this._minimapContent.scale.x = scale;
        this._minimapContent.scale.y = scale;
        
        // Render the tilemap to a bitmap
        this.renderMinimapTiles();
        
        // Create border as separate sprite that moves with content
        this.createMinimapBorder(mapPixelWidth, mapPixelHeight);
        
        this.addChild(this._minimapOverlay);
        this.addChild(this._minimapBorder);
        this.addChild(this._minimapContent);
        
        // Create title panel (moves with map) - at top
        this.createTitlePanel(mapPixelWidth, mapPixelHeight);
        
        // Create controls panel (moves with map) - at bottom
        this.createControlsPanel(mapPixelWidth, mapPixelHeight);
        
        // Create legend panel (moves with map) - on left side
        this.createLegendPanel(mapPixelWidth, mapPixelHeight);
        
        // Create exit destinations panel (moves with map) - on right side
        this.createExitDestinationsPanel(mapPixelWidth, mapPixelHeight);
        
        // Create exit markers (as separate sprites for positioning with zoom/pan)
        this.createExitMarkers();
        
        // Create player marker
        this.createMinimapPlayerMarker();
        
        // Initialize current transform values and position all elements correctly
        this._currentOffsetX = offsetX;
        this._currentOffsetY = offsetY;
        this._currentScale = scale;
        this.applyMinimapTransform();
    };
    
    Scene_Map.prototype.drawAtmosphericBackground = function() {
        const bitmap = this._minimapOverlay.bitmap;
        const ctx = bitmap.context;
        const w = Graphics.width;
        const h = Graphics.height;
        
        // Base dark parchment color
        ctx.fillStyle = '#1a1410';
        ctx.fillRect(0, 0, w, h);
        
        // Add subtle parchment texture noise
        for (let i = 0; i < 8000; i++) {
            const x = Math.random() * w;
            const y = Math.random() * h;
            const alpha = Math.random() * 0.08;
            const shade = Math.floor(Math.random() * 30) + 20;
            ctx.fillStyle = `rgba(${shade}, ${shade - 5}, ${shade - 10}, ${alpha})`;
            ctx.fillRect(x, y, 1, 1);
        }
        
        // Add vignette effect (darker edges)
        const gradient = ctx.createRadialGradient(w/2, h/2, h * 0.3, w/2, h/2, h * 0.8);
        gradient.addColorStop(0, 'rgba(0, 0, 0, 0)');
        gradient.addColorStop(0.7, 'rgba(0, 0, 0, 0.3)');
        gradient.addColorStop(1, 'rgba(0, 0, 0, 0.7)');
        ctx.fillStyle = gradient;
        ctx.fillRect(0, 0, w, h);
    };
    
    Scene_Map.prototype.createMinimapBorder = function(mapPixelWidth, mapPixelHeight) {
        const borderSize = 6;
        const padding = 20;  // Extra padding for the border sprite
        
        // Create border sprite sized to fit around the map
        this._minimapBorder = new Sprite();
        const borderWidth = mapPixelWidth + padding * 2;
        const borderHeight = mapPixelHeight + padding * 2;
        this._minimapBorder.bitmap = new Bitmap(borderWidth, borderHeight);
        
        const ctx = this._minimapBorder.bitmap.context;
        const x = padding;
        const y = padding;
        const width = mapPixelWidth;
        const height = mapPixelHeight;
        
        // Outer dark border
        ctx.strokeStyle = '#0d0805';
        ctx.lineWidth = borderSize + 4;
        ctx.strokeRect(x - borderSize - 2, y - borderSize - 2, width + (borderSize + 2) * 2, height + (borderSize + 2) * 2);
        
        // Main gold border
        ctx.strokeStyle = '#8b7355';
        ctx.lineWidth = borderSize;
        ctx.strokeRect(x - borderSize/2, y - borderSize/2, width + borderSize, height + borderSize);
        
        // Inner highlight
        ctx.strokeStyle = '#c9a959';
        ctx.lineWidth = 1;
        ctx.strokeRect(x - 1, y - 1, width + 2, height + 2);
        
        // Corner ornaments
        const cornerSize = 12;
        ctx.fillStyle = '#d4af37';
        
        // Top-left corner
        ctx.beginPath();
        ctx.arc(x, y, cornerSize/2, 0, Math.PI * 2);
        ctx.fill();
        
        // Top-right corner
        ctx.beginPath();
        ctx.arc(x + width, y, cornerSize/2, 0, Math.PI * 2);
        ctx.fill();
        
        // Bottom-left corner
        ctx.beginPath();
        ctx.arc(x, y + height, cornerSize/2, 0, Math.PI * 2);
        ctx.fill();
        
        // Bottom-right corner
        ctx.beginPath();
        ctx.arc(x + width, y + height, cornerSize/2, 0, Math.PI * 2);
        ctx.fill();
        
        // Inner corner dots
        ctx.fillStyle = '#1a0a00';
        const innerDot = 4;
        ctx.beginPath();
        ctx.arc(x, y, innerDot/2, 0, Math.PI * 2);
        ctx.fill();
        ctx.beginPath();
        ctx.arc(x + width, y, innerDot/2, 0, Math.PI * 2);
        ctx.fill();
        ctx.beginPath();
        ctx.arc(x, y + height, innerDot/2, 0, Math.PI * 2);
        ctx.fill();
        ctx.beginPath();
        ctx.arc(x + width, y + height, innerDot/2, 0, Math.PI * 2);
        ctx.fill();
        
        // Store the padding offset for positioning
        this._borderPadding = padding;
        
        // Position and scale to match content
        this._minimapBorder.x = this._minimapOffsetX - padding * this._minimapScale;
        this._minimapBorder.y = this._minimapOffsetY - padding * this._minimapScale;
        this._minimapBorder.scale.x = this._minimapScale;
        this._minimapBorder.scale.y = this._minimapScale;
    };
    
    Scene_Map.prototype.createTitlePanel = function(mapPixelWidth, mapPixelHeight) {
        const panelWidth = 350;
        const panelHeight = 65;
        
        // Create title sprite
        this._titlePanel = new Sprite();
        this._titlePanel.bitmap = new Bitmap(panelWidth, panelHeight);
        
        const bitmap = this._titlePanel.bitmap;
        const ctx = bitmap.context;
        
        // Draw background panel
        ctx.fillStyle = 'rgba(26, 20, 16, 0.9)';
        ctx.fillRect(0, 0, panelWidth, panelHeight);
        ctx.strokeStyle = '#8b7355';
        ctx.lineWidth = 2;
        ctx.strokeRect(0, 0, panelWidth, panelHeight);
        
        // Inner border
        ctx.strokeStyle = '#c9a959';
        ctx.lineWidth = 1;
        ctx.strokeRect(3, 3, panelWidth - 6, panelHeight - 6);
        
        bitmap.fontFace = 'GameFont';
        bitmap.fontSize = 26;
        bitmap.textColor = '#d4af37';
        bitmap.outlineColor = '#1a0a00';
        bitmap.outlineWidth = 4;
        
        // Main title
        bitmap.drawText('~ Cartograph ~', 0, 8, panelWidth, 30, 'center');
        
        // Map name
        const mapName = $gameMap.displayName() || 'Unknown Region';
        bitmap.fontSize = 18;
        bitmap.textColor = '#c9a959';
        bitmap.drawText('― ' + mapName + ' ―', 0, 38, panelWidth, 22, 'center');
        
        // Position panel above the map (centered)
        this._titlePanelOffset = 15;  // Gap between map and panel
        this._titlePanel.anchor = new Point(0.5, 1);  // Anchor at bottom center
        this._titlePanel.x = this._minimapOffsetX + (mapPixelWidth * this._minimapScale) / 2;
        this._titlePanel.y = this._minimapOffsetY - this._titlePanelOffset;
        
        this.addChild(this._titlePanel);
    };
    
    Scene_Map.prototype.createControlsPanel = function(mapPixelWidth, mapPixelHeight) {
        const panelWidth = 500;
        const panelHeight = 35;
        
        // Create controls sprite
        this._controlsPanel = new Sprite();
        this._controlsPanel.bitmap = new Bitmap(panelWidth, panelHeight);
        
        const bitmap = this._controlsPanel.bitmap;
        const ctx = bitmap.context;
        
        // Draw background panel
        ctx.fillStyle = 'rgba(26, 20, 16, 0.9)';
        ctx.fillRect(0, 0, panelWidth, panelHeight);
        ctx.strokeStyle = '#8b7355';
        ctx.lineWidth = 2;
        ctx.strokeRect(0, 0, panelWidth, panelHeight);
        
        // Inner border
        ctx.strokeStyle = '#c9a959';
        ctx.lineWidth = 1;
        ctx.strokeRect(3, 3, panelWidth - 6, panelHeight - 6);
        
        bitmap.fontFace = 'GameFont';
        bitmap.fontSize = 14;
        bitmap.textColor = '#8b7355';
        bitmap.outlineColor = '#1a0a00';
        bitmap.outlineWidth = 3;
        
        // Controls text
        bitmap.drawText('M: Close | Arrows: Pan | Shift/Ctrl/Scroll: Zoom | R: Reset', 0, 8, panelWidth, 20, 'center');
        
        // Position panel below the map (centered)
        this._controlsPanelOffset = 15;  // Gap between map and panel
        this._controlsPanel.anchor = new Point(0.5, 0);  // Anchor at top center
        this._controlsPanel.x = this._minimapOffsetX + (mapPixelWidth * this._minimapScale) / 2;
        this._controlsPanel.y = this._minimapOffsetY + (mapPixelHeight * this._minimapScale) + this._controlsPanelOffset;
        
        this.addChild(this._controlsPanel);
    };
    
    // Keep old function for compatibility but it does nothing now
    Scene_Map.prototype.drawOrnateBorder = function(x, y, width, height) {
        // Border is now drawn as a separate sprite in createMinimapBorder
    };
    
    Scene_Map.prototype.createLegendPanel = function(mapPixelWidth, mapPixelHeight) {
        const dotSize = 10;
        const lineHeight = 24;
        const padding = 15;
        const panelWidth = 120;
        const panelHeight = 35 + 5 * lineHeight + padding;
        
        // Create legend sprite
        this._legendPanel = new Sprite();
        this._legendPanel.bitmap = new Bitmap(panelWidth, panelHeight);
        
        const bitmap = this._legendPanel.bitmap;
        const ctx = bitmap.context;
        
        // Draw background panel
        ctx.fillStyle = 'rgba(26, 20, 16, 0.9)';
        ctx.fillRect(0, 0, panelWidth, panelHeight);
        ctx.strokeStyle = '#8b7355';
        ctx.lineWidth = 2;
        ctx.strokeRect(0, 0, panelWidth, panelHeight);
        
        // Inner border
        ctx.strokeStyle = '#c9a959';
        ctx.lineWidth = 1;
        ctx.strokeRect(3, 3, panelWidth - 6, panelHeight - 6);
        
        bitmap.fontFace = 'GameFont';
        bitmap.fontSize = 14;
        bitmap.textColor = '#d4af37';
        bitmap.outlineColor = '#1a0a00';
        bitmap.outlineWidth = 3;
        
        // Title
        const titleY = 8;
        bitmap.drawText('~ Legend ~', 0, titleY, panelWidth, 18, 'center');
        
        // Underline
        ctx.strokeStyle = '#8b7355';
        ctx.lineWidth = 1;
        ctx.beginPath();
        ctx.moveTo(padding, titleY + 22);
        ctx.lineTo(panelWidth - padding, titleY + 22);
        ctx.stroke();
        
        bitmap.fontSize = 12;
        bitmap.textColor = '#a89070';
        
        const startY = 32;
        const legendX = padding;
        
        // Player marker
        ctx.fillStyle = '#cc0000';
        ctx.beginPath();
        ctx.arc(legendX + dotSize/2, startY + dotSize/2 + 5, dotSize/2, 0, Math.PI * 2);
        ctx.fill();
        ctx.strokeStyle = '#ffcc00';
        ctx.lineWidth = 2;
        ctx.stroke();
        bitmap.drawText('You', legendX + dotSize + 8, startY + 2, 80, 18, 'left');
        
        // NPC marker (warm gold)
        ctx.fillStyle = '#daa520';
        ctx.beginPath();
        ctx.arc(legendX + dotSize/2, startY + lineHeight + dotSize/2 + 5, dotSize/2, 0, Math.PI * 2);
        ctx.fill();
        ctx.strokeStyle = '#2a1a00';
        ctx.lineWidth = 1;
        ctx.stroke();
        bitmap.drawText('NPC', legendX + dotSize + 8, startY + lineHeight + 2, 80, 18, 'left');
        
        // Locked door/chest marker (teal/mysterious)
        ctx.fillStyle = '#40e0d0';
        ctx.beginPath();
        ctx.arc(legendX + dotSize/2, startY + lineHeight * 2 + dotSize/2 + 5, dotSize/2, 0, Math.PI * 2);
        ctx.fill();
        ctx.strokeStyle = '#2a1a00';
        ctx.lineWidth = 1;
        ctx.stroke();
        bitmap.drawText('Locked', legendX + dotSize + 8, startY + lineHeight * 2 + 2, 80, 18, 'left');
        
        // Enemy marker (blood red)
        ctx.fillStyle = '#dc143c';
        ctx.beginPath();
        ctx.arc(legendX + dotSize/2, startY + lineHeight * 3 + dotSize/2 + 5, dotSize/2, 0, Math.PI * 2);
        ctx.fill();
        ctx.strokeStyle = '#2a1a00';
        ctx.lineWidth = 1;
        ctx.stroke();
        bitmap.drawText('Enemy', legendX + dotSize + 8, startY + lineHeight * 3 + 2, 80, 18, 'left');
        
        // Exit/Transfer marker (eerie green)
        ctx.fillStyle = '#7cfc00';
        ctx.beginPath();
        ctx.arc(legendX + dotSize/2, startY + lineHeight * 4 + dotSize/2 + 5, dotSize/2, 0, Math.PI * 2);
        ctx.fill();
        ctx.strokeStyle = '#2a1a00';
        ctx.lineWidth = 1;
        ctx.stroke();
        bitmap.drawText('Passage', legendX + dotSize + 8, startY + lineHeight * 4 + 2, 80, 18, 'left');
        
        // Position panel to the left of the map
        this._legendPanelOffset = 20;  // Gap between map and panel
        this._legendPanel.x = this._minimapOffsetX - panelWidth - this._legendPanelOffset;
        this._legendPanel.y = this._minimapOffsetY;
        
        this.addChild(this._legendPanel);
    };
    
    // Keep old function for compatibility
    Scene_Map.prototype.drawMinimapLegend = function() {
        // Now handled by createLegendPanel
    };
    
    Scene_Map.prototype.createExitDestinationsPanel = function(mapPixelWidth, mapPixelHeight) {
        if (exitLocations.length === 0) return;
        
        const lineHeight = 20;
        const padding = 15;
        const panelWidth = 280;
        const panelHeight = 35 + exitLocations.length * lineHeight + padding;
        
        // Create panel sprite
        this._exitDestinationsPanel = new Sprite();
        this._exitDestinationsPanel.bitmap = new Bitmap(panelWidth, panelHeight);
        
        const bitmap = this._exitDestinationsPanel.bitmap;
        const ctx = bitmap.context;
        
        // Draw background panel
        ctx.fillStyle = 'rgba(26, 20, 16, 0.9)';
        ctx.fillRect(0, 0, panelWidth, panelHeight);
        ctx.strokeStyle = '#8b7355';
        ctx.lineWidth = 2;
        ctx.strokeRect(0, 0, panelWidth, panelHeight);
        
        // Inner border
        ctx.strokeStyle = '#c9a959';
        ctx.lineWidth = 1;
        ctx.strokeRect(3, 3, panelWidth - 6, panelHeight - 6);
        
        bitmap.fontFace = 'GameFont';
        bitmap.fontSize = 14;
        bitmap.textColor = '#d4af37';
        bitmap.outlineColor = '#1a0a00';
        bitmap.outlineWidth = 3;
        
        // Title
        const titleY = 8;
        bitmap.drawText('~ Destinations ~', 0, titleY, panelWidth, 18, 'center');
        
        // Underline
        ctx.strokeStyle = '#8b7355';
        ctx.lineWidth = 1;
        ctx.beginPath();
        ctx.moveTo(padding, titleY + 22);
        ctx.lineTo(panelWidth - padding, titleY + 22);
        ctx.stroke();
        
        bitmap.fontSize = 12;
        bitmap.textColor = '#c9a959';
        
        // Draw each exit destination (no limit now)
        for (let i = 0; i < exitLocations.length; i++) {
            const exit = exitLocations[i];
            const y = 32 + i * lineHeight;
            
            // Draw number circle
            const circleX = padding + 10;
            const circleY = y + 9;
            ctx.fillStyle = '#7cfc00';
            ctx.shadowColor = '#7cfc00';
            ctx.shadowBlur = 3;
            ctx.beginPath();
            ctx.arc(circleX, circleY, 8, 0, Math.PI * 2);
            ctx.fill();
            ctx.shadowBlur = 0;
            ctx.strokeStyle = '#2a4a00';
            ctx.lineWidth = 1;
            ctx.stroke();
            
            // Draw number
            ctx.fillStyle = '#1a0a00';
            ctx.font = 'bold 10px GameFont';
            ctx.textAlign = 'center';
            ctx.textBaseline = 'middle';
            ctx.fillText(exit.number.toString(), circleX, circleY);
            ctx.textAlign = 'left';
            
            // Draw destination name (full name, no truncation)
            bitmap.drawText(exit.mapName, padding + 25, y, panelWidth - padding - 30, 18, 'left');
        }
        
        // Position panel to the right of the map
        this._exitPanelOffset = 20;  // Gap between map and panel
        this._exitDestinationsPanel.x = this._minimapOffsetX + mapPixelWidth * this._minimapScale + this._exitPanelOffset;
        this._exitDestinationsPanel.y = this._minimapOffsetY;
        
        this.addChild(this._exitDestinationsPanel);
    };
    
    // Keep old function for compatibility but redirect to new one
    Scene_Map.prototype.drawExitLegend = function() {
        // Now handled by createExitDestinationsPanel
    };
    
    Scene_Map.prototype.createExitMarkers = function() {
        this._exitMarkers = [];
        
        for (const exit of exitLocations) {
            const marker = new Sprite();
            marker.bitmap = new Bitmap(24, 24);
            
            const ctx = marker.bitmap.context;
            const cx = 12, cy = 12;
            
            // Draw green circle
            ctx.fillStyle = '#7cfc00';
            ctx.shadowColor = '#7cfc00';
            ctx.shadowBlur = 4;
            ctx.beginPath();
            ctx.arc(cx, cy, 10, 0, Math.PI * 2);
            ctx.fill();
            ctx.shadowBlur = 0;
            ctx.strokeStyle = '#2a4a00';
            ctx.lineWidth = 2;
            ctx.stroke();
            
            // Draw number
            ctx.fillStyle = '#1a0a00';
            ctx.font = 'bold 12px GameFont';
            ctx.textAlign = 'center';
            ctx.textBaseline = 'middle';
            ctx.fillText(exit.number.toString(), cx, cy);
            
            marker.anchor.x = 0.5;
            marker.anchor.y = 0.5;
            
            // Store exit data on marker for positioning
            marker._exitData = exit;
            
            this._exitMarkers.push(marker);
            this.addChild(marker);
        }
        
        this.updateExitMarkerPositions();
    };
    
    Scene_Map.prototype.updateExitMarkerPositions = function() {
        if (!this._exitMarkers) return;
        
        const offsetX = this._currentOffsetX || this._minimapOffsetX;
        const offsetY = this._currentOffsetY || this._minimapOffsetY;
        const scale = this._currentScale || this._minimapScale;
        
        for (const marker of this._exitMarkers) {
            const exit = marker._exitData;
            const markerX = offsetX + (exit.centerX + 0.5) * this._minimapTileWidth * scale;
            const markerY = offsetY + (exit.centerY + 0.5) * this._minimapTileHeight * scale;
            
            marker.x = markerX;
            marker.y = markerY;
            marker.scale.x = Math.max(0.5, minimapZoom * 0.8);
            marker.scale.y = Math.max(0.5, minimapZoom * 0.8);
        }
    };
    
    Scene_Map.prototype.renderMinimapTiles = function() {
        const mapWidth = $gameMap.width();
        const mapHeight = $gameMap.height();
        const tileWidth = $gameMap.tileWidth();
        const tileHeight = $gameMap.tileHeight();
        
        // Create bitmap for the map
        const bitmap = new Bitmap(mapWidth * tileWidth, mapHeight * tileHeight);
        this._minimapContent.bitmap = bitmap;
        
        // Get tileset
        const tileset = $gameMap.tileset();
        if (!tileset) return;
        
        // Dark fantasy color palette
        const wallColor = '#1a1410';        // Very dark brown/black for walls
        const floorColor = '#5a4f45';       // Lighter dusty floor (more contrast)
        const floorAltColor = '#4d4238';    // Floor variation
        
        // Simple tile rendering - draw colored rectangles based on passability
        for (let y = 0; y < mapHeight; y++) {
            for (let x = 0; x < mapWidth; x++) {
                const px = x * tileWidth;
                const py = y * tileHeight;
                
                // Check tile properties - use checkPassage for more accurate detection
                // checkPassage checks the actual tile bits rather than just directional passability
                const bit = 0x0f; // All directions
                const passage = $gameMap.checkPassage(x, y, bit);
                
                // Also check standard passability as backup
                const dirPassable = $gameMap.isPassable(x, y, 2) || 
                                    $gameMap.isPassable(x, y, 4) || 
                                    $gameMap.isPassable(x, y, 6) || 
                                    $gameMap.isPassable(x, y, 8);
                
                // Check if any tile at this location is a "void" tile (like pits)
                // by examining the actual tile IDs
                const tiles = $gameMap.allTiles(x, y);
                let hasFloorTile = false;
                
                // Look for actual floor/ground tiles
                // RPG Maker MZ Tileset Layout:
                // A1 (animated/water): 2048-2815 - water, waterfalls, poison swamps, lava
                // A2 (ground): 2816-4351 - grass, dirt, stone floors
                // A3 (buildings): 4352-5887 - roofs and building exteriors
                // A4 (walls): 5888-8191 - wall tops
                // A5 (normal tiles): 1536-1663 - simple ground tiles
                // B-E tiles: start at different offsets for decoration
                
                for (const tileId of tiles) {
                    if (tileId === 0) continue;
                    
                    // A5 tiles (simple ground): 1536-1663
                    if (tileId >= 1536 && tileId < 1664) {
                        hasFloorTile = true;
                        break;
                    }
                    // A1 tiles (water/animated - including poison, lava, swamps): 2048-2815
                    if (tileId >= 2048 && tileId < 2816) {
                        hasFloorTile = true;
                        break;
                    }
                    // A2 tiles (ground autotiles): 2816-4351
                    if (tileId >= 2816 && tileId < 4352) {
                        hasFloorTile = true;
                        break;
                    }
                    // B-E tiles can also be walkable floors (tile ID encoding varies)
                    // These are typically in lower ranges and used for details/overlays
                    // If a B-E tile is passable, it should be considered ground
                    if (tileId > 0 && tileId < 1536) {
                        // This is a B-E tile, check if it's passable via flags
                        const flags = $gameMap.tilesetFlags();
                        const flag = flags[tileId];
                        if (flag !== undefined && (flag & 0x10) === 0) {
                            // Not star passability (not an overlay) - could be floor
                            if ((flag & 0x0F) !== 0x0F) {
                                // Not fully blocked
                                hasFloorTile = true;
                                break;
                            }
                        }
                    }
                }
                
                // Consider passable only if: passage check passes AND has a floor tile
                // OR if standard directional passability says it's passable AND has floor
                const isPassable = (passage || dirPassable) && hasFloorTile;
                
                // Get terrain tag for variety
                const terrainTag = $gameMap.terrainTag(x, y);
                const regionId = $gameMap.regionId(x, y);
                
                // Color based on passability and terrain - dark fantasy palette
                let color;
                if (!isPassable) {
                    // Impassable - dark stone walls
                    color = wallColor;
                    // Add slight variation
                    if ((x * 7 + y * 13) % 5 === 0) {
                        color = '#352a24';
                    }
                } else if (terrainTag > 0) {
                    // Special terrain - different dungeon features
                    const terrainColors = [
                        '#3d4a3d',  // Mossy
                        '#4a4a3d',  // Sandy
                        '#3d3d4a',  // Damp stone
                        '#4a3d3d',  // Bloodstained
                        '#3d4a4a',  // Flooded
                        '#4a3d4a',  // Corrupted
                        '#4a4a4a'   // Ashen
                    ];
                    color = terrainColors[(terrainTag - 1) % terrainColors.length];
                } else {
                    // Normal passable floor - aged stone
                    color = (x + y) % 2 === 0 ? floorColor : floorAltColor;
                }
                
                // Add noise for texture
                const noise = ((x * 17 + y * 31) % 10) - 5;
                color = this.adjustColor(color, noise);
                
                bitmap.fillRect(px, py, tileWidth, tileHeight, color);
                
                // Draw subtle worn grid lines (like old stone tiles)
                const ctx = bitmap.context;
                ctx.strokeStyle = 'rgba(0, 0, 0, 0.15)';
                ctx.lineWidth = 1;
                ctx.strokeRect(px, py, tileWidth, tileHeight);
                
                // Add occasional cracks/details on floors
                if (isPassable && (x * 23 + y * 37) % 20 === 0) {
                    ctx.strokeStyle = 'rgba(0, 0, 0, 0.2)';
                    ctx.beginPath();
                    ctx.moveTo(px + 2, py + 2);
                    ctx.lineTo(px + tileWidth - 4, py + tileHeight - 4);
                    ctx.stroke();
                }
            }
        }
        
        // Draw important events as markers (except transfers - those are drawn as numbered markers separately)
        const revealAllMarkers = ConfigManager.minimapRevealAll;
        const fogOfWarEnabled = ConfigManager.minimapFogOfWar;
        const mapId = $gameMap.mapId();
        
        for (const event of $gameMap.events()) {
            if (!event) continue;
            
            const isExplored = $gameSystem.isTileExplored(mapId, event.x, event.y);
            const isEnemy = this.isEnemyEvent(event);
            
            // Enemies: visible if fog of war is off OR tile is explored
            // Other markers: visible if revealAll is on OR tile is explored
            if (isEnemy) {
                if (fogOfWarEnabled && !isExplored) continue;
            } else {
                if (!revealAllMarkers && !isExplored) continue;
            }
            
            const ex = event.x * tileWidth + tileWidth / 2;
            const ey = event.y * tileHeight + tileHeight / 2;
            const ctx = bitmap.context;
            const markerSize = Math.min(tileWidth, tileHeight) / 2.5;
            
            // Check event types in priority order
            if (this.isLockedDoorOrChest(event)) {
                // Draw locked door/chest marker (teal/mysterious)
                ctx.fillStyle = '#40e0d0';
                ctx.shadowColor = '#40e0d0';
                ctx.shadowBlur = 4;
                ctx.beginPath();
                ctx.arc(ex, ey, markerSize, 0, Math.PI * 2);
                ctx.fill();
                ctx.shadowBlur = 0;
                ctx.strokeStyle = '#1a3a3a';
                ctx.lineWidth = 2;
                ctx.stroke();
            } else if (this.isMapTransfer(event)) {
                // Skip - transfers are drawn as numbered markers by createExitMarkers()
            } else if (this.isEnemyEvent(event)) {
                // Draw enemy marker (blood red)
                ctx.fillStyle = '#dc143c';
                ctx.shadowColor = '#dc143c';
                ctx.shadowBlur = 4;
                ctx.beginPath();
                ctx.arc(ex, ey, markerSize, 0, Math.PI * 2);
                ctx.fill();
                ctx.shadowBlur = 0;
                ctx.strokeStyle = '#4a0a0a';
                ctx.lineWidth = 2;
                ctx.stroke();
            } else if (this.isImportantEvent(event)) {
                // Draw NPC marker (warm gold)
                ctx.fillStyle = '#daa520';
                ctx.shadowColor = '#daa520';
                ctx.shadowBlur = 3;
                ctx.beginPath();
                ctx.arc(ex, ey, markerSize, 0, Math.PI * 2);
                ctx.fill();
                ctx.shadowBlur = 0;
                ctx.strokeStyle = '#4a3500';
                ctx.lineWidth = 2;
                ctx.stroke();
            }
        }
        
        // Draw fog of war over unexplored areas (if enabled)
        if (ConfigManager.minimapFogOfWar) {
            this.drawFogOfWar(bitmap, mapWidth, mapHeight, tileWidth, tileHeight);
        }
    };
    
    Scene_Map.prototype.drawFogOfWar = function(bitmap, mapWidth, mapHeight, tileWidth, tileHeight) {
        const ctx = bitmap.context;
        const mapId = $gameMap.mapId();
        
        for (let y = 0; y < mapHeight; y++) {
            for (let x = 0; x < mapWidth; x++) {
                if (!$gameSystem.isTileExplored(mapId, x, y)) {
                    const px = x * tileWidth;
                    const py = y * tileHeight;
                    
                    // Draw dark fog
                    ctx.fillStyle = '#0a0806';
                    ctx.fillRect(px, py, tileWidth, tileHeight);
                    
                    // Add some texture/noise to the fog
                    if ((x + y) % 3 === 0) {
                        ctx.fillStyle = 'rgba(20, 15, 10, 0.5)';
                        ctx.fillRect(px, py, tileWidth, tileHeight);
                    }
                } else {
                    // Check for partially explored edges (adjacent to unexplored)
                    const hasUnexploredNeighbor = 
                        (x > 0 && !$gameSystem.isTileExplored(mapId, x - 1, y)) ||
                        (x < mapWidth - 1 && !$gameSystem.isTileExplored(mapId, x + 1, y)) ||
                        (y > 0 && !$gameSystem.isTileExplored(mapId, x, y - 1)) ||
                        (y < mapHeight - 1 && !$gameSystem.isTileExplored(mapId, x, y + 1));
                    
                    if (hasUnexploredNeighbor) {
                        // Draw subtle edge shadow
                        const px = x * tileWidth;
                        const py = y * tileHeight;
                        ctx.fillStyle = 'rgba(10, 8, 6, 0.3)';
                        ctx.fillRect(px, py, tileWidth, tileHeight);
                    }
                }
            }
        }
    };
    
    // Check if an event is a locked door, chest, or barred gate
    Scene_Map.prototype.isLockedDoorOrChest = function(event) {
        if (!event) return false;
        
        // Get the event data
        const eventData = event.event();
        if (!eventData) return false;
        
        const name = eventData.name;
        
        // Check for locked door patterns
        if (name.includes('鍵扉')) return true;  // "Locked door"
        
        // Check for chest patterns
        if (name.includes('宝箱')) return true;  // "Treasure chest"
        
        // Check for barred door/gate patterns (iron bars)
        if (name.includes('鉄格子')) return true;  // "Iron bars/Barred gate"
        
        // Check for barred/latch doors (opens from above/below pattern)
        if (name.includes('上から') && name.includes('下から')) return true;  // "From above... from below" latch doors
        
        return false;
    };
    
    // Check if an event transfers to another map
    Scene_Map.prototype.isMapTransfer = function(event) {
        if (!event) return false;
        
        // Get the event data
        const eventData = event.event();
        if (!eventData) return false;
        
        const name = eventData.name;
        
        // Check for transfer event name patterns
        if (name.includes('移動')) return true;  // "Transfer/Move"
        
        // Check the current page for Transfer Player command (code 201)
        const page = event.page();
        if (!page) return false;
        
        const list = page.list;
        if (!list) return false;
        
        for (const cmd of list) {
            if (cmd.code === 201) {  // Transfer Player command
                return true;
            }
        }
        
        return false;
    };
    
    // Check if an event is a locked door that can be picked (legacy - kept for compatibility)
    Scene_Map.prototype.isLockedDoor = function(event) {
        return this.isLockedDoorOrChest(event);
    };
    
    // Check if an event is an enemy (triggers battle)
    Scene_Map.prototype.isEnemyEvent = function(event) {
        if (!event) return false;
        
        // Get the current active page - if no page is active, event is not visible
        const page = event.page();
        if (!page) return false;
        
        // Must have a character graphic on the current page (enemy is visible)
        if (!page.image || !page.image.characterName) return false;
        
        // Get the event data
        const eventData = event.event();
        if (!eventData) return false;
        
        // Check for <EnemySymbol> tag in the event note (this game's primary enemy marker)
        const note = eventData.note || '';
        if (note.includes('<EnemySymbol>')) return true;
        
        // Check event name for specific enemy patterns used in this game
        const name = eventData.name;
        if (name.includes('エネミーシンボル')) return true;  // "Enemy Symbol"
        if (name.includes('ボス') && !name.includes('移動')) return true;  // "Boss" but not transfer events
        
        // Check the current page for Battle Processing command (code 301)
        const list = page.list;
        if (!list) return false;
        
        for (const cmd of list) {
            if (cmd.code === 301) {  // Battle Processing command
                return true;
            }
        }
        
        return false;
    };
    
    // Determine if an event is "important" (NPC, not decoration/ambient)
    Scene_Map.prototype.isImportantEvent = function(event) {
        if (!event) return false;
        
        // Must have a character graphic
        if (!event.characterName()) return false;
        
        // Get the event data
        const eventData = event.event();
        if (!eventData) return false;
        
        // Check the current page
        const page = event.page();
        if (!page) return false;
        
        // Skip if no trigger (parallel process/autorun without interaction)
        // Trigger types: 0=Action Button, 1=Player Touch, 2=Event Touch, 3=Autorun, 4=Parallel
        const trigger = page.trigger;
        
        // Only show Action Button (0) and Player Touch (1) - these are interactive NPCs
        if (trigger !== 0 && trigger !== 1) return false;
        
        // Skip common decoration/ambient event names
        const name = eventData.name.toLowerCase();
        const skipPatterns = [
            '窓', 'window',           // Windows
            '鳩', 'bird', 'pigeon',   // Birds
            '猫', 'cat',              // Cats  
            '犬', 'dog',              // Dogs
            'light', '灯', 'lamp',    // Lights
            'flame', '炎', 'fire',    // Fire effects
            'smoke', '煙',            // Smoke
            'effect', '効果',         // Effects
            'particle',               // Particles
            'ambient',                // Ambient
            'decor', '装飾',          // Decorations
            'bg', 'background',       // Background elements
            'fog', '霧',              // Fog
            'water', '水',            // Water effects
            'shadow', '影',           // Shadows
            'grass', '草',            // Grass
            'tree', '木',             // Trees
            'flower', '花',           // Flowers
            'rock', '岩',             // Rocks
            'sparkle', 'shine',       // Sparkle effects
            'animation', 'anim',      // Animations
        ];
        
        for (const pattern of skipPatterns) {
            if (name.includes(pattern)) return false;
        }
        
        // Skip events with very short command lists (likely just empty or simple triggers)
        const list = page.list;
        if (!list || list.length <= 2) return false;
        
        // Check if event has meaningful commands (text, choices, transfers, etc.)
        // Command codes: 101=Show Text, 102=Show Choices, 201=Transfer Player, 
        // 121=Control Switches, 122=Control Variables, 301=Battle Processing
        const meaningfulCodes = [101, 102, 103, 104, 105, 201, 301, 302, 303, 311, 312, 326];
        let hasMeaningfulCommand = false;
        
        for (const cmd of list) {
            if (meaningfulCodes.includes(cmd.code)) {
                hasMeaningfulCommand = true;
                break;
            }
        }
        
        return hasMeaningfulCommand;
    };
    
    Scene_Map.prototype.isTilePassable = function(x, y) {
        // First check: is this tile visually a "ceiling/void" tile?
        // These are often star-passable but should show as walls on minimap
        const tiles = $gameMap.allTiles(x, y);
        const flags = $gameMap.tilesetFlags();
        
        for (const tileId of tiles) {
            if (tileId === 0) continue;
            
            // A4 wall-top tiles (2048-2815) - these are wall tops/ceilings
            // A5 floor tiles start at 1536, A4 starts at 2048
            if (tileId >= 2048 && tileId < 2816) {
                // This is an A4 wall-top tile - treat as impassable for minimap
                return false;
            }
            
            // Check for tiles in the B-E range that have star passability
            // Star passable (0x10) tiles that are in upper layers are usually ceilings/walls
            if (tileId >= 256) { // B-E tiles
                const flag = flags[tileId];
                if (flag !== undefined && (flag & 0x10) !== 0) {
                    // Star passable - this is likely a ceiling tile, treat as wall
                    // Unless it's actually ground level
                    const layerTiles = $gameMap.layeredTiles(x, y);
                    if (layerTiles.length > 0 && layerTiles[0] === tileId) {
                        // This star tile is on the top layer - it's a ceiling/wall
                        return false;
                    }
                }
            }
        }
        
        // Check standard directional passability (all 4 directions)
        const passableDown = $gameMap.isPassable(x, y, 2);
        const passableLeft = $gameMap.isPassable(x, y, 4);
        const passableRight = $gameMap.isPassable(x, y, 6);
        const passableUp = $gameMap.isPassable(x, y, 8);
        
        // If any direction is passable, consider it a floor
        if (passableDown || passableLeft || passableRight || passableUp) {
            // But also check if there's a blocking event at this location
            const events = $gameMap.eventsXy(x, y);
            for (const event of events) {
                if (event && !event.isThrough() && event.isNormalPriority()) {
                    return false;
                }
            }
            return true;
        }
        
        return false;
    };
    
    Scene_Map.prototype.adjustColor = function(hex, amount) {
        // Simple color adjustment
        let r = parseInt(hex.slice(1, 3), 16);
        let g = parseInt(hex.slice(3, 5), 16);
        let b = parseInt(hex.slice(5, 7), 16);
        
        r = Math.min(255, Math.max(0, r + amount));
        g = Math.min(255, Math.max(0, g + amount));
        b = Math.min(255, Math.max(0, b + amount));
        
        return '#' + r.toString(16).padStart(2, '0') + 
                     g.toString(16).padStart(2, '0') + 
                     b.toString(16).padStart(2, '0');
    };
    
    Scene_Map.prototype.createMinimapPlayerMarker = function() {
        if (this._minimapPlayerMarker) return;
        
        // Create player marker sprite - mystical/atmospheric style
        this._minimapPlayerMarker = new Sprite();
        this._minimapPlayerMarker.bitmap = new Bitmap(36, 36);
        
        const ctx = this._minimapPlayerMarker.bitmap.context;
        const cx = 18, cy = 18;
        
        // Ethereal outer glow - deep crimson
        const outerGlow = ctx.createRadialGradient(cx, cy, 0, cx, cy, 16);
        outerGlow.addColorStop(0, 'rgba(139, 69, 19, 0)');
        outerGlow.addColorStop(0.5, 'rgba(139, 69, 19, 0.3)');
        outerGlow.addColorStop(1, 'rgba(139, 69, 19, 0)');
        ctx.fillStyle = outerGlow;
        ctx.beginPath();
        ctx.arc(cx, cy, 16, 0, Math.PI * 2);
        ctx.fill();
        
        // Main marker - mystical blood red
        const mainGrad = ctx.createRadialGradient(cx, cy, 0, cx, cy, 10);
        mainGrad.addColorStop(0, '#c41e3a');
        mainGrad.addColorStop(0.7, '#8b0000');
        mainGrad.addColorStop(1, '#4a0000');
        ctx.fillStyle = mainGrad;
        ctx.beginPath();
        ctx.arc(cx, cy, 10, 0, Math.PI * 2);
        ctx.fill();
        
        // Inner glow - warm amber
        const innerGrad = ctx.createRadialGradient(cx, cy, 0, cx, cy, 6);
        innerGrad.addColorStop(0, '#ffd700');
        innerGrad.addColorStop(0.5, '#daa520');
        innerGrad.addColorStop(1, '#b8860b');
        ctx.fillStyle = innerGrad;
        ctx.beginPath();
        ctx.arc(cx, cy, 6, 0, Math.PI * 2);
        ctx.fill();
        
        // Center soul light
        ctx.fillStyle = '#fff8dc';
        ctx.beginPath();
        ctx.arc(cx, cy, 2, 0, Math.PI * 2);
        ctx.fill();
        
        this._minimapPlayerMarker.anchor.x = 0.5;
        this._minimapPlayerMarker.anchor.y = 0.5;
        
        this.addChild(this._minimapPlayerMarker);
        this.updateMinimapPlayerMarker();
    };
    
    Scene_Map.prototype.updateMinimapPlayerMarker = function() {
        if (!this._minimapPlayerMarker) return;
        
        const playerX = $gamePlayer.x;
        const playerY = $gamePlayer.y;
        
        // Use current transform offsets for zoom/pan support
        const offsetX = this._currentOffsetX || this._minimapOffsetX;
        const offsetY = this._currentOffsetY || this._minimapOffsetY;
        const scale = this._currentScale || this._minimapScale;
        
        // Calculate marker position
        const markerX = offsetX + (playerX + 0.5) * this._minimapTileWidth * scale;
        const markerY = offsetY + (playerY + 0.5) * this._minimapTileHeight * scale;
        
        this._minimapPlayerMarker.x = markerX;
        this._minimapPlayerMarker.y = markerY;
        
        // Pulse effect with zoom scaling
        const pulse = Math.sin(Graphics.frameCount * 0.1) * 0.2 + 1;
        const zoomScale = Math.max(0.5, minimapZoom * 0.8);
        this._minimapPlayerMarker.scale.x = pulse * zoomScale;
        this._minimapPlayerMarker.scale.y = pulse * zoomScale;
    };
    
    Scene_Map.prototype.removeMinimapOverlay = function() {
        if (this._minimapOverlay) {
            this.removeChild(this._minimapOverlay);
            this._minimapOverlay = null;
        }
        if (this._minimapBorder) {
            this.removeChild(this._minimapBorder);
            this._minimapBorder = null;
        }
        if (this._minimapContent) {
            this.removeChild(this._minimapContent);
            this._minimapContent = null;
        }
        if (this._minimapPlayerMarker) {
            this.removeChild(this._minimapPlayerMarker);
            this._minimapPlayerMarker = null;
        }
        if (this._exitMarkers) {
            for (const marker of this._exitMarkers) {
                this.removeChild(marker);
            }
            this._exitMarkers = null;
        }
        if (this._exitDestinationsPanel) {
            this.removeChild(this._exitDestinationsPanel);
            this._exitDestinationsPanel = null;
        }
        if (this._legendPanel) {
            this.removeChild(this._legendPanel);
            this._legendPanel = null;
        }
        if (this._titlePanel) {
            this.removeChild(this._titlePanel);
            this._titlePanel = null;
        }
        if (this._controlsPanel) {
            this.removeChild(this._controlsPanel);
            this._controlsPanel = null;
        }
    };
    
    //=========================================================================
    // Handle scene transitions - Reset minimap when leaving map
    //=========================================================================
    
    const _Scene_Map_terminate = Scene_Map.prototype.terminate;
    Scene_Map.prototype.terminate = function() {
        if (minimapActive) {
            this.hideMinimap();
            minimapActive = false;
        }
        _Scene_Map_terminate.call(this);
    };
    
    //=========================================================================
    // Prevent menu/actions while minimap is active
    //=========================================================================
    
    const _Scene_Map_isMenuEnabled = Scene_Map.prototype.isMenuEnabled;
    Scene_Map.prototype.isMenuEnabled = function() {
        if (minimapActive) return false;
        return _Scene_Map_isMenuEnabled.call(this);
    };
    
    const _Scene_Map_isMapTouchOk = Scene_Map.prototype.isMapTouchOk;
    Scene_Map.prototype.isMapTouchOk = function() {
        if (minimapActive) return false;
        return _Scene_Map_isMapTouchOk.call(this);
    };
    
    const _Game_Player_canMove = Game_Player.prototype.canMove;
    Game_Player.prototype.canMove = function() {
        if (minimapActive) return false;
        return _Game_Player_canMove.call(this);
    };
    
    // Public accessor for minimap state
    Scene_Map.prototype.isMinimapActive = function() {
        return minimapActive;
    };
    
})();
