class BuildSystem { constructor(scene) { this.scene = scene; this.buildMode = false; this.selectedBuilding = 'fence'; this.previewSprite = null; this.placedBuildings = []; // Building definitions this.buildings = { 'fence': { name: 'Fence (Old)', textureKey: 'fence_isometric', cost: { wood: 2 }, collision: false, scale: 0.3 }, 'fence_post': { name: 'Fence Post', textureKey: 'fence_post', cost: { wood: 1 }, collision: false, scale: 0.2 }, 'fence_horizontal': { name: 'Fence →', textureKey: 'fence_horizontal', cost: { wood: 2 }, collision: false, scale: 0.2 }, 'fence_vertical': { name: 'Fence ↓', textureKey: 'fence_vertical', cost: { wood: 2 }, collision: false, scale: 0.2 }, 'fence_corner': { name: 'Fence ⌞', textureKey: 'fence_corner', cost: { wood: 2 }, collision: false, scale: 0.2 }, 'barn': { name: 'Barn', textureKey: 'barn_isometric', cost: { wood: 40, stone: 20 }, collision: true, scale: 0.5 }, 'grave': { name: 'Grave', textureKey: 'grave_zombie', cost: { stone: 10 }, collision: false, scale: 0.3 }, 'farmhouse': { name: 'Farmhouse', textureKey: 'farmhouse_isometric', cost: { wood: 50, stone: 30, gold: 100 }, collision: true, scale: 0.5 }, 'blacksmith': { name: 'Blacksmith', textureKey: 'blacksmith_workshop', cost: { wood: 30, stone: 40, gold: 80 }, collision: true, scale: 0.45 } }; } toggleBuildMode() { this.buildMode = !this.buildMode; console.log(`Build Mode: ${this.buildMode ? 'ON' : 'OFF'}`); // Show/hide preview if (this.buildMode) { this.createPreview(); this.showBuildUI(); // Dodaj UI } else { this.destroyPreview(); this.hideBuildUI(); // Skrij UI } return this.buildMode; } selectBuilding(buildingId) { if (!this.buildings[buildingId]) return; this.selectedBuilding = buildingId; // Refresh preview if (this.buildMode) { this.destroyPreview(); this.createPreview(); this.updateBuildUI(); // Posodobi UI } } showBuildUI() { const uiScene = this.scene.scene.get('UIScene'); if (!uiScene) return; const width = this.scene.cameras.main.width; const height = this.scene.cameras.main.height; // Ustvari UI container this.buildUIContainer = uiScene.add.container(width - 250, 100); this.buildUIContainer.setDepth(9999); this.buildUIContainer.setScrollFactor(0); // Ozadje panela const bg = uiScene.add.rectangle(0, 0, 220, 400, 0x1a1a2e, 0.95); bg.setStrokeStyle(3, 0x00ff41); this.buildUIContainer.add(bg); // Naslov const title = uiScene.add.text(0, -180, '🏗️ BUILD MODE', { fontSize: '20px', fontFamily: 'Courier New', color: '#00ff41', fontStyle: 'bold' }).setOrigin(0.5); this.buildUIContainer.add(title); // Izbrana stavba this.selectedBuildingText = uiScene.add.text(0, -150, '', { fontSize: '14px', fontFamily: 'Courier New', color: '#ffffff', align: 'center' }).setOrigin(0.5); this.buildUIContainer.add(this.selectedBuildingText); // Cena this.costText = uiScene.add.text(0, -120, '', { fontSize: '12px', fontFamily: 'Courier New', color: '#ffaa00', align: 'center' }).setOrigin(0.5); this.buildUIContainer.add(this.costText); // Kontrole const controls = [ '━━━━━━━━━━━━━━', 'CONTROLS:', '', '1 - Fence Post', '2 - Fence →', '3 - Fence ↓', '4 - Fence ⌞', '5 - Barn', '', 'Click - Place', 'B - Exit', '━━━━━━━━━━━━━━' ]; const controlsText = uiScene.add.text(0, 0, controls.join('\n'), { fontSize: '12px', fontFamily: 'Courier New', color: '#aaaaaa', align: 'center', lineSpacing: 4 }).setOrigin(0.5); this.buildUIContainer.add(controlsText); // Status this.statusText = uiScene.add.text(0, 170, '', { fontSize: '11px', fontFamily: 'Courier New', color: '#ffffff', align: 'center' }).setOrigin(0.5); this.buildUIContainer.add(this.statusText); this.updateBuildUI(); } updateBuildUI() { if (!this.buildUIContainer) return; const building = this.buildings[this.selectedBuilding]; // Posodobi ime this.selectedBuildingText.setText(`Selected:\n${building.name}`); // Posodobi ceno let costStr = 'Cost: '; const costs = []; for (const [resource, amount] of Object.entries(building.cost)) { if (resource === 'gold') { costs.push(`${amount} Gold`); } else { costs.push(`${amount} ${resource}`); } } costStr += costs.join(', '); this.costText.setText(costStr); // Preveri vire const hasResources = this.hasResources(building.cost); this.statusText.setText(hasResources ? '✅ Ready to build' : '❌ Not enough resources'); this.statusText.setColor(hasResources ? '#00ff41' : '#ff0000'); } hideBuildUI() { if (this.buildUIContainer) { this.buildUIContainer.destroy(); this.buildUIContainer = null; } } createPreview() { const building = this.buildings[this.selectedBuilding]; if (!this.scene.textures.exists(building.textureKey)) { console.warn(`Texture not found: ${building.textureKey}`); return; } this.previewSprite = this.scene.add.sprite(0, 0, building.textureKey); this.previewSprite.setOrigin(0.5, 1); this.previewSprite.setAlpha(0.6); this.previewSprite.setDepth(10000); // Always on top this.previewSprite.setScale(building.scale || 1.0); } destroyPreview() { if (this.previewSprite) { this.previewSprite.destroy(); this.previewSprite = null; } } update() { if (!this.buildMode || !this.previewSprite) return; // Follow mouse const pointer = this.scene.input.activePointer; const worldPoint = this.scene.cameras.main.getWorldPoint(pointer.x, pointer.y); const gridPos = this.scene.iso.toGrid(worldPoint.x, worldPoint.y); const screenPos = this.scene.iso.toScreen(gridPos.x, gridPos.y); this.previewSprite.setPosition(screenPos.x, screenPos.y); // Check if can place const canPlace = this.canPlaceAt(gridPos.x, gridPos.y); this.previewSprite.setTint(canPlace ? 0x00ff00 : 0xff0000); // Place on click if (pointer.isDown && canPlace) { this.placeBuilding(gridPos.x, gridPos.y); } } canPlaceAt(gridX, gridY) { // Check if already has building const exists = this.placedBuildings.find(b => b.gridX === gridX && b.gridY === gridY); if (exists) return false; // Check terrain (only on farm tiles) if (!this.scene.terrainSystem) return false; const tile = this.scene.terrainSystem.getTile(gridX, gridY); if (!tile || tile.type !== 'farm') return false; // Check cost const building = this.buildings[this.selectedBuilding]; if (!this.hasResources(building.cost)) return false; return true; } hasResources(cost) { const inv = this.scene.inventorySystem; if (!inv) return false; for (const [resource, amount] of Object.entries(cost)) { if (resource === 'gold') { if (inv.gold < amount) return false; } else { if (!inv.hasItem(resource, amount)) return false; } } return true; } placeBuilding(gridX, gridY) { const building = this.buildings[this.selectedBuilding]; // Consume resources const inv = this.scene.inventorySystem; for (const [resource, amount] of Object.entries(building.cost)) { if (resource === 'gold') { inv.gold -= amount; } else { inv.removeItem(resource, amount); } } // Create sprite const screenPos = this.scene.iso.toScreen(gridX, gridY); const sprite = this.scene.add.sprite(screenPos.x, screenPos.y, building.textureKey); sprite.setOrigin(0.5, 1); sprite.setScale(building.scale || 1.0); sprite.setDepth(this.scene.iso.getDepth(gridX, gridY) + 5); // Above terrain // Store this.placedBuildings.push({ gridX, gridY, type: this.selectedBuilding, sprite, collision: building.collision }); console.log(`🏗️ Placed ${building.name} at (${gridX}, ${gridY})`); // Update UI this.scene.events.emit('update-inventory'); } isCollisionAt(gridX, gridY) { const building = this.placedBuildings.find(b => b.gridX === gridX && b.gridY === gridY); return building ? building.collision : false; } /** * Ročno postavi ograjo na natančno koordinato. * @param {number} tileX - X koordinata ploščice (0 do 99). * @param {number} tileY - Y koordinata ploščice (0 do 99). * @param {string} fenceType - Tip ograje: 'fence', 'fence_post', 'fence_horizontal', 'fence_vertical', 'fence_corner' * @param {boolean} consumeResources - Ali naj porabi vire (privzeto: false) * @returns {boolean} - True če je bila ograja uspešno postavljena */ placeSingleFence(tileX, tileY, fenceType = 'fence_horizontal', consumeResources = false) { // 1. Preveri, ali je lokacija znotraj mape if (tileX < 0 || tileX >= 100 || tileY < 0 || tileY >= 100) { console.error(`❌ Poskus postavitve ograje izven robov mape: (${tileX}, ${tileY})`); return false; } // 2. Preveri, ali tip ograje obstaja if (!this.buildings[fenceType]) { console.error(`❌ Neznan tip ograje: ${fenceType}`); return false; } // 3. Preveri, ali že obstaja zgradba na tej lokaciji const exists = this.placedBuildings.find(b => b.gridX === tileX && b.gridY === tileY); if (exists) { console.warn(`⚠️ Na lokaciji (${tileX}, ${tileY}) že obstaja zgradba.`); return false; } const building = this.buildings[fenceType]; // 4. Preveri in porabi vire (če je zahtevano) if (consumeResources) { if (!this.hasResources(building.cost)) { console.warn(`⚠️ Ni dovolj virov za postavitev ${building.name}`); return false; } const inv = this.scene.inventorySystem; for (const [resource, amount] of Object.entries(building.cost)) { if (resource === 'gold') { inv.gold -= amount; } else { inv.removeItem(resource, amount); } } } // 5. Ustvari sprite const screenPos = this.scene.iso.toScreen(tileX, tileY); const sprite = this.scene.add.sprite(screenPos.x, screenPos.y, building.textureKey); sprite.setOrigin(0.5, 1); sprite.setScale(building.scale || 1.0); sprite.setDepth(this.scene.iso.getDepth(tileX, tileY) + 5); // Nad terenom // 6. Shrani this.placedBuildings.push({ gridX: tileX, gridY: tileY, type: fenceType, sprite, collision: building.collision }); console.log(`✅ ${building.name} postavljena na (${tileX}, ${tileY})`); // 7. Posodobi UI (če so bili porabljeni viri) if (consumeResources) { this.scene.events.emit('update-inventory'); } return true; } /** * Postavi linijo ograj med dvema točkama. * @param {number} startX - Začetna X koordinata * @param {number} startY - Začetna Y koordinata * @param {number} endX - Končna X koordinata * @param {number} endY - Končna Y koordinata * @param {string} fenceType - Tip ograje * @param {boolean} consumeResources - Ali naj porabi vire */ placeFenceLine(startX, startY, endX, endY, fenceType = 'fence_horizontal', consumeResources = false) { const dx = Math.abs(endX - startX); const dy = Math.abs(endY - startY); const sx = startX < endX ? 1 : -1; const sy = startY < endY ? 1 : -1; let err = dx - dy; let x = startX; let y = startY; while (true) { this.placeSingleFence(x, y, fenceType, consumeResources); if (x === endX && y === endY) break; const e2 = 2 * err; if (e2 > -dy) { err -= dy; x += sx; } if (e2 < dx) { err += dx; y += sy; } } console.log(`🔗 Linija ograj postavljena od (${startX}, ${startY}) do (${endX}, ${endY})`); } /** * Postavi pravokotnik ograj. * @param {number} x - Levi zgornji X * @param {number} y - Levi zgornji Y * @param {number} width - Širina * @param {number} height - Višina * @param {string} fenceType - Tip ograje * @param {boolean} consumeResources - Ali naj porabi vire */ placeFenceRectangle(x, y, width, height, fenceType = 'fence_horizontal', consumeResources = false) { // Zgornja linija for (let i = 0; i < width; i++) { this.placeSingleFence(x + i, y, fenceType, consumeResources); } // Spodnja linija for (let i = 0; i < width; i++) { this.placeSingleFence(x + i, y + height - 1, fenceType, consumeResources); } // Leva linija for (let i = 1; i < height - 1; i++) { this.placeSingleFence(x, y + i, fenceType, consumeResources); } // Desna linija for (let i = 1; i < height - 1; i++) { this.placeSingleFence(x + width - 1, y + i, fenceType, consumeResources); } console.log(`📦 Pravokotnik ograj postavljen na (${x}, ${y}) velikosti ${width}x${height}`); } showTutorial() { const uiScene = this.scene.scene.get('UIScene'); if (!uiScene) return; const width = this.scene.cameras.main.width; const height = this.scene.cameras.main.height; // Tutorial panel const panel = uiScene.add.container(width / 2, height / 2); panel.setDepth(10000); const bg = uiScene.add.rectangle(0, 0, 500, 300, 0x1a1a2e, 0.95); bg.setStrokeStyle(3, 0x00ff41); panel.add(bg); const title = uiScene.add.text(0, -120, '🏗️ BUILD MODE', { fontSize: '24px', fontFamily: 'Courier New', color: '#00ff41', fontStyle: 'bold' }).setOrigin(0.5); panel.add(title); const instructions = [ 'Controls:', '1-5: Select building type', 'Mouse: Move preview', 'Click: Place building', 'B: Exit build mode', '', 'Green = OK | Red = Blocked' ]; const text = uiScene.add.text(0, 0, instructions.join('\n'), { fontSize: '16px', fontFamily: 'Courier New', color: '#ffffff', align: 'center', lineSpacing: 8 }).setOrigin(0.5); panel.add(text); const closeBtn = uiScene.add.text(0, 120, '[Click to close]', { fontSize: '14px', color: '#888888' }).setOrigin(0.5); panel.add(closeBtn); // Auto-dismiss after 5 seconds uiScene.time.delayedCall(5000, () => { panel.destroy(); }); // Click to dismiss bg.setInteractive(); bg.on('pointerdown', () => { panel.destroy(); }); } }