// 2D Flat Map Data - Generated to match reference images // Map size: 100x100 tiles (48x48px each = 4800x4800px world) // Style: Stardew Valley smooth 2D top-down const Map2DData = { width: 100, height: 100, tileSize: 48, // Tile type IDs tileTypes: { GRASS: 0, GRASS_FLOWERS: 1, DIRT: 2, DIRT_EDGE: 3, WATER: 4, WATER_EDGE: 5, STONE: 6, TREE: 7, FLOWER_RED: 8, FLOWER_YELLOW: 9, FLOWER_BLUE: 10, LILY_PAD: 11, BUSH: 12 }, // Map layout - BEAUTIFUL NATURAL DESIGN! 🌳💧🛤️ generateMap: function () { const map = []; // Initialize with grass (some with flowers - 5%) for (let y = 0; y < this.height; y++) { map[y] = []; for (let x = 0; x < this.width; x++) { // Mix of clean grass and flowery grass map[y][x] = { base: Math.random() < 0.05 ? this.tileTypes.GRASS_FLOWERS : this.tileTypes.GRASS, decoration: null, walkable: true }; } } // 1. BEAUTIFUL ORGANIC POND (like reference image!) 💧 this.addPond(map, 60, 45, 18, 14); // Larger, more organic // 2. NO PATHS - clean grass! 🌿 // this.addWindingPath(map, 10, 10, 90, 90); // Disabled // this.addWindingPath(map, 90, 10, 10, 90); // Disabled // 3. SPARSE SCATTERED TREES 🌳 (NO CLUSTERS!) // Removed all corner forests - too crowded! // Just a few scattered trees across entire map for (let i = 0; i < 10; i++) { // VERY FEW! (was 15) this.addTreeCluster(map, 10 + Math.random() * 80, // Entire map 10 + Math.random() * 80, 1 // Single trees only ); } // 4. COLORFUL FLOWERS SCATTERED 🌸 this.addFlowers(map, 30); // 5. BUSHES near tree clusters 🌿 this.addBushes(map, 15); // 6. NO PUDDLES (no paths anymore!) // this.addPuddlesAlongPaths(map, 8); // Disabled return map; }, addPond: function (map, centerX, centerY, width, height) { // PERFECTLY ROUND/CIRCULAR pond! 🔵 const radius = Math.min(width, height) / 2; for (let y = -radius; y < radius; y++) { for (let x = -radius; x < radius; x++) { const dist = Math.sqrt(x * x + y * y); // Perfect circle - no noise! if (dist < radius) { const tileX = Math.floor(centerX + x); const tileY = Math.floor(centerY + y); if (tileX >= 0 && tileX < this.width && tileY >= 0 && tileY < this.height) { // Edge or center (smooth transition) if (dist > radius - 2) { map[tileY][tileX].base = this.tileTypes.WATER_EDGE; } else { map[tileY][tileX].base = this.tileTypes.WATER; } map[tileY][tileX].walkable = false; } } } } // Add lily pads in circular pattern for (let i = 0; i < 4; i++) { const angle = (Math.PI * 2 * i) / 4 + Math.random() * 0.5; const r = radius * (0.4 + Math.random() * 0.3); const lx = Math.floor(centerX + Math.cos(angle) * r); const ly = Math.floor(centerY + Math.sin(angle) * r); if (lx >= 0 && lx < this.width && ly >= 0 && ly < this.height) { if (map[ly][lx].base === this.tileTypes.WATER) { map[ly][lx].decoration = this.tileTypes.LILY_PAD; } } } }, addWindingPath: function (map, startX, startY, endX, endY) { const steps = 50; const pathWidth = 1; // NARROW path - 1 tile wide! for (let i = 0; i <= steps; i++) { const t = i / steps; // Cubic curve for natural winding const x = startX + (endX - startX) * t + Math.sin(t * Math.PI * 3) * 8; const y = startY + (endY - startY) * t + Math.cos(t * Math.PI * 2) * 6; // Draw path with width for (let py = -pathWidth; py <= pathWidth; py++) { for (let px = -pathWidth; px <= pathWidth; px++) { const dist = Math.sqrt(px * px + py * py); if (dist <= pathWidth) { const tileX = Math.floor(x + px); const tileY = Math.floor(y + py); if (tileX >= 0 && tileX < this.width && tileY >= 0 && tileY < this.height) { if (map[tileY][tileX].base !== this.tileTypes.WATER) { if (dist > pathWidth - 0.5) { map[tileY][tileX].base = this.tileTypes.DIRT_EDGE; } else { map[tileY][tileX].base = this.tileTypes.DIRT; } } } } } } } }, addPuddlesAlongPaths: function (map, count) { let placed = 0; let attempts = 0; while (placed < count && attempts < count * 10) { const x = Math.floor(Math.random() * this.width); const y = Math.floor(Math.random() * this.height); // Check if near path edge if (map[y][x].base === this.tileTypes.DIRT_EDGE || map[y][x].base === this.tileTypes.DIRT) { // Small puddle (already have sprite!) map[y][x].decoration = 'puddle'; placed++; } attempts++; } }, addTreeCluster: function (map, centerX, centerY, count) { for (let i = 0; i < count; i++) { const angle = (Math.PI * 2 * i) / count + Math.random() * 0.5; const radius = 8 + Math.random() * 7; // EVEN WIDER! (was 5+7) const tx = Math.floor(centerX + Math.cos(angle) * radius); const ty = Math.floor(centerY + Math.sin(angle) * radius); if (tx >= 0 && tx < this.width && ty >= 0 && ty < this.height) { if (map[ty][tx].walkable && map[ty][tx].base === this.tileTypes.GRASS) { map[ty][tx].decoration = this.tileTypes.TREE; map[ty][tx].walkable = false; } } } }, addFlowers: function (map, count) { const flowerTypes = [ this.tileTypes.FLOWER_RED, this.tileTypes.FLOWER_YELLOW, this.tileTypes.FLOWER_BLUE ]; for (let i = 0; i < count; i++) { const x = Math.floor(Math.random() * this.width); const y = Math.floor(Math.random() * this.height); if (map[y][x].base === this.tileTypes.GRASS && !map[y][x].decoration && map[y][x].walkable) { map[y][x].decoration = flowerTypes[Math.floor(Math.random() * flowerTypes.length)]; } } }, addBushes: function (map, count) { for (let i = 0; i < count; i++) { const x = Math.floor(Math.random() * this.width); const y = Math.floor(Math.random() * this.height); if (map[y][x].base === this.tileTypes.GRASS && !map[y][x].decoration && map[y][x].walkable) { map[y][x].decoration = this.tileTypes.BUSH; map[y][x].walkable = false; } } } }; // Export for use if (typeof module !== 'undefined' && module.exports) { module.exports = Map2DData; }