"""Conversation state tracking for player-NPC dialogues.""" from dataclasses import dataclass from mudlib.dialogue import DialogueNode, DialogueTree from mudlib.entity import Mob from mudlib.npc_behavior import transition_state from mudlib.player import Player @dataclass class ConversationState: """Tracks an active conversation between a player and NPC.""" tree: DialogueTree current_node: str npc: Mob previous_state: str = "idle" # Global registry of active conversations (keyed by player name) active_conversations: dict[str, ConversationState] = {} def start_conversation(player: Player, mob: Mob, tree: DialogueTree) -> DialogueNode: """Start a conversation between player and NPC. Args: player: The player starting the conversation mob: The NPC mob to talk to tree: The dialogue tree to use Returns: The root DialogueNode """ # Store mob's previous state for restoration previous_state = mob.behavior_state # Transition mob to converse state transition_state(mob, "converse") # Create conversation state state = ConversationState( tree=tree, current_node=tree.root_node, npc=mob, previous_state=previous_state, ) active_conversations[player.name] = state return tree.nodes[tree.root_node] def advance_conversation(player: Player, choice_index: int) -> DialogueNode | None: """Advance conversation based on player's choice. Args: player: The player making the choice choice_index: 1-indexed choice number Returns: Next DialogueNode (conversation state updated but not ended yet), or None if invalid choice """ conv = active_conversations.get(player.name) if conv is None: return None current = conv.tree.nodes[conv.current_node] # Validate choice index if choice_index < 1 or choice_index > len(current.choices): return None # Get the next node choice = current.choices[choice_index - 1] next_node = conv.tree.nodes[choice.next_node] # Update conversation state to new node conv.current_node = next_node.id return next_node def end_conversation(player: Player) -> None: """End the active conversation and clean up state. Args: player: The player whose conversation to end """ conv = active_conversations.get(player.name) if conv is None: return # Transition mob back to previous state transition_state(conv.npc, conv.previous_state) # Remove conversation state del active_conversations[player.name] def get_conversation(player: Player) -> ConversationState | None: """Get the active conversation for a player. Args: player: The player to look up Returns: ConversationState if active, None otherwise """ return active_conversations.get(player.name)