📊 Jan 8 Audio System Complete Organization + Generation Manifest
✅ AUDIO REORGANIZATION COMPLETE: **Files Moved:** - Moved 2 SFX WAV: footstep_grass.wav, wood_chop.wav → /sfx/ - Moved 1 Music MP3: forest_ambient.mp3 → /music/ - Moved 43 Voiceover WAV: prologue_sl files → /voiceover/ - Existing 20 Voice MP3: Ana, Kai, Mayor, Narrator, Teacher → /voices/ **Folder Structure Created:** /assets/audio/ ├── sfx/ │ ├── farming/ (8 placeholder .txt) │ ├── combat/ (8 placeholder .txt) │ ├── building/ (5 placeholder .txt) │ └── misc/ (4 placeholder .txt) ├── music/ (8 placeholder .txt + 1 MP3 ✅) ├── voices/ (20 MP3 ✅) └── voiceover/ (43 WAV ✅) 📋 CREATED DOCUMENTATION: 1. **AUDIO_GENERATION_MANIFEST.md** - Complete list of 33 missing audio files - Detailed specifications (duration, format, mood) - SFX: 25 files (farming, combat, building, misc) - Music: 8 files (themes, ambients, victory) - Generation instructions (AI tools, free libraries) 2. **scripts/convert_audio_to_ogg.py** - Auto-remove .txt placeholders - Convert MP3/WAV → OGG (ffmpeg) - Verify file integrity - Generate audioManifest.json for Phaser ❌ STILL MISSING: - 25 SFX .ogg files (placeholders only) - 7 Music .ogg files (placeholders only) 🎯 NEXT STEPS: 1. Generate audio using AI tools (ElevenLabs, Suno, etc.) 2. Run: python3 scripts/convert_audio_to_ogg.py 3. Verify all 33 files present **Current Audio Status:** 66/99 files (67% complete)
This commit is contained in:
221
scripts/complete_asset_audit.py
Executable file
221
scripts/complete_asset_audit.py
Executable file
@@ -0,0 +1,221 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Complete Asset Audit Script
|
||||
Systematically checks ALL assets vs documentation
|
||||
"""
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
from collections import defaultdict
|
||||
|
||||
# Base paths
|
||||
REPO_ROOT = Path("/Users/davidkotnik/repos/novafarma")
|
||||
ASSETS_REF = REPO_ROOT / "assets" / "references"
|
||||
|
||||
# Expected counts from DEMO_FAZA1_FAZA2_OVERVIEW.md
|
||||
EXPECTED = {
|
||||
"characters": {
|
||||
"kai": 21, # idle(5) + walk(6) + dig(5) + swing(5)
|
||||
"ana": 10, # idle(4) + walk(6)
|
||||
"gronk": 10, # idle(4) + walk(6)
|
||||
},
|
||||
"companions": {
|
||||
"susi": 12, # idle(4) + run(6) + bark(2)
|
||||
},
|
||||
"zombies": 45, # 3 types × 15 frames each
|
||||
"crops": {
|
||||
"wheat": 5,
|
||||
"carrot": 5,
|
||||
"tomato": 5,
|
||||
"potato": 5,
|
||||
"corn": 5,
|
||||
},
|
||||
"tools": 8,
|
||||
"ui": 28,
|
||||
"grassland": 27,
|
||||
}
|
||||
|
||||
def count_pngs(directory):
|
||||
"""Count PNG files in directory recursively"""
|
||||
if not directory.exists():
|
||||
return 0
|
||||
return len(list(directory.rglob("*.png")))
|
||||
|
||||
def audit_characters():
|
||||
"""Audit main characters"""
|
||||
print("\n## 1. MAIN CHARACTERS")
|
||||
print("=" * 60)
|
||||
|
||||
char_path = ASSETS_REF / "main_characters"
|
||||
results = {}
|
||||
|
||||
for char in ["kai", "ana", "gronk"]:
|
||||
char_dir = char_path / char
|
||||
actual = count_pngs(char_dir)
|
||||
expected = EXPECTED["characters"][char]
|
||||
status = "✅" if actual >= expected else "❌"
|
||||
gap = actual - expected
|
||||
|
||||
results[char] = {
|
||||
"expected": expected,
|
||||
"actual": actual,
|
||||
"status": status,
|
||||
"gap": gap
|
||||
}
|
||||
|
||||
print(f"\n{char.upper()}:")
|
||||
print(f" Expected: {expected}")
|
||||
print(f" Actual: {actual}")
|
||||
print(f" Status: {status} ({'+' if gap >= 0 else ''}{gap})")
|
||||
|
||||
return results
|
||||
|
||||
def audit_companions():
|
||||
"""Audit companion animals"""
|
||||
print("\n## 2. COMPANIONS")
|
||||
print("=" * 60)
|
||||
|
||||
comp_path = ASSETS_REF / "companions"
|
||||
results = {}
|
||||
|
||||
for comp in ["susi"]:
|
||||
comp_dir = comp_path / comp
|
||||
actual = count_pngs(comp_dir)
|
||||
expected = EXPECTED["companions"][comp]
|
||||
status = "✅" if actual >= expected else "❌"
|
||||
gap = actual - expected
|
||||
|
||||
results[comp] = {
|
||||
"expected": expected,
|
||||
"actual": actual,
|
||||
"status": status,
|
||||
"gap": gap
|
||||
}
|
||||
|
||||
print(f"\n{comp.upper()}:")
|
||||
print(f" Expected: {expected}")
|
||||
print(f" Actual: {actual}")
|
||||
print(f" Status: {status} ({'+' if gap >= 0 else ''}{gap})")
|
||||
|
||||
return results
|
||||
|
||||
def audit_crops():
|
||||
"""Audit crop growth stages"""
|
||||
print("\n## 3. CROPS")
|
||||
print("=" * 60)
|
||||
|
||||
crops_path = ASSETS_REF / "crops"
|
||||
results = {}
|
||||
|
||||
for crop in ["wheat", "carrot", "tomato", "potato", "corn"]:
|
||||
crop_dir = crops_path / crop / "growth_stages"
|
||||
actual = count_pngs(crop_dir)
|
||||
expected = EXPECTED["crops"][crop]
|
||||
status = "✅" if actual >= expected else "❌"
|
||||
gap = actual - expected
|
||||
|
||||
results[crop] = {
|
||||
"expected": expected,
|
||||
"actual": actual,
|
||||
"status": status,
|
||||
"gap": gap
|
||||
}
|
||||
|
||||
print(f"\n{crop.upper()}:")
|
||||
print(f" Expected: {expected}")
|
||||
print(f" Actual: {actual}")
|
||||
print(f" Status: {status} ({'+' if gap >= 0 else ''}{gap})")
|
||||
|
||||
return results
|
||||
|
||||
def audit_audio():
|
||||
"""Audit audio files"""
|
||||
print("\n## 4. AUDIO")
|
||||
print("=" * 60)
|
||||
|
||||
audio_path = ASSETS_REF.parent / "audio"
|
||||
|
||||
# Count voice files
|
||||
voices = audio_path / "voices"
|
||||
voice_count = len(list(voices.rglob("*.mp3"))) if voices.exists() else 0
|
||||
|
||||
# Count sound effects
|
||||
sfx = audio_path / "sfx"
|
||||
sfx_count = len(list(sfx.rglob("*.wav"))) if sfx.exists() else 0
|
||||
|
||||
# Count music
|
||||
music_path = REPO_ROOT / "music"
|
||||
music_count = len(list(music_path.rglob("*.mp3"))) if music_path.exists() else 0
|
||||
music_count += len(list(music_path.rglob("*.wav"))) if music_path.exists() else 0
|
||||
music_count += len(list(music_path.rglob("*.ogg"))) if music_path.exists() else 0
|
||||
|
||||
print(f"\nVOICES (MP3): {voice_count}")
|
||||
print(f"SOUND EFFECTS (WAV): {sfx_count}")
|
||||
print(f"MUSIC: {music_count} {'❌ MISSING!' if music_count == 0 else '✅'}")
|
||||
|
||||
return {
|
||||
"voices": voice_count,
|
||||
"sfx": sfx_count,
|
||||
"music": music_count
|
||||
}
|
||||
|
||||
def generate_report():
|
||||
"""Generate complete audit report"""
|
||||
print("\n" + "="*60)
|
||||
print("🔍 COMPLETE ASSET AUDIT - JAN 8, 2026")
|
||||
print("="*60)
|
||||
|
||||
# Run all audits
|
||||
chars = audit_characters()
|
||||
comps = audit_companions()
|
||||
crops = audit_crops()
|
||||
audio = audit_audio()
|
||||
|
||||
# Summary
|
||||
print("\n" + "="*60)
|
||||
print("📊 SUMMARY")
|
||||
print("="*60)
|
||||
|
||||
total_expected = sum(EXPECTED["characters"].values())
|
||||
total_expected += sum(EXPECTED["companions"].values())
|
||||
total_expected += sum(EXPECTED["crops"].values())
|
||||
total_expected += EXPECTED["zombies"]
|
||||
total_expected += EXPECTED["tools"]
|
||||
total_expected += EXPECTED["ui"]
|
||||
|
||||
total_actual = count_pngs(ASSETS_REF)
|
||||
|
||||
print(f"\nTOTAL PNG FILES: {total_actual}")
|
||||
print(f"AUDIO FILES: {audio['voices'] + audio['sfx'] + audio['music']}")
|
||||
print(f" - Voices: {audio['voices']}")
|
||||
print(f" - SFX: {audio['sfx']}")
|
||||
print(f" - Music: {audio['music']} {'❌' if audio['music'] == 0 else '✅'}")
|
||||
|
||||
# Missing items
|
||||
print("\n" + "="*60)
|
||||
print("❌ MISSING / NEEDS ATTENTION")
|
||||
print("="*60)
|
||||
|
||||
missing = []
|
||||
|
||||
for char, data in chars.items():
|
||||
if data['gap'] < 0:
|
||||
missing.append(f" - {char.upper()}: {abs(data['gap'])} sprites short")
|
||||
|
||||
for crop, data in crops.items():
|
||||
if data['gap'] < 0:
|
||||
missing.append(f" - {crop.upper()}: {abs(data['gap'])} sprites short")
|
||||
|
||||
if audio['music'] == 0:
|
||||
missing.append(f" - MUSIC: Need 3+ background tracks")
|
||||
|
||||
if missing:
|
||||
for item in missing:
|
||||
print(item)
|
||||
else:
|
||||
print(" ✅ ALL ASSETS COMPLETE!")
|
||||
|
||||
print("\n" + "="*60)
|
||||
|
||||
if __name__ == "__main__":
|
||||
generate_report()
|
||||
Reference in New Issue
Block a user