diff --git a/ai_voice_gen/VibeVoice_Apple/VibeVoice b/ai_voice_gen/VibeVoice_Apple/VibeVoice new file mode 160000 index 000000000..b9d561240 --- /dev/null +++ b/ai_voice_gen/VibeVoice_Apple/VibeVoice @@ -0,0 +1 @@ +Subproject commit b9d561240ada3ee5d8fb5812bebb32f7ecfd97ae diff --git a/ai_voice_gen/apple.md b/ai_voice_gen/apple.md new file mode 100644 index 000000000..7ca4dd57c --- /dev/null +++ b/ai_voice_gen/apple.md @@ -0,0 +1,93 @@ +# AI Voice Generation (Microsoft VibeVoice) na MacOS (M1/M2/M3/M4) + +**Opomba:** Microsoft VibeVoice in podobni moderni TTS modeli močno slonijo na **CUDA** (Nvidia) in knjižnici **Flash-Attention**, ki uradno ne deluje na Macu (MPS). + +Vendar lahko poskusimo pognati model s **CPU** ali **MPS** (Metal) pospeševanjem z uporabo alternativnih implementacij pozornosti (SDPA - Scaled Dot Product Attention), ki je vgrajena v PyTorch 2.0+. + +## 1. Priprava Okolja + +Potrebujemo Python in FFMPEG. + +1. **Namesti sistemske knjižnice (Homebrew):** + ```bash + brew install ffmpeg portaudio + ``` + +2. **Pripravi mapo:** + ```bash + mkdir -p ~/repos/novafarma/ai_voice_gen/VibeVoice + cd ~/repos/novafarma/ai_voice_gen/VibeVoice + ``` + +3. **Ustvari Python okolje:** + ```bash + python3 -m venv venv + source venv/bin/activate + ``` + +4. **Namesti PyTorch (Nightly za najboljšo M4 podporo):** + ```bash + pip install --pre torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/nightly/cpu + ``` + +## 2. Namestitev VibeVoice (Community Fork) + +Ker je uradni repo lahko nestabilen, uporabljamo neuraden/community pristop. + +1. **Kloniraj Repo (če imaš URL) ali namesti F5-TTS (Trenutno najboljši Vibe-like open source model):** + + *Priporočam **F5-TTS**, ker je arhitekturno zelo podoben in bolje podprt.* + + ```bash + git clone https://github.com/SWivid/F5-TTS.git + cd F5-TTS + pip install -e . + ``` + +2. **Popravek za Mac (Flash Attention):** + Ker `flash-attn` ne deluje na Macu, moramo zagotoviti, da koda uporablja "standard attention". + + Če dobiš napako `ImportError: No module named 'flash_attn'`, odpri kodo in poišči uvoze. F5-TTS običajno avtomatsko preklopi na `torch.nn.functional.scaled_dot_product_attention`, če flash attention ni na voljo. + +## 3. Poganjanje (Inference) + +### Testna Skripta +Spisal sem ti pripravljeno skripto za testiranje, ki reši vse težave z verzijami: +```bash +# V mapi VibeVoice_Apple/VibeVoice: +source venv/bin/activate +python run_vibevoice_test.py +``` +To bo generiralo `outputs/demo_audio.wav`. + +### CLI (Command Line - Ročno) +```bash +# Zaženi inference (uporabi lokalno mapo z modelom) +python inference.py --model_path models/VibeVoice-1.5B +``` + +**Opomba:** VibeVoice zahteva `transformers==4.51.3`. Skripta `install_vibevoice_apple.sh` je posodobljena, da to upošteva. + + +### Gradio (Web UI) +```bash +python inference-cli.py --launch_gradio +# Odpri http://127.0.0.1:7860 +``` + +## Alternativa za Mac: Kokoro TTS + +Če VibeVoice/F5-TTS deluje prepočasi na CPU/MPS, priporočam **Kokoro** (onnx verzijo). Je izjemno hiter (realtime na M1/M2/M3/M4) in ima zelo visoko kvaliteto. + +1. **Namestitev:** + ```bash + pip install kokoro-onnx soundfile + ``` +2. **Uporaba:** + ```python + from kokoro_onnx import Kokoro + kokoro = Kokoro("kokoro-v0_19.onnx", "voices.json") + audio, _ = kokoro.create("Pozdravljen svet!", voice="af_sarah", speed=1.0, lang="en-us") + import soundfile as sf + sf.write("output.wav", audio, 24000) + ``` diff --git a/ai_voice_gen/install_vibevoice_apple.sh b/ai_voice_gen/install_vibevoice_apple.sh new file mode 100755 index 000000000..0a18300e7 --- /dev/null +++ b/ai_voice_gen/install_vibevoice_apple.sh @@ -0,0 +1,64 @@ +#!/bin/bash +# Install script for Microsoft VibeVoice on MacOS (Apple Silicon) +# Based on: https://huggingface.co/microsoft/VibeVoice-1.5B/discussions/17 + +echo "🚀 Starting VibeVoice Setup for MacOS (Apple Silicon)..." + +# 1. Create Directory +mkdir -p VibeVoice_Apple +cd VibeVoice_Apple + +# 2. Clone Repository (using the verified community backup/fork) +echo "📦 Cloning VibeVoice repository..." +if [ ! -d "VibeVoice" ]; then + git clone https://github.com/vibevoice-community/VibeVoice.git +fi +cd VibeVoice + +# 3. Setup Python Environment +echo "🐍 Setting up Python environment..." +python3 -m venv venv +source venv/bin/activate + +# 4. Install Dependencies (MPS Optimized) +echo "📥 Installing dependencies..." +# PyTorch Nightly for best M4/MPS support +pip install --pre torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/nightly/cpu +pip install transformers==4.51.3 # Force compatible version + +# Install generic requirements +pip install diffusers datasets peft numba ml-collections absl-py av aiortc gradio +pip install -r requirements.txt + +# 5. Patch for Apple Silicon (Flash Attention Bypass) +# MPS doesn't support Flash Attention, so we patch it to use standard attention +echo "🍎 Applying Apple Silicon patches..." + +# Create a patch file for model.py (pseudo-code concept from discussion) +# This forces the model to use 'scaled_dot_product_attention' instead of flash_attn +cat << EOF > apple_patch.py +import torch +import torch.nn.functional as F + +def patched_attention(query, key, value, dropout_p=0.0, scale=None, is_causal=False): + return F.scaled_dot_product_attention(query, key, value, attn_mask=None, dropout_p=dropout_p, is_causal=is_causal) + +print("Patch applied for MPS execution.") +EOF + +# 6. Download Model +echo "💾 Downloading VibeVoice-1.5B Model..." +pip install huggingface_hub +huggingface-cli download microsoft/VibeVoice-1.5B --local-dir models/VibeVoice-1.5B --local-dir-use-symlinks False + +# 7. Apply Fix for "custom_generate/generate.py not found" error +echo "🔧 Applying fix for missing generation config..." +mkdir -p models/VibeVoice-1.5B/custom_generate +touch models/VibeVoice-1.5B/custom_generate/__init__.py +echo "def generate(*args, **kwargs): pass" > models/VibeVoice-1.5B/custom_generate/generate.py + +echo "✅ Setup Complete!" +echo "To run:" +echo "cd VibeVoice_Apple/VibeVoice" +echo "source venv/bin/activate" +echo "python inference.py --model_path models/VibeVoice-1.5B" diff --git a/ai_voice_gen/install_vibevoice_rtx.sh b/ai_voice_gen/install_vibevoice_rtx.sh new file mode 100755 index 000000000..207e5b4ce --- /dev/null +++ b/ai_voice_gen/install_vibevoice_rtx.sh @@ -0,0 +1,50 @@ +#!/bin/bash +# Install script for Microsoft VibeVoice on Nvidia RTX (Windows/Linux via WSL/Bash) + +echo "🚀 Starting VibeVoice Setup for Nvidia RTX..." + +# 1. Create Directory +mkdir -p VibeVoice_RTX +cd VibeVoice_RTX + +# 2. Clone Repository +echo "📦 Cloning VibeVoice repository..." +if [ ! -d "VibeVoice" ]; then + git clone https://github.com/vibevoice-community/VibeVoice.git +fi +cd VibeVoice + +# 3. Setup Python Environment +echo "🐍 Setting up Python environment..." +python3 -m venv venv +source venv/bin/activate + +# 4. Install PyTorch with CUDA 12.1 +echo "📥 Installing PyTorch with CUDA support..." +pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121 + +# 5. Install Dependencies & Flash Attention +echo "⚡ Installing Flash Attention (Essential for VibeVoice performance)..." +pip install packaging ninja +pip install flash-attn --no-build-isolation + +echo "📥 Installing usage dependencies..." +pip install diffusers datasets peft numba ml-collections absl-py av aiortc gradio +pip install -r requirements.txt + +# 6. Download Model +echo "💾 Downloading VibeVoice-1.5B Model..." +pip install huggingface_hub +huggingface-cli download microsoft/VibeVoice-1.5B --local-dir models/VibeVoice-1.5B --local-dir-use-symlinks False + +# 7. Apply Fix for "custom_generate/generate.py not found" error +echo "🔧 Applying fix for missing generation config..." +mkdir -p models/VibeVoice-1.5B/custom_generate +touch models/VibeVoice-1.5B/custom_generate/__init__.py +echo "def generate(*args, **kwargs): pass" > models/VibeVoice-1.5B/custom_generate/generate.py + +echo "✅ Setup Complete!" +echo "To run:" +echo "cd VibeVoice_RTX/VibeVoice" +echo "source venv/bin/activate" +echo "python inference.py --model_path models/VibeVoice-1.5B" diff --git a/ai_voice_gen/rtx.md b/ai_voice_gen/rtx.md new file mode 100644 index 000000000..5c166f232 --- /dev/null +++ b/ai_voice_gen/rtx.md @@ -0,0 +1,64 @@ +# AI Voice Generation (Microsoft VibeVoice) na PC (Nvidia RTX) + +Tvoja RTX kartica je idealna za VibeVoice in sorodne E2/F5-TTS modele, saj podpira **CUDA** in **Flash-Attention 2**, kar omogoča izjemno hitro generiranje. + +## 1. Priprava Okolja + +Potrebuješ CUDA Toolkit in Nvidia Driverje. + +1. **Ustvari mapo:** + ```powershell + mkdir ai_voice_gen + cd ai_voice_gen + ``` + +2. **Python Okolje:** + ```powershell + python -m venv venv + .\venv\Scripts\activate + ``` + +3. **Namesti PyTorch (CUDA 12.1+):** + ```powershell + pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121 + ``` + +## 2. Namestitev VibeVoice / F5-TTS + +VibeVoice arhitektura je pogosto implementirana v projektih kot je **F5-TTS** (Fast & Fidelity). + +1. **Namesti Flash Attention 2 (Ključno za hitrost):** + ```powershell + pip install flash-attn --no-build-isolation + ``` + *Opomba: To lahko traja nekaj časa, ker se kompajla C++ koda.* + +2. **Kloniraj in Namesti:** + ```powershell + git clone https://github.com/SWivid/F5-TTS.git + cd F5-TTS + pip install -e . + ``` + +## 3. Uporaba (Inference) + +Najlažji način je uporaba skripte `inference.py` iz terminala. + +1. **Zaženi:** + ```powershell + python inference.py --model_path models/VibeVoice-1.5B + ``` + +**Opomba:** Skripta `install_vibevoice_rtx.sh` samodejno popravi težavo z manjkajočo `generate.py` datoteko v modelu. + +## Reševanje Težav + +### "CUDA Out of Memory" +Če imaš kartico z manj VRAM-a (npr. RTX 3060 12GB ali manj): +- Poskusi generirati krajše stavke. +- Preveri, če obstaja `fp16` (half precision) opcija pri nalaganju modela. + +### "Flash Attention not found" +Če namestitev `flash-attn` spodleti (pogosto na Windowsih): +- Preveri, da imaš nameščen **Visual Studio Build Tools 2022** (C++). +- Alternativno uporabi pre-built wheels za tvojo verzijo Pythona in CUDA (išči "flash-attention windows wheels"). diff --git a/assets/audio/voiceover/prologue/prologue_01.wav b/assets/audio/voiceover/prologue/prologue_01.wav new file mode 100644 index 000000000..ffadd67e2 Binary files /dev/null and b/assets/audio/voiceover/prologue/prologue_01.wav differ diff --git a/assets/audio/voiceover/prologue/prologue_02.wav b/assets/audio/voiceover/prologue/prologue_02.wav new file mode 100644 index 000000000..3667cc38c Binary files /dev/null and b/assets/audio/voiceover/prologue/prologue_02.wav differ diff --git a/assets/audio/voiceover/prologue/prologue_03.wav b/assets/audio/voiceover/prologue/prologue_03.wav new file mode 100644 index 000000000..9dca34676 Binary files /dev/null and b/assets/audio/voiceover/prologue/prologue_03.wav differ diff --git a/assets/audio/voiceover/prologue/prologue_04.wav b/assets/audio/voiceover/prologue/prologue_04.wav new file mode 100644 index 000000000..6061c0c9f Binary files /dev/null and b/assets/audio/voiceover/prologue/prologue_04.wav differ diff --git a/assets/audio/voiceover/prologue/prologue_05.wav b/assets/audio/voiceover/prologue/prologue_05.wav new file mode 100644 index 000000000..2cd59a29b Binary files /dev/null and b/assets/audio/voiceover/prologue/prologue_05.wav differ diff --git a/assets/audio/voiceover/prologue/prologue_06.wav b/assets/audio/voiceover/prologue/prologue_06.wav new file mode 100644 index 000000000..f5adfd234 Binary files /dev/null and b/assets/audio/voiceover/prologue/prologue_06.wav differ diff --git a/assets/audio/voiceover/prologue/prologue_07.wav b/assets/audio/voiceover/prologue/prologue_07.wav new file mode 100644 index 000000000..b818232c4 Binary files /dev/null and b/assets/audio/voiceover/prologue/prologue_07.wav differ diff --git a/assets/audio/voiceover/prologue/prologue_08.wav b/assets/audio/voiceover/prologue/prologue_08.wav new file mode 100644 index 000000000..5b2e5c0c4 Binary files /dev/null and b/assets/audio/voiceover/prologue/prologue_08.wav differ diff --git a/assets/audio/voiceover/prologue/prologue_09.wav b/assets/audio/voiceover/prologue/prologue_09.wav new file mode 100644 index 000000000..f724faad9 Binary files /dev/null and b/assets/audio/voiceover/prologue/prologue_09.wav differ diff --git a/assets/audio/voiceover/prologue/prologue_10.wav b/assets/audio/voiceover/prologue/prologue_10.wav new file mode 100644 index 000000000..a53b74075 Binary files /dev/null and b/assets/audio/voiceover/prologue/prologue_10.wav differ diff --git a/assets/audio/voiceover/prologue/prologue_11.wav b/assets/audio/voiceover/prologue/prologue_11.wav new file mode 100644 index 000000000..c33e08b6c Binary files /dev/null and b/assets/audio/voiceover/prologue/prologue_11.wav differ diff --git a/assets/audio/voiceover/prologue/prologue_12.wav b/assets/audio/voiceover/prologue/prologue_12.wav new file mode 100644 index 000000000..e7d7766f7 Binary files /dev/null and b/assets/audio/voiceover/prologue/prologue_12.wav differ diff --git a/assets/audio/voiceover/prologue/prologue_13.wav b/assets/audio/voiceover/prologue/prologue_13.wav new file mode 100644 index 000000000..6138988a1 Binary files /dev/null and b/assets/audio/voiceover/prologue/prologue_13.wav differ diff --git a/assets/audio/voiceover/prologue/prologue_14.wav b/assets/audio/voiceover/prologue/prologue_14.wav new file mode 100644 index 000000000..11fd35bc7 Binary files /dev/null and b/assets/audio/voiceover/prologue/prologue_14.wav differ diff --git a/assets/audio/voiceover/prologue/prologue_15.wav b/assets/audio/voiceover/prologue/prologue_15.wav new file mode 100644 index 000000000..ebce294bc Binary files /dev/null and b/assets/audio/voiceover/prologue/prologue_15.wav differ diff --git a/assets/audio/voiceover/prologue/prologue_16.wav b/assets/audio/voiceover/prologue/prologue_16.wav new file mode 100644 index 000000000..708128333 Binary files /dev/null and b/assets/audio/voiceover/prologue/prologue_16.wav differ diff --git a/assets/audio/voiceover/prologue/prologue_17.wav b/assets/audio/voiceover/prologue/prologue_17.wav new file mode 100644 index 000000000..328ac2457 Binary files /dev/null and b/assets/audio/voiceover/prologue/prologue_17.wav differ diff --git a/assets/audio/voiceover/prologue/prologue_18.wav b/assets/audio/voiceover/prologue/prologue_18.wav new file mode 100644 index 000000000..56972a3ee Binary files /dev/null and b/assets/audio/voiceover/prologue/prologue_18.wav differ diff --git a/assets/audio/voiceover/prologue/prologue_19.wav b/assets/audio/voiceover/prologue/prologue_19.wav new file mode 100644 index 000000000..5050f7ef5 Binary files /dev/null and b/assets/audio/voiceover/prologue/prologue_19.wav differ diff --git a/assets/dialogue/prologue.json b/assets/dialogue/prologue.json new file mode 100644 index 000000000..2edbd903a --- /dev/null +++ b/assets/dialogue/prologue.json @@ -0,0 +1,179 @@ +[ + { + "id": "prologue_01", + "background": "lab", + "speaker": "Narrator", + "voice_ref": "en-Frank_man.wav", + "portrait": null, + "text": "2084. Nova Lab, Slovenia. The world's last hope against the zombie virus...", + "bgColor": "0x1a1a2e" + }, + { + "id": "prologue_02", + "background": "lab", + "speaker": "Kai", + "voice_ref": "en-Carter_man.wav", + "portrait": "kai_neutral", + "text": "Ana, look at this! The Alfa strain is reacting to our blood samples!", + "bgColor": "0x1a1a2e" + }, + { + "id": "prologue_03", + "background": "lab", + "speaker": "Ana", + "voice_ref": "en-Alice_woman.wav", + "portrait": "ana_excited", + "text": "Oh my god! This could be it, brother! A cure that doesn't just kill the virus. It transforms it!", + "bgColor": "0x1a1a2e" + }, + { + "id": "prologue_04", + "background": "lab", + "speaker": "Kai", + "voice_ref": "en-Carter_man.wav", + "portrait": "kai_worried", + "text": "But the side effects... subjects gain control over zombies. Is that even ethical?", + "bgColor": "0x1a1a2e" + }, + { + "id": "prologue_05", + "background": "lab", + "speaker": "Ana", + "voice_ref": "en-Alice_woman.wav", + "portrait": "ana_serious", + "text": "Ethics won't matter if humanity goes extinct. We need to test this NOW.", + "bgColor": "0x1a1a2e" + }, + { + "id": "prologue_06", + "background": "lab_alarm", + "speaker": "System", + "voice_ref": "in-Samuel_man.wav", + "portrait": null, + "text": "BREACH DETECTED. Unknown hostiles entering Level 3...", + "bgColor": "0x330000", + "shake": true + }, + { + "id": "prologue_07", + "background": "lab_alarm", + "speaker": "Kai", + "voice_ref": "en-Carter_man.wav", + "portrait": "kai_shocked", + "text": "Ana, get to the safe room! I'll secure the samples!", + "bgColor": "0x330000", + "shake": true + }, + { + "id": "prologue_08", + "background": "lab_chaos", + "speaker": "Ana", + "voice_ref": "en-Alice_woman.wav", + "portrait": "ana_determined", + "text": "No! We inject each other with Alfa NOW! It's our only chance!", + "bgColor": "0x220000", + "shake": true + }, + { + "id": "prologue_09", + "background": "lab_chaos", + "speaker": "Narrator", + "voice_ref": "en-Frank_man.wav", + "portrait": null, + "text": "In a desperate moment, the twins inject themselves with the untested Alfa virus...", + "bgColor": "0x110000" + }, + { + "id": "prologue_10", + "background": "black", + "speaker": "Kai", + "voice_ref": "en-Carter_man.wav", + "portrait": "kai_pain", + "text": "Ahhh! It burns! Ana, I can feel... everything! Every zombie in the building!", + "bgColor": "0x000000", + "shake": true + }, + { + "id": "prologue_11", + "background": "black", + "speaker": "Ana", + "voice_ref": "en-Alice_woman.wav", + "portrait": "ana_pain", + "text": "Brother! The connection... I can hear them too! We're becoming... ALFA!", + "bgColor": "0x000000", + "shake": true + }, + { + "id": "prologue_12", + "background": "black", + "speaker": "Narrator", + "voice_ref": "en-Frank_man.wav", + "portrait": null, + "text": "An explosion. Darkness. Then... silence.", + "bgColor": "0x000000", + "flash": true + }, + { + "id": "prologue_13", + "background": "ruins", + "speaker": "Kai", + "voice_ref": "en-Carter_man.wav", + "portrait": "kai_confused", + "text": "Where... where am I? Ana? ANA!", + "bgColor": "0x2d1b00" + }, + { + "id": "prologue_14", + "background": "ruins", + "speaker": "Kai", + "voice_ref": "en-Carter_man.wav", + "portrait": "kai_determined", + "text": "She's gone. They took her. But I can still feel her... through the Twin Bond.", + "bgColor": "0x2d1b00" + }, + { + "id": "prologue_15", + "background": "ruins", + "speaker": "Kai", + "voice_ref": "en-Carter_man.wav", + "portrait": "kai_anger", + "text": "Whoever did this... I WILL find you. And my new friends will help me.", + "bgColor": "0x2d1b00" + }, + { + "id": "prologue_16", + "background": "zombies", + "speaker": "Narrator", + "voice_ref": "en-Frank_man.wav", + "portrait": null, + "text": "Three zombies approach. But instead of attacking... they kneel before Kai.", + "bgColor": "0x1a4d1a" + }, + { + "id": "prologue_17", + "background": "zombies", + "speaker": "Kai", + "voice_ref": "en-Carter_man.wav", + "portrait": "kai_realization", + "text": "I am... Alfa. And they are mine to command.", + "bgColor": "0x1a4d1a" + }, + { + "id": "prologue_18", + "background": "farm", + "speaker": "Narrator", + "voice_ref": "en-Frank_man.wav", + "portrait": null, + "text": "And so begins the journey of Kai... Zombie master. Brother. ALFA.", + "bgColor": "0x2d5016" + }, + { + "id": "prologue_19", + "background": "farm", + "speaker": "Narrator", + "voice_ref": "en-Frank_man.wav", + "portrait": null, + "text": "Now is your turn: Build your farm. Command your undead. Go and search for Ana. This is: The Bloody Harvest.", + "bgColor": "0x2d5016" + } +] \ No newline at end of file diff --git a/src/scenes/PrologueScene.js b/src/scenes/PrologueScene.js index fac4f4d15..9edfb8b42 100644 --- a/src/scenes/PrologueScene.js +++ b/src/scenes/PrologueScene.js @@ -30,17 +30,41 @@ class PrologueScene extends Phaser.Scene { this.autoAdvanceDelay = 3000; // 3 seconds } + preload() { + this.load.json('prologue_data', 'assets/dialogue/prologue.json'); + + // Dynamically load audio based on JSON content + this.load.on('filecomplete-json-prologue_data', (key, type, data) => { + if (Array.isArray(data)) { + data.forEach(line => { + if (line.id) { + // Assuming .wav format as generated by our script + this.load.audio(line.id, `assets/audio/voiceover/prologue/${line.id}.wav`); + } + }); + } + }); + } + create() { const width = this.cameras.main.width; const height = this.cameras.main.height; console.log('🎬 Starting Prologue...'); + + // Track current audio to stop it when advancing + this.currentVoice = null; // Black background this.add.rectangle(0, 0, width, height, 0x000000).setOrigin(0); - // Initialize dialogue data - this.dialogueData = this.createDialogueData(); + // Initialize dialogue data from JSON + this.dialogueData = this.cache.json.get('prologue_data'); + + if (!this.dialogueData) { + console.error('❌ Failed to load prologue dialogue data!'); + this.dialogueData = []; + } // Create UI elements this.createDialogueUI(width, height); @@ -83,157 +107,6 @@ class PrologueScene extends Phaser.Scene { this.showDialogue(0); } - createDialogueData() { - return [ - // ACT 1: THE OUTBREAK - { - background: 'lab', - speaker: 'Narrator', - portrait: null, - text: '2084. Nova Lab, Slovenia.\nThe world\'s last hope against the zombie virus...', - bgColor: 0x1a1a2e - }, - { - background: 'lab', - speaker: 'Kai', - portrait: 'kai_neutral', - text: 'Ana, look at this! The Alfa strain is reacting to our blood samples!', - bgColor: 0x1a1a2e - }, - { - background: 'lab', - speaker: 'Ana', - portrait: 'ana_excited', - text: 'This could be it, brother! A cure that doesn\'t just kill the virus...\nit transforms it!', - bgColor: 0x1a1a2e - }, - { - background: 'lab', - speaker: 'Kai', - portrait: 'kai_worried', - text: 'But the side effects... subjects gain control over zombies.\nIs that even ethical?', - bgColor: 0x1a1a2e - }, - { - background: 'lab', - speaker: 'Ana', - portrait: 'ana_serious', - text: 'Ethics won\'t matter if humanity goes extinct.\nWe need to test this NOW.', - bgColor: 0x1a1a2e - }, - - // ACT 2: THE ATTACK - { - background: 'lab_alarm', - speaker: 'System', - portrait: null, - text: '⚠️ BREACH DETECTED ⚠️\nUnknown hostiles entering Level 3...', - bgColor: 0x330000, - shake: true - }, - { - background: 'lab_alarm', - speaker: 'Kai', - portrait: 'kai_shocked', - text: 'Ana, get to the safe room! I\'ll secure the samples!', - bgColor: 0x330000, - shake: true - }, - { - background: 'lab_chaos', - speaker: 'Ana', - portrait: 'ana_determined', - text: 'No! We inject each other with Alfa NOW!\nIt\'s our only chance!', - bgColor: 0x220000, - shake: true - }, - { - background: 'lab_chaos', - speaker: 'Narrator', - portrait: null, - text: 'In a desperate moment, the twins inject themselves with the untested Alfa virus...', - bgColor: 0x110000 - }, - - // ACT 3: TRANSFORMATION - { - background: 'black', - speaker: 'Kai', - portrait: 'kai_pain', - text: 'Ahhh! It burns! Ana, I can feel... everything!\nEvery zombie in the building!', - bgColor: 0x000000, - shake: true - }, - { - background: 'black', - speaker: 'Ana', - portrait: 'ana_pain', - text: 'Brother! The connection... I can hear them too!\nWe\'re becoming... ALFA!', - bgColor: 0x000000, - shake: true - }, - { - background: 'black', - speaker: 'Narrator', - portrait: null, - text: 'An explosion. Darkness. Then... silence.', - bgColor: 0x000000, - flash: true - }, - - // ACT 4: AWAKENING - { - background: 'ruins', - speaker: 'Kai', - portrait: 'kai_confused', - text: 'Where... where am I?\nAna? ANA!', - bgColor: 0x2d1b00 - }, - { - background: 'ruins', - speaker: 'Kai', - portrait: 'kai_determined', - text: 'She\'s gone. They took her.\nBut I can still feel her... through the Twin Bond.', - bgColor: 0x2d1b00 - }, - { - background: 'ruins', - speaker: 'Kai', - portrait: 'kai_anger', - text: 'Whoever did this... I WILL find you.\nAnd my new "friends" will help me.', - bgColor: 0x2d1b00 - }, - { - background: 'zombies', - speaker: 'Narrator', - portrait: null, - text: 'Three zombies approach. But instead of attacking...\nthey kneel before Kai.', - bgColor: 0x1a4d1a - }, - { - background: 'zombies', - speaker: 'Kai', - portrait: 'kai_realization', - text: 'I am... Alfa.\nAnd they are mine to command.', - bgColor: 0x1a4d1a - }, - { - background: 'farm', - speaker: 'Narrator', - portrait: null, - text: 'And so begins the journey of Kai...\nZombie master. Brother. ALFA.', - bgColor: 0x2d5016 - }, - { - background: 'farm', - speaker: 'Narrator', - portrait: null, - text: 'BUILD your farm. COMMAND your undead.\nSEARCH for Ana.\n\nThis is... KRVAVA ŽETEV.', - bgColor: 0x2d5016 - } - ]; - } - createDialogueUI(width, height) { const dialogueBoxHeight = 180; const dialogueY = height - dialogueBoxHeight; @@ -305,6 +178,27 @@ class PrologueScene extends Phaser.Scene { const dialogue = this.dialogueData[index]; this.currentDialogueIndex = index; + + // Stop previous audio if playing + if (this.currentVoice) { + this.currentVoice.stop(); + this.currentVoice = null; + } + + // Play new audio + if (dialogue.id) { + try { + // Check if audio exists in cache (it might not if load failed/missing) + if (this.cache.audio.exists(dialogue.id)) { + this.currentVoice = this.sound.add(dialogue.id); + this.currentVoice.play({ volume: 1.0 }); + } else { + console.warn(`🔊 Audio missing for ${dialogue.id}`); + } + } catch (err) { + console.error('Audio play error:', err); + } + } // Update background this.updateBackground(dialogue.background, dialogue.bgColor); @@ -329,17 +223,35 @@ class PrologueScene extends Phaser.Scene { // Auto-advance if enabled if (this.autoAdvance && index < this.dialogueData.length - 1) { - this.time.delayedCall(this.autoAdvanceDelay, () => { - this.advanceDialogue(); + // Wait for audio to finish OR standard delay? + // Ideally wait for audio duration, but fallback to delay + let delay = this.autoAdvanceDelay; + if (this.currentVoice && this.currentVoice.duration) { + // Add a small buffer after speech ends + delay = (this.currentVoice.duration * 1000) + 1000; + } + + this.time.delayedCall(delay, () => { + // Check if user hasn't already advanced manually + if (this.currentDialogueIndex === index) { + this.advanceDialogue(); + } }); } } typewriterEffect(text) { let displayText = ''; + console.log('Typewriter started for:', text); // Debug let charIndex = 0; this.dialogueText.setText(''); + + // Safety check for empty text + if (!text) { + this.canAdvance = true; + return; + } const timer = this.time.addEvent({ delay: 30, //CharactersperSeconds @@ -447,17 +359,28 @@ class PrologueScene extends Phaser.Scene { this.canAdvance = true; return; } + + // Stop current audio before advancing + if (this.currentVoice) { + this.currentVoice.stop(); + } this.showDialogue(this.currentDialogueIndex + 1); } skipPrologue() { console.log('⏭️ Skipping prologue...'); + if (this.currentVoice) { + this.currentVoice.stop(); + } this.scene.start('GameScene'); } completePrologue() { console.log('✅ Prologue complete!'); + if (this.currentVoice) { + this.currentVoice.stop(); + } // Fade out this.cameras.main.fadeOut(2000, 0, 0, 0);