Files
dnd-helpers/src/persistence/characters.py
T

91 lines
2.8 KiB
Python

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)