From fe267f527a905afe4b4654477196b121b1b02616 Mon Sep 17 00:00:00 2001 From: Mel-Raeven Date: Tue, 16 Dec 2025 13:55:35 +0100 Subject: [PATCH] new controls for admins to finish dragons/eggs/set money --- admin_helper.py | 469 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 469 insertions(+) create mode 100755 admin_helper.py diff --git a/admin_helper.py b/admin_helper.py new file mode 100755 index 0000000..55624fe --- /dev/null +++ b/admin_helper.py @@ -0,0 +1,469 @@ +#!/usr/bin/env python3 +""" +Dragon Riders Admin Helper +Provides admin functions for managing encrypted SQLite save data +""" + +import sys +import os +import time +from pathlib import Path +from typing import Optional, Dict, Any, List + +# Add src to path +sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src')) + +from src.save_system_sqlite import SQLiteSaveSystem +from src.utils.constants import SAVE_FILE + +# Color codes for terminal output +RED = '\033[0;31m' +GREEN = '\033[0;32m' +YELLOW = '\033[1;33m' +BLUE = '\033[0;34m' +NC = '\033[0m' # No Color + + +def print_success(msg: str): + print(f"{GREEN}✓{NC} {msg}") + + +def print_error(msg: str): + print(f"{RED}✗{NC} {msg}") + + +def print_info(msg: str): + print(f"{BLUE}ℹ{NC} {msg}") + + +def print_warning(msg: str): + print(f"{YELLOW}⚠{NC} {msg}") + + +def get_db_file(): + """Get the database file path.""" + return SAVE_FILE.replace('.json', '.db') + + +def get_save_system(): + """Get SQLite save system.""" + db_file = get_db_file() + return SQLiteSaveSystem(db_file) + + +def create_backup(): + """Create backup of database file.""" + timestamp = time.strftime("%Y%m%d_%H%M%S") + db_file = get_db_file() + + if os.path.exists(db_file): + backup_file = f"{db_file}.backup_{timestamp}" + with open(db_file, 'rb') as src, open(backup_file, 'wb') as dst: + dst.write(src.read()) + print_success(f"Created backup: {os.path.basename(backup_file)}") + else: + print_warning("No database file found to backup") + + +def show_status(): + """Show current game state.""" + db_file = get_db_file() + + print(f"\n{BLUE}=== Dragon Riders Game Status ==={NC}\n") + + if not os.path.exists(db_file): + print_warning("No database file found") + print_info(f"Expected location: {db_file}") + return + + print_info("Using SQLite database (encrypted)") + + try: + sqlite_save = get_save_system() + + state = sqlite_save.load_game_state() + dragons = sqlite_save.load_all_dragons() + eggs = sqlite_save.load_eggs() + inventory = sqlite_save.load_inventory() + + if state: + print(f"Coins: {state.get('coins', 0)}") + print(f"Meat: {state.get('meat', 0)}") + print(f"Minigame Score: {state.get('total_minigame_score', 0)}") + print(f"Dragons: {len(dragons)}") + print(f"Eggs: {len(eggs)}") + + if dragons: + print(f"\n{BLUE}Dragons:{NC}") + for idx, dragon in enumerate(dragons): + print(f" [{idx}] {dragon['name']} ({dragon['dragon_type']}, {dragon['stage']})") + + if eggs: + print(f"\n{BLUE}Eggs:{NC}") + for idx, egg in enumerate(eggs): + print(f" [{idx}] {egg['type']} (clicks: {egg['clicks']})") + + if inventory: + print(f"\n{BLUE}Inventory:{NC}") + for item, qty in inventory.items(): + print(f" - {item}: {qty}") + else: + print_error("Failed to load game state from database") + except Exception as e: + print_error(f"Error reading database: {e}") + + print() + + +def set_coins(amount: int): + """Set coins to specified amount.""" + if amount < 0: + print_error("Amount must be non-negative") + return + + db_file = get_db_file() + if not os.path.exists(db_file): + print_error("No database file found") + return + + create_backup() + + try: + sqlite_save = get_save_system() + state = sqlite_save.load_game_state() + if state: + state['coins'] = amount + if sqlite_save.save_game_state(state): + print_success(f"Set coins to {amount}") + else: + print_error("Failed to save to database") + else: + print_error("Failed to load game state") + except Exception as e: + print_error(f"Error setting coins: {e}") + + +def set_meat(amount: int): + """Set meat to specified amount.""" + if amount < 0: + print_error("Amount must be non-negative") + return + + db_file = get_db_file() + if not os.path.exists(db_file): + print_error("No database file found") + return + + create_backup() + + try: + sqlite_save = get_save_system() + state = sqlite_save.load_game_state() + if state: + state['meat'] = amount + if sqlite_save.save_game_state(state): + print_success(f"Set meat to {amount}") + else: + print_error("Failed to save to database") + else: + print_error("Failed to load game state") + except Exception as e: + print_error(f"Error setting meat: {e}") + + +def finish_eggs(): + """Set all eggs to 99 clicks (ready to hatch).""" + db_file = get_db_file() + if not os.path.exists(db_file): + print_error("No database file found") + return + + create_backup() + + try: + sqlite_save = get_save_system() + eggs = sqlite_save.load_eggs() + + if eggs: + # Update all eggs to 99 clicks + for egg in eggs: + egg['clicks'] = 99 + + if sqlite_save.save_eggs(eggs): + print_success(f"Set {len(eggs)} egg(s) to 99 clicks (ready to hatch)") + else: + print_error("Failed to save eggs") + else: + print_info("No eggs found in database") + except Exception as e: + print_error(f"Error finishing eggs: {e}") + + +def add_egg(egg_type: str): + """Add an egg of specified type.""" + valid_types = ['fire', 'water', 'earth', 'forest', 'ice', 'thunder', 'light', 'shadow', 'storm', 'crystal'] + + if egg_type not in valid_types: + print_error(f"Invalid egg type: {egg_type}") + print_info(f"Valid types: {', '.join(valid_types)}") + return + + db_file = get_db_file() + if not os.path.exists(db_file): + print_error("No database file found") + return + + create_backup() + + try: + sqlite_save = get_save_system() + eggs = sqlite_save.load_eggs() + + # Add new egg + eggs.append({'type': egg_type, 'clicks': 0}) + + if sqlite_save.save_eggs(eggs): + print_success(f"Added {egg_type} egg") + else: + print_error("Failed to add egg") + except Exception as e: + print_error(f"Error adding egg: {e}") + + +def grow_dragon(dragon_index: int, stage: str): + """Grow dragon to specific stage.""" + valid_stages = { + 'hatchling': 1, + 'juvenile': 2, + 'adult': 3, + 'elder': 4 + } + + if stage not in valid_stages: + print_error(f"Invalid stage: {stage}") + print_info(f"Valid stages: {', '.join(valid_stages.keys())}") + return + + db_file = get_db_file() + if not os.path.exists(db_file): + print_error("No database file found") + return + + create_backup() + + try: + sqlite_save = get_save_system() + dragons = sqlite_save.load_all_dragons() + + if dragon_index >= len(dragons): + print_error(f"Dragon index {dragon_index} not found (have {len(dragons)} dragons)") + return + + dragon = dragons[dragon_index] + dragon['stage'] = stage + dragon['stage_index'] = valid_stages[stage] + dragon['growth_progress'] = 0.0 + + if sqlite_save.save_dragon(dragon, dragon.get('_db_id')): + print_success(f"Grew dragon '{dragon['name']}' to {stage}") + else: + print_error("Failed to update dragon") + except Exception as e: + print_error(f"Error growing dragon: {e}") + + +def finish_dragons(): + """Grow all dragons to elder stage.""" + db_file = get_db_file() + if not os.path.exists(db_file): + print_error("No database file found") + return + + create_backup() + + try: + sqlite_save = get_save_system() + dragons = sqlite_save.load_all_dragons() + + if not dragons: + print_info("No dragons found in database") + return + + updated_count = 0 + for dragon in dragons: + if dragon['stage'] != 'elder': + dragon['stage'] = 'elder' + dragon['stage_index'] = 4 + dragon['growth_progress'] = 0.0 + + if sqlite_save.save_dragon(dragon, dragon.get('_db_id')): + print_success(f"Grew dragon '{dragon['name']}' to elder") + updated_count += 1 + else: + print_error(f"Failed to update dragon '{dragon['name']}'") + else: + print_info(f"Dragon '{dragon['name']}' is already elder") + + if updated_count > 0: + print_success(f"Finished growing {updated_count} dragon(s) to elder stage") + except Exception as e: + print_error(f"Error finishing dragons: {e}") + + +def add_item(item: str, quantity: int = 1): + """Add item to inventory.""" + if quantity < 1: + print_error("Quantity must be at least 1") + return + + db_file = get_db_file() + if not os.path.exists(db_file): + print_error("No database file found") + return + + create_backup() + + try: + sqlite_save = get_save_system() + inventory = sqlite_save.load_inventory() + + current = inventory.get(item, 0) + sqlite_save.save_inventory_item(item, current + quantity) + print_success(f"Added {quantity} x {item}") + except Exception as e: + print_error(f"Error adding item: {e}") + + +def set_minigame_score(score: int): + """Set minigame score.""" + if score < 0: + print_error("Score must be non-negative") + return + + db_file = get_db_file() + if not os.path.exists(db_file): + print_error("No database file found") + return + + create_backup() + + try: + sqlite_save = get_save_system() + state = sqlite_save.load_game_state() + if state: + state['total_minigame_score'] = score + if sqlite_save.save_game_state(state): + print_success(f"Set minigame score to {score}") + else: + print_error("Failed to save to database") + else: + print_error("Failed to load game state") + except Exception as e: + print_error(f"Error setting score: {e}") + + +def show_help(): + """Show help message.""" + print(f"{BLUE}Dragon Riders Admin Helper{NC}") + print() + print("Usage: python3 admin_helper.py [arguments]") + print() + print("Commands:") + print(" status - Show current game state") + print(" coins - Set coins to specified amount") + print(" meat - Set meat to specified amount") + print(" score - Set minigame score") + print(" finish-eggs - Set all eggs to 99 clicks (ready to hatch)") + print(" add-egg - Add an egg of specified type") + print(" grow-dragon - Grow dragon to specific stage") + print(" finish-dragons - Grow all dragons to elder stage") + print(" add-item [qty] - Add item to inventory") + print(" backup - Create backup of database") + print(" help - Show this help message") + print() + print("Examples:") + print(" python3 admin_helper.py status") + print(" python3 admin_helper.py coins 10000") + print(" python3 admin_helper.py meat 50") + print(" python3 admin_helper.py score 1000") + print(" python3 admin_helper.py finish-eggs") + print(" python3 admin_helper.py add-egg fire") + print(" python3 admin_helper.py grow-dragon 0 elder") + print(" python3 admin_helper.py finish-dragons") + print(" python3 admin_helper.py add-item gold_helmet 5") + print() + print("Valid egg types:") + print(" fire, water, earth, forest, ice, thunder, light, shadow, storm, crystal") + print() + print("Valid dragon stages:") + print(" hatchling, juvenile, adult, elder") + print() + + +def main(): + """Main entry point.""" + if len(sys.argv) < 2: + show_help() + return + + command = sys.argv[1].lower() + + try: + if command == 'status': + show_status() + elif command == 'coins': + if len(sys.argv) < 3: + print_error("Usage: python3 admin_helper.py coins ") + sys.exit(1) + set_coins(int(sys.argv[2])) + elif command == 'meat': + if len(sys.argv) < 3: + print_error("Usage: python3 admin_helper.py meat ") + sys.exit(1) + set_meat(int(sys.argv[2])) + elif command == 'score': + if len(sys.argv) < 3: + print_error("Usage: python3 admin_helper.py score ") + sys.exit(1) + set_minigame_score(int(sys.argv[2])) + elif command == 'finish-eggs': + finish_eggs() + elif command == 'add-egg': + if len(sys.argv) < 3: + print_error("Usage: python3 admin_helper.py add-egg ") + sys.exit(1) + add_egg(sys.argv[2]) + elif command == 'grow-dragon': + if len(sys.argv) < 4: + print_error("Usage: python3 admin_helper.py grow-dragon ") + sys.exit(1) + grow_dragon(int(sys.argv[2]), sys.argv[3]) + elif command == 'finish-dragons': + finish_dragons() + elif command == 'add-item': + if len(sys.argv) < 3: + print_error("Usage: python3 admin_helper.py add-item [quantity]") + sys.exit(1) + quantity = int(sys.argv[3]) if len(sys.argv) > 3 else 1 + add_item(sys.argv[2], quantity) + elif command == 'backup': + create_backup() + elif command in ['help', '--help', '-h']: + show_help() + else: + print_error(f"Unknown command: {command}") + print() + show_help() + sys.exit(1) + except ValueError as e: + print_error(f"Invalid value: {e}") + sys.exit(1) + except Exception as e: + print_error(f"Error: {e}") + import traceback + traceback.print_exc() + sys.exit(1) + + +if __name__ == '__main__': + main() \ No newline at end of file