Files
novafarma/DEBUG_TOTAL_RECOVERY/TwinBondSystem.js
2026-01-16 02:43:46 +01:00

433 lines
13 KiB
JavaScript

/**
* TwinBondSystem.js
* =================
* KRVAVA ŽETEV - Twin Bond Mechanic (Kai ↔ Ana Connection)
*
* Core Concept:
* Kai and Ana share a psychic bond through the Alfa virus
* As twins, they can:
* - Feel each other's emotions
* - Sense each other's location (vaguely)
* - Communicate telepathically (limited)
* - Share HP/stamina in emergencies
*
* Features:
* - Bond Strength meter (0-100)
* - Telepathic messages from Ana
* - Direction to Ana indicator
* - Twin abilities (heal twin, boost twin, swap positions)
* - Bond events (visions, flashbacks)
* - Ana's status tracking (health, danger level)
*
* @author NovaFarma Team
* @date 2025-12-23
*/
class TwinBondSystem {
constructor(scene) {
this.scene = scene;
// Bond state
this.bondStrength = 75; // Starts strong (0-100)
this.maxBondStrength = 100;
// Ana's state (unknown location)
this.anaState = {
alive: true,
health: 100,
dangerLevel: 0, // 0 = safe, 100 = critical
distance: 5000, // pixels from Kai (initially far)
direction: { x: 1000, y: 1000 }, // General direction
lastMessage: null,
messageTime: null
};
// Bond abilities
this.abilities = {
telepathy: { unlocked: true, cooldown: 0, maxCooldown: 30000 }, // 30s
sensePulse: { unlocked: true, cooldown: 0, maxCooldown: 60000 }, // 1min
emergencyLink: { unlocked: false, cooldown: 0, maxCooldown: 300000 }, // 5min
twinRecall: { unlocked: false, cooldown: 0, maxCooldown: 600000 } // 10min
};
// Messages from Ana (telepathic)
this.messageQueue = [];
this.lastMessageTime = 0;
// UI elements
this.bondUI = null;
// Events
this.bondEvents = this.defineBondEvents();
this.nextEventTime = Date.now() + 60000; // First event in 1 minute
console.log('💞 TwinBondSystem initialized - Bond Strength:', this.bondStrength);
}
/**
* Update bond strength based on actions
*/
update(delta) {
const deltaSeconds = delta / 1000;
// Passive bond decay (small)
this.bondStrength = Math.max(0, this.bondStrength - 0.01 * deltaSeconds);
// Update ability cooldowns
for (const ability in this.abilities) {
if (this.abilities[ability].cooldown > 0) {
this.abilities[ability].cooldown -= delta;
}
}
// Check for random bond events
if (Date.now() > this.nextEventTime) {
this.triggerRandomBondEvent();
this.nextEventTime = Date.now() + Phaser.Math.Between(60000, 180000); // 1-3 min
}
// Update Ana's danger level based on story progress
this.updateAnaDanger(deltaSeconds);
}
/**
* Define bond events (telepathic visions)
*/
defineBondEvents() {
return [
{
id: 'first_contact',
trigger: 'auto',
condition: null,
message: 'Kai... can you hear me? I\'m... somewhere dark...',
emotion: 'worried',
bondChange: +5
},
{
id: 'danger_warning',
trigger: 'danger_high',
condition: () => this.anaState.dangerLevel > 70,
message: 'Brother! They\'re coming for me! Please hurry!',
emotion: 'fear',
bondChange: -10
},
{
id: 'memory_flash',
trigger: 'random',
condition: null,
message: 'Remember when we first discovered the Alfa strain? We were so hopeful...',
emotion: 'sad',
bondChange: +3
},
{
id: 'location_hint',
trigger: 'sense_pulse',
condition: null,
message: 'I can feel concrete walls... cold metal... some kind of facility?',
emotion: 'neutral',
bondChange: +5
},
{
id: 'encouragement',
trigger: 'random',
condition: () => this.scene.player?.hp < 50,
message: 'Stay strong, Kai! I believe in you!',
emotion: 'determined',
bondChange: +10
}
];
}
/**
* Trigger a random bond event
*/
triggerRandomBondEvent() {
const randomEvents = this.bondEvents.filter(e => e.trigger === 'random');
if (randomEvents.length === 0) return;
const event = Phaser.Utils.Array.GetRandom(randomEvents);
// Check condition
if (event.condition && !event.condition()) {
return;
}
this.showTelepathicMessage(event.message, event.emotion);
this.changeBondStrength(event.bondChange);
}
/**
* Show telepathic message from Ana
*/
showTelepathicMessage(message, emotion = 'neutral') {
console.log(`💭 Twin Bond Message: ${message}`);
// Update Ana's last message
this.anaState.lastMessage = message;
this.anaState.messageTime = Date.now();
// Show in dialogue system
if (this.scene.dialogueSystem) {
const anaData = {
name: 'Ana (Twin Bond)',
id: 'ana_telepathy'
};
// Create temporary dialogue
const telepathyDialogue = {
root: 'message',
nodes: {
'message': {
speaker: 'Ana (Twin Bond)',
emotion: emotion,
text: message,
next: null // Auto-close
}
}
};
this.scene.dialogueSystem.registerDialogue('telepathy_' + Date.now(), telepathyDialogue);
this.scene.dialogueSystem.startDialogue('telepathy_' + Date.now(), anaData);
}
// Visual effect (bond pulse)
this.scene.cameras.main.flash(500, 150, 100, 255, false);
// Bond strength change
this.showBondPulse();
}
/**
* Change bond strength
*/
changeBondStrength(amount) {
this.bondStrength = Phaser.Math.Clamp(
this.bondStrength + amount,
0,
this.maxBondStrength
);
console.log(`💞 Bond Strength: ${this.bondStrength.toFixed(1)}% (${amount > 0 ? '+' : ''}${amount})`);
// Notify player
if (amount > 0) {
this.scene.events.emit('bondStrengthened', { strength: this.bondStrength });
} else {
this.scene.events.emit('bondWeakened', { strength: this.bondStrength });
}
}
/**
* Visual bond pulse effect
*/
showBondPulse() {
// TODO: Create particle effect at player position
console.log('💫 Bond pulse visualization');
}
/**
* Ability: Telepathy (send message to Ana)
*/
useTelepathy(message) {
if (!this.abilities.telepathy.unlocked) {
console.log('❌ Telepathy not unlocked');
return false;
}
if (this.abilities.telepathy.cooldown > 0) {
console.log('⏸️ Telepathy on cooldown');
return false;
}
console.log(`📡 Sending to Ana: ${message}`);
// Ana responds after delay
this.scene.time.delayedCall(2000, () => {
const responses = [
"I heard you! Keep searching!",
"Kai... I'm trying to stay strong...",
"They don't know about our bond. Use that!",
"I can feel you getting closer!"
];
const response = Phaser.Utils.Array.GetRandom(responses);
this.showTelepathicMessage(response, 'determined');
});
// Set cooldown
this.abilities.telepathy.cooldown = this.abilities.telepathy.maxCooldown;
this.changeBondStrength(+2); // Strengthen bond
return true;
}
/**
* Ability: Sense Pulse (detect Ana's direction)
*/
useSensePulse() {
if (!this.abilities.sensePulse.unlocked) {
console.log('❌ Sense Pulse not unlocked');
return null;
}
if (this.abilities.sensePulse.cooldown > 0) {
console.log('⏸️ Sense Pulse on cooldown');
return null;
}
console.log('📍 Sensing Ana\'s location...');
// Calculate general direction
const playerX = this.scene.player?.x || 0;
const playerY = this.scene.player?.y || 0;
const angle = Phaser.Math.Angle.Between(
playerX, playerY,
this.anaState.direction.x, this.anaState.direction.y
);
const distance = this.anaState.distance;
// Show visual indicator
this.showDirectionIndicator(angle, distance);
// Set cooldown
this.abilities.sensePulse.cooldown = this.abilities.sensePulse.maxCooldown;
this.changeBondStrength(+5);
return {
angle: angle,
distance: distance,
distanceCategory: this.getDistanceCategory(distance)
};
}
/**
* Get distance category (for vague communication)
*/
getDistanceCategory(distance) {
if (distance < 500) return 'very_close';
if (distance < 1500) return 'close';
if (distance < 3000) return 'far';
return 'very_far';
}
/**
* Show direction indicator
*/
showDirectionIndicator(angle, distance) {
const category = this.getDistanceCategory(distance);
const messages = {
'very_close': 'Ana is VERY CLOSE! ⬆️',
'close': 'Ana is nearby 📍',
'far': 'Ana is far away 🔭',
'very_far': 'Ana is very far 🌌'
};
console.log(`📍 ${messages[category]} (${Math.round(distance)}px)`);
// TODO: Show UI arrow pointing in direction
}
/**
* Update Ana's danger level
*/
updateAnaDanger(deltaSeconds) {
// Danger level increases over time (captors getting desperate)
if (this.anaState.alive) {
this.anaState.dangerLevel = Math.min(
100,
this.anaState.dangerLevel + 0.1 * deltaSeconds
);
// Trigger danger events
if (this.anaState.dangerLevel > 70 && Math.random() < 0.01) {
const dangerEvent = this.bondEvents.find(e => e.id === 'danger_warning');
if (dangerEvent) {
this.showTelepathicMessage(dangerEvent.message, dangerEvent.emotion);
}
}
}
}
/**
* Update Ana's position (for story progression)
*/
updateAnaLocation(x, y, distance) {
this.anaState.direction.x = x;
this.anaState.direction.y = y;
this.anaState.distance = distance;
console.log(`📍 Ana's location updated: (${x}, ${y}), distance: ${distance}px`);
}
/**
* Create Twin Bond UI
*/
createBondUI() {
const width = this.scene.cameras.main.width;
// Bond meter (top-left)
const x = 20;
const y = 120;
// Background
const bg = this.scene.add.rectangle(x, y, 200, 40, 0x2d1b00, 0.8);
bg.setOrigin(0, 0);
bg.setScrollFactor(0);
bg.setDepth(100);
// Title
const title = this.scene.add.text(x + 10, y + 5, '💞 Twin Bond', {
fontSize: '14px',
fontFamily: 'Georgia, serif',
color: '#FFD700',
fontStyle: 'bold'
});
title.setScrollFactor(0);
title.setDepth(100);
// Bond bar
const barBg = this.scene.add.rectangle(x + 10, y + 25, 180, 8, 0x000000, 0.8);
barBg.setOrigin(0, 0);
barBg.setScrollFactor(0);
barBg.setDepth(100);
const barFill = this.scene.add.rectangle(
x + 10, y + 25,
180 * (this.bondStrength / 100),
8,
0xFF69B4,
1
);
barFill.setOrigin(0, 0);
barFill.setScrollFactor(0);
barFill.setDepth(100);
this.bondUI = { bg, title, barBg, barFill };
// Update bar every frame
this.scene.events.on('update', () => {
if (this.bondUI && this.bondUI.barFill) {
this.bondUI.barFill.width = 180 * (this.bondStrength / 100);
}
});
}
/**
* Getters
*/
getBondStrength() {
return this.bondStrength;
}
getAnaStatus() {
return this.anaState;
}
isAnaSafe() {
return this.anaState.dangerLevel < 50;
}
}