class InteractionSystem { constructor(scene) { this.scene = scene; this.iso = new IsometricUtils(48, 24); // Input listener setup (only once) this.scene.input.on('pointerdown', (pointer) => { if (pointer.button === 0) { // Left Click this.handleLeftClick(pointer); } }); // Loot Array this.drops = []; } handleLeftClick(pointer) { if (!this.scene.player) return; // 1. Account for camera and offset const worldX = pointer.worldX - this.scene.terrainOffsetX; const worldY = pointer.worldY - this.scene.terrainOffsetY; // 2. Convert to Grid const gridPos = this.iso.toGrid(worldX, worldY); // 3. Check distance const playerPos = this.scene.player.getPosition(); const dist = Phaser.Math.Distance.Between(playerPos.x, playerPos.y, gridPos.x, gridPos.y); // Allow interaction within radius of 2.5 tiles if (dist > 2.5) { console.log('Too far:', dist.toFixed(1)); return; } console.log(`☝️ Clicked tile: ${gridPos.x},${gridPos.y}`); // DETERMINE TOOL / ACTION let activeTool = null; const uiScene = this.scene.scene.get('UIScene'); const invSys = this.scene.inventorySystem; if (uiScene && invSys) { const selectedIdx = uiScene.selectedSlot; const slotData = invSys.slots[selectedIdx]; if (slotData) activeTool = slotData.type; } // 0. Build Mode Override if (this.scene.buildingSystem && this.scene.buildingSystem.isBuildMode) { this.scene.buildingSystem.tryBuild(gridPos.x, gridPos.y); return; // Consume click } // 3.5 Check for NPC Click if (this.scene.npcs) { for (const npc of this.scene.npcs) { if (Math.abs(npc.gridX - gridPos.x) < 2.5 && Math.abs(npc.gridY - gridPos.y) < 2.5) { console.log(`🗣️ Interact with NPC: ${npc.type}`); if (npc.type === 'zombie') { // Taming Logic npc.toggleState(); return; // Done } if (npc.type === 'merchant') { // Open Trade Menu if (uiScene && invSys) { uiScene.showTradeMenu(invSys); } return; // Stop processing } return; // Stop processing other clicks (farming/terrain) if clicked NPC } } } // 4. Try Farming Action (Tilling, Planting, Harvesting) if (this.scene.farmingSystem) { const didFarm = this.scene.farmingSystem.interact(gridPos.x, gridPos.y, activeTool); if (didFarm) { // Animation? return; } } // 5. Try damage decoration (fallback) // 5. Try damage or interact decoration if (this.scene.terrainSystem) { const id = `${gridPos.x},${gridPos.y}`; if (this.scene.terrainSystem.decorationsMap.has(id)) { const decor = this.scene.terrainSystem.decorationsMap.get(id); // Ruin Interaction - Town Restoration if (decor.type === 'ruin' || decor.type === 'ruin_borut') { // Check if near if (dist > 2.5) { console.log('Ruin too far.'); return; } // Show Project Menu const uiScene = this.scene.scene.get('UIScene'); if (uiScene) { // Define requirements based on ruin type let req = { reqWood: 100, reqStone: 50, reqGold: 50 }; let ruinName = "Borut's Smithy"; // Default let npcType = 'merchant'; if (decor.type === 'ruin') { ruinName = "Merchant House"; req = { reqWood: 50, reqStone: 30, reqGold: 30 }; } uiScene.showProjectMenu(req, () => { // On Contribute Logic if (invSys) { const hasWood = invSys.hasItem('wood', req.reqWood); const hasStone = invSys.hasItem('stone', req.reqStone || 0); const hasGold = invSys.hasItem('gold', req.reqGold || 0); // Check all requirements if (hasWood && hasStone && hasGold) { // Consume materials invSys.removeItem('wood', req.reqWood); invSys.removeItem('stone', req.reqStone); invSys.removeItem('gold', req.reqGold); invSys.updateUI(); console.log(`🏗️ Restoring ${ruinName}...`); // Transform Ruin -> House this.scene.terrainSystem.removeDecoration(gridPos.x, gridPos.y); this.scene.terrainSystem.placeStructure(gridPos.x, gridPos.y, 'house'); // Spawn NPC nearby const npc = new NPC(this.scene, gridPos.x + 1, gridPos.y + 1, this.scene.terrainOffsetX, this.scene.terrainOffsetY, npcType); this.scene.npcs.push(npc); // Increase friendship (hearts) if (this.scene.statsSystem) { this.scene.statsSystem.addFriendship(npcType, 10); // +10 hearts } console.log(`✅ ${ruinName} Restored! +10 ❤️ Friendship`); // Play build sound if (this.scene.soundManager) this.scene.soundManager.playBuild(); } else { // Not enough materials const missing = []; if (!hasWood) missing.push(`${req.reqWood} Wood`); if (!hasStone) missing.push(`${req.reqStone} Stone`); if (!hasGold) missing.push(`${req.reqGold} Gold`); console.log(`❌ Not enough materials! Need: ${missing.join(', ')}`); alert(`Potrebuješ še: ${missing.join(', ')} da obnoviš ${ruinName}.`); } } }); } return; // Don't damage it } } const result = this.scene.terrainSystem.damageDecoration(gridPos.x, gridPos.y, 1); if (result === 'destroyed') { // Play chop sound if (this.scene.soundManager) this.scene.soundManager.playChop(); // Spawn loot this.spawnLoot(gridPos.x, gridPos.y, 'wood'); } else if (result === 'hit') { // Play hit sound if (this.scene.soundManager) this.scene.soundManager.playChop(); } } } spawnLoot(gridX, gridY, type) { console.log(`🎁 Spawning ${type} at ${gridX},${gridY}`); // Convert to Screen const screenPos = this.iso.toScreen(gridX, gridY); const x = screenPos.x + this.scene.terrainOffsetX; const y = screenPos.y + this.scene.terrainOffsetY; // Create simplistic item drop sprite let symbol = '?'; if (type === 'wood') symbol = '🪵'; if (type === 'seeds') symbol = '🌱'; if (type === 'wheat') symbol = '🌾'; if (type === 'hoe') symbol = '🛠️'; const drop = this.scene.add.text(x, y - 20, symbol, { fontSize: '20px' }); drop.setOrigin(0.5); drop.setDepth(this.iso.getDepth(gridX, gridY) + 500); // above tiles // Bounce animation this.scene.tweens.add({ targets: drop, y: y - 40, duration: 500, yoyo: true, ease: 'Sine.easeOut', repeat: -1 }); this.drops.push({ gridX, gridY, sprite: drop, type: type }); } update() { // Check for player pickup if (!this.scene.player) return; const playerPos = this.scene.player.getPosition(); // Filter drops to pick up for (let i = this.drops.length - 1; i >= 0; i--) { const drop = this.drops[i]; // Check if player is ON the drop tile if (Math.abs(drop.gridX - playerPos.x) < 0.8 && Math.abs(drop.gridY - playerPos.y) < 0.8) { // Pick up! console.log('🎒 Picked up:', drop.type); // Play pickup sound if (this.scene.soundManager) this.scene.soundManager.playPickup(); // Add to inventory if (this.scene.inventorySystem) { this.scene.inventorySystem.addItem(drop.type, 1); } // Destroy visual drop.sprite.destroy(); this.drops.splice(i, 1); } } } }