combat testing and polishing in the dev console, many bug fixes
This commit is contained in:
@@ -7,7 +7,7 @@ Provides the main gameplay interface with 3-column layout:
|
||||
- Right: Accordions for history, quests, NPCs, map
|
||||
"""
|
||||
|
||||
from flask import Blueprint, render_template, request
|
||||
from flask import Blueprint, render_template, request, redirect, url_for
|
||||
import structlog
|
||||
|
||||
from ..utils.api_client import get_api_client, APIError, APINotFoundError
|
||||
@@ -866,6 +866,220 @@ def npc_chat_history(session_id: str, npc_id: str):
|
||||
return '<div class="history-empty">Failed to load history</div>', 500
|
||||
|
||||
|
||||
# ===== Inventory Routes =====
|
||||
|
||||
@game_bp.route('/session/<session_id>/inventory-modal')
|
||||
@require_auth
|
||||
def inventory_modal(session_id: str):
|
||||
"""
|
||||
Get inventory modal with all items.
|
||||
|
||||
Supports filtering by item type via ?filter= parameter.
|
||||
"""
|
||||
client = get_api_client()
|
||||
filter_type = request.args.get('filter', 'all')
|
||||
|
||||
try:
|
||||
# Get session to find character
|
||||
session_response = client.get(f'/api/v1/sessions/{session_id}')
|
||||
session_data = session_response.get('result', {})
|
||||
character_id = session_data.get('character_id')
|
||||
|
||||
inventory = []
|
||||
equipped = {}
|
||||
gold = 0
|
||||
inventory_count = 0
|
||||
inventory_max = 100
|
||||
|
||||
if character_id:
|
||||
try:
|
||||
inv_response = client.get(f'/api/v1/characters/{character_id}/inventory')
|
||||
inv_data = inv_response.get('result', {})
|
||||
inventory = inv_data.get('inventory', [])
|
||||
equipped = inv_data.get('equipped', {})
|
||||
inventory_count = inv_data.get('inventory_count', len(inventory))
|
||||
inventory_max = inv_data.get('max_inventory', 100)
|
||||
|
||||
# Get gold from character
|
||||
char_response = client.get(f'/api/v1/characters/{character_id}')
|
||||
char_data = char_response.get('result', {})
|
||||
gold = char_data.get('gold', 0)
|
||||
except (APINotFoundError, APIError) as e:
|
||||
logger.warning("failed_to_load_inventory", character_id=character_id, error=str(e))
|
||||
|
||||
# Filter inventory by type if specified
|
||||
if filter_type != 'all':
|
||||
inventory = [item for item in inventory if item.get('item_type') == filter_type]
|
||||
|
||||
return render_template(
|
||||
'game/partials/inventory_modal.html',
|
||||
session_id=session_id,
|
||||
inventory=inventory,
|
||||
equipped=equipped,
|
||||
gold=gold,
|
||||
inventory_count=inventory_count,
|
||||
inventory_max=inventory_max,
|
||||
filter=filter_type
|
||||
)
|
||||
|
||||
except APIError as e:
|
||||
logger.error("failed_to_load_inventory_modal", session_id=session_id, error=str(e))
|
||||
return f'''
|
||||
<div class="modal-overlay" onclick="closeModal()">
|
||||
<div class="modal-content inventory-modal">
|
||||
<div class="modal-header">
|
||||
<h2>Inventory</h2>
|
||||
<button class="modal-close" onclick="closeModal()">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="inventory-empty">Failed to load inventory: {e}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
'''
|
||||
|
||||
|
||||
@game_bp.route('/session/<session_id>/inventory/item/<item_id>')
|
||||
@require_auth
|
||||
def inventory_item_detail(session_id: str, item_id: str):
|
||||
"""Get item detail partial for HTMX swap."""
|
||||
client = get_api_client()
|
||||
|
||||
try:
|
||||
# Get session to find character
|
||||
session_response = client.get(f'/api/v1/sessions/{session_id}')
|
||||
session_data = session_response.get('result', {})
|
||||
character_id = session_data.get('character_id')
|
||||
|
||||
item = None
|
||||
if character_id:
|
||||
# Get inventory and find the item
|
||||
inv_response = client.get(f'/api/v1/characters/{character_id}/inventory')
|
||||
inv_data = inv_response.get('result', {})
|
||||
inventory = inv_data.get('inventory', [])
|
||||
|
||||
for inv_item in inventory:
|
||||
if inv_item.get('item_id') == item_id:
|
||||
item = inv_item
|
||||
break
|
||||
|
||||
if not item:
|
||||
return '<div class="item-detail-empty">Item not found</div>', 404
|
||||
|
||||
# Determine suggested slot for equipment
|
||||
suggested_slot = None
|
||||
item_type = item.get('item_type', '')
|
||||
if item_type == 'weapon':
|
||||
suggested_slot = 'weapon'
|
||||
elif item_type == 'armor':
|
||||
# Could be any armor slot - default to chest
|
||||
suggested_slot = 'chest'
|
||||
|
||||
return render_template(
|
||||
'game/partials/inventory_item_detail.html',
|
||||
session_id=session_id,
|
||||
item=item,
|
||||
suggested_slot=suggested_slot
|
||||
)
|
||||
|
||||
except APIError as e:
|
||||
logger.error("failed_to_load_item_detail", session_id=session_id, item_id=item_id, error=str(e))
|
||||
return f'<div class="item-detail-empty">Failed to load item: {e}</div>', 500
|
||||
|
||||
|
||||
@game_bp.route('/session/<session_id>/inventory/use', methods=['POST'])
|
||||
@require_auth
|
||||
def inventory_use(session_id: str):
|
||||
"""Use a consumable item."""
|
||||
client = get_api_client()
|
||||
item_id = request.form.get('item_id')
|
||||
|
||||
if not item_id:
|
||||
return '<div class="error">No item selected</div>', 400
|
||||
|
||||
try:
|
||||
# Get session to find character
|
||||
session_response = client.get(f'/api/v1/sessions/{session_id}')
|
||||
session_data = session_response.get('result', {})
|
||||
character_id = session_data.get('character_id')
|
||||
|
||||
if not character_id:
|
||||
return '<div class="error">No character found</div>', 400
|
||||
|
||||
# Use the item via API
|
||||
client.post(f'/api/v1/characters/{character_id}/inventory/use', {
|
||||
'item_id': item_id
|
||||
})
|
||||
|
||||
# Return updated character panel
|
||||
return redirect(url_for('game.character_panel', session_id=session_id))
|
||||
|
||||
except APIError as e:
|
||||
logger.error("failed_to_use_item", session_id=session_id, item_id=item_id, error=str(e))
|
||||
return f'<div class="error">Failed to use item: {e}</div>', 500
|
||||
|
||||
|
||||
@game_bp.route('/session/<session_id>/inventory/equip', methods=['POST'])
|
||||
@require_auth
|
||||
def inventory_equip(session_id: str):
|
||||
"""Equip an item to a slot."""
|
||||
client = get_api_client()
|
||||
item_id = request.form.get('item_id')
|
||||
slot = request.form.get('slot')
|
||||
|
||||
if not item_id:
|
||||
return '<div class="error">No item selected</div>', 400
|
||||
|
||||
try:
|
||||
# Get session to find character
|
||||
session_response = client.get(f'/api/v1/sessions/{session_id}')
|
||||
session_data = session_response.get('result', {})
|
||||
character_id = session_data.get('character_id')
|
||||
|
||||
if not character_id:
|
||||
return '<div class="error">No character found</div>', 400
|
||||
|
||||
# Equip the item via API
|
||||
payload = {'item_id': item_id}
|
||||
if slot:
|
||||
payload['slot'] = slot
|
||||
|
||||
client.post(f'/api/v1/characters/{character_id}/inventory/equip', payload)
|
||||
|
||||
# Return updated character panel
|
||||
return redirect(url_for('game.character_panel', session_id=session_id))
|
||||
|
||||
except APIError as e:
|
||||
logger.error("failed_to_equip_item", session_id=session_id, item_id=item_id, error=str(e))
|
||||
return f'<div class="error">Failed to equip item: {e}</div>', 500
|
||||
|
||||
|
||||
@game_bp.route('/session/<session_id>/inventory/<item_id>', methods=['DELETE'])
|
||||
@require_auth
|
||||
def inventory_drop(session_id: str, item_id: str):
|
||||
"""Drop (delete) an item from inventory."""
|
||||
client = get_api_client()
|
||||
|
||||
try:
|
||||
# Get session to find character
|
||||
session_response = client.get(f'/api/v1/sessions/{session_id}')
|
||||
session_data = session_response.get('result', {})
|
||||
character_id = session_data.get('character_id')
|
||||
|
||||
if not character_id:
|
||||
return '<div class="error">No character found</div>', 400
|
||||
|
||||
# Delete the item via API
|
||||
client.delete(f'/api/v1/characters/{character_id}/inventory/{item_id}')
|
||||
|
||||
# Return updated inventory modal
|
||||
return redirect(url_for('game.inventory_modal', session_id=session_id))
|
||||
|
||||
except APIError as e:
|
||||
logger.error("failed_to_drop_item", session_id=session_id, item_id=item_id, error=str(e))
|
||||
return f'<div class="error">Failed to drop item: {e}</div>', 500
|
||||
|
||||
|
||||
@game_bp.route('/session/<session_id>/npc/<npc_id>/talk', methods=['POST'])
|
||||
@require_auth
|
||||
def talk_to_npc(session_id: str, npc_id: str):
|
||||
|
||||
Reference in New Issue
Block a user