/** * ============================================================ * WaterSystem.js — Nova Farma (DEMO) * ============================================================ * Voda je omejena v Demu — edini vir = Rain Catcher. * * Logika: * - Rain Catcher zbira vodo med dežjem (triggerRainfall) * - Max kapaciteta = 20 L na Rain Catcher * - Zalivanje porabi 1 L na crop * - Kai dobi "vedro" (watering_can) s 5L kapaciteto * - [E] blizu Rain Catcher → Napolni vedro iz Rain Catcher-ja * - UIScene prikaže: 💧 vedro: 3/5 | 🪣 RC: 12/20 * ============================================================ */ export default class WaterSystem { /** * @param {Phaser.Scene} scene * @param {object} options — { islandX, islandY, tileSize } */ constructor(scene, options = {}) { this.scene = scene; this.tileSize = options.tileSize || 128; // === Vedro (Watering Can) === this.canCurrent = 3; // Začne s 3L this.canMax = 5; // Max 5L v vedru this.canPerCrop = 1; // 1L na zalivanje // === Rain Catcher objekti === this.rainCatchers = []; // { x, y, sprite, current, max, label } // === Highlights === this.highlightGfx = scene.add.graphics().setDepth(9001); // === Input [F] za napolnit vedro === this.keyF = scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.F); // === Interact razdalja === this.interactRange = 100; // === Dežjni multiplier === this.rainCollectRate = 4; // L na dežen dan na RC console.log('💧 WaterSystem initialized'); } // ───────────────────────────────────────────────────────────────────────── // PRELOAD // ───────────────────────────────────────────────────────────────────────── static preload(scene) { scene.load.image('rain_catcher', 'DEMO_FAZA1/Structures/rain_catcher.png'); } // ───────────────────────────────────────────────────────────────────────── // PLACE RAIN CATCHER (kliče se ob postavitvi zgradbe ali ob init) // ───────────────────────────────────────────────────────────────────────── placeRainCatcher(x, y) { const targetH = 100; // px višina v svetu const texture = this.scene.textures.get('rain_catcher'); const srcH = texture?.getSourceImage()?.height || 512; const scale = targetH / srcH; const sprite = this.scene.add.image(x, y, 'rain_catcher') .setScale(scale) .setOrigin(0.5, 1.0) .setDepth(y) .setInteractive(); // Label nad RC const label = this.scene.add.text(x, y - targetH - 8, '🪣 0/20L', { fontFamily: 'Arial Black', fontSize: '12px', color: '#44aaff', stroke: '#000000', strokeThickness: 3, }).setOrigin(0.5, 1.0).setDepth(y + 1); const rc = { x, y, sprite, label, current: 0, max: 20, }; this.rainCatchers.push(rc); this._updateLabel(rc); // Pop-in animacija sprite.setAlpha(0).setScale(scale * 0.1); this.scene.tweens.add({ targets: sprite, alpha: 1, scaleX: scale, scaleY: scale, duration: 500, ease: 'Back.out', }); console.log(`🪣 Rain Catcher postavljen @ ${x}, ${y}`); return rc; } // ───────────────────────────────────────────────────────────────────────── // UPDATE — kliči iz scene.update() // ───────────────────────────────────────────────────────────────────────── update(kai) { this.highlightGfx.clear(); const nearRC = this._getRCNear(kai); if (nearRC) { // Highlight RC this.highlightGfx.lineStyle(2, 0x44aaff, 0.9); this.highlightGfx.strokeCircle(nearRC.x, nearRC.y - 50, 60); // Tooltip this._showRCTooltip(nearRC); } else { this._hideRCTooltip(); } // [F] — Napolni vedro if (Phaser.Input.Keyboard.JustDown(this.keyF)) { if (nearRC) { this._fillCan(nearRC); } else { this._showFloatingTextAt(kai.x, kai.y - 40, '🪣 Bliže Rain Catcher!', '#aaaaff', 14); } } } // ───────────────────────────────────────────────────────────────────────── // NAPOLNI VEDRO iz Rain Catcher-ja // ───────────────────────────────────────────────────────────────────────── _fillCan(rc) { if (rc.current <= 0) { this._showFloatingTextAt(rc.x, rc.y - 110, '❌ RC je prazen!', '#ff6666'); return; } if (this.canCurrent >= this.canMax) { this._showFloatingTextAt(rc.x, rc.y - 110, '✅ Vedro je polno!', '#44ffcc'); return; } const needed = this.canMax - this.canCurrent; const take = Math.min(needed, rc.current); rc.current -= take; this.canCurrent += take; this._updateLabel(rc); this.scene.events.emit('waterChanged', { can: this.canCurrent, canMax: this.canMax, }); // Animacija — vodni curek (modri krogci padajo v vedro) this._fillAnimation(rc.x, rc.y - 30); this._showFloatingTextAt(rc.x, rc.y - 110, `💧 +${take}L (vedro: ${this.canCurrent}/${this.canMax}L)`, '#44aaff', 16); console.log(`💧 Napolnjeno: +${take}L. Vedro: ${this.canCurrent}/${this.canMax}L. RC: ${rc.current}/${rc.max}L`); } // ───────────────────────────────────────────────────────────────────────── // PORABI VODO ZA ZALIVANJE (kliče FarmingSystem) // ───────────────────────────────────────────────────────────────────────── useWater(amount = 1) { if (this.canCurrent < amount) return false; // Ni dovolj vode! this.canCurrent -= amount; this.scene.events.emit('waterChanged', { can: this.canCurrent, canMax: this.canMax, }); return true; } hasWater(amount = 1) { return this.canCurrent >= amount; } // ───────────────────────────────────────────────────────────────────────── // DEŽNI TICK — kliči ob dežju (triggerRainfall v GrassScene) // ───────────────────────────────────────────────────────────────────────── onRain() { let total = 0; for (const rc of this.rainCatchers) { const collected = Math.min(this.rainCollectRate, rc.max - rc.current); rc.current += collected; total += collected; this._updateLabel(rc); // Ripple animacija na RC this._rainRipple(rc.x, rc.y - 40); } if (total > 0) { console.log(`🌧️ Dež zbral ${total}L v Rain Catcher-jih`); } this.scene.events.emit('waterChanged', { can: this.canCurrent, canMax: this.canMax, }); } // ───────────────────────────────────────────────────────────────────────── // POMOŽNE METODE // ───────────────────────────────────────────────────────────────────────── _getRCNear(kai) { let closest = null; let minDist = this.interactRange; for (const rc of this.rainCatchers) { const d = Phaser.Math.Distance.Between(kai.x, kai.y, rc.x, rc.y); if (d < minDist) { minDist = d; closest = rc; } } return closest; } _updateLabel(rc) { const pct = rc.current / rc.max; const color = pct > 0.5 ? '#44aaff' : pct > 0.2 ? '#ffaa00' : '#ff4444'; rc.label .setText(`🪣 ${rc.current}/${rc.max}L`) .setColor(color); } _showRCTooltip(rc) { if (!this._rcTooltip) { this._rcTooltip = this.scene.add.text(0, 0, '', { fontFamily: 'Arial Black', fontSize: '13px', color: '#ffffff', stroke: '#000000', strokeThickness: 4, backgroundColor: '#00000099', padding: { x: 8, y: 4 }, }).setDepth(9999).setScrollFactor(1); } const label = this.canCurrent >= this.canMax ? `✅ Vedro polno (${this.canCurrent}L)` : `[F] Napolni vedro 💧${this.canCurrent}/${this.canMax}L`; this._rcTooltip .setText(label) .setAlpha(1) .setPosition(rc.x - this._rcTooltip.width / 2, rc.y - 115); } _hideRCTooltip() { if (this._rcTooltip) this._rcTooltip.setAlpha(0); } _fillAnimation(x, y) { // Padajoče kapljice for (let i = 0; i < 5; i++) { const drop = this.scene.add.graphics().setDepth(9998); const ox = x + Phaser.Math.Between(-15, 15); drop.fillStyle(0x44aaff, 0.8); drop.fillEllipse(ox, y, 4, 8); this.scene.tweens.add({ targets: drop, y: y + 30 + Phaser.Math.Between(0, 20), alpha: 0, delay: i * 60, duration: 300, ease: 'Quad.in', onComplete: () => drop.destroy(), }); } } _rainRipple(x, y) { const gfx = this.scene.add.graphics().setDepth(9997); let r = 2, alpha = 0.6; const ev = this.scene.time.addEvent({ delay: 50, repeat: 5, callback: () => { gfx.clear(); gfx.lineStyle(1, 0x44aaff, alpha); gfx.strokeEllipse(x, y, r * 2, r); r += 4; alpha -= 0.1; if (r > 25) { gfx.destroy(); ev.remove(); } } }); } _showFloatingTextAt(x, y, msg, color = '#ffffff', fontSize = 18) { const txt = this.scene.add.text(x, y, msg, { fontFamily: 'Arial Black', fontSize: `${fontSize}px`, color, stroke: '#000000', strokeThickness: 4, }).setOrigin(0.5).setDepth(9998); this.scene.tweens.add({ targets: txt, y: y - 50, alpha: { from: 1, to: 0 }, duration: 1600, ease: 'Cubic.out', onComplete: () => txt.destroy(), }); } // ───────────────────────────────────────────────────────────────────────── // PUBLIC API // ───────────────────────────────────────────────────────────────────────── /** Vrni stanje za save */ getState() { return { can: this.canCurrent, catchers: this.rainCatchers.map(rc => ({ x: rc.x, y: rc.y, current: rc.current })), }; } destroy() { this.highlightGfx?.destroy(); this._rcTooltip?.destroy(); this.rainCatchers.forEach(rc => { rc.sprite?.destroy(); rc.label?.destroy(); }); this.rainCatchers = []; } }