#!/usr/bin/env python3 """ šŸ¦– ANOMALOUS ZONE FAUNA GENERATOR Generates creatures for all 8 remaining anomalous zones Based on DLC_TO_BASE_GAME_COMPLETE.md specifications """ import os import sys import time from pathlib import Path from PIL import Image try: import google.generativeai as genai except ImportError: print("āŒ google-generativeai not installed!") print(" Run: pip install google-generativeai") sys.exit(1) # Configuration REPO = Path("/Users/davidkotnik/repos/novafarma") ASSETS = REPO / "assets/slike" # Setup API api_key = os.environ.get("GEMINI_API_KEY") if not api_key: print("āŒ GEMINI_API_KEY not set!") print(" Run: export GEMINI_API_KEY='your-key-here'") sys.exit(1) genai.configure(api_key=api_key) # Style prompts STYLE_A = """ISOLATED ON PURE WHITE BACKGROUND. 2D indie game creature sprite, cartoon vector art style, bold black outlines, flat colors, cute and playful aesthetic, NO shadows, NO gradients, simple clean design, centered, full body visible, game asset""" STYLE_B = """ISOLATED ON PURE WHITE BACKGROUND. 2D indie game creature sprite, dark hand-drawn gritty noir style, dramatic shadows, high contrast, sketchy atmospheric lines, mature 90s cartoon aesthetic, centered, full body visible, game asset""" # All anomalous zones with their creatures ANOMALOUS_ZONES = { "mythical_highlands": [ ("unicorn", "white unicorn with rainbow mane, golden spiral horn, magical glowing"), ("dragon_fire", "fire dragon, red scales, breathing flames, large wings"), ("dragon_ice", "ice dragon, blue scales, frost breath, majestic wings"), ("griffin", "griffin, eagle head, lion body, large wings, fierce"), ("phoenix", "phoenix bird, fire feathers, glowing orange-red, rebirth flames"), ("pegasus", "pegasus flying horse, white with large wings, graceful"), ("yeti", "yeti creature, white fur, friendly peaceful, mountain dweller"), ], "endless_forest": [ ("bigfoot", "bigfoot sasquatch, massive brown fur, gentle giant, forest guardian"), ("wendigo", "wendigo horror creature, skeletal antlers, dark menacing, night stalker"), ("forest_spirit", "forest spirit, ethereal glowing green, nature guardian, mystical"), ("tree_ent", "tree ent, giant walking tree, ancient wise, moss covered"), ("will_o_wisp", "will-o-wisp floating light, blue ethereal glow, mysterious"), ], "loch_ness": [ ("nessie", "loch ness monster, long neck, friendly, water serpent, scottish"), ("leprechaun", "leprechaun small irish, green suit, red beard, gold pot guardian"), ("kelpie", "kelpie water horse, mystical, celtic mythology"), ("selkie", "selkie seal-human, shapeshifter, scottish folklore"), ], "egyptian_desert": [ ("mummy_pharaoh", "mummy pharaoh boss, golden crown, wrapped bandages, ancient curse"), ("mummy_soldier", "mummy soldier guard, spear weapon, bandaged warrior"), ("scarab_giant", "giant scarab beetle, massive, egyptian sacred"), ("scorpion_giant", "giant scorpion, desert predator, venomous stinger"), ("sand_serpent", "sand serpent, desert snake, camouflaged sand colored"), ("sphinx", "sphinx creature, lion body human head, riddle guardian"), ("anubis_guardian", "anubis guardian, jackal headed, egyptian god, temple protector"), ], "amazonas": [ ("jaguar", "jaguar big cat, spotted, stealth predator, jungle hunter"), ("anaconda", "anaconda giant snake, massive coiled, green patterned"), ("poison_dart_frog", "poison dart frog, vibrant toxic colors, small deadly"), ("macaw", "macaw parrot, colorful red blue, large tropical bird"), ("piranha", "piranha fish, sharp teeth, aggressive swarm"), ("mega_jaguar", "mega jaguar boss, car sized, alpha predator"), ("carnivorous_plant", "carnivorous plant, venus flytrap giant, mobile threat"), ], "atlantis": [ ("mermaid", "mermaid, beautiful fish tail, underwater dweller, aquatic"), ("sea_serpent", "sea serpent, long coiled, underwater dragon, oceanic"), ("kraken", "kraken giant octopus, massive tentacles, deep sea monster"), ("seahorse_giant", "giant seahorse, rideable, graceful underwater"), ("dolphin", "dolphin, friendly intelligent, ocean companion"), ("anglerfish_giant", "giant anglerfish, glowing lure, deep sea predator"), ], "chernobyl": [ ("radioactive_zombie", "radioactive zombie, glowing green, hazmat torn, mutated"), ("mutant_dog", "mutant dog, two heads, radiation scarred, aggressive"), ("nuclear_rat_giant", "giant nuclear rat, glowing mutations, toxic"), ("radiation_stalker", "radiation stalker, invisible shimmer, hazmat creature"), ("alpha_troll_king", "alpha troll king BOSS, massive green, tribal crown, 50000 HP"), ], "catacombs": [ ("skeleton_warrior", "skeleton warrior, armor bones, sword shield, undead fighter"), ("skeleton_knight", "skeleton knight, heavy armor, mounted, elite undead"), ("ghost", "ghost spirit, ethereal transparent, floating, supernatural"), ("bone_golem", "bone golem, massive skeleton construct, regenerating"), ("necromancer", "necromancer dark mage, skull staff, raising dead, boss"), ("revenant", "revenant cursed soul, dark armor, vengeance spirit"), ("shadow_stalker", "shadow stalker, invisible in dark, sneaky wraith"), ], } def create_preview(image_path: Path, size=256): """Create preview version""" try: img = Image.open(image_path) preview = img.resize((size, size), Image.Resampling.LANCZOS) preview_path = image_path.parent / f"{image_path.stem}_preview_{size}x{size}.png" preview.save(preview_path, 'PNG', optimize=True) return preview_path except Exception as e: print(f" āš ļø Preview failed: {e}") return None def generate_creature(zone_name: str, creature_name: str, description: str, style: str, log_file) -> bool: """Generate a single creature sprite""" start = time.time() style_suffix = "stylea" if style == "A" else "styleb" output_path = ASSETS / zone_name / f"{creature_name}_{style_suffix}.png" # Skip if exists if output_path.exists(): print(f" ā­ļø Already exists") return True # Create prompt style_prompt = STYLE_A if style == "A" else STYLE_B full_prompt = f"{style_prompt}\n\n{description}\n\nGame sprite asset." try: print(f" šŸŽØ Generating {style_suffix}: {creature_name}") log_file.write(f"{time.strftime('%H:%M:%S')} - Generating {output_path.name}\n") log_file.flush() # Generate image model = genai.GenerativeModel("gemini-2.5-flash") response = model.generate_content([full_prompt]) if hasattr(response, '_result') and response._result.candidates: image_data = response._result.candidates[0].content.parts[0].inline_data.data # Save original output_path.parent.mkdir(parents=True, exist_ok=True) with open(output_path, 'wb') as f: f.write(image_data) # Create preview preview = create_preview(output_path) elapsed = time.time() - start print(f" āœ… Saved ({elapsed:.1f}s)") log_file.write(f"{time.strftime('%H:%M:%S')} - SUCCESS {output_path.name} ({elapsed:.1f}s)\n") log_file.flush() return True else: print(f" āŒ No image data") log_file.write(f"{time.strftime('%H:%M:%S')} - FAILED {output_path.name} - No data\n") log_file.flush() return False except Exception as e: print(f" āŒ Error: {e}") log_file.write(f"{time.strftime('%H:%M:%S')} - ERROR {output_path.name} - {e}\n") log_file.flush() return False def main(): # Create log log_dir = REPO / "logs" log_dir.mkdir(exist_ok=True) log_file = open(log_dir / f"anomalous_fauna_{time.strftime('%Y%m%d_%H%M%S')}.log", 'w') print("="*70) print("šŸ¦– ANOMALOUS ZONE FAUNA GENERATOR") print("="*70) total_creatures = sum(len(creatures) for creatures in ANOMALOUS_ZONES.values()) total_images = total_creatures * 2 # styleA + styleB print(f"\n{len(ANOMALOUS_ZONES)} zones | {total_creatures} creatures Ɨ 2 styles = {total_images} images") print() log_file.write(f"ANOMALOUS FAUNA GENERATION - {time.strftime('%Y-%m-%d %H:%M:%S')}\n") log_file.write(f"Total: {total_images} images\n") log_file.write("="*70 + "\n\n") log_file.flush() success = 0 failed = 0 current = 0 try: for zone_name, creatures in ANOMALOUS_ZONES.items(): print(f"\n{'='*70}") print(f"šŸŒ {zone_name.upper().replace('_', ' ')}") print(f"{'='*70}") print(f" {len(creatures)} creatures") log_file.write(f"\n{'='*70}\n") log_file.write(f"ZONE: {zone_name}\n") log_file.write(f"{'='*70}\n\n") log_file.flush() for creature_name, description in creatures: current += 1 print(f"\n[{current}/{total_creatures}] {creature_name}") # Generate both styles for style in ["A", "B"]: if generate_creature(zone_name, creature_name, description, style, log_file): success += 1 else: failed += 1 # Rate limiting (5 requests/min limit) time.sleep(15) # Progress progress = ((current / total_creatures) * 100) print(f"\nšŸ“Š Progress: {progress:.1f}% | Success: {success}/{total_images} | Failed: {failed}") # Final summary print("\n" + "="*70) print("šŸŽ‰ GENERATION COMPLETE!") print("="*70) print(f"āœ… Success: {success}/{total_images}") print(f"āŒ Failed: {failed}/{total_images}") print(f"šŸ“Š Success rate: {(success/total_images)*100:.1f}%") log_file.write(f"\n{'='*70}\n") log_file.write(f"GENERATION COMPLETE\n") log_file.write(f"Success: {success}\n") log_file.write(f"Failed: {failed}\n") except KeyboardInterrupt: print(f"\n\nāš ļø INTERRUPTED at creature {current}") log_file.write(f"\n\nINTERRUPTED at creature {current}\n") finally: log_file.close() if __name__ == "__main__": main()