/** * 🏛️ STRUCTURE INTERACTION SYSTEM * Enables player interaction with structures in the world * - Enter buildings * - Loot chests * - Landmark treasures * - Lock/unlock mechanics */ class StructureInteractionSystem { constructor(scene) { this.scene = scene; // Interaction markers this.interactionMarkers = []; // Loot chests (generated per structure) this.chests = new Map(); // key: "x,y" → chest data // Active interactions this.nearbyStructures = []; this.currentInteraction = null; // Loot tables per biome this.lootTables = { 'Grassland': [ { item: 'wheat_seeds', min: 5, max: 15, chance: 0.7 }, { item: 'wood', min: 10, max: 30, chance: 0.8 }, { item: 'gold', min: 20, max: 50, chance: 0.5 }, { item: 'iron_ore', min: 1, max: 5, chance: 0.3 } ], 'Forest': [ { item: 'wood', min: 20, max: 50, chance: 0.9 }, { item: 'apple', min: 3, max: 10, chance: 0.6 }, { item: 'berry', min: 5, max: 15, chance: 0.7 }, { item: 'mushroom', min: 2, max: 8, chance: 0.4 } ], 'Desert': [ { item: 'gold', min: 50, max: 150, chance: 0.6 }, { item: 'ruby', min: 1, max: 3, chance: 0.2 }, { item: 'ancient_scroll', min: 1, max: 1, chance: 0.1 }, { item: 'cactus_fruit', min: 3, max: 10, chance: 0.5 } ], 'Mountain': [ { item: 'iron_ore', min: 10, max: 30, chance: 0.8 }, { item: 'gold_ore', min: 5, max: 15, chance: 0.6 }, { item: 'diamond', min: 1, max: 3, chance: 0.15 }, { item: 'stone', min: 20, max: 50, chance: 0.9 } ], 'Swamp': [ { item: 'herbs', min: 5, max: 20, chance: 0.7 }, { item: 'mushroom', min: 10, max: 30, chance: 0.8 }, { item: 'slime', min: 5, max: 15, chance: 0.6 }, { item: 'ancient_bone', min: 1, max: 5, chance: 0.3 } ] }; // Landmark treasure (special rare items) this.landmarkTreasures = { 'ancient_temple': [ { item: 'legendary_sword', min: 1, max: 1, chance: 1.0 }, { item: 'gold', min: 500, max: 1000, chance: 1.0 }, { item: 'ancient_artifact', min: 1, max: 1, chance: 1.0 } ], 'great_pyramid': [ { item: 'pharaoh_staff', min: 1, max: 1, chance: 1.0 }, { item: 'ruby', min: 10, max: 20, chance: 1.0 }, { item: 'mummy_wraps', min: 5, max: 10, chance: 1.0 } ], 'mountain_peak': [ { item: 'titan_hammer', min: 1, max: 1, chance: 1.0 }, { item: 'diamond', min: 10, max: 20, chance: 1.0 }, { item: 'eagle_feather', min: 1, max: 1, chance: 1.0 } ], 'abandoned_city': [ { item: 'ancient_key', min: 1, max: 1, chance: 1.0 }, { item: 'gold', min: 1000, max: 2000, chance: 1.0 }, { item: 'city_map', min: 1, max: 1, chance: 1.0 } ], 'dragon_skeleton': [ { item: 'dragon_scale', min: 5, max: 10, chance: 1.0 }, { item: 'dragon_tooth', min: 1, max: 3, chance: 1.0 }, { item: 'dragon_heart', min: 1, max: 1, chance: 1.0 } ] }; console.log('🏛️ StructureInteractionSystem initialized'); } // Generate chests for all structures generateChestsForStructures(structureSystem) { if (!structureSystem) return; let chestsGenerated = 0; // Regular structures for (const structure of structureSystem.structures) { // 70% chance to have a chest if (Math.random() < 0.7) { const chestKey = `${structure.x},${structure.y}`; this.chests.set(chestKey, { x: structure.x, y: structure.y, biome: structure.biome, opened: false, loot: this.generateLoot(structure.biome) }); chestsGenerated++; } } // Landmarks (always have treasure) for (const landmark of structureSystem.landmarks) { const chestKey = `${landmark.x},${landmark.y}`; this.chests.set(chestKey, { x: landmark.x, y: landmark.y, type: 'landmark', landmarkType: landmark.type, opened: false, loot: this.generateLandmarkTreasure(landmark.type) }); chestsGenerated++; } console.log(`✅ Generated ${chestsGenerated} chests (${this.chests.size} total)`); } // Generate loot based on biome generateLoot(biome) { const lootTable = this.lootTables[biome] || this.lootTables['Grassland']; const loot = []; for (const entry of lootTable) { if (Math.random() < entry.chance) { const amount = Math.floor(Math.random() * (entry.max - entry.min + 1)) + entry.min; loot.push({ item: entry.item, amount: amount }); } } return loot; } // Generate landmark treasure (always guaranteed) generateLandmarkTreasure(landmarkType) { const treasureTable = this.landmarkTreasures[landmarkType]; if (!treasureTable) return []; const loot = []; for (const entry of treasureTable) { const amount = Math.floor(Math.random() * (entry.max - entry.min + 1)) + entry.min; loot.push({ item: entry.item, amount: amount, legendary: true // Mark as legendary loot }); } return loot; } // Check for nearby structures update(playerX, playerY) { this.nearbyStructures = []; // Check all chests for (const [key, chest] of this.chests) { const dist = Math.sqrt((chest.x - playerX) ** 2 + (chest.y - playerY) ** 2); if (dist < 3 && !chest.opened) { this.nearbyStructures.push({ type: chest.type === 'landmark' ? 'landmark' : 'structure', x: chest.x, y: chest.y, key: key, data: chest }); } } // Show interaction prompt if nearby if (this.nearbyStructures.length > 0 && !this.currentInteraction) { this.showInteractionPrompt(); } else if (this.nearbyStructures.length === 0) { this.hideInteractionPrompt(); } } // Show UI prompt to interact showInteractionPrompt() { if (this.interactionPrompt) return; const nearest = this.nearbyStructures[0]; const promptText = nearest.type === 'landmark' ? '⭐ Press E to open LEGENDARY TREASURE' : '📦 Press E to open chest'; this.interactionPrompt = this.scene.add.text( this.scene.cameras.main.centerX, this.scene.cameras.main.height - 100, promptText, { fontSize: '24px', fontFamily: 'Arial', color: nearest.type === 'landmark' ? '#FFD700' : '#ffffff', backgroundColor: '#000000', padding: { x: 20, y: 10 } } ); this.interactionPrompt.setOrigin(0.5); this.interactionPrompt.setScrollFactor(0); this.interactionPrompt.setDepth(10000); } // Hide interaction prompt hideInteractionPrompt() { if (this.interactionPrompt) { this.interactionPrompt.destroy(); this.interactionPrompt = null; } } // Player presses E to interact interact() { if (this.nearbyStructures.length === 0) return; const nearest = this.nearbyStructures[0]; this.openChest(nearest.key, nearest.data); } // Open chest and give loot to player openChest(chestKey, chestData) { if (chestData.opened) return; // Mark as opened chestData.opened = true; this.chests.set(chestKey, chestData); // Give loot to player const inventory = this.scene.inventorySystem; if (!inventory) { console.warn('⚠️ InventorySystem not found'); return; } console.log(`📦 Opening chest at (${chestData.x}, ${chestData.y})`); let totalValue = 0; for (const lootItem of chestData.loot) { if (lootItem.item === 'gold') { inventory.gold += lootItem.amount; totalValue += lootItem.amount; } else { inventory.addItem(lootItem.item, lootItem.amount); totalValue += lootItem.amount * 10; // Estimate value } console.log(` + ${lootItem.amount}x ${lootItem.item}${lootItem.legendary ? ' (LEGENDARY!)' : ''}`); } // Show loot notification this.showLootNotification(chestData, totalValue); // Play sound if (this.scene.soundManager) { this.scene.soundManager.beepPickup(); } // Hide prompt this.hideInteractionPrompt(); } // Show loot notification UI showLootNotification(chestData, totalValue) { const isLandmark = chestData.type === 'landmark'; const notification = this.scene.add.text( this.scene.cameras.main.centerX, this.scene.cameras.main.centerY - 100, isLandmark ? `⭐ LEGENDARY TREASURE FOUND! ⭐\n${chestData.landmarkType}\nValue: ${totalValue} gold` : `📦 Chest Opened!\nValue: ${totalValue} gold`, { fontSize: isLandmark ? '32px' : '24px', fontFamily: 'Arial', color: isLandmark ? '#FFD700' : '#ffffff', backgroundColor: '#000000', padding: { x: 30, y: 20 }, align: 'center' } ); notification.setOrigin(0.5); notification.setScrollFactor(0); notification.setDepth(10001); // Fade out after 3 seconds this.scene.tweens.add({ targets: notification, alpha: 0, duration: 1000, delay: 2000, onComplete: () => notification.destroy() }); // Particle effect if (this.scene.particleEffects && isLandmark) { // Golden particles for landmarks for (let i = 0; i < 20; i++) { const particle = this.scene.add.circle( this.scene.cameras.main.centerX + (Math.random() - 0.5) * 100, this.scene.cameras.main.centerY - 100, 5, 0xFFD700 ); particle.setScrollFactor(0); particle.setDepth(10000); this.scene.tweens.add({ targets: particle, y: particle.y - 100, alpha: 0, duration: 1500, onComplete: () => particle.destroy() }); } } } // Get statistics getStats() { const opened = Array.from(this.chests.values()).filter(c => c.opened).length; return { totalChests: this.chests.size, chestsOpened: opened, chestsRemaining: this.chests.size - opened }; } // Export/Import for save system exportData() { const chestsArray = []; for (const [key, chest] of this.chests) { chestsArray.push({ key, opened: chest.opened }); } return { chests: chestsArray }; } importData(data) { if (!data || !data.chests) return; for (const savedChest of data.chests) { if (this.chests.has(savedChest.key)) { const chest = this.chests.get(savedChest.key); chest.opened = savedChest.opened; this.chests.set(savedChest.key, chest); } } } destroy() { this.hideInteractionPrompt(); this.interactionMarkers.forEach(m => m.destroy()); this.chests.clear(); } }