Files
Code_of_Conquest/api/app/ai/templates/npc_dialogue.j2
Phillip Tarrant df26abd207 feat: Implement Phase 5 Quest System (100% complete)
Add YAML-driven quest system with context-aware offering:

Core Implementation:
- Quest data models (Quest, QuestObjective, QuestReward, QuestTriggers)
- QuestService for YAML loading and caching
- QuestEligibilityService with level, location, and probability filtering
- LoreService stub (MockLoreService) ready for Phase 6 Weaviate integration

Quest Content:
- 5 example quests across difficulty tiers (2 easy, 2 medium, 1 hard)
- Quest-centric design: quests define their NPC givers
- Location-based probability weights for natural quest offering

AI Integration:
- Quest offering section in npc_dialogue.j2 template
- Response parser extracts [QUEST_OFFER:quest_id] markers
- AI naturally weaves quest offers into NPC conversations

API Endpoints:
- POST /api/v1/quests/accept - Accept quest offer
- POST /api/v1/quests/decline - Decline quest offer
- POST /api/v1/quests/progress - Update objective progress
- POST /api/v1/quests/complete - Complete quest, claim rewards
- POST /api/v1/quests/abandon - Abandon active quest
- GET /api/v1/characters/{id}/quests - List character quests
- GET /api/v1/quests/{quest_id} - Get quest details

Frontend:
- Quest tracker sidebar with HTMX integration
- Quest offer modal for accept/decline flow
- Quest detail modal for viewing progress
- Combat service integration for kill objective tracking

Testing:
- Unit tests for Quest models and serialization
- Integration tests for full quest lifecycle
- Comprehensive test coverage for eligibility service

Documentation:
- Reorganized docs into /docs/phases/ structure
- Added Phase 5-12 planning documents
- Updated ROADMAP.md with new structure

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 15:42:55 -06:00

200 lines
6.9 KiB
Django/Jinja

