#!/usr/bin/env python3 """ Example: Loading StarCraft Assets into a Game Engine ===================================================== This is a conceptual example showing how to load and use extracted StarCraft assets in a hypothetical game engine. This demonstrates: - Loading audio files - Loading and displaying graphics - Parsing data files - Organizing assets for runtime use Note: This is educational/demonstration code for engine developers. """ from pathlib import Path from typing import Dict, List, Optional import struct class AssetManager: """ Example asset manager for a game engine. This shows how to organize and load StarCraft assets for use in an alternative game engine. """ def __init__(self, assets_dir: str = "assets"): self.assets_dir = Path(assets_dir) self.audio_cache = {} self.graphics_cache = {} self.data_cache = {} print(f"AssetManager initialized with: {self.assets_dir}") def load_audio(self, audio_id: int) -> Optional[bytes]: """ Load an audio file by its ID. Args: audio_id: Numeric ID (e.g., 123 for File00000123.wav) Returns: Audio data as bytes, or None if not found """ # Check cache first if audio_id in self.audio_cache: return self.audio_cache[audio_id] # Find file filename = f"File{audio_id:08d}.wav" audio_path = self.assets_dir / "audio" / filename if not audio_path.exists(): print(f"⚠️ Audio {audio_id} not found: {filename}") return None # Load file with open(audio_path, 'rb') as f: data = f.read() # Cache it self.audio_cache[audio_id] = data print(f"✓ Loaded audio {audio_id}: {len(data)} bytes") return data def load_pcx_image(self, filename: str) -> Optional[Dict]: """ Load a PCX image file. Args: filename: Name of PCX file Returns: Dictionary with image data, or None if failed """ # Check cache if filename in self.graphics_cache: return self.graphics_cache[filename] pcx_path = self.assets_dir / "graphics" / filename if not pcx_path.exists(): print(f"⚠️ Image not found: {filename}") return None # Try to load with PIL if available try: from PIL import Image img = Image.open(pcx_path) image_data = { 'width': img.width, 'height': img.height, 'mode': img.mode, 'data': img.tobytes(), 'palette': img.getpalette() if img.mode == 'P' else None, 'path': str(pcx_path) } self.graphics_cache[filename] = image_data print(f"✓ Loaded image {filename}: {img.width}x{img.height} {img.mode}") return image_data except ImportError: print("⚠️ PIL/Pillow not available - returning raw data") with open(pcx_path, 'rb') as f: raw_data = f.read() return {'raw': raw_data, 'path': str(pcx_path)} except Exception as e: print(f"✗ Failed to load {filename}: {e}") return None def load_palette(self, palette_name: str) -> Optional[List[tuple]]: """ Load a color palette file. Args: palette_name: Name of palette file (.pal or .wpe) Returns: List of (R, G, B) tuples, or None if failed """ pal_path = self.assets_dir / "data" / palette_name if not pal_path.exists(): print(f"⚠️ Palette not found: {palette_name}") return None try: with open(pal_path, 'rb') as f: data = f.read(768) # 256 colors * 3 bytes palette = [] for i in range(0, 768, 3): r, g, b = data[i], data[i+1], data[i+2] palette.append((r, g, b)) print(f"✓ Loaded palette {palette_name}: 256 colors") return palette except Exception as e: print(f"✗ Failed to load palette {palette_name}: {e}") return None def search_assets(self, pattern: str) -> List[Path]: """ Search for assets matching a pattern. Args: pattern: Search pattern (e.g., "*.wav", "unit*") Returns: List of matching file paths """ matches = list(self.assets_dir.rglob(pattern)) return [m for m in matches if m.is_file()] def get_asset_info(self, category: str) -> Dict: """ Get information about a category of assets. Args: category: Category name (e.g., "audio", "graphics") Returns: Dictionary with count and size information """ category_dir = self.assets_dir / category if not category_dir.exists(): return {'exists': False} files = [f for f in category_dir.rglob("*") if f.is_file()] total_size = sum(f.stat().st_size for f in files) return { 'exists': True, 'count': len(files), 'total_size': total_size, 'files': [f.name for f in files[:10]] # Sample } class GameEngine: """ Conceptual game engine showing asset integration. This demonstrates how a real game engine might use the extracted StarCraft assets. """ def __init__(self): self.assets = AssetManager() self.loaded_sounds = {} self.loaded_textures = {} print("\n" + "="*80) print("Game Engine Initialized") print("="*80) def preload_common_sounds(self): """Preload commonly used sound effects""" print("\nPreloading common sounds...") # Example: Load first 10 sound files for sound_id in range(29, 39): # Based on actual file numbers audio_data = self.assets.load_audio(sound_id) if audio_data: self.loaded_sounds[sound_id] = audio_data print(f"✓ Preloaded {len(self.loaded_sounds)} sounds") def preload_ui_graphics(self): """Preload UI graphics""" print("\nPreloading UI graphics...") # Search for PCX files pcx_files = self.assets.search_assets("*.pcx") # Load first few as examples for pcx_file in pcx_files[:3]: img_data = self.assets.load_pcx_image(pcx_file.name) if img_data: self.loaded_textures[pcx_file.stem] = img_data print(f"✓ Preloaded {len(self.loaded_textures)} textures") def print_asset_summary(self): """Print summary of available assets""" print("\n" + "="*80) print("Asset Summary") print("="*80) categories = ['audio', 'graphics', 'video', 'data', 'maps'] for category in categories: info = self.assets.get_asset_info(category) if info['exists']: size_mb = info['total_size'] / 1024 / 1024 print(f"\n📁 {category.upper()}/") print(f" Files: {info['count']}") print(f" Size: {size_mb:.1f} MB") if info['files']: print(f" Sample files:") for filename in info['files'][:3]: print(f" - {filename}") def play_sound(self, sound_id: int): """ Play a sound effect (conceptual). In a real engine, this would: 1. Get audio data from cache or load it 2. Decode the WAV format 3. Send to audio mixer 4. Play through audio device """ print(f"\n🔊 Playing sound {sound_id}...") if sound_id in self.loaded_sounds: audio_data = self.loaded_sounds[sound_id] print(f" Using cached audio: {len(audio_data)} bytes") else: audio_data = self.assets.load_audio(sound_id) if not audio_data: print(f" ✗ Sound not found!") return # In real engine: decode and play audio print(f" ✓ Audio ready for playback") def render_texture(self, texture_name: str): """ Render a texture (conceptual). In a real engine, this would: 1. Get texture from cache or load it 2. Upload to GPU 3. Render to screen with proper coordinates """ print(f"\n🖼️ Rendering texture: {texture_name}") if texture_name in self.loaded_textures: tex_data = self.loaded_textures[texture_name] if 'width' in tex_data: print(f" Using cached texture: {tex_data['width']}x{tex_data['height']}") else: print(f" Using raw texture data") else: print(f" ⚠️ Texture not in cache - would load on demand") # In real engine: upload to GPU and render print(f" ✓ Texture rendered") def demo(): """Run a demonstration of asset loading""" print("\n" + "="*80) print("StarCraft Asset Loading Demo") print("="*80) print("\nThis demonstrates how a game engine would load extracted assets") print() # Check if assets exist if not Path("assets").exists(): print("❌ Assets directory not found!") print("\nPlease extract assets first:") print(" python extract_starcraft_assets.py") return # Create engine instance engine = GameEngine() # Show available assets engine.print_asset_summary() # Preload common assets print("\n" + "="*80) print("Preloading Assets") print("="*80) engine.preload_common_sounds() engine.preload_ui_graphics() # Simulate gameplay print("\n" + "="*80) print("Simulating Game Actions") print("="*80) # Play some sounds engine.play_sound(29) engine.play_sound(35) # Render some textures if engine.loaded_textures: first_texture = list(engine.loaded_textures.keys())[0] engine.render_texture(first_texture) # Summary print("\n" + "="*80) print("Demo Complete!") print("="*80) print(f"\nLoaded in memory:") print(f" Sounds: {len(engine.loaded_sounds)}") print(f" Textures: {len(engine.loaded_textures)}") print("\nThis demonstrates the basics of asset loading.") print("A real engine would include:") print(" - Audio decoding and playback") print(" - Texture uploading to GPU") print(" - Sprite rendering with animations") print(" - Data table parsing (units, weapons, etc.)") print(" - Map loading and terrain rendering") print() if __name__ == "__main__": demo()