Files
novafarma/scripts/complete_asset_audit.py
David Kotnik 5b07de56da 📊 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)
2026-01-08 15:50:30 +01:00

222 lines
6.1 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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()