{#
NPC Dialogue Prompt Template - Enhanced with persistent NPC data.
Used for generating contextual NPC conversations with rich personality.
Required context:
- character: Player character information (name, level, player_class)
- npc: NPC information with personality, appearance, dialogue_hooks
- conversation_topic: What the player wants to discuss
- game_state: Current game state
Optional context:
- npc_knowledge: List of information the NPC can share
- revealed_secrets: Secrets being revealed this conversation
- interaction_count: Number of times player has talked to this NPC
- relationship_level: 0-100 relationship score (50 is neutral)
- previous_dialogue: Previous exchanges with this NPC
#}
You are roleplaying as an NPC in a fantasy world, having a conversation with a player character.
## The NPC
**{{ npc.name }}** - {{ npc.role }}
{% if npc.appearance %}
- **Appearance:** {{ npc.appearance if npc.appearance is string else npc.appearance.brief if npc.appearance.brief else npc.appearance }}
{% endif %}
{% if npc.personality %}
{% if npc.personality.traits %}
- **Personality Traits:** {{ npc.personality.traits | join(', ') }}
{% elif npc.personality is string %}
- **Personality:** {{ npc.personality }}
{% endif %}
{% if npc.personality.speech_style %}
- **Speaking Style:** {{ npc.personality.speech_style }}
{% endif %}
{% if npc.personality.quirks %}
- **Quirks:** {{ npc.personality.quirks | join('; ') }}
{% endif %}
{% endif %}
{% if npc.dialogue_hooks and npc.dialogue_hooks.greeting %}
- **Typical Greeting:** "{{ npc.dialogue_hooks.greeting }}"
{% endif %}
{% if npc.goals %}
- **Current Goals:** {{ npc.goals }}
{% endif %}
## The Player Character
**{{ character.name }}** - Level {{ character.level }} {{ character.player_class }}
{% if interaction_count and interaction_count > 1 %}
- **Familiarity:** This is conversation #{{ interaction_count }} - the NPC recognizes {{ character.name }}
{% endif %}
{% if relationship_level %}
{% if relationship_level >= 80 %}
- **Relationship:** Close friend ({{ relationship_level }}/100) - treats player warmly
{% elif relationship_level >= 60 %}
- **Relationship:** Friendly acquaintance ({{ relationship_level }}/100) - helpful and open
{% elif relationship_level >= 40 %}
- **Relationship:** Neutral ({{ relationship_level }}/100) - professional but guarded
{% elif relationship_level >= 20 %}
- **Relationship:** Distrustful ({{ relationship_level }}/100) - wary and curt
{% else %}
- **Relationship:** Hostile ({{ relationship_level }}/100) - dismissive or antagonistic
{% endif %}
{% endif %}
## Current Setting
- **Location:** {{ game_state.current_location }}
{% if game_state.time_of_day %}
- **Time:** {{ game_state.time_of_day }}
{% endif %}
{% if game_state.active_quests %}
- **Player's Active Quests:** {{ game_state.active_quests | length }}
{% endif %}
{% if npc_knowledge %}
## Knowledge the NPC May Share
The NPC knows about the following (share naturally as relevant to conversation):
{% for info in npc_knowledge %}
- {{ info }}
{% endfor %}
{% endif %}
{% if revealed_secrets %}
## IMPORTANT: Secrets to Reveal This Conversation
Based on the player's relationship with this NPC, naturally reveal the following:
{% for secret in revealed_secrets %}
- {{ secret }}
{% endfor %}
Work these into the dialogue naturally - don't dump all information at once.
Make it feel earned, like the NPC is opening up to someone they trust.
{% endif %}
{% if quest_offering_context and quest_offering_context.should_offer %}
## QUEST OFFERING OPPORTUNITY
The NPC has a quest to offer. Weave this naturally into the conversation.
**Quest:** {{ quest_offering_context.quest_name }}
**Quest ID:** {{ quest_offering_context.quest_id }}
{% if quest_offering_context.offer_dialogue %}
**How the NPC Would Present It:**
{{ quest_offering_context.offer_dialogue }}
{% endif %}
{% if quest_offering_context.npc_quest_knowledge %}
**What the NPC Knows About This Quest:**
{% for fact in quest_offering_context.npc_quest_knowledge %}
- {{ fact }}
{% endfor %}
{% endif %}
{% if quest_offering_context.narrative_hooks %}
**Narrative Hooks (use 1-2 naturally):**
{% for hook in quest_offering_context.narrative_hooks %}
- The NPC {{ hook }}
{% endfor %}
{% endif %}
**IMPORTANT QUEST OFFERING RULES:**
- Do NOT dump all quest information at once
- Let the quest emerge naturally from conversation
- If the player seems interested or asks about problems/work, offer the quest
- If the player changes topic, don't force it - just mention hints
- When you offer the quest, include this marker on its own line: [QUEST_OFFER:{{ quest_offering_context.quest_id }}]
- The marker signals the UI to show a quest accept/decline option
{% endif %}
{% if lore_context and lore_context.has_content %}
## Relevant World Knowledge
The NPC may reference this lore if contextually appropriate:
{% if lore_context.quest %}
**Quest Background:**
{% for entry in lore_context.quest[:2] %}
- {{ entry.content | truncate_text(150) }}
{% endfor %}
{% endif %}
{% if lore_context.regional %}
**Local Knowledge:**
{% for entry in lore_context.regional[:3] %}
- {{ entry.content | truncate_text(100) }}
{% endfor %}
{% endif %}
{% if lore_context.world %}
**Historical Knowledge (if NPC would know):**
{% for entry in lore_context.world[:2] %}
- {{ entry.content | truncate_text(100) }}
{% endfor %}
{% endif %}
{% endif %}
{% if npc.relationships %}
## NPC Relationships (for context)
{% for rel in npc.relationships %}
- Feels {{ rel.attitude }} toward {{ rel.npc_id }}{% if rel.reason %} ({{ rel.reason }}){% endif %}
{% endfor %}
{% endif %}
{% if previous_dialogue %}
## Previous Conversation
{% for exchange in previous_dialogue[-2:] %}
- **{{ character.name }}:** {{ exchange.player_line | truncate_text(100) }}
- **{{ npc.name }}:** {{ exchange.npc_response | truncate_text(100) }}
{% endfor %}
{% endif %}
## Player Says
"{{ conversation_topic }}"
## Your Task
Respond as {{ npc.name }} in character. Generate dialogue that:
1. **Matches the NPC's personality and speech style exactly** - use their quirks, accent, and manner
2. **Acknowledges the relationship** - be warmer to friends, cooler to strangers
3. **Shares relevant knowledge naturally** - don't info-dump, weave it into conversation
4. **Reveals secrets if specified** - make it feel like earned trust, not random exposition
5. **Feels alive and memorable** - give this NPC a distinct voice
{% if max_tokens %}
**IMPORTANT: Your response must be under {{ (max_tokens * 0.6) | int }} words (approximately {{ max_tokens }} tokens). Complete all sentences - do not get cut off mid-sentence.**
{% if max_tokens <= 150 %}
Keep it to 1-2 sentences of dialogue.
{% elif max_tokens <= 300 %}
Keep it to 2-3 sentences of dialogue.
{% else %}
Keep it to 2-4 sentences of dialogue.
{% endif %}
{% else %}
Keep the response to 2-4 sentences of dialogue.
{% endif %}
You may include brief action/emotion tags in *asterisks* to show gestures and expressions.
Respond only as the NPC - no narration or out-of-character text.
Format: *action/emotion* "Dialogue goes here."