/** * ⚡ BUILDING UPGRADE SYSTEM - Week 1 Priority * Generator + Power Grid + Electrician NPC + Maintenance * * Features: * - Generator building (electricity for city) * - Power grid system (poles connecting generator) * - Electrician NPC employment (2 Cekini/day) * - Repair mechanics (generator, poles, UV lights) * - Breakdown prevention when Electrician employed * - Electric sparks VFX + Repair sparkles * * Assets Used: * - /assets/buildings/generator.png * - /assets/buildings/power_pole_straight.png * - /assets/buildings/power_pole_corner.png * - /assets/characters/electrician/ (11 sprites) * - /assets/vfx/electric_spark.png * - /assets/vfx/sparkle_repair.png */ export default class BuildingUpgradeSystem { constructor(scene) { this.scene = scene; // Generator system this.generator = null; this.generatorHealth = 100; this.generatorMaxHealth = 100; this.generatorActive = false; this.generatorBreakdownChance = 0.05; // 5% per day without Electrician // Power grid this.powerPoles = []; this.isPowered = false; // Electrician NPC this.electrician = null; this.electricianEmployed = false; this.electricianSalary = 2; // Cekini per day this.electricianWorkSchedule = { inspectionTime: 10, // 10 AM repairTime: 14 // 2 PM }; // Repair system this.repairCost = { generator: 50, // Wood powerPole: 20, uvLight: 30 }; // Buildings that need electricity this.electricBuildings = []; this.init(); } init() { console.log('[BuildingUpgrade] Initializing building upgrade system...'); // Load sprites this.loadSprites(); // Setup daily maintenance check this.setupMaintenanceRoutine(); } loadSprites() { // Generator if (!this.scene.textures.exists('generator')) { this.scene.load.image('generator', 'assets/buildings/generator.png'); } // Power poles if (!this.scene.textures.exists('power_pole_straight')) { this.scene.load.image('power_pole_straight', 'assets/buildings/power_pole_straight.png'); } if (!this.scene.textures.exists('power_pole_corner')) { this.scene.load.image('power_pole_corner', 'assets/buildings/power_pole_corner.png'); } // Electrician sprites const directions = ['south', 'north', 'east', 'west']; const actions = ['idle', 'walk']; directions.forEach(dir => { actions.forEach(action => { const key = `electrician_${action}_${dir}`; if (!this.scene.textures.exists(key)) { this.scene.load.image(key, `assets/characters/electrician/${action}_${dir}.png`); } }); }); // Action sprites if (!this.scene.textures.exists('electrician_action_repair')) { this.scene.load.image('electrician_action_repair', 'assets/characters/electrician/action_repair.png'); } if (!this.scene.textures.exists('electrician_action_inspect')) { this.scene.load.image('electrician_action_inspect', 'assets/characters/electrician/action_inspect.png'); } if (!this.scene.textures.exists('electrician_portrait')) { this.scene.load.image('electrician_portrait', 'assets/characters/electrician/portrait.png'); } // VFX if (!this.scene.textures.exists('electric_spark')) { this.scene.load.image('electric_spark', 'assets/vfx/electric_spark.png'); } if (!this.scene.textures.exists('sparkle_repair')) { this.scene.load.image('sparkle_repair', 'assets/vfx/sparkle_repair.png'); } this.scene.load.start(); } /** * Build Generator */ buildGenerator(x, y) { if (this.generator) { console.warn('[BuildingUpgrade] Generator already exists!'); return false; } // Check resources (if resource system exists) const cost = { wood: 100, stone: 50, coal: 20 }; if (this.scene.resourceLogisticsSystem) { if (!this.scene.resourceLogisticsSystem.hasResources(cost)) { console.warn('[BuildingUpgrade] Not enough resources to build generator!'); return false; } // Spend resources Object.entries(cost).forEach(([type, amount]) => { this.scene.resourceLogisticsSystem.removeResource(type, amount); }); } // Create generator sprite this.generator = this.scene.add.sprite(x, y, 'generator'); this.generator.setOrigin(0.5, 0.5); this.generator.setInteractive(); // Generator data this.generator.buildingData = { type: 'generator', health: this.generatorMaxHealth, active: true, lastMaintenance: Date.now() }; // Click to interact this.generator.on('pointerdown', () => { this.interactWithGenerator(); }); // Activate generator this.generatorActive = true; this.isPowered = true; // Create smoke effect this.createGeneratorSmoke(x, y); console.log('[BuildingUpgrade] Generator built at', x, y); return true; } /** * Create smoke effect for generator */ createGeneratorSmoke(x, y) { // Simple smoke particles const smoke = this.scene.add.particles(x, y - 40, 'electric_spark', { speed: { min: 20, max: 40 }, angle: { min: 260, max: 280 }, scale: { start: 0.3, end: 0 }, alpha: { start: 0.3, end: 0 }, lifespan: 2000, frequency: 500, tint: 0x666666, blendMode: 'NORMAL' }); this.generator.smokeEffect = smoke; } /** * Place power pole */ placePowerPole(x, y, type = 'straight') { const sprite = type === 'straight' ? 'power_pole_straight' : 'power_pole_corner'; const pole = this.scene.add.sprite(x, y, sprite); pole.setOrigin(0.5, 1); // Bottom-centered pole.setInteractive(); pole.poleData = { type: type, health: 100, connected: false }; this.powerPoles.push(pole); // Check connections this.updatePowerGrid(); console.log('[BuildingUpgrade] Power pole placed at', x, y); return pole; } /** * Update power grid connections */ updatePowerGrid() { if (!this.generator) { this.isPowered = false; return; } // Simple proximity check for now // TODO: Implement proper grid pathfinding this.powerPoles.forEach(pole => { const distance = Phaser.Math.Distance.Between( this.generator.x, this.generator.y, pole.x, pole.y ); pole.poleData.connected = distance < 500; // 500px max distance }); this.isPowered = this.generatorActive; } /** * Spawn Electrician NPC */ spawnElectrician(x, y) { if (this.electrician) { console.warn('[BuildingUpgrade] Electrician already exists!'); return; } this.electrician = this.scene.add.sprite(x, y, 'electrician_idle_south'); this.electrician.setOrigin(0.5, 0.5); this.electrician.setInteractive(); // NPC data this.electrician.npcData = { name: 'Electrician', type: 'town_worker', employed: false, salary: this.electricianSalary, workLocation: this.generator, skills: ['generator_repair', 'power_grid', 'uv_lights'] }; // Click to hire/talk this.electrician.on('pointerdown', () => { this.interactWithElectrician(); }); // Idle animation this.createElectricianIdleAnimation(); console.log('[BuildingUpgrade] Electrician spawned at', x, y); } /** * Create idle animation for Electrician */ createElectricianIdleAnimation() { if (!this.electrician) return; this.scene.time.addEvent({ delay: 3000, callback: () => { if (this.electrician && !this.electrician.isWorking) { // Look around with tools const directions = ['south', 'east', 'west']; const randomDir = Phaser.Utils.Array.GetRandom(directions); this.electrician.setTexture(`electrician_idle_${randomDir}`); } }, loop: true }); } /** * Interact with Electrician (hire or request repair) */ interactWithElectrician() { if (!this.electrician) return; if (!this.electricianEmployed) { this.showElectricianEmploymentDialog(); } else { this.showElectricianDialog(); } } /** * Show employment dialog */ showElectricianEmploymentDialog() { const dialogText = `Need an electrician?\n\nSalary: ${this.electricianSalary} Cekini/day\n\nI'll maintain your generator, prevent breakdowns, and repair everything for FREE when employed!`; if (this.scene.dialogueSystem) { this.scene.dialogueSystem.showDialog({ portrait: 'electrician_portrait', name: 'Electrician', text: dialogText, choices: [ { text: `Hire (${this.electricianSalary} Cekini/day)`, callback: () => this.hireElectrician() }, { text: 'Not now', callback: () => console.log('[BuildingUpgrade] Employment declined') } ] }); } else { console.log('[BuildingUpgrade] Employment dialog:', dialogText); // Auto-hire for testing this.hireElectrician(); } } /** * Hire Electrician */ hireElectrician() { this.electricianEmployed = true; this.electrician.npcData.employed = true; // Add to worker count if (this.scene.cityManagementSystem) { this.scene.cityManagementSystem.addPopulation('worker', 1); } console.log('[BuildingUpgrade] Electrician hired! Salary:', this.electricianSalary, 'Cekini/day'); // Start work routine this.startElectricianWorkRoutine(); } /** * Start Electrician's work routine */ startElectricianWorkRoutine() { if (!this.electricianEmployed) return; // Daily inspection at 10 AM this.scene.time.addEvent({ delay: 60000, // Check every minute callback: () => { if (this.scene.timeSystem) { const hour = this.scene.timeSystem.getCurrentHour(); // Morning inspection if (hour === this.electricianWorkSchedule.inspectionTime) { this.electricianInspectGenerator(); } // Afternoon repair if needed if (hour === this.electricianWorkSchedule.repairTime) { if (this.generatorHealth < this.generatorMaxHealth) { this.electricianRepairGenerator(); } } } }, loop: true }); } /** * Electrician inspects generator */ electricianInspectGenerator() { if (!this.electrician || !this.generator) return; console.log('[BuildingUpgrade] Electrician inspecting generator...'); // Walk to generator this.walkElectricianTo(this.generator.x, this.generator.y + 60, () => { // Show inspect action this.electrician.setTexture('electrician_action_inspect'); this.electrician.isWorking = true; // Check health this.scene.time.delayedCall(2000, () => { console.log(`[BuildingUpgrade] Generator health: ${this.generatorHealth}%`); // Return to idle this.electrician.setTexture('electrician_idle_south'); this.electrician.isWorking = false; }); }); } /** * Electrician repairs generator */ electricianRepairGenerator() { if (!this.electrician || !this.generator) return; console.log('[BuildingUpgrade] Electrician repairing generator...'); // Walk to generator this.walkElectricianTo(this.generator.x, this.generator.y + 60, () => { // Show repair action this.electrician.setTexture('electrician_action_repair'); this.electrician.isWorking = true; // Play electric sparks VFX this.playElectricSparks(this.generator.x, this.generator.y); // Repair after 3 seconds this.scene.time.delayedCall(3000, () => { // Restore health this.generatorHealth = this.generatorMaxHealth; if (this.generator.buildingData) { this.generator.buildingData.health = this.generatorMaxHealth; } // Play repair sparkles this.playRepairSparkles(this.generator.x, this.generator.y); console.log('[BuildingUpgrade] Generator fully repaired!'); // Return to idle this.electrician.setTexture('electrician_idle_south'); this.electrician.isWorking = false; }); }); } /** * Walk Electrician to location */ walkElectricianTo(targetX, targetY, onComplete) { if (!this.electrician) return; // Calculate direction const dx = targetX - this.electrician.x; const direction = dx > 0 ? 'east' : 'west'; // Walk animation this.scene.tweens.add({ targets: this.electrician, x: targetX, y: targetY, duration: 2000, ease: 'Linear', onUpdate: () => { this.electrician.setTexture(`electrician_walk_${direction}`); }, onComplete: () => { if (onComplete) onComplete(); } }); } /** * Play electric sparks VFX */ playElectricSparks(x, y) { if (!this.scene.textures.exists('electric_spark')) return; const emitter = this.scene.add.particles(x, y, 'electric_spark', { speed: { min: 100, max: 200 }, angle: { min: 0, max: 360 }, scale: { start: 0.8, end: 0.2 }, alpha: { start: 1, end: 0 }, lifespan: 400, quantity: 3, frequency: 100, blendMode: 'ADD', tint: 0x00FFFF // Blue electric }); // Stop after 3 seconds this.scene.time.delayedCall(3000, () => { emitter.stop(); this.scene.time.delayedCall(500, () => emitter.destroy()); }); } /** * Play repair sparkles VFX (4-frame animation!) */ playRepairSparkles(x, y) { if (!this.scene.textures.exists('sparkle_repair')) return; const emitter = this.scene.add.particles(x, y - 20, 'sparkle_repair', { speed: { min: 20, max: 50 }, angle: { min: 0, max: 360 }, scale: { start: 1, end: 0 }, alpha: { start: 1, end: 0 }, lifespan: 1000, quantity: 12, blendMode: 'ADD', tint: 0xFFD700 // Gold sparkles }); // Destroy after animation this.scene.time.delayedCall(1500, () => { emitter.destroy(); }); } /** * Daily maintenance check */ setupMaintenanceRoutine() { this.scene.time.addEvent({ delay: 86400000, // Daily (or faster in-game) callback: () => this.performDailyMaintenance(), loop: true }); } /** * Perform daily maintenance */ performDailyMaintenance() { if (!this.generator || !this.generatorActive) return; if (!this.electricianEmployed) { // Chance of breakdown without Electrician if (Math.random() < this.generatorBreakdownChance) { this.generatorBreakdown(); } else { // Gradual degradation this.generatorHealth -= 10; if (this.generatorHealth < 0) { this.generatorBreakdown(); } } } else { // Electrician prevents breakdowns! console.log('[BuildingUpgrade] Electrician prevented breakdown!'); } } /** * Generator breakdown */ generatorBreakdown() { console.warn('[BuildingUpgrade] GENERATOR BREAKDOWN!'); this.generatorActive = false; this.generatorHealth = 0; this.isPowered = false; // Visual feedback if (this.generator && this.generator.smokeEffect) { this.generator.smokeEffect.stop(); } // Show warning if (this.scene.centralPopupSystem) { this.scene.centralPopupSystem.showMessage( 'GENERATOR BREAKDOWN! Hire an Electrician or repair manually!', 'critical' ); } // Turn off electric buildings this.powerOffBuildings(); } /** * Power off all electric buildings */ powerOffBuildings() { this.electricBuildings.forEach(building => { if (building.powerOff) { building.powerOff(); } }); } /** * Interact with generator */ interactWithGenerator() { if (!this.generator) return; const health = this.generatorHealth; const status = this.generatorActive ? 'ACTIVE' : 'OFFLINE'; const info = ` === GENERATOR STATUS === Status: ${status} Health: ${health}/${this.generatorMaxHealth} Power: ${this.isPowered ? 'ONLINE' : 'OFFLINE'} Maintenance: ${this.electricianEmployed ? 'Automatic' : 'Manual'} `; console.log(info); if (this.scene.centralPopupSystem) { this.scene.centralPopupSystem.showMessage(info, 'info'); } } /** * Show Electrician dialogue */ showElectricianDialog() { const dialogues = [ "Generator's running smooth. No problems here.", "Just did my daily inspection. All systems nominal.", "Power grid is stable. Good work building it.", "I'll keep everything running. Don't worry.", "Found a loose wire this morning. Fixed it.", "UV lights in the basement need checking soon." ]; const randomDialogue = Phaser.Utils.Array.GetRandom(dialogues); if (this.scene.dialogueSystem) { this.scene.dialogueSystem.showDialog({ portrait: 'electrician_portrait', name: 'Electrician', text: randomDialogue }); } else { console.log('[BuildingUpgrade] Electrician:', randomDialogue); } } /** * Register electric building */ registerElectricBuilding(building) { this.electricBuildings.push(building); } /** * Check if power is available */ hasPower() { return this.isPowered; } /** * Pay daily salaries */ payDailySalaries() { if (!this.electricianEmployed) return; if (this.scene.economySystem) { this.scene.economySystem.spendCekini(this.electricianSalary); console.log(`[BuildingUpgrade] Paid Electrician ${this.electricianSalary} Cekini`); } } update(time, delta) { // System updates handled by time events } destroy() { if (this.generator) { if (this.generator.smokeEffect) this.generator.smokeEffect.destroy(); this.generator.destroy(); } this.powerPoles.forEach(pole => pole.destroy()); this.powerPoles = []; if (this.electrician) this.electrician.destroy(); } }