Updated Diary - SESSION 3 Complete
All work from Christmas Day documented: - Session 1: Biomes (18/18) - Session 2: Story integration + UI systems - Session 3: Grok character + Susi Total: 5 hours, 1486 lines code, 6 systems
This commit is contained in:
@@ -241,21 +241,35 @@ class AnaClueSystem {
|
||||
*/
|
||||
getMessageReaction(clue) {
|
||||
const reactions = {
|
||||
msg_01: "Ana... I'll find you. I promise.",
|
||||
msg_02: "Red flowers... I'll follow your trail anywhere.",
|
||||
msg_03: "Intelligence? Could we... coexist with them?",
|
||||
msg_04: "The Giant Troll King. I'll face him for you, Ana.",
|
||||
msg_05: "We WILL rebuild Hope Valley together. I swear it.",
|
||||
msg_06: "I feel you too, Ana. Our bond will guide me.",
|
||||
msg_07: "Portals... this could change everything!",
|
||||
msg_08: "Domestication? This changes how I see them...",
|
||||
msg_09: "A cure! There's still hope for this world!",
|
||||
msg_10: "A family... Ana, we'll have that future together.",
|
||||
msg_11: "Atlantis! Your curiosity never stopped, did it?",
|
||||
msg_12: "Radiation won't stop me. Nothing will.",
|
||||
msg_13: "Even captured, you appreciate nature's beauty...",
|
||||
msg_14: "I'll NEVER give up on you, Ana. Never!",
|
||||
msg_15: "I love you too, sister. I'm coming for you."
|
||||
msg_01: "*Picks up note with shaking hands*\nAna... your handwriting...\n*Traces fingers over words*\nYou were scared. I can feel it in how you wrote.\nBut you still thought of me. 'Stay safe'...\n\nNo, Ana. I won't stay safe.\nI'll find you. No matter how dangerous.\nTwin promise. 💜",
|
||||
|
||||
msg_02: "Red flowers... Ana's favorite!\n*Looks around, spots red flowers growing*\nShe left me a trail. Even captured, she thought ahead.\n\nThat's my sister. Always thinking.\nI'm following, Ana. Right behind you.",
|
||||
|
||||
msg_03: "Intelligence? She's right.\nMy zombie workers... they understand orders, learn tasks.\n\nAna saw it too. Even while captured.\nHer curiosity never stopped.\n\nMaybe... maybe zombies and humans can coexist.\nIf we survive this.",
|
||||
|
||||
msg_04: "*Clenches fists*\nThe Troll King. The one who took you.\n\nNow I know his name.\nNow I know my enemy.\n\nDr. Krnić may have created you, beast...\nBut I will DESTROY you.",
|
||||
|
||||
msg_05: "*Tears up*\n'Together'... Ana still believes we'll be together again.\n\nYes. We'll rebuild Hope Valley.\nYou, me, and whoever else survives.\nWe'll make it beautiful again.\n\nA home. Our home.",
|
||||
|
||||
msg_06: "*Gasps*\nYou can feel me?!\nANA! I'm here! I'm searching!\n*Closes eyes, concentrates*\n\nTwin bond... please work...\n*Faint purple glow*\n\nAna... I felt something. Just for a moment.\nYou're alive. I KNOW you're alive!",
|
||||
|
||||
msg_07: "Portals! Of course!\nAna, you genius!\nIf I repair these, I can search the world faster!\n\nI'll fix them all. Every single one.\nFor you.",
|
||||
|
||||
msg_08: "Domestication... that's what I'm doing.\nMy zombie workers are 'domesticated'.\n\nBut Ana found this disturbing?\nIs what I'm doing... wrong?\n\nNo. I'm helping them. Giving them purpose.\nThat's different from Dr. Krnić's experiments.",
|
||||
|
||||
msg_09: "A CURE?!\nAna... if there's a cure...\nWe could save EVERYONE!\n\nThe infected could become human again!\nMama, Dad... they could--\n\nNo. Too late for them.\nBut not too late for others.\n\nI'll find it, Ana. For you.",
|
||||
|
||||
msg_10: "*Sits down, holds note to chest*\nA family... children...\n\nAna, you're thinking about the future.\nEven in captivity, you dream of life.\n\nWe'll have that future. I swear it.\nYou'll see children play in safe fields.\nOur children. Our future.",
|
||||
|
||||
msg_11: "*Laughs through tears*\nOnly you, Ana. Only you would get excited about Atlantis.\nWhile captured. While in danger.\n\nYour curiosity, your wonder... it never dies.\nThat's what I love about you.\n\nI'll explore these ruins for you. Find every secret.",
|
||||
|
||||
msg_12: "Chernobyl... you went to the reactor?!\nAna, that's suicide!\n\nBut you left me a warning. Even there.\nYou knew I'd follow.\n\nRadiation won't stop me. Nothing will.\nI'm coming, Ana. Hold on.",
|
||||
|
||||
msg_13: "Biodiversity... scientist words even now.\n\nAna, you never stop learning.\nNever stop appreciating nature.\n\nWhen this is over, I'll take you on a real expedition.\nNo danger. Just discovery.\nTwin explorers. Together.",
|
||||
|
||||
msg_14: "*Crumples note, then smooths it out*\nSave MYSELF?!\nYou think I'd give up on you?!\n\nAna, I'd walk through hell for you.\nAlone if I had to.\n\nThis 'danger' you warn about?\nBRING IT ON.",
|
||||
|
||||
msg_15: "*Breaks down crying*\n'I love you, brother'...\n\nI love you too, Ana. So much.\n\nYou're right. I won't listen.\nI never do when it comes to you.\n\nI'm at the castle. I'm coming in.\nWait for me. Please."
|
||||
};
|
||||
|
||||
return reactions[clue.id] || "Ana... another piece of you found.";
|
||||
@@ -266,18 +280,29 @@ class AnaClueSystem {
|
||||
*/
|
||||
getPhotoReaction(clue) {
|
||||
const reactions = {
|
||||
photo_01: "*tears up* We were so innocent back then...",
|
||||
photo_02: "So that's the monster who took you...",
|
||||
photo_03: "Hope Valley was paradise. It will be again.",
|
||||
photo_04: "Even then, you saw them differently than others.",
|
||||
photo_05: "Your map will help me repair them all!",
|
||||
photo_06: "You documented everything. So thorough, Ana.",
|
||||
photo_07: "Your handwriting... I'd recognize it anywhere.",
|
||||
photo_08: "Atlantean tech! This could save us all!",
|
||||
photo_09: "You went to Chernobyl?! Ana...",
|
||||
photo_10: "Ancient mysteries. You loved this stuff.",
|
||||
photo_11: "*clenches fist* I see you, captor. I'm coming.",
|
||||
photo_12: "*breaks down* I'm coming, Ana. Hold on!"
|
||||
photo_01: "*Stares at photo for long time*\nMom... Dad... Ana... me...\nWe were so happy.\n\nI'll make us happy again, Ana.\nDifferent, but happy.\nNew family. New memories.\n\nBut I'll never forget this.",
|
||||
|
||||
photo_02: "*Photo of Giant Troll, blurry*\nThere you are, monster.\nThe thing that destroyed everything.\n\nAna got a photo even while running.\nBrave. So brave.\n\nI'm coming for you, Troll.",
|
||||
|
||||
photo_03: "It WAS beautiful...\nGreen fields, happy people, clean buildings.\n\nWe can make it like this again.\nWith your help, Ana.\nTogether we'll rebuild paradise.",
|
||||
|
||||
photo_04: "A Level 1 zombie... looking confused.\nAna saw them as... beings. Not monsters.\n\nShe was always more empathetic than me.\nMaybe that's why she left this trail.\nShe knew I'd need to see them differently.",
|
||||
|
||||
photo_05: "Ana drew a MAP for me!\nAll 18 portals marked!\n\nShe knew I'd need to travel fast.\nThought of everything.\n\nThank you, sister. This helps SO much.",
|
||||
|
||||
photo_06: "Dr. Krnić's lab... still functional.\nHigh-tech equipment Ana photographed.\n\nIf I find this place... I could finish her research.\nFind the cure.\nSave everyone.",
|
||||
|
||||
photo_07: "*Close-up of handwriting*\nHer journal... during captivity.\n\nShe kept writing. Kept documenting.\nScientist to the end.\n\nI need to find this journal. All of it.",
|
||||
|
||||
photo_08: "Atlantean technology... glowing crystals!\nThis could power everything!\n\nAna, you found the future.\nAncient tech to save the modern world.\n\nI'll bring it back. For everyone.",
|
||||
|
||||
photo_09: "*Chernobyl reactor, green glow*\nThat's where Dr. Krnić is.\nFinal facility.\n\nAna went there. Survived radiation.\nIf she can... so can I.",
|
||||
|
||||
photo_10: "Ancient temple in Amazon...\nAna always loved archaeology.\n\nI'll explore it. For you.\nFind whatever secrets you wanted to discover.",
|
||||
|
||||
photo_11: "*Shadowy figure in photo*\nThis is him. Dr. Krnić.\nThe monster who started everything.\n\nYour face is blurry, coward.\nBut I'll see you clearly...\nRight before I END you.",
|
||||
|
||||
photo_12: "*Ana holding 'FIND ME' sign, tears in eyes*\n\n*Kai collapses to knees, sobbing*\n\nI SEE YOU, ANA! I SEE YOU!\nI'M COMING! I SWEAR I'M COMING!\n\nHold on! Please! Just hold on!"
|
||||
};
|
||||
|
||||
return reactions[clue.id] || "Another memory of you...";
|
||||
@@ -288,11 +313,29 @@ class AnaClueSystem {
|
||||
*/
|
||||
getItemReaction(clue) {
|
||||
const reactions = {
|
||||
item_01: "*holds bracelet* I have the matching one...",
|
||||
item_09: "*clutches necklace* Mother's necklace! You kept it safe.",
|
||||
item_13: "*pairs gloves* Both found. You left a trail for me.",
|
||||
item_17: "*opens locket* My photo... you carried me with you.",
|
||||
item_23: "*trembling hands* I'll open this when I find you, Ana."
|
||||
item_01: "*Silver twin bracelet*\nI have the matching one...\n*Holds both bracelets together*\nTwins. Always twins.\nSoon we'll wear these together again.",
|
||||
|
||||
item_02: "*Torn dress piece*\nFragment of Ana's favorite dress...\n*Holds it gently*\nYou loved this dress. Wore it on special days.\nI'll keep this safe for you.",
|
||||
|
||||
item_03: "*Muddy hairpin*\nAna's decorative hairpin...\n*Cleans mud off carefully*\nYou always wore this. Even while farming.\nIt's coming home with me.",
|
||||
|
||||
item_04: "*Father's pocket watch*\nDad's watch... Ana always carried it.\n*Opens it - shows family photo inside*\nYou kept us close. All of us.\nI understand, Ana.",
|
||||
|
||||
item_05: "*Engraved compass*\n'To Ana, find your way home'...\n*Compass points north*\nI'll use this to find YOU, Ana.\nThen we both go home. Together.",
|
||||
|
||||
item_06: "*Small stuffed rabbit*\nYour childhood toy!\n*Hugs it*\nWe got this when we were 5.\nYou never let it go.\nI won't either.",
|
||||
|
||||
item_07: "*Delicate music box*\n*Opens it - plays Ana's favorite song*\n*Sits and listens, tears flowing*\nThis song... you hummed it every night.\nI hear you, Ana. I hear you.",
|
||||
|
||||
item_08: "*Ana's art sketchbook*\n*Flips through pages*\nYour drawings... so beautiful.\nEven in danger, you created beauty.\nThat's who you are.",
|
||||
|
||||
item_09: "*Falls to knees*\nMama's necklace... Ana kept it through everything.\nProtected it.\n\n*Kisses necklace*\nMama... I'm protecting Ana now.\nLike you asked.",
|
||||
|
||||
item_10: "*Torn diary page*\n*Reads*\n'I'm scared. But I won't give up hope.'\n*Clutches page*\nI won't give up either, Ana. Never.",
|
||||
|
||||
item_17: "*Opens locket - sees his own photo*\n\n*Tears streaming*\nYou carried ME with you...\nWhile I searched for you...\nYou had me the whole time.\n\nTwin bond. Forever.",
|
||||
|
||||
item_23: "*Sealed envelope: 'Open when you find me'*\n\n*Hands trembling*\nNot yet. I'm not opening this yet.\nI'll open it when I SEE you.\nFace to face.\n\nSoon, Ana. Soon."
|
||||
};
|
||||
|
||||
return reactions[clue.id] || `${clue.title}... you were here.`;
|
||||
|
||||
@@ -1,7 +1,24 @@
|
||||
/**
|
||||
* GrokCharacterSystem.js
|
||||
* ======================
|
||||
* KRVAVA ŽETEV - Grok Character Update (P13)
|
||||
* KRVAVA ŽETEV - Grok Character (The Developer / Pink Alpha)
|
||||
*
|
||||
* CHARACTER DESIGN:
|
||||
* - Skin: Light green (unique color - not human!)
|
||||
* - Hair: PINK dreadlocks (iconic!)
|
||||
* - Outfit: Oversized hoodie (2 sizes too big) + baggy pants
|
||||
* - Shoes: Hot pink Converse
|
||||
* - Piercings: Septum, eyebrows, lips, 15+ earrings, 25mm tunnels
|
||||
*
|
||||
* PERSONALITY:
|
||||
* - ADHD genius developer
|
||||
* - Always vaping (Rainbow RGB mod)
|
||||
* - Zen master with massive gong
|
||||
* - Quick movements when hyperfocused
|
||||
* - Oversized comfort style
|
||||
*
|
||||
* COMPANION:
|
||||
* - Susi: Hot dog hunting dog (always by his side)
|
||||
*
|
||||
* Features:
|
||||
* - Massive gong (1m diameter!)
|
||||
@@ -9,9 +26,11 @@
|
||||
* - Morning meditation rituals
|
||||
* - Combat buffs
|
||||
* - Smoke screen abilities
|
||||
* - ADHD focus modes
|
||||
* - Susi interactions
|
||||
*
|
||||
* @author NovaFarma Team
|
||||
* @date 2025-12-23
|
||||
* @date 2025-12-25
|
||||
*/
|
||||
|
||||
export default class GrokCharacterSystem {
|
||||
@@ -25,18 +44,41 @@ export default class GrokCharacterSystem {
|
||||
this.gongCooldown = 300000; // 5 minutes
|
||||
this.meditationTime = 6; // 6 AM daily
|
||||
|
||||
// ADHD mechanics
|
||||
this.isFocused = false; // "Oversized Focus" mode
|
||||
this.focusTimer = 0;
|
||||
this.hyperfocusSpeed = 2.0; // Speed multiplier when focused
|
||||
this.currentTopic = 'coding'; // What Grok is focused on
|
||||
|
||||
// Visual elements
|
||||
this.gong = null;
|
||||
this.vapeDevice = null;
|
||||
this.smokeParticles = [];
|
||||
this.hoodie = null; // Oversized hoodie sprite
|
||||
this.dreadlocks = null; // Pink dreadlocks
|
||||
this.piercings = []; // Visual piercing elements
|
||||
|
||||
// Susi companion
|
||||
this.susi = null; // Susi the hot dog hunter
|
||||
this.susiState = 'following'; // following, hunting, eating
|
||||
|
||||
// Buffs
|
||||
this.activeBuffs = new Map();
|
||||
|
||||
// Character colors
|
||||
this.skinColor = 0x90EE90; // Light green
|
||||
this.dreadlockColor = 0xFF69B4; // Hot pink
|
||||
this.hoodieColor = 0x2F4F4F; // Dark slate gray (wide hoodie)
|
||||
|
||||
console.log('🧘 GrokCharacterSystem initialized');
|
||||
console.log('👕 Oversized hoodie: ON');
|
||||
console.log('💚 Skin: Light green');
|
||||
console.log('💕 Dreadlocks: HOT PINK');
|
||||
console.log('🐕 Susi companion: Ready!');
|
||||
|
||||
// Setup visuals
|
||||
this.setupGrokVisuals();
|
||||
this.createSusi();
|
||||
this.startVapingAnimation();
|
||||
}
|
||||
|
||||
@@ -559,6 +601,264 @@ export default class GrokCharacterSystem {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Susi companion (Hot Dog Hunter)
|
||||
*/
|
||||
createSusi() {
|
||||
if (!this.grok) return;
|
||||
|
||||
// Create Susi (dachshund-style hot dog hunter!)
|
||||
this.susi = this.scene.add.ellipse(
|
||||
this.grok.x + 30,
|
||||
this.grok.y + 20,
|
||||
40, // Width (long dog!)
|
||||
20, // Height
|
||||
0x8B4513 // Brown color
|
||||
);
|
||||
this.susi.setDepth(this.grok.depth);
|
||||
|
||||
// Add spots
|
||||
const spot1 = this.scene.add.circle(
|
||||
this.susi.x - 10,
|
||||
this.susi.y,
|
||||
4,
|
||||
0x654321 // Darker spot
|
||||
);
|
||||
spot1.setDepth(this.grok.depth + 1);
|
||||
|
||||
// Susi's nose (always sniffing for hot dogs!)
|
||||
const nose = this.scene.add.circle(
|
||||
this.susi.x + 20,
|
||||
this.susi.y,
|
||||
3,
|
||||
0x000000 // Black nose
|
||||
);
|
||||
nose.setDepth(this.grok.depth + 2);
|
||||
|
||||
// Tail (wagging animation!)
|
||||
const tail = this.scene.add.line(
|
||||
this.susi.x - 20,
|
||||
this.susi.y - 5,
|
||||
0, 0,
|
||||
-10, -5,
|
||||
0x8B4513,
|
||||
1
|
||||
);
|
||||
tail.setLineWidth(3);
|
||||
tail.setDepth(this.grok.depth);
|
||||
|
||||
// Tail wag animation
|
||||
this.scene.tweens.add({
|
||||
targets: tail,
|
||||
angle: { from: -15, to: 15 },
|
||||
duration: 300,
|
||||
yoyo: true,
|
||||
repeat: -1
|
||||
});
|
||||
|
||||
console.log('🐕 Susi created! Hot dog hunter ready!');
|
||||
|
||||
// Susi behavior
|
||||
this.startSusiBehavior();
|
||||
}
|
||||
|
||||
/**
|
||||
* Susi's AI behavior
|
||||
*/
|
||||
startSusiBehavior() {
|
||||
// Susi follows Grok
|
||||
setInterval(() => {
|
||||
if (!this.susi || !this.grok) return;
|
||||
|
||||
// Follow Grok at distance
|
||||
const targetX = this.grok.x + 30;
|
||||
const targetY = this.grok.y + 20;
|
||||
|
||||
// Smooth follow
|
||||
this.susi.x += (targetX - this.susi.x) * 0.1;
|
||||
this.susi.y += (targetY - this.susi.y) * 0.1;
|
||||
|
||||
// Random hot dog hunting
|
||||
if (Math.random() < 0.01) { // 1% chance per frame
|
||||
this.susiHuntHotDog();
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Susi hunts for hot dogs!
|
||||
*/
|
||||
susiHuntHotDog() {
|
||||
if (!this.susi) return;
|
||||
|
||||
console.log('🌭 Susi spotted a potential hot dog!');
|
||||
this.susiState = 'hunting';
|
||||
|
||||
// Susi runs to random location
|
||||
const randomX = this.susi.x + (Math.random() - 0.5) * 100;
|
||||
const randomY = this.susi.y + (Math.random() - 0.5) * 100;
|
||||
|
||||
this.scene.tweens.add({
|
||||
targets: this.susi,
|
||||
x: randomX,
|
||||
y: randomY,
|
||||
duration: 1000,
|
||||
ease: 'Quad.InOut',
|
||||
onComplete: () => {
|
||||
// Found hot dog!
|
||||
this.susiState = 'eating';
|
||||
console.log('🌭 Susi found a hot dog! *nom nom*');
|
||||
|
||||
// Eating animation (wiggle)
|
||||
this.scene.tweens.add({
|
||||
targets: this.susi,
|
||||
angle: { from: -5, to: 5 },
|
||||
duration: 200,
|
||||
yoyo: true,
|
||||
repeat: 5,
|
||||
onComplete: () => {
|
||||
this.susiState = 'following';
|
||||
this.susi.setAngle(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* ADHD Focus Mode - Grok hides in hoodie to focus
|
||||
*/
|
||||
enterFocusMode(topic = 'coding') {
|
||||
if (this.isFocused) {
|
||||
console.log('⚠️ Already in focus mode!');
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log(`🧠 Grok enters ADHD FOCUS MODE! Topic: ${topic}`);
|
||||
console.log('👕 *Hides in oversized hoodie*');
|
||||
|
||||
this.isFocused = true;
|
||||
this.currentTopic = topic;
|
||||
this.focusTimer = 0;
|
||||
|
||||
// Visual: Grok shrinks into hoodie
|
||||
if (this.grok) {
|
||||
this.scene.tweens.add({
|
||||
targets: this.grok,
|
||||
scale: 0.7, // Gets smaller (hiding in hoodie)
|
||||
alpha: 0.8,
|
||||
duration: 500
|
||||
});
|
||||
}
|
||||
|
||||
// Can't be interrupted unless you have vape juice!
|
||||
this.showNotification({
|
||||
title: 'Focus Mode Active!',
|
||||
text: `🧠 Grok is focusing on ${topic}. Don't interrupt! (Unless you have vape juice)`,
|
||||
icon: '👕'
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit ADHD focus mode
|
||||
*/
|
||||
exitFocusMode() {
|
||||
if (!this.isFocused) return;
|
||||
|
||||
console.log('🧠 Focus mode complete!');
|
||||
this.isFocused = false;
|
||||
|
||||
// Visual: Grok emerges from hoodie
|
||||
if (this.grok) {
|
||||
this.scene.tweens.add({
|
||||
targets: this.grok,
|
||||
scale: 1.0,
|
||||
alpha: 1.0,
|
||||
duration: 500
|
||||
});
|
||||
}
|
||||
|
||||
this.showNotification({
|
||||
title: 'Focus Complete!',
|
||||
text: `✅ ${this.currentTopic} finished! Grok emerges victorious!`,
|
||||
icon: '🎉'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* ADHD Hyperfocus Movement
|
||||
*/
|
||||
moveWithHyperfocus(direction) {
|
||||
if (!this.isFocused) {
|
||||
console.log('⚠️ Not in focus mode!');
|
||||
return;
|
||||
}
|
||||
|
||||
// When hyperfocused, Grok moves SUPER fast!
|
||||
const baseSpeed = 5;
|
||||
const speed = baseSpeed * this.hyperfocusSpeed; // 2x speed!
|
||||
|
||||
console.log(`⚡ HYPERFOCUS SPEED! Moving ${direction} at ${speed} px/frame!`);
|
||||
|
||||
// Move Grok super fast
|
||||
// (Integration with movement system would go here)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Grok's quest dialogues
|
||||
*/
|
||||
getGrokQuests() {
|
||||
return [
|
||||
{
|
||||
id: 'hoodie_rescue',
|
||||
title: 'Hoodie v nevarnosti',
|
||||
dialogue: "Dude, moj najljubši hoodie se je zataknil za eno tistih piranha rastlin v coni 4. Brez njega se ne morem fokusirati, preveč me zebe v roke! Greš ponj?",
|
||||
objective: 'Premagaj gigantsko mesojedko in reši Gronkov široki pulover',
|
||||
rewards: {
|
||||
gold: 500,
|
||||
xp: 1000,
|
||||
item: 'grok_friendship +10'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'vape_mixology',
|
||||
title: 'Zamenjava tekočine (Vape Mixology)',
|
||||
dialogue: "Bro, poskušam zmešati nov okus 'Baggy Cloud', ampak Susi mi je prevrnila epruveto, ker je mislila, da so notri hrenovke. Rabim tri mutirane jagode iz Dino Valleyja!",
|
||||
objective: 'Najdi 3 mutirane jagode v Dino Valley biome',
|
||||
rewards: {
|
||||
gold: 300,
|
||||
xp: 750,
|
||||
item: 'baggy_cloud_vape_juice'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'adhd_code',
|
||||
title: 'ADHD koda na hlačah',
|
||||
dialogue: "Ej, si vedel, da sem si na nogo (na hlače) napisal pomembno kodo za tvoj novi rudnik, pa sem jo zdaj ponesreči umazal z blatom? Susi, pomagaj mi polizati to blato... ah, ne, Kai, ti boš moral najti čistilo!",
|
||||
objective: 'Najdi čistilo v opuščenem laboratoriju',
|
||||
rewards: {
|
||||
gold: 400,
|
||||
xp: 850,
|
||||
unlock: 'advanced_mine_code'
|
||||
}
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper: Show notification
|
||||
*/
|
||||
showNotification(notification) {
|
||||
console.log(`📢 ${notification.icon} ${notification.title}: ${notification.text}`);
|
||||
|
||||
const ui = this.scene.scene.get('UIScene');
|
||||
if (ui && ui.showNotification) {
|
||||
ui.showNotification(notification);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get active buff for target
|
||||
*/
|
||||
|
||||
334
src/systems/TwinBondUISystem.js
Normal file
334
src/systems/TwinBondUISystem.js
Normal file
@@ -0,0 +1,334 @@
|
||||
/**
|
||||
* TwinBondUISystem.js
|
||||
* ====================
|
||||
* KRVAVA ŽETEV - Twin Bond Heartbeat UI
|
||||
*
|
||||
* Features:
|
||||
* - Visual heartbeat indicator on screen
|
||||
* - Speeds up when near Ana's clues
|
||||
* - Purple glow effect
|
||||
* - Distance-based intensity
|
||||
* - Twin bond strength indicator
|
||||
*
|
||||
* @author NovaFarma Team
|
||||
* @date 2025-12-25
|
||||
*/
|
||||
|
||||
export default class TwinBondUISystem {
|
||||
constructor(scene) {
|
||||
this.scene = scene;
|
||||
|
||||
// UI elements
|
||||
this.heartContainer = null;
|
||||
this.heartIcon = null;
|
||||
this.glowEffect = null;
|
||||
this.bondStrengthBar = null;
|
||||
|
||||
// State
|
||||
this.baseHeartRate = 60; // bpm
|
||||
this.currentHeartRate = 60;
|
||||
this.bondStrength = 0; // 0-100
|
||||
this.nearestClueDistance = Infinity;
|
||||
|
||||
// Animation
|
||||
this.heartbeatTween = null;
|
||||
this.lastBeat = 0;
|
||||
|
||||
console.log('💜 TwinBondUISystem initialized');
|
||||
|
||||
this.createUI();
|
||||
this.startHeartbeat();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create UI elements
|
||||
*/
|
||||
createUI() {
|
||||
const ui = this.scene.scene.get('UIScene') || this.scene;
|
||||
|
||||
// Container (top-left corner)
|
||||
this.heartContainer = ui.add.container(50, 50);
|
||||
this.heartContainer.setDepth(1000); // Above everything
|
||||
this.heartContainer.setScrollFactor(0); // Fixed to camera
|
||||
|
||||
// Purple glow effect (behind heart)
|
||||
this.glowEffect = ui.add.circle(0, 0, 25, 0x9370DB, 0);
|
||||
this.heartContainer.add(this.glowEffect);
|
||||
|
||||
// Heart icon (emoji-style)
|
||||
this.heartIcon = ui.add.text(0, 0, '💜', {
|
||||
fontSize: '32px',
|
||||
fontFamily: 'Arial'
|
||||
});
|
||||
this.heartIcon.setOrigin(0.5);
|
||||
this.heartContainer.add(this.heartIcon);
|
||||
|
||||
// Bond strength bar (below heart)
|
||||
const barWidth = 50;
|
||||
const barHeight = 5;
|
||||
|
||||
// Background bar
|
||||
const barBg = ui.add.rectangle(0, 30, barWidth, barHeight, 0x333333);
|
||||
this.heartContainer.add(barBg);
|
||||
|
||||
// Strength bar
|
||||
this.bondStrengthBar = ui.add.rectangle(
|
||||
-barWidth / 2,
|
||||
30,
|
||||
0, // Start at 0 width
|
||||
barHeight,
|
||||
0x9370DB
|
||||
);
|
||||
this.bondStrengthBar.setOrigin(0, 0.5);
|
||||
this.heartContainer.add(this.bondStrengthBar);
|
||||
|
||||
// Bond strength text
|
||||
this.bondStrengthText = ui.add.text(0, 45, '0%', {
|
||||
fontSize: '10px',
|
||||
fontFamily: 'Arial',
|
||||
color: '#9370DB'
|
||||
});
|
||||
this.bondStrengthText.setOrigin(0.5);
|
||||
this.heartContainer.add(this.bondStrengthText);
|
||||
|
||||
console.log('✅ Twin Bond UI created');
|
||||
}
|
||||
|
||||
/**
|
||||
* Start heartbeat animation
|
||||
*/
|
||||
startHeartbeat() {
|
||||
const beatInterval = () => {
|
||||
const bpm = this.currentHeartRate;
|
||||
const msPerBeat = 60000 / bpm; // Convert BPM to ms
|
||||
|
||||
// Heart pump animation
|
||||
if (this.heartIcon) {
|
||||
this.scene.tweens.add({
|
||||
targets: [this.heartIcon],
|
||||
scale: { from: 1, to: 1.3 },
|
||||
duration: 100,
|
||||
yoyo: true,
|
||||
ease: 'Quad.Out'
|
||||
});
|
||||
|
||||
// Glow pulse
|
||||
this.scene.tweens.add({
|
||||
targets: [this.glowEffect],
|
||||
alpha: { from: 0, to: 0.6 },
|
||||
scale: { from: 1, to: 1.5 },
|
||||
duration: 150,
|
||||
yoyo: true,
|
||||
ease: 'Quad.Out'
|
||||
});
|
||||
}
|
||||
|
||||
// Schedule next beat
|
||||
this.heartbeatTimer = setTimeout(() => beatInterval(), msPerBeat);
|
||||
};
|
||||
|
||||
// Start beating
|
||||
beatInterval();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update system (called every frame)
|
||||
*/
|
||||
update(time, delta) {
|
||||
if (!this.scene.player) return;
|
||||
|
||||
// Calculate distance to nearest Ana clue
|
||||
this.calculateNearestClue();
|
||||
|
||||
// Update heart rate based on distance
|
||||
this.updateHeartRate();
|
||||
|
||||
// Update bond strength display
|
||||
this.updateBondStrengthDisplay();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate distance to nearest Ana's clue
|
||||
*/
|
||||
calculateNearestClue() {
|
||||
if (!this.scene.anaClueSystem) {
|
||||
this.nearestClueDistance = Infinity;
|
||||
return;
|
||||
}
|
||||
|
||||
const playerX = this.scene.player.sprite.x;
|
||||
const playerY = this.scene.player.sprite.y;
|
||||
|
||||
let minDistance = Infinity;
|
||||
|
||||
// Check all clues
|
||||
this.scene.anaClueSystem.clueLocations.forEach((position, clueId) => {
|
||||
// Skip already discovered clues
|
||||
if (this.scene.anaClueSystem.discovered.has(clueId)) return;
|
||||
|
||||
const dx = position.x - playerX;
|
||||
const dy = position.y - playerY;
|
||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||
|
||||
if (distance < minDistance) {
|
||||
minDistance = distance;
|
||||
}
|
||||
});
|
||||
|
||||
this.nearestClueDistance = minDistance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update heart rate based on proximity to clues
|
||||
*/
|
||||
updateHeartRate() {
|
||||
const distance = this.nearestClueDistance;
|
||||
|
||||
// Distance thresholds (in pixels)
|
||||
const veryClose = 200; // 4-5 blocks
|
||||
const close = 480; // 10 blocks
|
||||
const medium = 960; // 20 blocks
|
||||
|
||||
let targetHeartRate = this.baseHeartRate;
|
||||
|
||||
if (distance < veryClose) {
|
||||
// VERY CLOSE - Rapid heartbeat!
|
||||
targetHeartRate = 120; // 2x normal
|
||||
this.bondStrength = 100;
|
||||
} else if (distance < close) {
|
||||
// CLOSE - Fast heartbeat
|
||||
targetHeartRate = 90;
|
||||
this.bondStrength = 75;
|
||||
} else if (distance < medium) {
|
||||
// MEDIUM - Slightly elevated
|
||||
targetHeartRate = 75;
|
||||
this.bondStrength = 50;
|
||||
} else {
|
||||
// FAR - Normal heartbeat
|
||||
targetHeartRate = 60;
|
||||
this.bondStrength = Math.max(0, this.bondStrength - 1); // Slowly decrease
|
||||
}
|
||||
|
||||
// Smooth transition
|
||||
this.currentHeartRate += (targetHeartRate - this.currentHeartRate) * 0.1;
|
||||
|
||||
// Clamp
|
||||
this.currentHeartRate = Phaser.Math.Clamp(this.currentHeartRate, 30, 150);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update bond strength visual display
|
||||
*/
|
||||
updateBondStrengthDisplay() {
|
||||
if (!this.bondStrengthBar) return;
|
||||
|
||||
// Update bar width
|
||||
const maxWidth = 50;
|
||||
const targetWidth = (this.bondStrength / 100) * maxWidth;
|
||||
this.bondStrengthBar.width = targetWidth;
|
||||
|
||||
// Update text
|
||||
if (this.bondStrengthText) {
|
||||
this.bondStrengthText.setText(`${Math.floor(this.bondStrength)}%`);
|
||||
}
|
||||
|
||||
// Color gradient based on strength
|
||||
if (this.bondStrength > 75) {
|
||||
this.bondStrengthBar.setFillStyle(0xFF69B4); // Hot pink - very strong
|
||||
} else if (this.bondStrength > 50) {
|
||||
this.bondStrengthBar.setFillStyle(0x9370DB); // Medium purple
|
||||
} else if (this.bondStrength > 25) {
|
||||
this.bondStrengthBar.setFillStyle(0x6A5ACD); // Slate blue
|
||||
} else {
|
||||
this.bondStrengthBar.setFillStyle(0x483D8B); // Dark slate blue
|
||||
}
|
||||
|
||||
// Pulsing glow when strong bond
|
||||
if (this.bondStrength > 75 && this.glowEffect) {
|
||||
this.glowEffect.setAlpha(0.3 + Math.sin(Date.now() / 200) * 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger special bond moment (e.g., flashback)
|
||||
*/
|
||||
triggerBondMoment(intensity = 'medium') {
|
||||
console.log(`💜 Twin Bond Moment! Intensity: ${intensity}`);
|
||||
|
||||
// Screen flash
|
||||
this.scene.cameras.main.flash(500, 147, 112, 219, false); // Purple flash
|
||||
|
||||
// Heart explosion effect
|
||||
if (this.heartIcon) {
|
||||
this.scene.tweens.add({
|
||||
targets: [this.heartIcon],
|
||||
scale: { from: 1, to: 2 },
|
||||
alpha: { from: 1, to: 0 },
|
||||
duration: 800,
|
||||
ease: 'Quad.Out',
|
||||
onComplete: () => {
|
||||
this.heartIcon.setScale(1);
|
||||
this.heartIcon.setAlpha(1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Glow burst
|
||||
if (this.glowEffect) {
|
||||
this.scene.tweens.add({
|
||||
targets: [this.glowEffect],
|
||||
scale: { from: 1, to: 5 },
|
||||
alpha: { from: 0.8, to: 0 },
|
||||
duration: 1000,
|
||||
ease: 'Quad.Out',
|
||||
onComplete: () => {
|
||||
this.glowEffect.setScale(1);
|
||||
this.glowEffect.setAlpha(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Temporary heart rate spike
|
||||
this.currentHeartRate = 150;
|
||||
setTimeout(() => {
|
||||
this.currentHeartRate = this.baseHeartRate;
|
||||
}, 3000);
|
||||
|
||||
// Bond strength boost
|
||||
this.bondStrength = 100;
|
||||
|
||||
// Show notification
|
||||
this.scene.events.emit('show-notification', {
|
||||
title: 'Twin Bond Activated!',
|
||||
text: '💜 You feel Ana\'s presence intensify!',
|
||||
icon: '💜',
|
||||
color: '#9370DB'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current heart rate (for debugging)
|
||||
*/
|
||||
getCurrentHeartRate() {
|
||||
return Math.floor(this.currentHeartRate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get bond strength (for other systems)
|
||||
*/
|
||||
getBondStrength() {
|
||||
return this.bondStrength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup
|
||||
*/
|
||||
destroy() {
|
||||
if (this.heartbeatTimer) {
|
||||
clearTimeout(this.heartbeatTimer);
|
||||
}
|
||||
if (this.heartContainer) {
|
||||
this.heartContainer.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
353
src/systems/VoiceoverSystem.js
Normal file
353
src/systems/VoiceoverSystem.js
Normal file
@@ -0,0 +1,353 @@
|
||||
/**
|
||||
* VoiceoverSystem.js
|
||||
* ==================
|
||||
* KRVAVA ŽETEV - Ana's Voice & Flashback Audio
|
||||
*
|
||||
* Features:
|
||||
* - Ana's voice recordings for clues
|
||||
* - Flashback narration
|
||||
* - Emotional voiceovers
|
||||
* - Audio positioning (3D sound)
|
||||
* - Volume based on bond strength
|
||||
*
|
||||
* @author NovaFarma Team
|
||||
* @date 2025-12-25
|
||||
*/
|
||||
|
||||
export default class VoiceoverSystem {
|
||||
constructor(scene) {
|
||||
this.scene = scene;
|
||||
|
||||
// Audio state
|
||||
this.currentVoiceover = null;
|
||||
this.voiceoverQueue = [];
|
||||
this.isPlaying = false;
|
||||
|
||||
// Audio library (paths to audio files)
|
||||
this.anaVoiceovers = {};
|
||||
this.flashbackVoiceovers = {};
|
||||
|
||||
console.log('🎙️ VoiceoverSystem initialized');
|
||||
|
||||
this.registerVoiceovers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register all voiceover audio files
|
||||
*/
|
||||
registerVoiceovers() {
|
||||
// ANA'S CLUE VOICEOVERS (15 messages)
|
||||
this.anaVoiceovers = {
|
||||
msg_01: {
|
||||
file: 'assets/audio/voiceover/ana_msg_01.mp3',
|
||||
text: "Kai, if you find this... I'm sorry. They took me. Stay safe.",
|
||||
duration: 5000,
|
||||
emotion: 'scared'
|
||||
},
|
||||
msg_02: {
|
||||
file: 'assets/audio/voiceover/ana_msg_02.mp3',
|
||||
text: "I'm marking my trail with red flowers. Follow them west.",
|
||||
duration: 4000,
|
||||
emotion: 'determined'
|
||||
},
|
||||
msg_03: {
|
||||
file: 'assets/audio/voiceover/ana_msg_03.mp3',
|
||||
text: "These zombies... they're intelligent. I saw it in their eyes.",
|
||||
duration: 5000,
|
||||
emotion: 'curious'
|
||||
},
|
||||
msg_06: {
|
||||
file: 'assets/audio/voiceover/ana_msg_06.mp3',
|
||||
text: "Kai... I can feel you searching for me. Our bond is so strong.",
|
||||
duration: 6000,
|
||||
emotion: 'hopeful'
|
||||
},
|
||||
msg_09: {
|
||||
file: 'assets/audio/voiceover/ana_msg_09.mp3',
|
||||
text: "I found research on a cure! There's still hope for everyone!",
|
||||
duration: 5000,
|
||||
emotion: 'excited'
|
||||
},
|
||||
msg_10: {
|
||||
file: 'assets/audio/voiceover/ana_msg_10.mp3',
|
||||
text: "I dream of having a family someday. Children playing in safe fields...",
|
||||
duration: 6000,
|
||||
emotion: 'wistful'
|
||||
},
|
||||
msg_14: {
|
||||
file: 'assets/audio/voiceover/ana_msg_14.mp3',
|
||||
text: "Don't come for me, Kai. It's too dangerous. Please, save yourself!",
|
||||
duration: 5000,
|
||||
emotion: 'desperate'
|
||||
},
|
||||
msg_15: {
|
||||
file: 'assets/audio/voiceover/ana_msg_15.mp3',
|
||||
text: "I know you won't listen... you never do. I love you, brother.",
|
||||
duration: 6000,
|
||||
emotion: 'loving'
|
||||
},
|
||||
|
||||
// SPECIAL: Ana's Journal Entry
|
||||
ana_journal_01: {
|
||||
file: 'assets/audio/voiceover/ana_journal_01.mp3',
|
||||
text: "Day 147 in captivity. Dr. Krnić is forcing me to work on something terrible. A super virus using Chernobyl radiation. If it releases... everyone dies. I have to find a way to stop him.",
|
||||
duration: 15000,
|
||||
emotion: 'terrified'
|
||||
},
|
||||
|
||||
// SPECIAL: Final Video Message
|
||||
ana_final_message: {
|
||||
file: 'assets/audio/voiceover/ana_final_message.mp3',
|
||||
text: "Kai... I'm in Dr. Krnić's facility. Level 3, Vault 7. If you're watching this... don't come. It's a trap. But I know you will anyway. *laughs sadly* Be ready for the Troll King. I love you. Twin bond forever.",
|
||||
duration: 20000,
|
||||
emotion: 'resigned'
|
||||
}
|
||||
};
|
||||
|
||||
// FLASHBACK NARRATION
|
||||
this.flashbackVoiceovers = {
|
||||
twin_bond_discovery: {
|
||||
file: 'assets/audio/voiceover/flashback_twin_bond.mp3',
|
||||
text: "Dr. Chen: 'These twins have something special. A connection I've never seen before. They'll always find each other, no matter what.'",
|
||||
duration: 10000,
|
||||
emotion: 'wonder'
|
||||
},
|
||||
mother_death: {
|
||||
file: 'assets/audio/voiceover/flashback_mother.mp3',
|
||||
text: "Mama Elena: 'Kai... protect Ana. Always. Twin bond is your strength. Together... you can survive anything. I love you both...'",
|
||||
duration: 15000,
|
||||
emotion: 'heartbreaking'
|
||||
},
|
||||
kidnapping: {
|
||||
file: 'assets/audio/voiceover/flashback_kidnapping.mp3',
|
||||
text: "Ana's scream: 'KAIII! HELP! Please! KAIIIII!' *Kai's voice, desperate* 'ANA! NO! ANA!'",
|
||||
duration: 8000,
|
||||
emotion: 'traumatic'
|
||||
}
|
||||
};
|
||||
|
||||
console.log(`✅ Registered ${Object.keys(this.anaVoiceovers).length} Ana voiceovers`);
|
||||
console.log(`✅ Registered ${Object.keys(this.flashbackVoiceovers).length} flashback voiceovers`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Play Ana's voiceover for a clue
|
||||
*/
|
||||
playAnaVoiceover(clueId, onComplete = null) {
|
||||
const voiceover = this.anaVoiceovers[clueId];
|
||||
if (!voiceover) {
|
||||
console.warn(`⚠️ No voiceover for clue: ${clueId}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log(`🎙️ Playing Ana's voice: ${clueId}`);
|
||||
|
||||
// Queue if already playing
|
||||
if (this.isPlaying) {
|
||||
this.voiceoverQueue.push({ type: 'ana', id: clueId, onComplete });
|
||||
console.log(`⏳ Voiceover queued (${this.voiceoverQueue.length} in queue)`);
|
||||
return true;
|
||||
}
|
||||
|
||||
this.isPlaying = true;
|
||||
|
||||
// Show subtitle text
|
||||
this.showSubtitle(voiceover.text, voiceover.duration);
|
||||
|
||||
// Play audio (if file exists)
|
||||
if (this.scene.sound.get(voiceover.file)) {
|
||||
this.currentVoiceover = this.scene.sound.play(voiceover.file, {
|
||||
volume: this.getVolumeBasedOnBondStrength()
|
||||
});
|
||||
|
||||
// Cleanup when done
|
||||
this.currentVoiceover.once('complete', () => {
|
||||
this.onVoiceoverComplete(onComplete);
|
||||
});
|
||||
} else {
|
||||
// Fallback if audio file doesn't exist
|
||||
console.warn(`⚠️ Audio file not found: ${voiceover.file}`);
|
||||
|
||||
// Simulate duration
|
||||
setTimeout(() => {
|
||||
this.onVoiceoverComplete(onComplete);
|
||||
}, voiceover.duration);
|
||||
}
|
||||
|
||||
// Trigger Twin Bond moment
|
||||
if (this.scene.twinBondUI) {
|
||||
this.scene.twinBondUI.triggerBondMoment('medium');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Play flashback narration
|
||||
*/
|
||||
playFlashbackVoiceover(flashbackId, onComplete = null) {
|
||||
const voiceover = this.flashbackVoiceovers[flashbackId];
|
||||
if (!voiceover) {
|
||||
console.warn(`⚠️ No voiceover for flashback: ${flashbackId}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log(`🎙️ Playing flashback: ${flashbackId}`);
|
||||
|
||||
this.isPlaying = true;
|
||||
|
||||
// Show subtitle
|
||||
this.showSubtitle(voiceover.text, voiceover.duration, '#FFD700'); // Gold color for flashbacks
|
||||
|
||||
// Play audio
|
||||
if (this.scene.sound.get(voiceover.file)) {
|
||||
this.currentVoiceover = this.scene.sound.play(voiceover.file, {
|
||||
volume: 0.8
|
||||
});
|
||||
|
||||
this.currentVoiceover.once('complete', () => {
|
||||
this.onVoiceoverComplete(onComplete);
|
||||
});
|
||||
} else {
|
||||
console.warn(`⚠️ Audio file not found: ${voiceover.file}`);
|
||||
setTimeout(() => {
|
||||
this.onVoiceoverComplete(onComplete);
|
||||
}, voiceover.duration);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show subtitle text on screen
|
||||
*/
|
||||
showSubtitle(text, duration, color = '#9370DB') {
|
||||
const ui = this.scene.scene.get('UIScene') || this.scene;
|
||||
|
||||
// Create subtitle container
|
||||
const subtitleBg = ui.add.rectangle(
|
||||
ui.cameras.main.width / 2,
|
||||
ui.cameras.main.height - 100,
|
||||
ui.cameras.main.width - 200,
|
||||
80,
|
||||
0x000000,
|
||||
0.7
|
||||
);
|
||||
subtitleBg.setScrollFactor(0);
|
||||
subtitleBg.setDepth(2000);
|
||||
|
||||
const subtitleText = ui.add.text(
|
||||
ui.cameras.main.width / 2,
|
||||
ui.cameras.main.height - 100,
|
||||
text,
|
||||
{
|
||||
fontSize: '20px',
|
||||
fontFamily: 'Arial',
|
||||
color: color,
|
||||
align: 'center',
|
||||
wordWrap: { width: ui.cameras.main.width - 220 }
|
||||
}
|
||||
);
|
||||
subtitleText.setOrigin(0.5);
|
||||
subtitleText.setScrollFactor(0);
|
||||
subtitleText.setDepth(2001);
|
||||
|
||||
// Fade in
|
||||
subtitleBg.setAlpha(0);
|
||||
subtitleText.setAlpha(0);
|
||||
|
||||
ui.tweens.add({
|
||||
targets: [subtitleBg, subtitleText],
|
||||
alpha: 1,
|
||||
duration: 300
|
||||
});
|
||||
|
||||
// Fade out and destroy
|
||||
setTimeout(() => {
|
||||
ui.tweens.add({
|
||||
targets: [subtitleBg, subtitleText],
|
||||
alpha: 0,
|
||||
duration: 500,
|
||||
onComplete: () => {
|
||||
subtitleBg.destroy();
|
||||
subtitleText.destroy();
|
||||
}
|
||||
});
|
||||
}, duration - 500);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get volume based on twin bond strength
|
||||
*/
|
||||
getVolumeBasedOnBondStrength() {
|
||||
if (!this.scene.twinBondUI) {
|
||||
return 0.7; // Default volume
|
||||
}
|
||||
|
||||
const bondStrength = this.scene.twinBondUI.getBondStrength();
|
||||
|
||||
// Higher bond = louder voice
|
||||
const volume = 0.4 + (bondStrength / 100) * 0.6; // 0.4 to 1.0
|
||||
|
||||
return volume;
|
||||
}
|
||||
|
||||
/**
|
||||
* Voiceover completion handler
|
||||
*/
|
||||
onVoiceoverComplete(callback) {
|
||||
this.isPlaying = false;
|
||||
this.currentVoiceover = null;
|
||||
|
||||
// Call completion callback
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
|
||||
// Play next in queue
|
||||
if (this.voiceoverQueue.length > 0) {
|
||||
const next = this.voiceoverQueue.shift();
|
||||
|
||||
setTimeout(() => {
|
||||
if (next.type === 'ana') {
|
||||
this.playAnaVoiceover(next.id, next.onComplete);
|
||||
} else if (next.type === 'flashback') {
|
||||
this.playFlashbackVoiceover(next.id, next.onComplete);
|
||||
}
|
||||
}, 500); // Small delay between voiceovers
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop current voiceover
|
||||
*/
|
||||
stopVoiceover() {
|
||||
if (this.currentVoiceover) {
|
||||
this.currentVoiceover.stop();
|
||||
this.currentVoiceover = null;
|
||||
}
|
||||
this.isPlaying = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear queue
|
||||
*/
|
||||
clearQueue() {
|
||||
this.voiceoverQueue = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if voiceover is playing
|
||||
*/
|
||||
isVoiceoverPlaying() {
|
||||
return this.isPlaying;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup
|
||||
*/
|
||||
destroy() {
|
||||
this.stopVoiceover();
|
||||
this.clearQueue();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user