import random
import math
import noise

class EnhancedStructureGenerator:
    def __init__(self, game):
        self.game = game
        self.CHUNK_SIZE = game.CHUNK_SIZE if hasattr(game, 'CHUNK_SIZE') else 16
        
        # Block palette for different structure types
        self.palettes = {
            'noble': {
                'primary_wall': ['castle_wall', 'brick', 'stone'],
                'secondary_wall': ['castle_wall_outer', 'marble'],
                'floor': ['castle_floor', 'marble'],
                'roof': ['tower_top', 'gold', 'roof'],
                'decoration': ['castle_ornament', 'lantern', 'banner_blue']
            },
            'common': {
                'primary_wall': ['wood', 'brick', 'cobblestone'],
                'secondary_wall': ['wood', 'stone'],
                'floor': ['wood', 'dirt', 'stone'],
                'roof': ['roof', 'wood'],
                'decoration': ['lantern', 'banner_red']
            },
            'service': {
                'primary_wall': ['stone', 'brick', 'wood'],
                'secondary_wall': ['cobblestone', 'wood'],
                'floor': ['stone', 'dirt'],
                'roof': ['wood', 'roof'],
                'decoration': ['lantern']
            },
            'magical': {
                'primary_wall': ['obsidian', 'castle_wall'],
                'secondary_wall': ['marble', 'obsidian'],
                'floor': ['obsidian', 'marble'],
                'roof': ['gold', 'tower_top'],
                'decoration': ['lantern', 'royal_tapestry', 'banner_blue', 'banner_red']
            },
            'military': {
                'primary_wall': ['castle_wall_outer', 'stone', 'cobblestone'],
                'secondary_wall': ['stone', 'castle_wall'],
                'floor': ['stone', 'castle_floor'],
                'roof': ['tower_top', 'stone'],
                'decoration': ['lantern', 'banner_blue', 'banner_red']
            }
        }
        
        # Structure generation tracking
        self.generated_structures = {}
    
    def choose_from_palette(self, structure_type, element):
        """Choose a random block from the palette for a given structure type and element"""
        if structure_type in self.palettes and element in self.palettes[structure_type]:
            return random.choice(self.palettes[structure_type][element])
        return 'stone'  # Default fallback
    
    def generate_enhanced_castle(self, chunk):
        """Generate a more complex castle with multiple towers, courtyards, and decorative elements"""
        # Determine castle size and complexity
        castle_size = random.randint(8, 14)
        num_towers = random.randint(4, 8)
        has_moat = random.random() < 0.7
        has_dungeon = random.random() < 0.9
        has_grand_hall = random.random() < 0.8
        
        # Determine castle style
        castle_style = random.choice(['noble', 'military', 'magical'])
        
        # Find a suitable position
        start_x = random.randint(2, self.CHUNK_SIZE - castle_size - 2)
        start_y = random.randint(2, self.CHUNK_SIZE - castle_size - 2)
        
        # Generate base terrain
        self._prepare_castle_terrain(chunk, start_x, start_y, castle_size, has_moat)
        
        # Build main castle structure
        structure_id = self._build_castle_main(chunk, start_x, start_y, castle_size, castle_style)
        
        # Add towers
        tower_positions = self._add_castle_towers(chunk, start_x, start_y, castle_size, num_towers, castle_style)
        
        # Add inner buildings
        if has_grand_hall:
            self._add_castle_grand_hall(chunk, start_x, start_y, castle_size, castle_style)
        
        # Add underground levels if applicable
        underground_levels = []
        if has_dungeon:
            underground_levels = self._add_castle_dungeon(chunk, start_x, start_y, castle_size, castle_style)
        
        # Add decorative elements throughout
        self._decorate_castle(chunk, start_x, start_y, castle_size, castle_style)
        
        # Add roads leading to castle
        self._add_castle_roads(chunk, start_x, start_y, castle_size)
        
        # Store castle data for future reference
        self.generated_structures[structure_id] = {
            'type': 'castle',
            'style': castle_style,
            'x': start_x,
            'y': start_y,
            'size': castle_size,
            'towers': tower_positions,
            'underground': underground_levels,
            'has_moat': has_moat
        }
        
        return structure_id
    
    def _prepare_castle_terrain(self, chunk, start_x, start_y, castle_size, has_moat):
        """Prepare and level terrain for castle construction"""
        moat_width = 3 if has_moat else 0
        area_size = castle_size + 2 * moat_width + 4  # Extra space for surroundings
        
        # Level the area
        for x in range(area_size):
            for y in range(area_size):
                check_x = start_x - moat_width - 2 + x
                check_y = start_y - moat_width - 2 + y
                
                # Skip if out of bounds
                if not (0 <= check_x < self.CHUNK_SIZE and 0 <= check_y < self.CHUNK_SIZE):
                    continue
                
                # Determine terrain type
                if has_moat and (
                    moat_width <= x < area_size - moat_width and
                    moat_width <= y < area_size - moat_width and
                    (x < moat_width + 2 or x >= area_size - moat_width - 2 or
                     y < moat_width + 2 or y >= area_size - moat_width - 2)
                ):
                    # Create moat
                    chunk[check_y][check_x] = 'moat_water'
                elif moat_width + 2 <= x < area_size - moat_width - 2 and moat_width + 2 <= y < area_size - moat_width - 2:
                    # Inside castle walls - set to flat ground
                    chunk[check_y][check_x] = 'castle_floor'
                else:
                    # Surrounding terrain - leave natural or create approach
                    if random.random() < 0.4:
                        chunk[check_y][check_x] = 'grass'
    
    def _build_castle_main(self, chunk, start_x, start_y, castle_size, castle_style):
        """Build the main castle structure with walls, gatehouses, and keeps"""
        # Generate a unique ID for this castle
        structure_id = f"castle_{start_x}_{start_y}_{random.randint(1000, 9999)}"
        
        # Choose blocks from palette
        wall_block = self.choose_from_palette(castle_style, 'primary_wall')
        inner_wall_block = self.choose_from_palette(castle_style, 'secondary_wall')
        floor_block = self.choose_from_palette(castle_style, 'floor')
        
        # Build outer walls with crenellations and variable thickness
        wall_thickness = random.randint(1, 2)
        for x in range(castle_size):
            for y in range(castle_size):
                check_x = start_x + x
                check_y = start_y + y
                
                # Skip if out of bounds
                if not (0 <= check_x < self.CHUNK_SIZE and 0 <= check_y < self.CHUNK_SIZE):
                    continue
                
                # Check if we're at a wall position
                is_outer_edge = (x < wall_thickness or x >= castle_size - wall_thickness or 
                                y < wall_thickness or y >= castle_size - wall_thickness)
                
                if is_outer_edge:
                    # Main walls
                    chunk[check_y][check_x] = wall_block
                    
                    # Add crenellations on top edges
                    if (x == 0 or x == castle_size - 1 or y == 0 or y == castle_size - 1) and random.random() < 0.3:
                        # Place something on top of the wall (would be a block above in 3D)
                        pass
                else:
                    # Interior courtyard
                    chunk[check_y][check_x] = floor_block
        
        # Add gatehouse
        gate_side = random.choice(['north', 'east', 'south', 'west'])
        gate_pos = castle_size // 2
        
        if gate_side == 'north':
            for i in range(wall_thickness):
                gate_x = start_x + gate_pos
                gate_y = start_y + i
                chunk[gate_y][gate_x] = 'castle_door' if i == wall_thickness - 1 else 'air'
                
                # Add gatehouse structure
                for dx in [-1, 0, 1]:
                    for dy in [-2, -1, 0]:
                        check_x = gate_x + dx
                        check_y = gate_y + dy
                        if 0 <= check_x < self.CHUNK_SIZE and 0 <= check_y < self.CHUNK_SIZE:
                            # Don't overwrite the gate itself
                            if not (dx == 0 and dy == 0):
                                chunk[check_y][check_x] = wall_block
        elif gate_side == 'east':
            for i in range(wall_thickness):
                gate_x = start_x + castle_size - 1 - i
                gate_y = start_y + gate_pos
                chunk[gate_y][gate_x] = 'castle_door' if i == wall_thickness - 1 else 'air'
                
                # Add gatehouse structure
                for dx in [0, 1, 2]:
                    for dy in [-1, 0, 1]:
                        check_x = gate_x + dx
                        check_y = gate_y + dy
                        if 0 <= check_x < self.CHUNK_SIZE and 0 <= check_y < self.CHUNK_SIZE:
                            if not (dx == 0 and dy == 0):
                                chunk[check_y][check_x] = wall_block
        elif gate_side == 'south':
            for i in range(wall_thickness):
                gate_x = start_x + gate_pos
                gate_y = start_y + castle_size - 1 - i
                chunk[gate_y][gate_x] = 'castle_door' if i == wall_thickness - 1 else 'air'
                
                # Add gatehouse structure
                for dx in [-1, 0, 1]:
                    for dy in [0, 1, 2]:
                        check_x = gate_x + dx
                        check_y = gate_y + dy
                        if 0 <= check_x < self.CHUNK_SIZE and 0 <= check_y < self.CHUNK_SIZE:
                            if not (dx == 0 and dy == 0):
                                chunk[check_y][check_x] = wall_block
        else:  # west
            for i in range(wall_thickness):
                gate_x = start_x + i
                gate_y = start_y + gate_pos
                chunk[gate_y][gate_x] = 'castle_door' if i == wall_thickness - 1 else 'air'
                
                # Add gatehouse structure
                for dx in [-2, -1, 0]:
                    for dy in [-1, 0, 1]:
                        check_x = gate_x + dx
                        check_y = gate_y + dy
                        if 0 <= check_x < self.CHUNK_SIZE and 0 <= check_y < self.CHUNK_SIZE:
                            if not (dx == 0 and dy == 0):
                                chunk[check_y][check_x] = wall_block
        
        # Add drawbridge if there's a moat
        if chunk[start_y + gate_pos - 1][start_x - 1] == 'moat_water':  # Check if there's water outside
            # This would depend on gate direction but simplified here
            bridge_length = 3
            for i in range(bridge_length):
                bridge_x = start_x - 1 - i
                bridge_y = start_y + gate_pos
                if 0 <= bridge_x < self.CHUNK_SIZE and 0 <= bridge_y < self.CHUNK_SIZE:
                    chunk[bridge_y][bridge_x] = 'drawbridge'
        
        # Add inner keep
        keep_size = castle_size // 3
        keep_x = start_x + (castle_size - keep_size) // 2
        keep_y = start_y + (castle_size - keep_size) // 2
        
        # Build keep
        for x in range(keep_size):
            for y in range(keep_size):
                check_x = keep_x + x
                check_y = keep_y + y
                
                if 0 <= check_x < self.CHUNK_SIZE and 0 <= check_y < self.CHUNK_SIZE:
                    if x == 0 or x == keep_size - 1 or y == 0 or y == keep_size - 1:
                        chunk[check_y][check_x] = inner_wall_block
                    else:
                        # Keep interior
                        chunk[check_y][check_x] = floor_block
        
        # Add keep entrance
        door_side = random.choice(['north', 'east', 'south', 'west'])
        door_pos = keep_size // 2
        
        if door_side == 'north':
            chunk[keep_y][keep_x + door_pos] = 'castle_door'
        elif door_side == 'east':
            chunk[keep_y + door_pos][keep_x + keep_size - 1] = 'castle_door'
        elif door_side == 'south':
            chunk[keep_y + keep_size - 1][keep_x + door_pos] = 'castle_door'
        else:  # west
            chunk[keep_y + door_pos][keep_x] = 'castle_door'
        
        # Add ladder to dungeon in the keep
        ladder_x = keep_x + keep_size // 2
        ladder_y = keep_y + keep_size // 2
        if 0 <= ladder_x < self.CHUNK_SIZE and 0 <= ladder_y < self.CHUNK_SIZE:
            chunk[ladder_y][ladder_x] = 'ladder_down'
        
        return structure_id
    
    def _add_castle_towers(self, chunk, start_x, start_y, castle_size, num_towers, castle_style):
        """Add various towers to the castle corners and walls"""
        # Choose blocks from palette
        wall_block = self.choose_from_palette(castle_style, 'primary_wall')
        roof_block = self.choose_from_palette(castle_style, 'roof')
        
        # Determine tower positions (start with corners)
        tower_positions = []
        
        # Add corner towers
        corners = [
            (start_x, start_y),  # NW
            (start_x + castle_size - 1, start_y),  # NE
            (start_x, start_y + castle_size - 1),  # SW
            (start_x + castle_size - 1, start_y + castle_size - 1)  # SE
        ]
        
        for tx, ty in corners:
            # Determine tower size and shape
            tower_type = random.choice(['round', 'square', 'octagonal'])
            tower_size = random.randint(3, 5)
            
            # Build tower
            if tower_type == 'round':
                self._build_round_tower(chunk, tx, ty, tower_size, wall_block, roof_block)
            elif tower_type == 'square':
                self._build_square_tower(chunk, tx, ty, tower_size, wall_block, roof_block)
            else:
                self._build_octagonal_tower(chunk, tx, ty, tower_size, wall_block, roof_block)
            
            tower_positions.append((tx, ty, tower_type, tower_size))
        
        # Add additional towers along walls if requested
        remaining_towers = num_towers - 4
        if remaining_towers > 0:
            # Positions along walls
            wall_positions = []
            
            # North wall
            for i in range(castle_size // 4, castle_size - castle_size // 4, castle_size // 4):
                wall_positions.append((start_x + i, start_y))
            
            # East wall
            for i in range(castle_size // 4, castle_size - castle_size // 4, castle_size // 4):
                wall_positions.append((start_x + castle_size - 1, start_y + i))
            
            # South wall
            for i in range(castle_size // 4, castle_size - castle_size // 4, castle_size // 4):
                wall_positions.append((start_x + i, start_y + castle_size - 1))
            
            # West wall
            for i in range(castle_size // 4, castle_size - castle_size // 4, castle_size // 4):
                wall_positions.append((start_x, start_y + i))
            
            # Shuffle and select
            random.shuffle(wall_positions)
            for i in range(min(remaining_towers, len(wall_positions))):
                tx, ty = wall_positions[i]
                
                # Determine tower size and shape
                tower_type = random.choice(['round', 'square'])
                tower_size = random.randint(2, 4)
                
                # Build tower
                if tower_type == 'round':
                    self._build_round_tower(chunk, tx, ty, tower_size, wall_block, roof_block)
                else:
                    self._build_square_tower(chunk, tx, ty, tower_size, wall_block, roof_block)
                
                tower_positions.append((tx, ty, tower_type, tower_size))
        
        return tower_positions
    
    def _build_round_tower(self, chunk, center_x, center_y, radius, wall_block, roof_block):
        """Build a round tower"""
        for dx in range(-radius, radius + 1):
            for dy in range(-radius, radius + 1):
                x = center_x + dx
                y = center_y + dy
                
                # Skip if out of bounds
                if not (0 <= x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE):
                    continue
                
                # Calculate distance from center
                distance = math.sqrt(dx*dx + dy*dy)
                
                if distance <= radius:
                    # Interior
                    if distance > radius - 1:
                        # Wall
                        chunk[y][x] = wall_block
                    else:
                        # Floor
                        chunk[y][x] = 'castle_floor'
                
                # Add roof/battlements
                if radius - 1 < distance <= radius and random.random() < 0.4:
                    chunk[y][x] = roof_block
        
        # Add light
        chunk[center_y][center_x] = 'lantern'
    
    def _build_square_tower(self, chunk, corner_x, corner_y, size, wall_block, roof_block):
        """Build a square tower"""
        for dx in range(size):
            for dy in range(size):
                x = corner_x + dx - size//2
                y = corner_y + dy - size//2
                
                # Skip if out of bounds
                if not (0 <= x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE):
                    continue
                
                if dx == 0 or dx == size - 1 or dy == 0 or dy == size - 1:
                    chunk[y][x] = wall_block
                    
                    # Add battlements
                    if random.random() < 0.4:
                        # Would be a block above in 3D
                        chunk[y][x] = roof_block
                else:
                    chunk[y][x] = 'castle_floor'
        
        # Add light
        center_x = corner_x - size//2 + size//2
        center_y = corner_y - size//2 + size//2
        if 0 <= center_x < self.CHUNK_SIZE and 0 <= center_y < self.CHUNK_SIZE:
            chunk[center_y][center_x] = 'lantern'
    
    def _build_octagonal_tower(self, chunk, center_x, center_y, radius, wall_block, roof_block):
        """Build an octagonal tower"""
        for dx in range(-radius, radius + 1):
            for dy in range(-radius, radius + 1):
                x = center_x + dx
                y = center_y + dy
                
                # Skip if out of bounds
                if not (0 <= x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE):
                    continue
                
                # Calculate Manhattan distance for octagonal shape
                dist = abs(dx) + abs(dy)
                
                if dist <= radius + 1:
                    if dist > radius - 1:
                        # Wall
                        chunk[y][x] = wall_block
                        
                        # Add battlements
                        if dist == radius + 1 and random.random() < 0.4:
                            chunk[y][x] = roof_block
                    else:
                        # Floor
                        chunk[y][x] = 'castle_floor'
        
        # Add light
        chunk[center_y][center_x] = 'lantern'
    
    def _add_castle_grand_hall(self, chunk, start_x, start_y, castle_size, castle_style):
        """Add a grand hall to the castle interior"""
        # Calculate hall position and size
        hall_width = max(3, castle_size // 3)
        hall_length = max(5, castle_size // 2)
        
        # Position in the center of the courtyard
        hall_x = start_x + (castle_size - hall_width) // 2
        hall_y = start_y + (castle_size - hall_length) // 2
        
        # Choose blocks from palette
        wall_block = self.choose_from_palette(castle_style, 'secondary_wall')
        floor_block = self.choose_from_palette(castle_style, 'floor')
        roof_block = self.choose_from_palette(castle_style, 'roof')
        
        # Build hall structure
        for x in range(hall_width):
            for y in range(hall_length):
                check_x = hall_x + x
                check_y = hall_y + y
                
                # Skip if out of bounds
                if not (0 <= check_x < self.CHUNK_SIZE and 0 <= check_y < self.CHUNK_SIZE):
                    continue
                
                # Walls
                if x == 0 or x == hall_width - 1 or y == 0 or y == hall_length - 1:
                    chunk[check_y][check_x] = wall_block
                else:
                    # Floor
                    chunk[check_y][check_x] = floor_block
        
        # Add roof
        for x in range(hall_width):
            for y in range(hall_length):
                check_x = hall_x + x
                check_y = hall_y + y
                
                # Skip if out of bounds or on walls
                if not (0 <= check_x < self.CHUNK_SIZE and 0 <= check_y < self.CHUNK_SIZE):
                    continue
                
                # Add decorative roof
                if (x == 0 or x == hall_width - 1 or y == 0 or y == hall_length - 1) and random.random() < 0.5:
                    # Would be above the wall in 3D
                    chunk[check_y][check_x] = roof_block
        
        # Add entrance door
        door_side = random.choice(['north', 'east', 'south', 'west'])
        
        if door_side == 'north':
            door_x = hall_x + hall_width // 2
            door_y = hall_y
            chunk[door_y][door_x] = 'castle_door'
        elif door_side == 'east':
            door_x = hall_x + hall_width - 1
            door_y = hall_y + hall_length // 2
            chunk[door_y][door_x] = 'castle_door'
        elif door_side == 'south':
            door_x = hall_x + hall_width // 2
            door_y = hall_y + hall_length - 1
            chunk[door_y][door_x] = 'castle_door'
        else:  # west
            door_x = hall_x
            door_y = hall_y + hall_length // 2
            chunk[door_y][door_x] = 'castle_door'
        
        # Add throne
        throne_x = hall_x + hall_width // 2
        throne_y = hall_y + hall_length - 2
        if 0 <= throne_x < self.CHUNK_SIZE and 0 <= throne_y < self.CHUNK_SIZE:
            chunk[throne_y][throne_x] = 'throne'
        
        # Add carpet
        for y in range(1, hall_length - 1):
            carpet_x = hall_x + hall_width // 2
            carpet_y = hall_y + y
            if 0 <= carpet_x < self.CHUNK_SIZE and 0 <= carpet_y < self.CHUNK_SIZE:
                chunk[carpet_y][carpet_x] = 'royal_carpet'
        
        # Add lights
        for i in range(1, hall_length - 1, 2):
            for j in [-1, 1]:
                light_x = hall_x + hall_width // 2 + j
                light_y = hall_y + i
                if (0 <= light_x < self.CHUNK_SIZE and 0 <= light_y < self.CHUNK_SIZE and
                    chunk[light_y][light_x] == floor_block):
                    chunk[light_y][light_x] = 'lantern'
    
    def _add_castle_dungeon(self, chunk, start_x, start_y, castle_size, castle_style):
        """Add dungeon markings to represent underground levels"""
        # In a real 3D game, we would generate multiple underground levels
        # Here we'll just mark the entrances and simulate it
        
        # Determine dungeon depth
        dungeon_levels = random.randint(1, 3)
        dungeon_entrances = []
        
        # Main entrance in the keep
        keep_size = castle_size // 3
        keep_x = start_x + (castle_size - keep_size) // 2
        keep_y = start_y + (castle_size - keep_size) // 2
        
        main_entrance_x = keep_x + keep_size // 2
        main_entrance_y = keep_y + keep_size // 2
        
        if 0 <= main_entrance_x < self.CHUNK_SIZE and 0 <= main_entrance_y < self.CHUNK_SIZE:
            # Already placed ladder_down in the keep building
            dungeon_entrances.append((main_entrance_x, main_entrance_y, 'main'))
        
        # Add secret entrances
        num_secret = random.randint(0, 2)
        for _ in range(num_secret):
            # Pick a random location in the castle
            secret_x = start_x + random.randint(2, castle_size - 3)
            secret_y = start_y + random.randint(2, castle_size - 3)
            
            # Make sure it doesn't conflict with other structures
            while (chunk[secret_y][secret_x] != 'castle_floor' and 
                   abs(secret_x - main_entrance_x) + abs(secret_y - main_entrance_y) < 5):
                secret_x = start_x + random.randint(2, castle_size - 3)
                secret_y = start_y + random.randint(2, castle_size - 3)
            
            if 0 <= secret_x < self.CHUNK_SIZE and 0 <= secret_y < self.CHUNK_SIZE:
                chunk[secret_y][secret_x] = 'ladder_down'
                dungeon_entrances.append((secret_x, secret_y, 'secret'))
        
        # Return info for underground levels
        return [{'level': i+1, 'entrances': dungeon_entrances} for i in range(dungeon_levels)]
    
    def _decorate_castle(self, chunk, start_x, start_y, castle_size, castle_style):
        """Add decorative elements throughout the castle"""
        # Choose decorative blocks from palette
        decor_block = self.choose_from_palette(castle_style, 'decoration')
        
        # Add tapestries and banners along walls
        for x in range(castle_size):
            for y in range(castle_size):
                check_x = start_x + x
                check_y = start_y + y
                
                # Skip if out of bounds
                if not (0 <= check_x < self.CHUNK_SIZE and 0 <= check_y < self.CHUNK_SIZE):
                    continue
                
                # Check for walls to decorate
                if chunk[check_y][check_x] in ['castle_wall', 'castle_wall_outer', 'brick', 'stone']:
                    # Check if there's open space next to the wall
                    for dx, dy in [(0, 1), (1, 0), (0, -1), (-1, 0)]:
                        neighbor_x = check_x + dx
                        neighbor_y = check_y + dy
                        
                        if (0 <= neighbor_x < self.CHUNK_SIZE and 0 <= neighbor_y < self.CHUNK_SIZE and
                            chunk[neighbor_y][neighbor_x] in ['castle_floor', 'air']):
                            
                            # 15% chance for decoration
                            if random.random() < 0.15:
                                # Place decoration
                                chunk[neighbor_y][neighbor_x] = decor_block
                                break
        
        # Add lights in corners and along pathways
        for x in range(1, castle_size - 1):
            for y in range(1, castle_size - 1):
                check_x = start_x + x
                check_y = start_y + y
                
                # Skip if out of bounds
                if not (0 <= check_x < self.CHUNK_SIZE and 0 <= check_y < self.CHUNK_SIZE):
                    continue
                
                # Check for strategic positions for lights
                is_corner = False
                is_pathway = False

# Check for corner position
                wall_count = 0
                for dx, dy in [(0, 1), (1, 0), (0, -1), (-1, 0)]:
                    neighbor_x = check_x + dx
                    neighbor_y = check_y + dy
                    
                    if (0 <= neighbor_x < self.CHUNK_SIZE and 0 <= neighbor_y < self.CHUNK_SIZE and
                        chunk[neighbor_y][neighbor_x] in ['castle_wall', 'castle_wall_outer', 'brick', 'stone']):
                        wall_count += 1
                
                is_corner = wall_count >= 2
                
                # Check for pathway
                floor_count = 0
                for dx, dy in [(0, 1), (1, 0), (0, -1), (-1, 0)]:
                    neighbor_x = check_x + dx
                    neighbor_y = check_y + dy
                    
                    if (0 <= neighbor_x < self.CHUNK_SIZE and 0 <= neighbor_y < self.CHUNK_SIZE and
                        chunk[neighbor_y][neighbor_x] == 'castle_floor'):
                        floor_count += 1
                
                is_pathway = floor_count >= 3
                
                # Place light if appropriate
                if (is_corner or is_pathway) and chunk[check_y][check_x] == 'castle_floor' and random.random() < 0.4:
                    chunk[check_y][check_x] = 'lantern'
    
    def _add_castle_roads(self, chunk, start_x, start_y, castle_size):
        """Add roads leading to and around the castle"""
        # Determine main gate position
        gates = []
        
        # Check for gates (doors on outer wall)
        for x in range(castle_size):
            # North wall
            if chunk[start_y][start_x + x] == 'castle_door':
                gates.append(('north', start_x + x, start_y))
            
            # South wall
            if chunk[start_y + castle_size - 1][start_x + x] == 'castle_door':
                gates.append(('south', start_x + x, start_y + castle_size - 1))
        
        for y in range(castle_size):
            # West wall
            if chunk[start_y + y][start_x] == 'castle_door':
                gates.append(('west', start_x, start_y + y))
            
            # East wall
            if chunk[start_y + y][start_x + castle_size - 1] == 'castle_door':
                gates.append(('east', start_x + castle_size - 1, start_y + y))
        
        # If no gates found, don't add roads
        if not gates:
            return
        
        # Add roads leading from each gate
        for direction, gate_x, gate_y in gates:
            # Determine road length and width
            road_length = random.randint(10, 20)
            road_width = random.randint(2, 3)
            
            # Set road direction
            dx, dy = 0, 0
            if direction == 'north':
                dy = -1
            elif direction == 'east':
                dx = 1
            elif direction == 'south':
                dy = 1
            else:  # west
                dx = -1
            
            # Create main road
            for i in range(1, road_length + 1):
                road_x = gate_x + dx * i
                road_y = gate_y + dy * i
                
                # Skip if out of bounds
                if not (0 <= road_x < self.CHUNK_SIZE and 0 <= road_y < self.CHUNK_SIZE):
                    continue
                
                # Main road path
                chunk[road_y][road_x] = 'cobblestone'
                
                # Road width
                for w in range(1, road_width):
                    if dx == 0:  # North/South road
                        width_x = road_x + w
                        width_y = road_y
                    else:  # East/West road
                        width_x = road_x
                        width_y = road_y + w
                    
                    if 0 <= width_x < self.CHUNK_SIZE and 0 <= width_y < self.CHUNK_SIZE:
                        current_block = chunk[width_y][width_x]
                        # Don't overwrite existing structures
                        if current_block in ['grass', 'dirt', 'stone']:
                            chunk[width_y][width_x] = 'cobblestone'
            
            # Add decorations along the road
            for i in range(3, road_length, 4):
                for side in [-1, 1]:
                    # Position perpendicular to road
                    if dx == 0:  # North/South road
                        decor_x = gate_x + side * (road_width + 1)
                        decor_y = gate_y + dy * i
                    else:  # East/West road
                        decor_x = gate_x + dx * i
                        decor_y = gate_y + side * (road_width + 1)
                    
                    if 0 <= decor_x < self.CHUNK_SIZE and 0 <= decor_y < self.CHUNK_SIZE:
                        current_block = chunk[decor_y][decor_x]
                        if current_block in ['grass', 'dirt']:
                            # Add lighting, trees, or other decorations
                            if random.random() < 0.3:
                                chunk[decor_y][decor_x] = 'lantern'
                            elif random.random() < 0.5:
                                chunk[decor_y][decor_x] = 'wood'  # Tree trunk
                            
                            # Sometimes add small structures
                            if random.random() < 0.2:
                                self._add_roadside_structure(chunk, decor_x, decor_y)
    
    def _add_roadside_structure(self, chunk, center_x, center_y):
        """Add a small roadside structure like a shrine, well, or signpost"""
        structure_type = random.choice(['well', 'shrine', 'signpost'])
        
        if structure_type == 'well':
            # Simple well
            if 0 <= center_x < self.CHUNK_SIZE and 0 <= center_y < self.CHUNK_SIZE:
                chunk[center_y][center_x] = 'water'
                
                # Stone rim
                for dx, dy in [(0, 1), (1, 0), (0, -1), (-1, 0), (1, 1), (1, -1), (-1, 1), (-1, -1)]:
                    x = center_x + dx
                    y = center_y + dy
                    if 0 <= x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE:
                        chunk[y][x] = 'stone'
        
        elif structure_type == 'shrine':
            # Small shrine or monument
            if 0 <= center_x < self.CHUNK_SIZE and 0 <= center_y < self.CHUNK_SIZE:
                chunk[center_y][center_x] = 'castle_pillar'
                
                # Base
                for dx, dy in [(0, 1), (1, 0), (0, -1), (-1, 0)]:
                    x = center_x + dx
                    y = center_y + dy
                    if 0 <= x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE:
                        chunk[y][x] = 'castle_floor'
        
        else:  # signpost
            # Simple signpost
            if 0 <= center_x < self.CHUNK_SIZE and 0 <= center_y < self.CHUNK_SIZE:
                chunk[center_y][center_x] = 'wood'
    
    def generate_enhanced_village(self, chunk):
        """Generate a more detailed village with varied buildings and improved layout"""
        # Village parameters
        village_size = random.randint(12, 18)
        village_style = random.choice(['common', 'service', 'noble'])
        num_buildings = random.randint(6, 12)
        
        # Find a suitable position
        start_x = random.randint(3, self.CHUNK_SIZE - village_size - 3)
        start_y = random.randint(3, self.CHUNK_SIZE - village_size - 3)
        
        # Prepare village terrain
        self._prepare_village_terrain(chunk, start_x, start_y, village_size)
        
        # Create road network
        road_network = self._create_village_roads(chunk, start_x, start_y, village_size)
        
        # Generate village structure ID
        structure_id = f"village_{start_x}_{start_y}_{random.randint(1000, 9999)}"
        
        # Build special buildings first
        special_buildings = {
            'tavern': {'size': (6, 5), 'importance': 10},
            'blacksmith': {'size': (5, 4), 'importance': 8},
            'market': {'size': (7, 7), 'importance': 9},
            'townhall': {'size': (6, 6), 'importance': 7},
            'temple': {'size': (5, 5), 'importance': 6}
        }
        
        # Sort special buildings by importance
        sorted_buildings = sorted(special_buildings.items(), key=lambda x: x[1]['importance'], reverse=True)
        
        # Build special structures
        built_special = []
        for name, data in sorted_buildings:
            width, height = data['size']
            # Find appropriate spot near a road intersection
            for road_x, road_y in road_network['intersections']:
                # Check if there's enough space
                if self._check_building_space(chunk, road_x, road_y, width, height):
                    # Build the special building
                    self._build_village_special(chunk, road_x, road_y, width, height, name, village_style)
                    built_special.append((name, road_x, road_y, width, height))
                    break
        
        # Fill in with regular houses
        houses_built = 0
        for road_x, road_y in road_network['roads']:
            if houses_built >= num_buildings - len(built_special):
                break
                
            # Vary house size
            width = random.randint(3, 5)
            height = random.randint(3, 5)
            
            # Check if the space is available
            if self._check_building_space(chunk, road_x, road_y, width, height):
                # Build a house
                house_type = random.choice(['normal', 'shop', 'large', 'small'])
                self._build_village_house(chunk, road_x, road_y, width, height, house_type, village_style)
                houses_built += 1
        
        # Add village decorations
        self._decorate_village(chunk, start_x, start_y, village_size, village_style)
        
        # Add villager spawners
        self._add_village_spawners(chunk, start_x, start_y, village_size, road_network)
        
        # Store village data
        self.generated_structures[structure_id] = {
            'type': 'village',
            'style': village_style,
            'x': start_x,
            'y': start_y,
            'size': village_size,
            'buildings': built_special + [('house', houses_built)]
        }
        
        return structure_id
    
    def _prepare_village_terrain(self, chunk, start_x, start_y, village_size):
        """Prepare terrain for village construction"""
        # Level the area
        for x in range(village_size):
            for y in range(village_size):
                check_x = start_x + x
                check_y = start_y + y
                
                # Skip if out of bounds
                if not (0 <= check_x < self.CHUNK_SIZE and 0 <= check_y < self.CHUNK_SIZE):
                    continue
                
                # Set to flat ground
                if random.random() < 0.85:
                    chunk[check_y][check_x] = 'grass'
                else:
                    chunk[check_y][check_x] = 'dirt'  # Some dirt patches
    
    def _create_village_roads(self, chunk, start_x, start_y, village_size):
        """Create an organic road network for the village"""
        # Road data structures
        roads = []
        intersections = []
        
        # Create main road
        main_road_type = random.choice(['straight', 'curved', 'cross'])
        
        if main_road_type == 'straight':
            # Straight road through village
            direction = random.choice(['horizontal', 'vertical'])
            
            if direction == 'horizontal':
                y = start_y + village_size // 2
                for x in range(village_size):
                    check_x = start_x + x
                    
                    if 0 <= check_x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE:
                        chunk[y][check_x] = 'cobblestone'
                        roads.append((check_x, y))
            else:
                x = start_x + village_size // 2
                for y in range(village_size):
                    check_y = start_y + y
                    
                    if 0 <= x < self.CHUNK_SIZE and 0 <= check_y < self.CHUNK_SIZE:
                        chunk[check_y][x] = 'cobblestone'
                        roads.append((x, check_y))
            
            # Add a central intersection
            center_x = start_x + village_size // 2
            center_y = start_y + village_size // 2
            intersections.append((center_x, center_y))
            
            # Add perpendicular road at center
            if direction == 'horizontal':
                for y_offset in range(-village_size//2, village_size//2 + 1):
                    y = center_y + y_offset
                    if 0 <= center_x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE:
                        chunk[y][center_x] = 'cobblestone'
                        roads.append((center_x, y))
            else:
                for x_offset in range(-village_size//2, village_size//2 + 1):
                    x = center_x + x_offset
                    if 0 <= x < self.CHUNK_SIZE and 0 <= center_y < self.CHUNK_SIZE:
                        chunk[center_y][x] = 'cobblestone'
                        roads.append((x, center_y))
        
        elif main_road_type == 'curved':
            # Curved main road
            center_x = start_x + village_size // 2
            center_y = start_y + village_size // 2
            radius = village_size // 3
            
            # Create a partial circle
            start_angle = random.randint(0, 180)
            end_angle = start_angle + 180
            
            for angle in range(start_angle, end_angle, 5):
                rad = math.radians(angle)
                x = int(center_x + radius * math.cos(rad))
                y = int(center_y + radius * math.sin(rad))
                
                if 0 <= x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE:
                    chunk[y][x] = 'cobblestone'
                    roads.append((x, y))
            
            # Add a few spokes
            num_spokes = random.randint(2, 4)
            for _ in range(num_spokes):
                angle = random.randint(start_angle, end_angle)
                rad = math.radians(angle)
                
                # Point on the circle
                circle_x = int(center_x + radius * math.cos(rad))
                circle_y = int(center_y + radius * math.sin(rad))
                
                # Create road from center to edge
                for i in range(radius + 1):
                    lerp = i / radius
                    x = int(center_x * (1-lerp) + circle_x * lerp)
                    y = int(center_y * (1-lerp) + circle_y * lerp)
                    
                    if 0 <= x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE:
                        chunk[y][x] = 'cobblestone'
                        roads.append((x, y))
                
                # This creates an intersection
                intersections.append((circle_x, circle_y))
            
            # Center is also an intersection
            intersections.append((center_x, center_y))
        
        else:  # cross
            # Simple cross road pattern
            center_x = start_x + village_size // 2
            center_y = start_y + village_size // 2
            
            # Horizontal road
            for x in range(village_size):
                check_x = start_x + x
                if 0 <= check_x < self.CHUNK_SIZE and 0 <= center_y < self.CHUNK_SIZE:
                    chunk[center_y][check_x] = 'cobblestone'
                    roads.append((check_x, center_y))
            
            # Vertical road
            for y in range(village_size):
                check_y = start_y + y
                if 0 <= center_x < self.CHUNK_SIZE and 0 <= check_y < self.CHUNK_SIZE:
                    chunk[check_y][center_x] = 'cobblestone'
                    roads.append((center_x, check_y))
            
            # Add central intersection
            intersections.append((center_x, center_y))
            
            # Add one or two additional roads
            for _ in range(random.randint(1, 2)):
                # Starting point somewhere on existing roads
                start_point = random.choice(roads)
                start_road_x, start_road_y = start_point
                
                # Direction perpendicular to nearest main road
                near_center_x = abs(start_road_x - center_x) < abs(start_road_y - center_y)
                
                if near_center_x:
                    # Close to horizontal road, branch vertically
                    direction = random.choice([(0, -1), (0, 1)])
                else:
                    # Close to vertical road, branch horizontally
                    direction = random.choice([(-1, 0), (1, 0)])
                
                # Create branch road
                branch_length = random.randint(village_size // 4, village_size // 2)
                dx, dy = direction
                
                for i in range(1, branch_length + 1):
                    branch_x = start_road_x + dx * i
                    branch_y = start_road_y + dy * i
                    
                    if (0 <= branch_x < self.CHUNK_SIZE and 0 <= branch_y < self.CHUNK_SIZE and
                        0 <= branch_x - start_x < village_size and 0 <= branch_y - start_y < village_size):
                        chunk[branch_y][branch_x] = 'cobblestone'
                        roads.append((branch_x, branch_y))
                
                # Add intersection
                intersections.append((start_road_x, start_road_y))
        
        # Add town square at a major intersection
        if intersections:
            square_center = random.choice(intersections)
            square_x, square_y = square_center
            square_size = random.randint(3, 5)
            
            # Create square
            for dx in range(-square_size, square_size + 1):
                for dy in range(-square_size, square_size + 1):
                    x = square_x + dx
                    y = square_y + dy
                    
                    if (0 <= x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE and
                        abs(dx) + abs(dy) <= square_size):  # Diamond shape
                        chunk[y][x] = 'castle_floor'  # Nice flooring for town square
        
        # Return road network data for building placement
        return {
            'roads': list(set(roads)),  # Remove duplicates
            'intersections': intersections
        }
    
    def _check_building_space(self, chunk, center_x, center_y, width, height):
        """Check if there's enough space for a building"""
        # Calculate building bounds
        start_x = center_x - width // 2
        start_y = center_y - height // 2
        end_x = start_x + width
        end_y = start_y + height
        
        # Check if out of chunk bounds
        if not (0 <= start_x < self.CHUNK_SIZE and 0 <= start_y < self.CHUNK_SIZE and
                0 <= end_x < self.CHUNK_SIZE and 0 <= end_y < self.CHUNK_SIZE):
            return False
        
        # Check for existing structures
        for x in range(start_x - 1, end_x + 1):
            for y in range(start_y - 1, end_y + 1):
                if 0 <= x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE:
                    block = chunk[y][x]
                    if block not in ['grass', 'dirt', 'cobblestone']:
                        return False
        
        return True
    
    def _build_village_special(self, chunk, center_x, center_y, width, height, building_type, village_style):
        """Build a special building in the village"""
        # Choose blocks based on village style and building type
        if building_type == 'tavern':
            wall_block = self.choose_from_palette(village_style, 'primary_wall')
            floor_block = 'wood'
            roof_block = 'roof'
        elif building_type == 'blacksmith':
            wall_block = 'stone'
            floor_block = 'stone'
            roof_block = 'stone'
        elif building_type == 'market':
            wall_block = 'wood'
            floor_block = 'castle_floor'
            roof_block = 'wood'
        elif building_type == 'townhall':
            wall_block = self.choose_from_palette('noble', 'primary_wall')
            floor_block = self.choose_from_palette('noble', 'floor')
            roof_block = self.choose_from_palette('noble', 'roof')
        elif building_type == 'temple':
            wall_block = 'marble'
            floor_block = 'marble'
            roof_block = 'gold'
        else:
            # Default
            wall_block = self.choose_from_palette(village_style, 'primary_wall')
            floor_block = self.choose_from_palette(village_style, 'floor')
            roof_block = self.choose_from_palette(village_style, 'roof')
        
        # Calculate building bounds
        start_x = center_x - width // 2
        start_y = center_y - height // 2
        
        # Generate building structure
        for x in range(width):
            for y in range(height):
                check_x = start_x + x
                check_y = start_y + y
                
                # Skip if out of bounds
                if not (0 <= check_x < self.CHUNK_SIZE and 0 <= check_y < self.CHUNK_SIZE):
                    continue
                
                # Determine block type
                if x == 0 or x == width - 1 or y == 0 or y == height - 1:
                    # Walls
                    chunk[check_y][check_x] = wall_block
                else:
                    # Floor
                    chunk[check_y][check_x] = floor_block
        
        # Add door
        # Find closest road block
        min_dist = float('inf')
        door_x, door_y = None, None
        
        for x in range(width):
            for y in range(height):
                if x == 0 or x == width - 1 or y == 0 or y == height - 1:
                    check_x = start_x + x
                    check_y = start_y + y
                    
                    # Check adjacent blocks for roads
                    for dx, dy in [(0, 1), (1, 0), (0, -1), (-1, 0)]:
                        adj_x = check_x + dx
                        adj_y = check_y + dy
                        
                        if (0 <= adj_x < self.CHUNK_SIZE and 0 <= adj_y < self.CHUNK_SIZE and
                            chunk[adj_y][adj_x] == 'cobblestone'):
                            # Calculate distance to center
                            dist = abs(check_x - center_x) + abs(check_y - center_y)
                            if dist < min_dist:
                                min_dist = dist
                                door_x, door_y = check_x, check_y
        
        # Place door
        if door_x is not None and door_y is not None:
            chunk[door_y][door_x] = 'door_closed'
        
        # Add roof and special features
        if building_type == 'tavern':
            # Add bar counter
            bar_x = start_x + width // 4
            bar_y = start_y + height // 2
            
            for i in range(width // 2):
                check_x = bar_x + i
                if 0 <= check_x < self.CHUNK_SIZE and 0 <= bar_y < self.CHUNK_SIZE:
                    chunk[bar_y][check_x] = 'wood'
            
            # Add some tables
            for _ in range(2):
                table_x = start_x + random.randint(width // 4, 3 * width // 4)
                table_y = start_y + random.randint(height // 4, 3 * height // 4)
                
                if (0 <= table_x < self.CHUNK_SIZE and 0 <= table_y < self.CHUNK_SIZE and
                    chunk[table_y][table_x] == floor_block):
                    chunk[table_y][table_x] = 'wood'
        
        elif building_type == 'blacksmith':
            # Add forge
            forge_x = start_x + width // 4
            forge_y = start_y + height // 4
            
            if 0 <= forge_x < self.CHUNK_SIZE and 0 <= forge_y < self.CHUNK_SIZE:
                chunk[forge_y][forge_x] = 'lantern'  # Fire/forge
                
                # Add anvil and tools around forge
                for dx, dy in [(1, 0), (0, 1)]:
                    x = forge_x + dx
                    y = forge_y + dy
                    if 0 <= x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE:
                        chunk[y][x] = 'stone'  # Anvil/workbench
        
        elif building_type == 'market':
            # Add stalls
            for _ in range(3):
                stall_x = start_x + random.randint(1, width - 2)
                stall_y = start_y + random.randint(1, height - 2)
                
                if 0 <= stall_x < self.CHUNK_SIZE and 0 <= stall_y < self.CHUNK_SIZE:
                    chunk[stall_y][stall_x] = 'wood'
                    
                    # Add goods around stall
                    for dx, dy in [(0, 1), (1, 0), (0, -1), (-1, 0)]:
                        x = stall_x + dx
                        y = stall_y + dy
                        if (0 <= x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE and
                            x >= start_x and x < start_x + width and y >= start_y and y < start_y + height and
                            chunk[y][x] == floor_block and random.random() < 0.5):
                            chunk[y][x] = random.choice(['gold', 'iron', 'wood'])  # Various goods
        
        elif building_type == 'townhall':
            # Add central table
            table_x = center_x
            table_y = center_y
            
            if 0 <= table_x < self.CHUNK_SIZE and 0 <= table_y < self.CHUNK_SIZE:
                chunk[table_y][table_x] = 'wood'
                
                # Add chairs around table
                for dx, dy in [(0, 1), (1, 0), (0, -1), (-1, 0)]:
                    x = table_x + dx
                    y = table_y + dy
                    if (0 <= x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE and
                        x >= start_x and x < start_x + width and y >= start_y and y < start_y + height):
                        chunk[y][x] = 'wood'
        
        elif building_type == 'temple':
            # Add altar
            altar_x = start_x + width // 2
            altar_y = start_y + height // 4
            
            if 0 <= altar_x < self.CHUNK_SIZE and 0 <= altar_y < self.CHUNK_SIZE:
                chunk[altar_y][altar_x] = 'gold'
                
                # Add decorative elements
                for dx, dy in [(0, 1), (1, 0), (0, -1), (-1, 0)]:
                    x = altar_x + dx
                    y = altar_y + dy
                    if (0 <= x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE and
                        x >= start_x and x < start_x + width and y >= start_y and y < start_y + height):
                        chunk[y][x] = random.choice(['lantern', 'banner_blue', 'banner_red'])
    
    def _build_village_house(self, chunk, center_x, center_y, width, height, house_type, village_style):
        """Build a regular house in the village"""
        # Choose blocks based on village style and house type
        if house_type == 'shop':
            wall_block = self.choose_from_palette(village_style, 'primary_wall')
            floor_block = self.choose_from_palette(village_style, 'floor')
            roof_block = self.choose_from_palette(village_style, 'roof')
        elif house_type == 'large':
            wall_block = self.choose_from_palette('noble', 'primary_wall')
            floor_block = self.choose_from_palette('noble', 'floor')
            roof_block = self.choose_from_palette('noble', 'roof')
        elif house_type == 'small':
            wall_block = self.choose_from_palette('common', 'primary_wall')
            floor_block = 'dirt'
            roof_block = 'wood'
        else:  # normal
            wall_block = self.choose_from_palette(village_style, 'primary_wall')
            floor_block = self.choose_from_palette(village_style, 'floor')
            roof_block = self.choose_from_palette(village_style, 'roof')
        
# Calculate building bounds
        start_x = center_x - width // 2
        start_y = center_y - height // 2
        
        # Generate building structure with random elements for variety
        has_L_shape = False
        if house_type == 'large' and random.random() < 0.5:
            # Create L-shaped house
            has_L_shape = True
            # Determine which corner to remove for L-shape
            remove_corner = random.choice(['NE', 'NW', 'SE', 'SW'])
            corner_width = width // 3
            corner_height = height // 3
            
            if remove_corner == 'NE':
                corner_start_x = start_x + width - corner_width
                corner_start_y = start_y
            elif remove_corner == 'NW':
                corner_start_x = start_x
                corner_start_y = start_y
            elif remove_corner == 'SE':
                corner_start_x = start_x + width - corner_width
                corner_start_y = start_y + height - corner_height
            else:  # SW
                corner_start_x = start_x
                corner_start_y = start_y + height - corner_height
        
        # Build walls and floor
        for x in range(width):
            for y in range(height):
                check_x = start_x + x
                check_y = start_y + y
                
                # Skip if out of bounds
                if not (0 <= check_x < self.CHUNK_SIZE and 0 <= check_y < self.CHUNK_SIZE):
                    continue
                
                # Skip if L-shaped and in removed corner
                if has_L_shape:
                    if remove_corner == 'NE' and x >= width - corner_width and y < corner_height:
                        continue
                    elif remove_corner == 'NW' and x < corner_width and y < corner_height:
                        continue
                    elif remove_corner == 'SE' and x >= width - corner_width and y >= height - corner_height:
                        continue
                    elif remove_corner == 'SW' and x < corner_width and y >= height - corner_height:
                        continue
                
                # Determine block type
                if x == 0 or x == width - 1 or y == 0 or y == height - 1:
                    # Don't place walls where L-shape creates an interior corner
                    if has_L_shape:
                        is_interior_corner = False
                        if remove_corner == 'NE':
                            is_interior_corner = (x == width - corner_width - 1 and y < corner_height) or (y == corner_height and x >= width - corner_width)
                        elif remove_corner == 'NW':
                            is_interior_corner = (x == corner_width and y < corner_height) or (y == corner_height and x < corner_width)
                        elif remove_corner == 'SE':
                            is_interior_corner = (x == width - corner_width - 1 and y >= height - corner_height) or (y == height - corner_height - 1 and x >= width - corner_width)
                        elif remove_corner == 'SW':
                            is_interior_corner = (x == corner_width and y >= height - corner_height) or (y == height - corner_height - 1 and x < corner_width)
                        
                        if is_interior_corner:
                            continue
                    
                    # Walls
                    chunk[check_y][check_x] = wall_block
                else:
                    # Floor
                    chunk[check_y][check_x] = floor_block
        
        # Add door - find nearest road
        min_dist = float('inf')
        door_x, door_y = None, None
        
        for x in range(width):
            for y in range(height):
                if x == 0 or x == width - 1 or y == 0 or y == height - 1:
                    check_x = start_x + x
                    check_y = start_y + y
                    
                    # Skip if out of bounds or part of L-shape cutout
                    if not (0 <= check_x < self.CHUNK_SIZE and 0 <= check_y < self.CHUNK_SIZE):
                        continue
                    
                    # Skip if L-shaped and in removed corner boundary
                    if has_L_shape:
                        is_corner_boundary = False
                        if remove_corner == 'NE':
                            is_corner_boundary = (x >= width - corner_width and y == corner_height) or (x == width - corner_width and y < corner_height)
                        elif remove_corner == 'NW':
                            is_corner_boundary = (x < corner_width and y == corner_height) or (x == corner_width and y < corner_height)
                        elif remove_corner == 'SE':
                            is_corner_boundary = (x >= width - corner_width and y == height - corner_height - 1) or (x == width - corner_width - 1 and y >= height - corner_height)
                        elif remove_corner == 'SW':
                            is_corner_boundary = (x < corner_width and y == height - corner_height - 1) or (x == corner_width and y >= height - corner_height)
                        
                        if is_corner_boundary:
                            continue
                    
                    # Check if there's a wall here
                    if chunk[check_y][check_x] != wall_block:
                        continue
                    
                    # Check adjacent blocks for roads
                    for dx, dy in [(0, 1), (1, 0), (0, -1), (-1, 0)]:
                        adj_x = check_x + dx
                        adj_y = check_y + dy
                        
                        if (0 <= adj_x < self.CHUNK_SIZE and 0 <= adj_y < self.CHUNK_SIZE and
                            chunk[adj_y][adj_x] == 'cobblestone'):
                            # Calculate distance to center
                            dist = abs(check_x - center_x) + abs(check_y - center_y)
                            if dist < min_dist:
                                min_dist = dist
                                door_x, door_y = check_x, check_y
        
        # Place door
        if door_x is not None and door_y is not None:
            chunk[door_y][door_x] = 'door_closed'
        
        # Add roof
        self._add_house_roof(chunk, start_x, start_y, width, height, roof_block, has_L_shape, remove_corner if has_L_shape else None)
        
        # Add interior details based on house type
        if house_type == 'shop':
            # Add counter
            counter_x = start_x + width // 4
            counter_y = start_y + height // 2
            
            # Make sure it's inside the building and not in L-shape cutout
            if (0 <= counter_x < self.CHUNK_SIZE and 0 <= counter_y < self.CHUNK_SIZE and
                counter_x >= start_x and counter_x < start_x + width and
                counter_y >= start_y and counter_y < start_y + height):
                
                # Skip if in L-shape cutout
                if not has_L_shape or not self._is_in_corner_cutout(counter_x, counter_y, start_x, start_y, width, height, remove_corner, corner_width, corner_height):
                    chunk[counter_y][counter_x] = 'wood'
        
        elif house_type == 'large':
            # Add furniture
            furniture_positions = [
                (start_x + width // 4, start_y + height // 4),
                (start_x + 3 * width // 4, start_y + height // 4),
                (start_x + width // 4, start_y + 3 * height // 4),
                (start_x + 3 * width // 4, start_y + 3 * height // 4)
            ]
            
            for pos_x, pos_y in furniture_positions:
                # Make sure it's inside the building and not in L-shape cutout
                if (0 <= pos_x < self.CHUNK_SIZE and 0 <= pos_y < self.CHUNK_SIZE and
                    pos_x >= start_x and pos_x < start_x + width and
                    pos_y >= start_y and pos_y < start_y + height):
                    
                    # Skip if in L-shape cutout
                    if not has_L_shape or not self._is_in_corner_cutout(pos_x, pos_y, start_x, start_y, width, height, remove_corner, corner_width, corner_height):
                        chunk[pos_y][pos_x] = random.choice(['wood', 'castle_ornament'])
        
        # Add light source
        light_x = center_x
        light_y = center_y
        
        # Make sure it's inside the building and not in L-shape cutout
        if (0 <= light_x < self.CHUNK_SIZE and 0 <= light_y < self.CHUNK_SIZE and
            light_x >= start_x and light_x < start_x + width and
            light_y >= start_y and light_y < start_y + height):
            
            # Skip if in L-shape cutout
            if not has_L_shape or not self._is_in_corner_cutout(light_x, light_y, start_x, start_y, width, height, remove_corner, corner_width, corner_height):
                chunk[light_y][light_x] = 'lantern'
    
    def _is_in_corner_cutout(self, x, y, start_x, start_y, width, height, corner, corner_width, corner_height):
        """Helper function to check if a point is in an L-shape cutout"""
        if corner == 'NE':
            return x >= start_x + width - corner_width and y < start_y + corner_height
        elif corner == 'NW':
            return x < start_x + corner_width and y < start_y + corner_height
        elif corner == 'SE':
            return x >= start_x + width - corner_width and y >= start_y + height - corner_height
        elif corner == 'SW':
            return x < start_x + corner_width and y >= start_y + height - corner_height
        return False
    
    def _add_house_roof(self, chunk, start_x, start_y, width, height, roof_block, is_l_shaped, l_corner):
        """Add a roof to a house based on its shape"""
        # For simplicity in 2D, we'll just place blocks that would be above the walls in 3D
        # and leave the center open to simulate a peaked roof
        
        if not is_l_shaped:
            # Simple rectangular roof
            for x in range(width):
                for y in range(height):
                    roof_x = start_x + x
                    roof_y = start_y + y
                    
                    # Skip if out of bounds
                    if not (0 <= roof_x < self.CHUNK_SIZE and 0 <= roof_y < self.CHUNK_SIZE):
                        continue
                    
                    # Only add roof along walls and not near center
                    is_edge = x == 0 or x == width - 1 or y == 0 or y == height - 1
                    is_not_center = abs(x - width // 2) > width // 4 or abs(y - height // 2) > height // 4
                    
                    if is_edge and is_not_center:
                        # Would be above the wall in 3D
                        if chunk[roof_y][roof_x] not in ['door_closed', 'air']:
                            chunk[roof_y][roof_x] = roof_block
        else:
            # L-shaped roof - more complex
            corner_width = width // 3
            corner_height = height // 3
            
            for x in range(width):
                for y in range(height):
                    roof_x = start_x + x
                    roof_y = start_y + y
                    
                    # Skip if out of bounds
                    if not (0 <= roof_x < self.CHUNK_SIZE and 0 <= roof_y < self.CHUNK_SIZE):
                        continue
                    
                    # Skip if in removed corner
                    if l_corner == 'NE' and x >= width - corner_width and y < corner_height:
                        continue
                    elif l_corner == 'NW' and x < corner_width and y < corner_height:
                        continue
                    elif l_corner == 'SE' and x >= width - corner_width and y >= height - corner_height:
                        continue
                    elif l_corner == 'SW' and x < corner_width and y >= height - corner_height:
                        continue
                    
                    # Only add roof along walls and interior edges
                    is_outer_edge = x == 0 or x == width - 1 or y == 0 or y == height - 1
                    
                    # Check for interior L edges
                    is_interior_edge = False
                    if l_corner == 'NE':
                        is_interior_edge = (x == width - corner_width) and y < corner_height or (y == corner_height and x >= width - corner_width)
                    elif l_corner == 'NW':
                        is_interior_edge = (x == corner_width) and y < corner_height or (y == corner_height and x < corner_width)
                    elif l_corner == 'SE':
                        is_interior_edge = (x == width - corner_width) and y >= height - corner_height or (y == height - corner_height and x >= width - corner_width)
                    elif l_corner == 'SW':
                        is_interior_edge = (x == corner_width) and y >= height - corner_height or (y == height - corner_height and x < corner_width)
                    
                    if (is_outer_edge or is_interior_edge) and chunk[roof_y][roof_x] not in ['door_closed', 'air']:
                        chunk[roof_y][roof_x] = roof_block
    
    def _decorate_village(self, chunk, start_x, start_y, village_size, village_style):
        """Add decorative elements throughout the village"""
        # Add wells, gardens, benches, etc.
        num_decorations = random.randint(3, 6)
        
        # Find open spaces
        open_spaces = []
        for x in range(village_size):
            for y in range(village_size):
                check_x = start_x + x
                check_y = start_y + y
                
                # Skip if out of bounds
                if not (0 <= check_x < self.CHUNK_SIZE and 0 <= check_y < self.CHUNK_SIZE):
                    continue
                
                # Check if this is an open grass or dirt space
                if chunk[check_y][check_x] in ['grass', 'dirt']:
                    # Check surrounding blocks to make sure it's not adjacent to a building
                    is_open = True
                    for dx, dy in [(0, 1), (1, 0), (0, -1), (-1, 0), (1, 1), (1, -1), (-1, 1), (-1, -1)]:
                        nx = check_x + dx
                        ny = check_y + dy
                        
                        if (0 <= nx < self.CHUNK_SIZE and 0 <= ny < self.CHUNK_SIZE and
                            chunk[ny][nx] not in ['grass', 'dirt', 'cobblestone']):
                            is_open = False
                            break
                    
                    if is_open:
                        open_spaces.append((check_x, check_y))
        
        # Shuffle and select spots for decorations
        if open_spaces:
            random.shuffle(open_spaces)
            for i in range(min(num_decorations, len(open_spaces))):
                decor_x, decor_y = open_spaces[i]
                
                # Choose decoration type
                decor_type = random.choice(['well', 'garden', 'statue', 'tree'])
                
                if decor_type == 'well':
                    # Simple well
                    chunk[decor_y][decor_x] = 'water'
                    
                    # Stone rim
                    for dx, dy in [(0, 1), (1, 0), (0, -1), (-1, 0)]:
                        x = decor_x + dx
                        y = decor_y + dy
                        if 0 <= x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE:
                            chunk[y][x] = 'cobblestone'
                
                elif decor_type == 'garden':
                    # Small garden
                    chunk[decor_y][decor_x] = 'dirt'
                    
                    # Add flowers and plants
                    for dx, dy in [(0, 1), (1, 0), (0, -1), (-1, 0), (1, 1), (1, -1), (-1, 1), (-1, -1)]:
                        x = decor_x + dx
                        y = decor_y + dy
                        if (0 <= x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE and
                            chunk[y][x] in ['grass', 'dirt']):
                            # 50% chance for decoration
                            if random.random() < 0.5:
                                chunk[y][x] = random.choice(['banner_red', 'banner_blue', 'leaves'])
                
                elif decor_type == 'statue':
                    # Small statue or monument
                    chunk[decor_y][decor_x] = 'castle_pillar'
                    
                    # Create base
                    for dx, dy in [(0, 1), (1, 0), (0, -1), (-1, 0)]:
                        x = decor_x + dx
                        y = decor_y + dy
                        if 0 <= x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE and chunk[y][x] in ['grass', 'dirt']:
                            chunk[y][x] = 'castle_floor'
                
                else:  # tree
                    # Simple tree
                    chunk[decor_y][decor_x] = 'wood'  # Trunk
                    
                    # Leaves
                    for dx, dy in [(0, 1), (1, 0), (0, -1), (-1, 0), (1, 1), (1, -1), (-1, 1), (-1, -1)]:
                        x = decor_x + dx
                        y = decor_y + dy
                        if 0 <= x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE and chunk[y][x] in ['grass', 'dirt']:
                            chunk[y][x] = 'leaves'
        
        # Add road decorations
        for x in range(village_size):
            for y in range(village_size):
                check_x = start_x + x
                check_y = start_y + y
                
                # Skip if out of bounds
                if not (0 <= check_x < self.CHUNK_SIZE and 0 <= check_y < self.CHUNK_SIZE):
                    continue
                
                # Find road blocks
                if chunk[check_y][check_x] == 'cobblestone':
                    # Check if this is an intersection or corner
                    road_adjacents = []
                    for dx, dy in [(0, 1), (1, 0), (0, -1), (-1, 0)]:
                        nx = check_x + dx
                        ny = check_y + dy
                        
                        if (0 <= nx < self.CHUNK_SIZE and 0 <= ny < self.CHUNK_SIZE and
                            chunk[ny][nx] == 'cobblestone'):
                            road_adjacents.append((dx, dy))
                    
                    # If it's an intersection, add a lamppost nearby
                    if len(road_adjacents) >= 3:
                        # Look for a nearby spot that's not a road or building
                        for dx, dy in [(1, 1), (1, -1), (-1, 1), (-1, -1)]:
                            light_x = check_x + dx
                            light_y = check_y + dy
                            
                            if (0 <= light_x < self.CHUNK_SIZE and 0 <= light_y < self.CHUNK_SIZE and
                                chunk[light_y][light_x] in ['grass', 'dirt']):
                                chunk[light_y][light_x] = 'lantern'
                                break
    
    def _add_village_spawners(self, chunk, start_x, start_y, village_size, road_network):
        """Add villager spawners throughout the village"""
        # Add spawners in key locations
        spawner_count = 0
        max_spawners = 5
        
        # Try spawners at intersections first
        for x, y in road_network['intersections']:
            # Skip if we have enough spawners
            if spawner_count >= max_spawners:
                break
                
            # Look for nearby open spaces
            for dx, dy in [(1, 1), (1, -1), (-1, 1), (-1, -1)]:
                spawner_x = x + dx
                spawner_y = y + dy
                
                if (0 <= spawner_x < self.CHUNK_SIZE and 0 <= spawner_y < self.CHUNK_SIZE and
                    chunk[spawner_y][spawner_x] in ['grass', 'dirt', 'castle_floor']):
                    chunk[spawner_y][spawner_x] = 'spawner'
                    spawner_count += 1
                    break
        
        # Add additional spawners in open areas if needed
        if spawner_count < max_spawners:
            for x in range(village_size):
                for y in range(village_size):
                    # Skip if we have enough spawners
                    if spawner_count >= max_spawners:
                        break
                        
                    check_x = start_x + x
                    check_y = start_y + y
                    
                    # Skip if out of bounds
                    if not (0 <= check_x < self.CHUNK_SIZE and 0 <= check_y < self.CHUNK_SIZE):
                        continue
                    
                    # Find open areas near roads
                    if chunk[check_y][check_x] in ['grass', 'dirt', 'castle_floor']:
                        # Check if there's a road nearby
                        has_road_nearby = False
                        for dx, dy in [(0, 1), (1, 0), (0, -1), (-1, 0), (1, 1), (1, -1), (-1, 1), (-1, -1)]:
                            nx = check_x + dx
                            ny = check_y + dy
                            
                            if (0 <= nx < self.CHUNK_SIZE and 0 <= ny < self.CHUNK_SIZE and
                                chunk[ny][nx] == 'cobblestone'):
                                has_road_nearby = True
                                break
                        
                        if has_road_nearby and random.random() < 0.1:  # 10% chance if criteria met
                            chunk[check_y][check_x] = 'spawner'
                            spawner_count += 1
    
    def generate_underground_complex(self, chunk, level_id):
        """Generate complex underground structures with multiple levels and rooms"""
        # Determine structure type based on depth
        if level_id <= 5:
            # Upper levels - mine shafts and caves
            return self._generate_enhanced_mineshaft(chunk, level_id)
        elif level_id <= 15:
            # Mid levels - ruins and dungeons
            return self._generate_enhanced_dungeon(chunk, level_id)
        else:
            # Deep levels - ancient structures and special complexes
            return self._generate_ancient_complex(chunk, level_id)
    
    def _generate_enhanced_mineshaft(self, chunk, level_id):
        """Generate improved mineshafts with realistic mining patterns"""
        # Mine parameters
        mine_complexity = random.randint(3, 6)  # Number of main tunnels
        has_ore_veins = random.random() < 0.8  # 80% chance for ore veins
        has_cave_in = random.random() < 0.3  # 30% chance for cave-in
        has_underground_water = random.random() < 0.4  # 40% chance for water
        
        # Find a suitable position
        center_x = random.randint(self.CHUNK_SIZE // 4, 3 * self.CHUNK_SIZE // 4)
        center_y = random.randint(self.CHUNK_SIZE // 4, 3 * self.CHUNK_SIZE // 4)
        
        # Create main hub
        hub_radius = random.randint(3, 5)
        for dx in range(-hub_radius, hub_radius + 1):
            for dy in range(-hub_radius, hub_radius + 1):
                x = center_x + dx
                y = center_y + dy
                
                # Skip if out of bounds
                if not (0 <= x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE):
                    continue
                
                # Create circular hub
                if dx*dx + dy*dy <= hub_radius*hub_radius:
                    chunk[y][x] = 'air'
                    
                    # Add wooden supports around edges
                    if abs(dx*dx + dy*dy - hub_radius*hub_radius) < 2:
                        chunk[y][x] = 'wood'
        
        # Generate main tunnels
        tunnel_directions = []
        potential_directions = [(1, 0), (0, 1), (-1, 0), (0, -1), (1, 1), (1, -1), (-1, 1), (-1, -1)]
        random.shuffle(potential_directions)
        
        # Choose random directions for tunnels
        tunnel_directions = potential_directions[:mine_complexity]
        
        # Create tunnels
        tunnels = []
        for dx, dy in tunnel_directions:
            tunnel_length = random.randint(10, 20)
            tunnel_width = random.randint(2, 3)
            
            tunnel_points = []
            # Create main tunnel path with slight variations for realism
            current_x = center_x
            current_y = center_y
            
            for _ in range(tunnel_length):
                # Slight wobble in tunnel direction
                wobble_x = dx + random.uniform(-0.3, 0.3)
                wobble_y = dy + random.uniform(-0.3, 0.3)
                
                # Normalize to maintain consistent speed
                magnitude = math.sqrt(wobble_x*wobble_x + wobble_y*wobble_y)
                if magnitude > 0:
                    wobble_x /= magnitude
                    wobble_y /= magnitude
                
                # Move forward
                current_x += wobble_x
                current_y += wobble_y
                
                # Round to nearest grid position
                grid_x = int(round(current_x))
                grid_y = int(round(current_y))
                
                # Skip if out of bounds
                if not (0 <= grid_x < self.CHUNK_SIZE and 0 <= grid_y < self.CHUNK_SIZE):
                    break
                
                # Add to tunnel points
                tunnel_points.append((grid_x, grid_y))
            
            # Create actual tunnel including width
            for tunnel_x, tunnel_y in tunnel_points:
                # Main tunnel path
                chunk[tunnel_y][tunnel_x] = 'air'
                
                # Add width
                for w_dx, w_dy in [(1, 0), (0, 1), (-1, 0), (0, -1)]:
                    # Skip diagonal directions
                    if dx*w_dx + dy*w_dy == 0:  # Perpendicular
                        for w in range(1, tunnel_width):
                            width_x = tunnel_x + w_dx * w
                            width_y = tunnel_y + w_dy * w
                            
                            if 0 <= width_x < self.CHUNK_SIZE and 0 <= width_y < self.CHUNK_SIZE:
                                chunk[width_y][width_x] = 'air'
            
            # Add supports every few blocks
            for i in range(0, len(tunnel_points), 5):
                if i < len(tunnel_points):
                    support_x, support_y = tunnel_points[i]
                    
                    # Add wooden supports
                    for w_dx, w_dy in [(1, 0), (0, 1), (-1, 0), (0, -1)]:
                        # Skip directions along the tunnel
                        if abs(dx*w_dx + dy*w_dy) < 0.5:  # Not parallel
                            support_block_x = support_x + w_dx
                            support_block_y = support_y + w_dy
                            
                            if (0 <= support_block_x < self.CHUNK_SIZE and 
                                0 <= support_block_y < self.CHUNK_SIZE and
                                chunk[support_block_y][support_block_x] == 'stone'):
                                chunk[support_block_y][support_block_x] = 'wood'
            
            # Add small rooms occasionally
            if random.random() < 0.5 and len(tunnel_points) > 5:
                room_index = random.randint(5, len(tunnel_points) - 1)
                room_x, room_y = tunnel_points[room_index]
                room_size = random.randint(3, 5)
                
                for r_dx in range(-room_size, room_size + 1):
                    for r_dy in range(-room_size, room_size + 1):
                        room_block_x = room_x + r_dx
                        room_block_y = room_y + r_dy
                        
                        # Skip if out of bounds
                        if not (0 <= room_block_x < self.CHUNK_SIZE and 0 <= room_block_y < self.CHUNK_SIZE):
                            continue
                        
                        # Create oval room
                        if (r_dx*r_dx)/(room_size*room_size) + (r_dy*r_dy)/(room_size*room_size) <= 1:
                            chunk[room_block_y][room_block_x] = 'air'
                            
                            # Add mining equipment or treasure
                            if r_dx == 0 and r_dy == 0 and random.random() < 0.5:
                                chunk[room_block_y][room_block_x] = 'spawner'  # Represents a chest or equipment
            
            tunnels.append(tunnel_points)
        
        # Add ore veins
        if has_ore_veins:
            num_veins = random.randint(3, 6)
            ore_types = ['coal', 'iron', 'gold', 'diamond']
            
            for _ in range(num_veins):
                # Choose ore type based on depth
                max_ore_index = min(level_id // 5, len(ore_types) - 1)
                ore_type = ore_types[random.randint(0, max_ore_index)]
                
# Choose random location near a tunnel
                if tunnels:
                    tunnel = random.choice(tunnels)
                    if tunnel:
                        vein_start = random.choice(tunnel)
                        vein_x, vein_y = vein_start
                        
                        # Generate vein
                        vein_length = random.randint(5, 10)
                        vein_direction = (random.uniform(-1, 1), random.uniform(-1, 1))
                        dx, dy = vein_direction
                        
                        # Normalize
                        magnitude = math.sqrt(dx*dx + dy*dy)
                        if magnitude > 0:
                            dx /= magnitude
                            dy /= magnitude
                        
                        # Create vein
                        for i in range(vein_length):
                            current_x = int(vein_x + dx * i)
                            current_y = int(vein_y + dy * i)
                            
                            if not (0 <= current_x < self.CHUNK_SIZE and 0 <= current_y < self.CHUNK_SIZE):
                                break
                            
                            # Don't overwrite existing air (tunnels)
                            if chunk[current_y][current_x] != 'air':
                                chunk[current_y][current_x] = ore_type
                                
                                # Add some adjacent ore blocks for thicker veins
                                for adj_dx, adj_dy in [(1, 0), (0, 1), (-1, 0), (0, -1)]:
                                    adj_x = current_x + adj_dx
                                    adj_y = current_y + adj_dy
                                    
                                    if (0 <= adj_x < self.CHUNK_SIZE and 0 <= adj_y < self.CHUNK_SIZE and
                                        chunk[adj_y][adj_x] == 'stone' and random.random() < 0.4):
                                        chunk[adj_y][adj_x] = ore_type
        
        # Add cave-in
        if has_cave_in:
            # Pick a tunnel
            if tunnels:
                cave_in_tunnel = random.choice(tunnels)
                if cave_in_tunnel:
                    # Pick a point along the tunnel
                    cave_in_index = random.randint(0, len(cave_in_tunnel) - 1)
                    cave_in_x, cave_in_y = cave_in_tunnel[cave_in_index]
                    
                    # Create rubble
                    for dx in range(-2, 3):
                        for dy in range(-2, 3):
                            x = cave_in_x + dx
                            y = cave_in_y + dy
                            
                            if not (0 <= x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE):
                                continue
                            
                            # Fill with rubble (mix of stone and dirt)
                            if random.random() < 0.7:
                                chunk[y][x] = 'stone' if random.random() < 0.6 else 'dirt'
        
        # Add underground water
        if has_underground_water:
            # Pick a tunnel end or room
            if tunnels:
                water_tunnel = random.choice(tunnels)
                if water_tunnel and len(water_tunnel) > 5:
                    # Start near the end of a tunnel
                    water_index = random.randint(len(water_tunnel) // 2, len(water_tunnel) - 1)
                    water_x, water_y = water_tunnel[water_index]
                    
                    # Create pool
                    pool_size = random.randint(3, 6)
                    for dx in range(-pool_size, pool_size + 1):
                        for dy in range(-pool_size, pool_size + 1):
                            x = water_x + dx
                            y = water_y + dy
                            
                            if not (0 <= x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE):
                                continue
                            
                            # Create oval/irregular pool
                            distance = math.sqrt(dx*dx + dy*dy)
                            if distance <= pool_size * (0.7 + 0.3 * noise.pnoise2(x/10, y/10, octaves=1)):
                                chunk[y][x] = 'water'
        
        # Add ladders connecting to levels above/below
        ladder_up_x = center_x + random.randint(-2, 2)
        ladder_up_y = center_y + random.randint(-2, 2)
        
        if 0 <= ladder_up_x < self.CHUNK_SIZE and 0 <= ladder_up_y < self.CHUNK_SIZE:
            chunk[ladder_up_y][ladder_up_x] = 'ladder_up'
        
        if level_id < 20:  # Don't add down ladders at the very bottom levels
            ladder_down_x = center_x + random.randint(-2, 2)
            ladder_down_y = center_y + random.randint(-2, 2)
            
            if (0 <= ladder_down_x < self.CHUNK_SIZE and 0 <= ladder_down_y < self.CHUNK_SIZE and
                (ladder_down_x != ladder_up_x or ladder_down_y != ladder_up_y)):
                chunk[ladder_down_y][ladder_down_x] = 'ladder_down'
        
        # Generate structure ID
        structure_id = f"mineshaft_{center_x}_{center_y}_{random.randint(1000, 9999)}"
        
        # Return structure data
        return structure_id
    
    def _generate_enhanced_dungeon(self, chunk, level_id):
        """Generate a complex dungeon with themed rooms and traps"""
        # Dungeon parameters
        dungeon_size = random.randint(10, 15)
        num_rooms = random.randint(4, 8)
        
        # Choose dungeon theme based on depth
        if level_id <= 10:
            theme = random.choice(['stone', 'abandoned', 'prison'])
        else:
            theme = random.choice(['ancient', 'ritual', 'crypt'])
        
        # Select appropriate blocks based on theme
        if theme == 'stone':
            wall_block = 'stone'
            floor_block = 'stone'
            decor_block = 'cobblestone'
        elif theme == 'abandoned':
            wall_block = 'cobblestone'
            floor_block = 'dirt'
            decor_block = 'wood'
        elif theme == 'prison':
            wall_block = 'castle_wall'
            floor_block = 'stone'
            decor_block = 'iron'
        elif theme == 'ancient':
            wall_block = 'castle_wall_outer'
            floor_block = 'castle_floor'
            decor_block = 'gold'
        elif theme == 'ritual':
            wall_block = 'obsidian'
            floor_block = 'stone'
            decor_block = 'portal_component'
        else:  # crypt
            wall_block = 'stone'
            floor_block = 'dirt'
            decor_block = 'obsidian'
        
        # Find suitable position
        center_x = random.randint(dungeon_size // 2, self.CHUNK_SIZE - dungeon_size // 2 - 1)
        center_y = random.randint(dungeon_size // 2, self.CHUNK_SIZE - dungeon_size // 2 - 1)
        
        # Generate rooms first
        rooms = []
        for _ in range(num_rooms):
            # Random room position within dungeon area
            room_x = center_x + random.randint(-dungeon_size // 2 + 3, dungeon_size // 2 - 3)
            room_y = center_y + random.randint(-dungeon_size // 2 + 3, dungeon_size // 2 - 3)
            
            # Random room size
            room_width = random.randint(4, 7)
            room_height = random.randint(4, 7)
            
            # Check for overlap with existing rooms
            overlaps = False
            for existing_room in rooms:
                ex, ey, ew, eh = existing_room
                
                # Check if bounding boxes overlap
                if (room_x - 1 < ex + ew + 1 and room_x + room_width + 1 > ex - 1 and
                    room_y - 1 < ey + eh + 1 and room_y + room_height + 1 > ey - 1):
                    overlaps = True
                    break
            
            if not overlaps:
                rooms.append((room_x, room_y, room_width, room_height))
        
        # If we couldn't place enough rooms, add a few more attempts
        while len(rooms) < 3:
            room_x = center_x + random.randint(-dungeon_size // 2 + 3, dungeon_size // 2 - 3)
            room_y = center_y + random.randint(-dungeon_size // 2 + 3, dungeon_size // 2 - 3)
            
            room_width = random.randint(3, 5)
            room_height = random.randint(3, 5)
            
            rooms.append((room_x, room_y, room_width, room_height))
        
        # Create rooms
        for room_x, room_y, room_width, room_height in rooms:
            # Room shape - sometimes irregular
            shape = random.choice(['rectangle', 'oval', 'cross', 'irregular'])
            
            if shape == 'rectangle':
                # Simple rectangular room
                for x in range(room_width):
                    for y in range(room_height):
                        check_x = room_x + x
                        check_y = room_y + y
                        
                        # Skip if out of bounds
                        if not (0 <= check_x < self.CHUNK_SIZE and 0 <= check_y < self.CHUNK_SIZE):
                            continue
                        
                        # Walls
                        if x == 0 or x == room_width - 1 or y == 0 or y == room_height - 1:
                            chunk[check_y][check_x] = wall_block
                        else:
                            # Floor
                            chunk[check_y][check_x] = floor_block
            
            elif shape == 'oval':
                # Oval room
                for x in range(room_width):
                    for y in range(room_height):
                        check_x = room_x + x
                        check_y = room_y + y
                        
                        # Skip if out of bounds
                        if not (0 <= check_x < self.CHUNK_SIZE and 0 <= check_y < self.CHUNK_SIZE):
                            continue
                        
                        # Calculate normalized position in oval
                        nx = 2 * x / room_width - 1
                        ny = 2 * y / room_height - 1
                        distance = nx*nx + ny*ny
                        
                        if distance <= 1:
                            # Inside oval
                            chunk[check_y][check_x] = floor_block
                        elif distance <= 1.2:
                            # Wall thickness
                            chunk[check_y][check_x] = wall_block
            
            elif shape == 'cross':
                # Cross-shaped room
                for x in range(room_width):
                    for y in range(room_height):
                        check_x = room_x + x
                        check_y = room_y + y
                        
                        # Skip if out of bounds
                        if not (0 <= check_x < self.CHUNK_SIZE and 0 <= check_y < self.CHUNK_SIZE):
                            continue
                        
                        # Check if in cross pattern
                        in_horizontal = y >= room_height // 3 and y < 2 * room_height // 3
                        in_vertical = x >= room_width // 3 and x < 2 * room_width // 3
                        
                        if in_horizontal or in_vertical:
                            # Cross interior
                            is_edge = (x == 0 or x == room_width - 1 or 
                                     y == 0 or y == room_height - 1 or
                                     (in_horizontal and (x == room_width // 3 - 1 or x == 2 * room_width // 3)) or
                                     (in_vertical and (y == room_height // 3 - 1 or y == 2 * room_height // 3)))
                            
                            if is_edge:
                                chunk[check_y][check_x] = wall_block
                            else:
                                chunk[check_y][check_x] = floor_block
            
            else:  # irregular
                # Create an irregular room with noise
                for x in range(room_width):
                    for y in range(room_height):
                        check_x = room_x + x
                        check_y = room_y + y
                        
                        # Skip if out of bounds
                        if not (0 <= check_x < self.CHUNK_SIZE and 0 <= check_y < self.CHUNK_SIZE):
                            continue
                        
                        # Calculate center distance
                        nx = 2 * x / room_width - 1
                        ny = 2 * y / room_height - 1
                        base_distance = nx*nx + ny*ny
                        
                        # Add noise to create irregular edges
                        noise_val = noise.pnoise2(x/5, y/5, octaves=1) * 0.3
                        effective_distance = base_distance + noise_val
                        
                        if effective_distance <= 1:
                            # Inside irregular room
                            chunk[check_y][check_x] = floor_block
                        elif effective_distance <= 1.2:
                            # Wall thickness
                            chunk[check_y][check_x] = wall_block
            
            # Add room features based on theme
            self._add_dungeon_room_features(chunk, room_x, room_y, room_width, room_height, theme, shape)
        
        # Connect rooms with corridors
        self._connect_dungeon_rooms(chunk, rooms, wall_block, floor_block)
        
        # Add entrance and exit
        if rooms:
            # Entrance in first room
            entrance_room = rooms[0]
            ex, ey, ew, eh = entrance_room
            entrance_x = ex + ew // 2
            entrance_y = ey + eh // 2
            
            if 0 <= entrance_x < self.CHUNK_SIZE and 0 <= entrance_y < self.CHUNK_SIZE:
                chunk[entrance_y][entrance_x] = 'ladder_up'
            
            # Exit in last room
            exit_room = rooms[-1]
            ex, ey, ew, eh = exit_room
            exit_x = ex + ew // 2
            exit_y = ey + eh // 2
            
            if 0 <= exit_x < self.CHUNK_SIZE and 0 <= exit_y < self.CHUNK_SIZE:
                chunk[exit_y][exit_x] = 'ladder_down'
        
        # Add random traps and special features
        self._add_dungeon_traps(chunk, center_x, center_y, dungeon_size, theme)
        
        # Generate structure ID
        structure_id = f"dungeon_{center_x}_{center_y}_{random.randint(1000, 9999)}"
        
        # Return structure data
        return structure_id
    
    def _add_dungeon_room_features(self, chunk, room_x, room_y, room_width, room_height, theme, shape):
        """Add themed features to a dungeon room"""
        # Different features based on room theme
        if theme == 'prison':
            # Add cells
            num_cells = random.randint(2, 4)
            for _ in range(num_cells):
                cell_x = room_x + random.randint(1, room_width - 2)
                cell_y = room_y + random.randint(1, room_height - 2)
                
                if 0 <= cell_x < self.CHUNK_SIZE and 0 <= cell_y < self.CHUNK_SIZE:
                    chunk[cell_y][cell_x] = 'iron'  # Cell bars
        
        elif theme == 'ritual':
            # Add ritual circle
            center_x = room_x + room_width // 2
            center_y = room_y + room_height // 2
            
            if 0 <= center_x < self.CHUNK_SIZE and 0 <= center_y < self.CHUNK_SIZE:
                chunk[center_y][center_x] = 'portal_component'
                
                # Circle around it
                for i in range(4):
                    angle = i * math.pi / 2
                    x = int(center_x + 2 * math.cos(angle))
                    y = int(center_y + 2 * math.sin(angle))
                    
                    if 0 <= x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE:
                        chunk[y][x] = 'obsidian'
        
        elif theme == 'crypt':
            # Add graves/tombs
            num_tombs = random.randint(3, 6)
            for _ in range(num_tombs):
                tomb_x = room_x + random.randint(1, room_width - 2)
                tomb_y = room_y + random.randint(1, room_height - 2)
                
                if 0 <= tomb_x < self.CHUNK_SIZE and 0 <= tomb_y < self.CHUNK_SIZE:
                    chunk[tomb_y][tomb_x] = 'stone'
                    
                    # Add some decoration
                    for dx, dy in [(0, 1), (1, 0), (0, -1), (-1, 0)]:
                        x = tomb_x + dx
                        y = tomb_y + dy
                        
                        if (0 <= x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE and
                            x >= room_x and x < room_x + room_width and
                            y >= room_y and y < room_y + room_height and
                            random.random() < 0.3):
                            chunk[y][x] = 'obsidian'
        
        else:  # Other themes
            # Add columns or other decorations
            num_decorations = random.randint(2, 5)
            for _ in range(num_decorations):
                decor_x = room_x + random.randint(1, room_width - 2)
                decor_y = room_y + random.randint(1, room_height - 2)
                
                if 0 <= decor_x < self.CHUNK_SIZE and 0 <= decor_y < self.CHUNK_SIZE:
                    chunk[decor_y][decor_x] = 'castle_pillar'
        
        # Add occasional spawners
        if random.random() < 0.3:
            spawner_x = room_x + room_width // 2
            spawner_y = room_y + room_height // 2
            
            if 0 <= spawner_x < self.CHUNK_SIZE and 0 <= spawner_y < self.CHUNK_SIZE:
                chunk[spawner_y][spawner_x] = 'spawner'
        
        # Add chests with treasure
        if random.random() < 0.4:
            # Place near a wall
            wall_positions = []
            
            for x in range(1, room_width - 1):
                wall_positions.append((room_x + x, room_y + 1))  # North wall
                wall_positions.append((room_x + x, room_y + room_height - 2))  # South wall
            
            for y in range(1, room_height - 1):
                wall_positions.append((room_x + 1, room_y + y))  # West wall
                wall_positions.append((room_x + room_width - 2, room_y + y))  # East wall
            
            if wall_positions:
                chest_pos = random.choice(wall_positions)
                chest_x, chest_y = chest_pos
                
                if 0 <= chest_x < self.CHUNK_SIZE and 0 <= chest_y < self.CHUNK_SIZE:
                    chunk[chest_y][chest_x] = 'chest'
    
    def _connect_dungeon_rooms(self, chunk, rooms, wall_block, floor_block):
        """Connect dungeon rooms with corridors"""
        if len(rooms) <= 1:
            return
        
        # Sort rooms by position for more logical connections
        rooms_by_x = sorted(rooms, key=lambda r: r[0])
        
        # Connect adjacent rooms
        for i in range(len(rooms_by_x) - 1):
            current_room = rooms_by_x[i]
            next_room = rooms_by_x[i + 1]
            
            # Calculate center points
            current_center_x = current_room[0] + current_room[2] // 2
            current_center_y = current_room[1] + current_room[3] // 2
            
            next_center_x = next_room[0] + next_room[2] // 2
            next_center_y = next_room[1] + next_room[3] // 2
            
            # Choose corridor style
            corridor_style = random.choice(['straight', 'L-shaped', 'winding'])
            
            if corridor_style == 'straight':
                # Direct corridor
                self._create_straight_corridor(chunk, current_center_x, current_center_y, 
                                          next_center_x, next_center_y, wall_block, floor_block)
            
            elif corridor_style == 'L-shaped':
                # L-shaped corridor through intermediate point
                mid_x = current_center_x
                mid_y = next_center_y
                
                # First leg
                self._create_straight_corridor(chunk, current_center_x, current_center_y, 
                                          mid_x, mid_y, wall_block, floor_block)
                
                # Second leg
                self._create_straight_corridor(chunk, mid_x, mid_y, 
                                          next_center_x, next_center_y, wall_block, floor_block)
            
            else:  # winding
                # Create a winding path with multiple segments
                num_segments = random.randint(2, 4)
                
                # Create waypoints
                waypoints = [(current_center_x, current_center_y)]
                
                for s in range(1, num_segments):
                    # Interpolate position
                    t = s / num_segments
                    way_x = int(current_center_x * (1-t) + next_center_x * t)
                    way_y = int(current_center_y * (1-t) + next_center_y * t)
                    
                    # Add some randomness
                    way_x += random.randint(-3, 3)
                    way_y += random.randint(-3, 3)
                    
                    waypoints.append((way_x, way_y))
                
                waypoints.append((next_center_x, next_center_y))
                
                # Connect waypoints
                for j in range(len(waypoints) - 1):
                    start_x, start_y = waypoints[j]
                    end_x, end_y = waypoints[j + 1]
                    
                    self._create_straight_corridor(chunk, start_x, start_y, 
                                             end_x, end_y, wall_block, floor_block)
    
    def _create_straight_corridor(self, chunk, start_x, start_y, end_x, end_y, wall_block, floor_block):
        """Create a straight corridor between two points"""
        # Calculate direction and steps
        dx = end_x - start_x
        dy = end_y - start_y
        steps = max(abs(dx), abs(dy))
        
        if steps == 0:
            return
        
        # Step size
        step_x = dx / steps
        step_y = dy / steps
        
        # Create corridor
        for i in range(steps + 1):
            x = int(start_x + step_x * i)
            y = int(start_y + step_y * i)
            
            # Skip if out of bounds
            if not (0 <= x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE):
                continue
            
            # Set floor
            chunk[y][x] = floor_block
            
            # Add walls
            for wall_dx, wall_dy in [(0, 1), (1, 0), (0, -1), (-1, 0)]:
                wall_x = x + wall_dx
                wall_y = y + wall_dy
                
                if 0 <= wall_x < self.CHUNK_SIZE and 0 <= wall_y < self.CHUNK_SIZE:
                    # Only add wall if it's not replacing a floor
                    if chunk[wall_y][wall_x] != floor_block and chunk[wall_y][wall_x] != 'ladder_up' and chunk[wall_y][wall_x] != 'ladder_down':
                        chunk[wall_y][wall_x] = wall_block
    
    def _add_dungeon_traps(self, chunk, center_x, center_y, dungeon_size, theme):
        """Add various traps and special features to the dungeon"""
        # Search for corridors to place traps
        trap_spots = []
        
        for x in range(center_x - dungeon_size, center_x + dungeon_size):
            for y in range(center_y - dungeon_size, center_y + dungeon_size):
                # Skip if out of bounds
                if not (0 <= x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE):
                    continue
                
                # Check if this is a corridor (floor with walls on opposite sides)
                if chunk[y][x] == 'stone' or chunk[y][x] == 'castle_floor':
                    # Check horizontal corridor
                    has_horizontal_walls = (0 <= y-1 < self.CHUNK_SIZE and 0 <= y+1 < self.CHUNK_SIZE and
                                          chunk[y-1][x] not in ['stone', 'castle_floor', 'air'] and
                                          chunk[y+1][x] not in ['stone', 'castle_floor', 'air'])
                    
                    # Check vertical corridor
                    has_vertical_walls = (0 <= x-1 < self.CHUNK_SIZE and 0 <= x+1 < self.CHUNK_SIZE and
                                        chunk[y][x-1] not in ['stone', 'castle_floor', 'air'] and
                                        chunk[y][x+1] not in ['stone', 'castle_floor', 'air'])
                    
                    if has_horizontal_walls or has_vertical_walls:
                        trap_spots.append((x, y))
        
        # Add a few traps
        num_traps = min(len(trap_spots) // 3, 5)
        
        if trap_spots and num_traps > 0:
            random.shuffle(trap_spots)
            
            for i in range(num_traps):
                trap_x, trap_y = trap_spots[i]
                
                # Different trap types based on theme
                if theme == 'prison':
                    # Iron bars trap
                    chunk[trap_y][trap_x] = 'iron'
                elif theme == 'ritual':
                    # Magic trap
                    chunk[trap_y][trap_x] = 'portal_component'
                elif theme == 'crypt':
                    # Spawner trap
                    chunk[trap_y][trap_x] = 'spawner'
                else:
                    # Default pit trap (represented by water)
                    chunk[trap_y][trap_x] = 'water'
    
    def _generate_ancient_complex(self, chunk, level_id):
        """Generate an ancient complex structure for deep underground levels"""
        # Structure parameters
        complex_size = random.randint(12, 16)
        
        # Choose complex type based on depth
        if level_id <= 30:
            complex_type = random.choice(['abandoned_laboratory', 'ancient_temple', 'crystal_cavern'])
        else:
            complex_type = random.choice(['infernal_forge', 'void_nexus', 'elder_library'])
        
        # Choose blocks based on complex type
        if complex_type == 'abandoned_laboratory':
            wall_block = 'stone'
            floor_block = 'obsidian'
            special_block = 'portal_component'
        elif complex_type == 'ancient_temple':
            wall_block = 'castle_wall'
            floor_block = 'marble'
            special_block = 'gold'
        elif complex_type == 'crystal_cavern':
            wall_block = 'stone'
            floor_block = 'air'
            special_block = 'diamond'
        elif complex_type == 'infernal_forge':
            wall_block = 'obsidian'
            floor_block = 'brimstone'
            special_block = 'lava'
        elif complex_type == 'void_nexus':
            wall_block = 'obsidian'
            floor_block = 'obsidian'
            special_block = 'portal_component'
        else:  # elder_library
            wall_block = 'castle_wall_outer'
            floor_block = 'wood'
            special_block = 'castle_ornament'
        
        # Find suitable center position
        center_x = random.randint(complex_size, self.CHUNK_SIZE - complex_size - 1)
        center_y = random.randint(complex_size, self.CHUNK_SIZE - complex_size - 1)
        
        # Generate complex layout
        if complex_type in ['abandoned_laboratory', 'infernal_forge', 'elder_library']:
            # Geometric layout with rooms and labs
            return self._generate_geometric_complex(chunk, center_x, center_y, complex_size, 
                                              wall_block, floor_block, special_block, complex_type)
        else:
            # Organic layout with chambers
            return self._generate_organic_complex(chunk, center_x, center_y, complex_size, 
                                            wall_block, floor_block, special_block, complex_type)
    
    def _generate_geometric_complex(self, chunk, center_x, center_y, complex_size, 
                                   wall_block, floor_block, special_block, complex_type):
        """Generate a complex with geometric rooms and corridors"""
        # Create a grid of rooms
        grid_size = 3  # 3x3 grid of rooms
        room_size = complex_size // grid_size
        
        # Create rooms
        rooms = []
        for gx in range(grid_size):
            for gy in range(grid_size):
                # Determine if this grid cell should have a room
                has_room = random.random() < 0.7  # 70% chance
                
                if gx == grid_size // 2 and gy == grid_size // 2:
                    has_room = True  # Always have center room
                
                if has_room:
                 
# Calculate room position
                    room_x = center_x - complex_size // 2 + gx * room_size
                    room_y = center_y - complex_size // 2 + gy * room_size
                    
                    # Randomize room size slightly
                    width = room_size - random.randint(1, 3)
                    height = room_size - random.randint(1, 3)
                    
                    # Store room data
                    rooms.append((room_x, room_y, width, height, f"room_{gx}_{gy}"))
        
        # Create rooms
        for room_x, room_y, width, height, room_id in rooms:
            # Create room walls and floor
            for x in range(width):
                for y in range(height):
                    check_x = room_x + x
                    check_y = room_y + y
                    
                    # Skip if out of bounds
                    if not (0 <= check_x < self.CHUNK_SIZE and 0 <= check_y < self.CHUNK_SIZE):
                        continue
                    
                    # Walls
                    if x == 0 or x == width - 1 or y == 0 or y == height - 1:
                        chunk[check_y][check_x] = wall_block
                    else:
                        # Floor
                        chunk[check_y][check_x] = floor_block
            
            # Add room features based on complex type
            if complex_type == 'abandoned_laboratory':
                # Add lab equipment
                num_equipment = random.randint(1, 3)
                for _ in range(num_equipment):
                    equip_x = room_x + random.randint(1, width - 2)
                    equip_y = room_y + random.randint(1, height - 2)
                    
                    if 0 <= equip_x < self.CHUNK_SIZE and 0 <= equip_y < self.CHUNK_SIZE:
                        chunk[equip_y][equip_x] = special_block
            
            elif complex_type == 'infernal_forge':
                # Add forge and lava
                if width >= 3 and height >= 3:
                    forge_x = room_x + width // 2
                    forge_y = room_y + height // 2
                    
                    if 0 <= forge_x < self.CHUNK_SIZE and 0 <= forge_y < self.CHUNK_SIZE:
                        chunk[forge_y][forge_x] = special_block
                        
                        # Add some lava pools
                        for dx, dy in [(1, 0), (0, 1), (-1, 0), (0, -1)]:
                            x = forge_x + dx
                            y = forge_y + dy
                            
                            if (0 <= x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE and
                                random.random() < 0.5):
                                chunk[y][x] = 'lava'
            
            else:  # elder_library
                # Add bookshelves along walls
                for x in range(1, width - 1):
                    # North and south walls
                    if 0 <= room_x + x < self.CHUNK_SIZE:
                        if 0 <= room_y + 1 < self.CHUNK_SIZE and random.random() < 0.7:
                            chunk[room_y + 1][room_x + x] = special_block
                        
                        if 0 <= room_y + height - 2 < self.CHUNK_SIZE and random.random() < 0.7:
                            chunk[room_y + height - 2][room_x + x] = special_block
                
                for y in range(1, height - 1):
                    # East and west walls
                    if 0 <= room_y + y < self.CHUNK_SIZE:
                        if 0 <= room_x + 1 < self.CHUNK_SIZE and random.random() < 0.7:
                            chunk[room_y + y][room_x + 1] = special_block
                        
                        if 0 <= room_x + width - 2 < self.CHUNK_SIZE and random.random() < 0.7:
                            chunk[room_y + y][room_x + width - 2] = special_block
        
        # Create corridors to connect rooms
        for i in range(len(rooms)):
            room1 = rooms[i]
            
            # Connect to 1-2 other rooms
            connections = random.randint(1, 2)
            connected = 0
            
            # Shuffle other rooms for random connections
            other_rooms = rooms.copy()
            random.shuffle(other_rooms)
            
            for room2 in other_rooms:
                if room1 == room2 or connected >= connections:
                    continue
                
                # Calculate room centers
                room1_center_x = room1[0] + room1[2] // 2
                room1_center_y = room1[1] + room1[3] // 2
                
                room2_center_x = room2[0] + room2[2] // 2
                room2_center_y = room2[1] + room2[3] // 2
                
                # Create corridor
                self._create_complex_corridor(chunk, room1_center_x, room1_center_y, 
                                         room2_center_x, room2_center_y, 
                                         wall_block, floor_block)
                
                connected += 1
        
        # Add entrance and exit
        if rooms:
            # Entrance in first corner room
            entrance_room = rooms[0]
            entrance_x = entrance_room[0] + entrance_room[2] // 2
            entrance_y = entrance_room[1] + entrance_room[3] // 2
            
            if 0 <= entrance_x < self.CHUNK_SIZE and 0 <= entrance_y < self.CHUNK_SIZE:
                chunk[entrance_y][entrance_x] = 'ladder_up'
            
            # Exit in opposite corner room or special central room
            if complex_type == 'void_nexus':
                # Central portal
                exit_x = center_x
                exit_y = center_y
                
                if 0 <= exit_x < self.CHUNK_SIZE and 0 <= exit_y < self.CHUNK_SIZE:
                    for dx in range(-1, 2):
                        for dy in range(-1, 2):
                            x = exit_x + dx
                            y = exit_y + dy
                            
                            if 0 <= x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE:
                                if dx == 0 and dy == 0:
                                    chunk[y][x] = 'portal_brimstone' if random.random() < 0.5 else 'ladder_down'
                                else:
                                    chunk[y][x] = special_block
            else:
                # Normal exit
                exit_room = rooms[-1]
                exit_x = exit_room[0] + exit_room[2] // 2
                exit_y = exit_room[1] + exit_room[3] // 2
                
                if 0 <= exit_x < self.CHUNK_SIZE and 0 <= exit_y < self.CHUNK_SIZE:
                    chunk[exit_y][exit_x] = 'ladder_down'
        
        # Add special central feature based on complex type
        self._add_complex_central_feature(chunk, center_x, center_y, complex_type, special_block)
        
        # Generate structure ID
        structure_id = f"complex_{center_x}_{center_y}_{random.randint(1000, 9999)}"
        
        return structure_id
    
    def _create_complex_corridor(self, chunk, start_x, start_y, end_x, end_y, wall_block, floor_block):
        """Create a corridor between rooms in a geometric complex"""
        # Determine if straight or L-shaped
        use_l_shape = random.random() < 0.7  # 70% chance for L-shape
        
        if use_l_shape:
            # Create L-shaped corridor
            mid_x = start_x
            mid_y = end_y
            
            # First segment
            for y in range(min(start_y, mid_y), max(start_y, mid_y) + 1):
                if 0 <= mid_x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE:
                    # Floor
                    chunk[y][mid_x] = floor_block
                    
                    # Walls
                    for dx in [-1, 1]:
                        wall_x = mid_x + dx
                        if 0 <= wall_x < self.CHUNK_SIZE and chunk[y][wall_x] not in [floor_block, 'ladder_up', 'ladder_down']:
                            chunk[y][wall_x] = wall_block
            
            # Second segment
            for x in range(min(mid_x, end_x), max(mid_x, end_x) + 1):
                if 0 <= x < self.CHUNK_SIZE and 0 <= mid_y < self.CHUNK_SIZE:
                    # Floor
                    chunk[mid_y][x] = floor_block
                    
                    # Walls
                    for dy in [-1, 1]:
                        wall_y = mid_y + dy
                        if 0 <= wall_y < self.CHUNK_SIZE and chunk[wall_y][x] not in [floor_block, 'ladder_up', 'ladder_down']:
                            chunk[wall_y][x] = wall_block
        else:
            # Create straight corridor
            # Calculate direction and steps
            dx = end_x - start_x
            dy = end_y - start_y
            steps = max(abs(dx), abs(dy))
            
            if steps == 0:
                return
            
            # Step size
            step_x = dx / steps
            step_y = dy / steps
            
            # Create corridor
            for i in range(steps + 1):
                x = int(start_x + step_x * i)
                y = int(start_y + step_y * i)
                
                # Skip if out of bounds
                if not (0 <= x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE):
                    continue
                
                # Set floor
                chunk[y][x] = floor_block
                
                # Add walls
                if abs(dx) > abs(dy):  # Horizontal corridor
                    for wall_dy in [-1, 1]:
                        wall_y = y + wall_dy
                        if 0 <= wall_y < self.CHUNK_SIZE and chunk[wall_y][x] not in [floor_block, 'ladder_up', 'ladder_down']:
                            chunk[wall_y][x] = wall_block
                else:  # Vertical corridor
                    for wall_dx in [-1, 1]:
                        wall_x = x + wall_dx
                        if 0 <= wall_x < self.CHUNK_SIZE and chunk[y][wall_x] not in [floor_block, 'ladder_up', 'ladder_down']:
                            chunk[y][wall_x] = wall_block
    
    def _add_complex_central_feature(self, chunk, center_x, center_y, complex_type, special_block):
        """Add a special central feature to the complex"""
        # Different features based on complex type
        if complex_type == 'abandoned_laboratory':
            # Portal experiment
            for dx in range(-2, 3):
                for dy in range(-2, 3):
                    x = center_x + dx
                    y = center_y + dy
                    
                    if not (0 <= x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE):
                        continue
                    
                    # Diamond shape
                    if abs(dx) + abs(dy) <= 2:
                        if dx == 0 and dy == 0:
                            chunk[y][x] = 'portal_component'
                        else:
                            chunk[y][x] = special_block
        
        elif complex_type == 'infernal_forge':
            # Central forge with lava
            lava_radius = 3
            for dx in range(-lava_radius, lava_radius + 1):
                for dy in range(-lava_radius, lava_radius + 1):
                    x = center_x + dx
                    y = center_y + dy
                    
                    if not (0 <= x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE):
                        continue
                    
                    # Circular lava pool
                    distance = math.sqrt(dx*dx + dy*dy)
                    if distance <= lava_radius - 1:
                        chunk[y][x] = 'lava'
                    elif distance <= lava_radius:
                        chunk[y][x] = 'obsidian'
        
        elif complex_type == 'elder_library':
            # Grand library with special item
            for dx in range(-3, 4):
                for dy in range(-3, 4):
                    x = center_x + dx
                    y = center_y + dy
                    
                    if not (0 <= x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE):
                        continue
                    
                    # Square room
                    if abs(dx) <= 2 and abs(dy) <= 2:
                        # Floor
                        chunk[y][x] = floor_block
                        
                        # Bookshelves around edges
                        if (abs(dx) == 2 or abs(dy) == 2) and random.random() < 0.7:
                            chunk[y][x] = special_block
            
            # Central pedestal
            if 0 <= center_x < self.CHUNK_SIZE and 0 <= center_y < self.CHUNK_SIZE:
                chunk[center_y][center_x] = 'gold'
    
    def _generate_organic_complex(self, chunk, center_x, center_y, complex_size, 
                                 wall_block, floor_block, special_block, complex_type):
        """Generate a complex with organic chambers and natural formations"""
        # Create large central chamber
        central_radius = complex_size // 3
        
        # Add noise to create natural formations
        for dx in range(-complex_size, complex_size + 1):
            for dy in range(-complex_size, complex_size + 1):
                x = center_x + dx
                y = center_y + dy
                
                # Skip if out of bounds
                if not (0 <= x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE):
                    continue
                
                # Calculate base distance from center
                distance = math.sqrt(dx*dx + dy*dy)
                
                # Add perlin noise
                noise_value = noise.pnoise2(x/10, y/10, octaves=2) * 3.0
                
                # Determine block type based on distance + noise
                if distance + noise_value < central_radius:
                    # Central chamber
                    chunk[y][x] = floor_block
                elif distance + noise_value < complex_size:
                    # Create caves and passages based on noise
                    second_noise = noise.pnoise2(x/5, y/5, octaves=4) * 2.0
                    
                    if second_noise > 0.3:
                        chunk[y][x] = floor_block
                    else:
                        chunk[y][x] = 'stone'  # Natural rock
        
        # Add special features based on complex type
        if complex_type == 'ancient_temple':
            # Add pillars and structures in temple
            self._add_temple_features(chunk, center_x, center_y, central_radius, wall_block, special_block)
        
        elif complex_type == 'crystal_cavern':
            # Add crystal formations
            self._add_crystal_features(chunk, center_x, center_y, complex_size, special_block)
        
        elif complex_type == 'void_nexus':
            # Add void elements
            self._add_void_features(chunk, center_x, center_y, central_radius, special_block)
        
        # Add entrance and exit
        # Find suitable entrance point
        entrance_distance = central_radius + random.randint(1, 3)
        entrance_angle = random.uniform(0, 2 * math.pi)
        entrance_x = int(center_x + entrance_distance * math.cos(entrance_angle))
        entrance_y = int(center_y + entrance_distance * math.sin(entrance_angle))
        
        if 0 <= entrance_x < self.CHUNK_SIZE and 0 <= entrance_y < self.CHUNK_SIZE:
            chunk[entrance_y][entrance_x] = 'ladder_up'
        
        # Exit is either central portal or opposite entrance
        if complex_type == 'void_nexus':
            # Central void portal
            chunk[center_y][center_x] = 'portal_brimstone'
        else:
            # Exit opposite entrance
            exit_angle = entrance_angle + math.pi
            exit_distance = central_radius - random.randint(0, 2)
            exit_x = int(center_x + exit_distance * math.cos(exit_angle))
            exit_y = int(center_y + exit_distance * math.sin(exit_angle))
            
            if 0 <= exit_x < self.CHUNK_SIZE and 0 <= exit_y < self.CHUNK_SIZE:
                chunk[exit_y][exit_x] = 'ladder_down'
        
        # Generate structure ID
        structure_id = f"organic_{center_x}_{center_y}_{random.randint(1000, 9999)}"
        
        return structure_id
    
    def _add_temple_features(self, chunk, center_x, center_y, radius, wall_block, special_block):
        """Add temple features to an organic complex"""
        # Add pillars in a circle
        num_pillars = 8
        for i in range(num_pillars):
            angle = 2 * math.pi * i / num_pillars
            pillar_distance = radius * 0.7
            
            pillar_x = int(center_x + pillar_distance * math.cos(angle))
            pillar_y = int(center_y + pillar_distance * math.sin(angle))
            
            if 0 <= pillar_x < self.CHUNK_SIZE and 0 <= pillar_y < self.CHUNK_SIZE:
                chunk[pillar_y][pillar_x] = 'castle_pillar'
        
        # Add central altar
        altar_size = 3
        for dx in range(-altar_size, altar_size + 1):
            for dy in range(-altar_size, altar_size + 1):
                x = center_x + dx
                y = center_y + dy
                
                if not (0 <= x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE):
                    continue
                
                # Diamond/square shape
                if abs(dx) + abs(dy) <= altar_size:
                    if dx == 0 and dy == 0:
                        chunk[y][x] = special_block
                    else:
                        chunk[y][x] = wall_block
    
    def _add_crystal_features(self, chunk, center_x, center_y, complex_size, special_block):
        """Add crystal formations to an organic complex"""
        # Add large crystal clusters throughout the cavern
        num_clusters = random.randint(5, 10)
        
        for _ in range(num_clusters):
            # Random position within complex
            cluster_x = center_x + random.randint(-complex_size + 3, complex_size - 3)
            cluster_y = center_y + random.randint(-complex_size + 3, complex_size - 3)
            
            # Skip if out of bounds
            if not (0 <= cluster_x < self.CHUNK_SIZE and 0 <= cluster_y < self.CHUNK_SIZE):
                continue
            
            # Skip if not in an open area
            if chunk[cluster_y][cluster_x] != 'air':
                continue
            
            # Create crystal cluster
            cluster_size = random.randint(1, 3)
            for dx in range(-cluster_size, cluster_size + 1):
                for dy in range(-cluster_size, cluster_size + 1):
                    x = cluster_x + dx
                    y = cluster_y + dy
                    
                    if not (0 <= x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE):
                        continue
                    
                    # Skip if not in an open area
                    if chunk[y][x] != 'air':
                        continue
                    
                    # Create jagged crystal shape
                    if abs(dx) + abs(dy) <= cluster_size and random.random() < 0.7:
                        chunk[y][x] = special_block
    
    def _add_void_features(self, chunk, center_x, center_y, radius, special_block):
        """Add void-related features to an organic complex"""
        # Create a void circle
        void_radius = radius // 2
        
        for dx in range(-void_radius, void_radius + 1):
            for dy in range(-void_radius, void_radius + 1):
                x = center_x + dx
                y = center_y + dy
                
                if not (0 <= x < self.CHUNK_SIZE and 0 <= y < self.CHUNK_SIZE):
                    continue
                
                # Calculate distance from center
                distance = math.sqrt(dx*dx + dy*dy)
                
                if distance <= void_radius - 1:
                    # Void center
                    if distance < 2:
                        chunk[y][x] = 'portal_brimstone'
                    else:
                        chunk[y][x] = 'obsidian'  # Void material
                elif distance <= void_radius:
                    # Edge of the void
                    chunk[y][x] = special_block