Files
novafarma/old_logic/src_backup_1768938138/systems/SusiCompanion.js
2026-01-21 01:08:21 +01:00

339 lines
8.6 KiB
JavaScript

/**
* 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;