/** * SUSI COMPANION AI - THE HUNTER * Rottweiler tracking system for finding Ana's memories */ class SusiCompanion { constructor(scene, kai) { this.scene = scene; this.kai = kai; this.sprite = null; this.isUnlocked = false; // Susi states this.state = 'following'; // 'following', 'tracking', 'sitting', 'sleeping' this.followDistance = 50; this.trackingTarget = null; // Memory tracking this.memoryScent = null; this.trackingProgress = 0; this.init(); } init() { // Check if Susi is unlocked const save = localStorage.getItem('player_progress'); if (save) { const data = JSON.parse(save); this.isUnlocked = data.susi_unlocked || false; } if (this.isUnlocked) { this.spawn(); } } /** * SPAWN SUSI IN GAME */ spawn() { if (this.sprite) return; // Create Susi sprite this.sprite = this.scene.physics.add.sprite( this.kai.x + 50, this.kai.y, 'susi_idle' // Sprite sheet key ); this.sprite.setDepth(19); // Just behind Kai this.sprite.setCollideWorldBounds(true); // Setup animations this.setupAnimations(); console.log('🐕 Susi spawned!'); } /** * SETUP SUSI ANIMATIONS */ setupAnimations() { if (!this.scene.anims.exists('susi_idle')) { this.scene.anims.create({ key: 'susi_idle', frames: this.scene.anims.generateFrameNumbers('susi_idle', { start: 0, end: 3 }), frameRate: 8, repeat: -1 }); } if (!this.scene.anims.exists('susi_run')) { this.scene.anims.create({ key: 'susi_run', frames: this.scene.anims.generateFrameNumbers('susi_run', { start: 0, end: 5 }), frameRate: 12, repeat: -1 }); } if (!this.scene.anims.exists('susi_sit')) { this.scene.anims.create({ key: 'susi_sit', frames: this.scene.anims.generateFrameNumbers('susi_sit', { start: 0, end: 2 }), frameRate: 4, repeat: 0 }); } this.sprite.play('susi_idle'); } /** * UPDATE SUSI BEHAVIOR (called every frame) */ update() { if (!this.sprite || !this.isUnlocked) return; switch (this.state) { case 'following': this.followKai(); break; case 'tracking': this.trackMemory(); break; case 'sitting': this.sprite.play('susi_sit', true); break; case 'sleeping': // Play sleep animation break; } } /** * FOLLOW KAI LOGIC */ followKai() { const distance = Phaser.Math.Distance.Between( this.sprite.x, this.sprite.y, this.kai.x, this.kai.y ); // If too far, run to catch up if (distance > this.followDistance + 20) { this.sprite.play('susi_run', true); // Move towards Kai this.scene.physics.moveToObject(this.sprite, this.kai, 150); // Flip sprite based on direction if (this.sprite.body.velocity.x < 0) { this.sprite.setFlipX(true); } else if (this.sprite.body.velocity.x > 0) { this.sprite.setFlipX(false); } } // If close enough, idle else if (distance <= this.followDistance) { this.sprite.setVelocity(0, 0); this.sprite.play('susi_idle', true); } } /** * TRACK MEMORY SCENT * Used when Ana's memory item is nearby */ trackMemory() { if (!this.trackingTarget) return; const distance = Phaser.Math.Distance.Between( this.sprite.x, this.sprite.y, this.trackingTarget.x, this.trackingTarget.y ); if (distance > 10) { // Run to memory location this.sprite.play('susi_run', true); this.scene.physics.moveToObject(this.sprite, this.trackingTarget, 180); // Flip sprite if (this.sprite.body.velocity.x < 0) { this.sprite.setFlipX(true); } else { this.sprite.setFlipX(false); } } else { // Found it! Bark and show indicator this.sprite.setVelocity(0, 0); this.bark(); this.showMemoryIndicator(); // Return to following after found this.scene.time.delayedCall(2000, () => { this.state = 'following'; this.trackingTarget = null; }); } } /** * RESPOND TO KAI'S WHISTLE (Xbox Y button) */ whistle() { if (!this.isUnlocked) return; console.log('🎵 Kai whistles to Susi!'); // Susi responds this.bark(); // If far away, run to Kai immediately const distance = Phaser.Math.Distance.Between( this.sprite.x, this.sprite.y, this.kai.x, this.kai.y ); if (distance > 100) { this.state = 'following'; this.scene.physics.moveToObject(this.sprite, this.kai, 200); } } /** * BARK ANIMATION */ bark() { if (!this.sprite) return; // Play bark animation this.sprite.play('susi_bark', true); // Play bark sound if (this.scene.sound.get('susi_bark')) { this.scene.sound.play('susi_bark', { volume: 0.5 }); } // Show bark indicator this.showBarkIndicator(); } /** * SHOW BARK INDICATOR (speech bubble with "WOOF!") */ showBarkIndicator() { const bark = this.scene.add.text( this.sprite.x, this.sprite.y - 40, 'WOOF!', { fontSize: '16px', fontFamily: 'Arial Black', color: '#ffffff', stroke: '#000000', strokeThickness: 4 } ); bark.setOrigin(0.5); bark.setDepth(100); // Bounce animation this.scene.tweens.add({ targets: bark, y: bark.y - 10, alpha: 0, duration: 1000, ease: 'Cubic.easeOut', onComplete: () => bark.destroy() }); } /** * SHOW MEMORY FOUND INDICATOR */ showMemoryIndicator() { const indicator = this.scene.add.sprite( this.sprite.x, this.sprite.y - 50, 'memory_indicator' ); indicator.setDepth(100); indicator.setScale(0); // Pop in animation this.scene.tweens.add({ targets: indicator, scale: 1, duration: 300, ease: 'Back.easeOut', yoyo: true, hold: 1000, onComplete: () => indicator.destroy() }); } /** * START TRACKING A MEMORY */ startTracking(memoryObject) { this.state = 'tracking'; this.trackingTarget = memoryObject; this.memoryScent = memoryObject.scent || 'ana'; console.log('🐕 Susi started tracking:', this.memoryScent); // Show tracking UI const event = new CustomEvent('susi-tracking', { detail: { scent: this.memoryScent } }); window.dispatchEvent(event); } /** * SIT COMMAND */ sit() { this.state = 'sitting'; this.sprite.setVelocity(0, 0); console.log('🐕 Susi sits'); } /** * UNLOCK SUSI (when found in game) */ unlock() { this.isUnlocked = true; // Save unlock status const save = JSON.parse(localStorage.getItem('player_progress') || '{}'); save.susi_unlocked = true; localStorage.setItem('player_progress', JSON.stringify(save)); this.spawn(); console.log('🐕 SUSI UNLOCKED!'); // Show unlock notification const event = new CustomEvent('companion-unlocked', { detail: { companion: 'susi', name: 'Susi the Hunter', ability: 'Track memories and items' } }); window.dispatchEvent(event); } destroy() { if (this.sprite) { this.sprite.destroy(); this.sprite = null; } } } export default SusiCompanion;