/** * 👤 NPC IDLE BEHAVIOR SYSTEM * "Krvava Žetev" - Gothic Farm Game * * Makes NPCs feel alive with random idle animations: * - Fix hat * - Wipe sweat * - Look around * - Scratch head * - Adjust clothes */ export class NPCIdleBehavior { constructor(scene, sprite, npcType) { this.scene = scene; this.sprite = sprite; this.npcType = npcType; // Idle animation timing this.idleTimer = 0; this.nextIdleTime = Phaser.Math.Between(3000, 8000); // Available idle animations this.idleAnimations = this.getIdleAnimations(); this.currentIdle = null; } getIdleAnimations() { // Different NPCs have different idle behaviors const genericIdles = [ 'fix_hat', 'wipe_sweat', 'look_around', 'scratch_head', 'adjust_clothes', 'yawn', 'stretch' ]; const npcSpecific = { 'gronk': [...genericIdles, 'adjust_apron', 'count_coins', 'polish_item'], 'farmer': [...genericIdles, 'lean_on_fence', 'check_watch', 'spit'], 'merchant': [...genericIdles, 'fix_glasses', 'write_note', 'arrange_goods'], 'default': genericIdles }; return npcSpecific[this.npcType] || npcSpecific.default; } update(time, delta) { if (!this.sprite.active) return; this.idleTimer += delta; // Trigger random idle animation if (this.idleTimer >= this.nextIdleTime && !this.currentIdle) { this.playRandomIdle(); this.idleTimer = 0; this.nextIdleTime = Phaser.Math.Between(3000, 8000); } } playRandomIdle() { const idle = Phaser.Utils.Array.GetRandom(this.idleAnimations); this.currentIdle = idle; // Play animation if it exists const animKey = `${this.npcType}_${idle}`; if (this.sprite.anims && this.sprite.anims.exists(animKey)) { this.sprite.play(animKey); // Return to default idle after animation this.sprite.on('animationcomplete', () => { this.sprite.play(`${this.npcType}_idle`); this.currentIdle = null; }, this); } else { // Fallback: simple visual effects for idle this.playFallbackIdle(idle); } } playFallbackIdle(idleType) { // Create simple tween-based idle behaviors as fallback switch (idleType) { case 'fix_hat': this.scene.tweens.add({ targets: this.sprite, angle: -5, duration: 200, yoyo: true, onComplete: () => { this.currentIdle = null; } }); break; case 'wipe_sweat': this.scene.tweens.add({ targets: this.sprite, scaleY: 0.98, duration: 300, yoyo: true, onComplete: () => { this.currentIdle = null; } }); break; case 'look_around': this.scene.tweens.add({ targets: this.sprite, scaleX: -Math.abs(this.sprite.scaleX), duration: 400, yoyo: true, onComplete: () => { this.currentIdle = null; } }); break; case 'scratch_head': this.scene.tweens.add({ targets: this.sprite, y: this.sprite.y - 5, duration: 150, yoyo: true, repeat: 2, onComplete: () => { this.currentIdle = null; } }); break; default: // Generic bob this.scene.tweens.add({ targets: this.sprite, y: this.sprite.y - 3, duration: 200, yoyo: true, onComplete: () => { this.currentIdle = null; } }); } } destroy() { this.sprite = null; } }