import json from pathlib import Path from typing import Any, Dict, Optional from src.llm.models import CharacterStateUpdate DATA_CHARS_DIR = Path("data/chars") def ensure_chars_dir(): """Ensures the character data directory exists.""" DATA_CHARS_DIR.mkdir(parents=True, exist_ok=True) def get_character_state(character_name: str) -> Dict[str, Any]: """ Reads character state from a JSON file. If the character doesn't exist, returns a default state. """ ensure_chars_dir() file_path = DATA_CHARS_DIR / f"{character_name}.json" if not file_path.exists(): return { "character_name": character_name, "stats": {"hp": 0, "max_hp": 0, "ac": 0}, "status_effects": [], "inventory": [], } with open(file_path, "r", encoding="utf-8") as f: return json.load(f) def update_character_state(update: CharacterStateUpdate): """ Updates character state based on a CharacterStateUpdate model. Reads the current state, applies changes, and writes it back. """ ensure_chars_dir() state = get_character_state(update.character_name) # Update HP if update.hp_change is not None: current_hp = state.get("stats", {}).get("hp", 0) state["stats"]["hp"] = current_hp + update.hp_change # Update Status Effects status_effects = set(state.get("status_effects", [])) for effect in update.status_effects_added: status_effects.add(effect) for effect in update.status_effects_removed: status_effects.discard(effect) state["status_effects"] = list(status_effects) # Update Inventory inventory = state.get("inventory", []) for change in update.inventory_changes: # Find if item already exists item_exists = False for item in inventory: if item["item"] == change.item: if change.action == "added": item["quantity"] = item.get("quantity", 1) + change.quantity elif change.action == "removed": item["quantity"] = max(0, item.get("quantity", 1) - change.quantity) item_exists = True break if not item_exists: if change.action == "added": inventory.append( { "item": change.item, "quantity": change.quantity, "weight": 0, # Default weight if not provided } ) elif change.action == "removed": # Item not in inventory, do nothing or log pass state["inventory"] = inventory file_path = DATA_CHARS_DIR / f"{update.character_name}.json" with open(file_path, "w", encoding="utf-8") as f: json.dump(state, f, indent=4) return str(file_path)