Files
Code_of_Conquest/public_web/templates/game/partials/sidebar_quests.html
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

84 lines
3.1 KiB
HTML

{#
Quests Accordion Content
Shows active quests with objectives and progress
Enhanced with HTMX for live updates and clickable quest details
#}
<div id="quest-list-container"
hx-get="{{ url_for('game.quests_accordion', session_id=session_id) }}"
hx-trigger="questAccepted from:body, questCompleted from:body, questAbandoned from:body, combatEnded from:body"
hx-swap="innerHTML">
{% if quests %}
<div class="quest-list">
{% for quest in quests %}
<div class="quest-item {% if quest.is_complete %}quest-item--ready{% endif %}"
hx-get="{{ url_for('game.quest_detail', session_id=session_id, quest_id=quest.quest_id) }}"
hx-target="#modal-container"
hx-swap="innerHTML"
role="button"
tabindex="0"
aria-label="View quest details: {{ quest.name }}">
{# Ready to Complete Banner #}
{% if quest.is_complete %}
<div class="quest-ready-banner">
<span class="ready-icon">&#10003;</span>
<span class="ready-text">Ready to Turn In!</span>
</div>
{% endif %}
<div class="quest-header">
<span class="quest-name">{{ quest.name }}</span>
<span class="quest-difficulty quest-difficulty--{{ quest.difficulty }}">
{{ quest.difficulty }}
</span>
</div>
{% if quest.quest_giver %}
<div class="quest-giver">From: {{ quest.quest_giver }}</div>
{% endif %}
<div class="quest-objectives">
{% for objective in quest.objectives %}
<div class="quest-objective {% if objective.is_complete %}objective-complete{% endif %}">
<span class="quest-objective-check">
{% if objective.is_complete %}&#10003;{% else %}&#9675;{% endif %}
</span>
<span class="quest-objective-text {% if objective.is_complete %}text-strikethrough{% endif %}">
{{ objective.description }}
</span>
{% if objective.required > 1 %}
<span class="quest-objective-progress">
{{ objective.current }}/{{ objective.required }}
</span>
{% endif %}
</div>
{% endfor %}
</div>
{# Progress Bar for Multi-objective Quests #}
{% if quest.objectives|length > 1 %}
{% set completed_count = quest.objectives|selectattr('is_complete')|list|length %}
{% set total_count = quest.objectives|length %}
<div class="quest-overall-progress">
<div class="mini-progress-bar">
<div class="mini-progress-fill"
style="width: {{ (completed_count / total_count * 100)|int }}%">
</div>
</div>
<span class="mini-progress-text">{{ completed_count }}/{{ total_count }}</span>
</div>
{% endif %}
</div>
{% endfor %}
</div>
{% else %}
<div class="quest-empty">
<span class="empty-icon">&#128220;</span>
<p class="empty-text">No active quests.</p>
<p class="empty-hint">Talk to NPCs to find adventures!</p>
</div>
{% endif %}
</div>