When using combat abilities (like "smite"), the web frontend was calling GET /api/v1/abilities/{ability_id} to fetch ability details for display, but this endpoint didn't exist, causing a 404 error.
Additionally, after fixing that, the ability would execute but:
1. Modal onclick issue: The onclick="closeModal()" on ability buttons was removing the button from the DOM before HTMX could fire the request
2. Field name mismatch: The API returns mana_cost but the frontend expected mp_cost
3. Duplicate text in combat log: The web view was adding "You" as actor and damage separately, but the API message already contained both
4. Page not auto-refreshing: Various attempts to use HX-Trigger headers failed due to HTMX overwriting them
Fixes Made
1. Created /api/app/api/abilities.py - New abilities API endpoint with GET /api/v1/abilities and GET /api/v1/abilities/<ability_id>
2. Modified /api/app/__init__.py - Registered the new abilities blueprint
3. Modified /public_web/templates/game/partials/ability_modal.html - Changed onclick="closeModal()" to hx-on::before-request="closeModal()" so HTMX captures the request before modal closes
4. Modified /public_web/app/views/combat_views.py:
- Fixed mp_cost → mana_cost field name lookup
- Removed duplicate actor/damage from combat log entries (API message is self-contained)
- Added inline script to trigger page refresh after combat actions
5. Modified /public_web/templates/game/combat.html - Updated JavaScript for combat action handling (though final fix was server-side script injection)
130 lines
3.4 KiB
Python
130 lines
3.4 KiB
Python
"""
|
|
Abilities API Blueprint
|
|
|
|
This module provides API endpoints for fetching ability information:
|
|
- List all available abilities
|
|
- Get details for a specific ability
|
|
"""
|
|
|
|
from flask import Blueprint
|
|
|
|
from app.models.abilities import AbilityLoader
|
|
from app.utils.response import (
|
|
success_response,
|
|
not_found_response,
|
|
)
|
|
from app.utils.logging import get_logger
|
|
|
|
|
|
# Initialize logger
|
|
logger = get_logger(__file__)
|
|
|
|
# Create blueprint
|
|
abilities_bp = Blueprint('abilities', __name__, url_prefix='/api/v1/abilities')
|
|
|
|
# Initialize ability loader (singleton pattern)
|
|
_ability_loader = None
|
|
|
|
|
|
def get_ability_loader() -> AbilityLoader:
|
|
"""
|
|
Get the singleton AbilityLoader instance.
|
|
|
|
Returns:
|
|
AbilityLoader: The ability loader instance
|
|
"""
|
|
global _ability_loader
|
|
if _ability_loader is None:
|
|
_ability_loader = AbilityLoader()
|
|
return _ability_loader
|
|
|
|
|
|
# =============================================================================
|
|
# Ability Endpoints
|
|
# =============================================================================
|
|
|
|
@abilities_bp.route('', methods=['GET'])
|
|
def list_abilities():
|
|
"""
|
|
List all available abilities.
|
|
|
|
Returns all abilities defined in the system with their full details.
|
|
|
|
Returns:
|
|
{
|
|
"abilities": [
|
|
{
|
|
"ability_id": "smite",
|
|
"name": "Smite",
|
|
"description": "Call down holy light...",
|
|
"ability_type": "spell",
|
|
"base_power": 20,
|
|
"damage_type": "holy",
|
|
"mana_cost": 10,
|
|
"cooldown": 0,
|
|
...
|
|
},
|
|
...
|
|
],
|
|
"count": 5
|
|
}
|
|
"""
|
|
logger.info("Listing all abilities")
|
|
|
|
loader = get_ability_loader()
|
|
abilities = loader.load_all_abilities()
|
|
|
|
# Convert to list of dicts for JSON serialization
|
|
abilities_list = [ability.to_dict() for ability in abilities.values()]
|
|
|
|
logger.info("Abilities listed", count=len(abilities_list))
|
|
|
|
return success_response({
|
|
"abilities": abilities_list,
|
|
"count": len(abilities_list)
|
|
})
|
|
|
|
|
|
@abilities_bp.route('/<ability_id>', methods=['GET'])
|
|
def get_ability(ability_id: str):
|
|
"""
|
|
Get details for a specific ability.
|
|
|
|
Args:
|
|
ability_id: The unique identifier for the ability (e.g., "smite")
|
|
|
|
Returns:
|
|
{
|
|
"ability_id": "smite",
|
|
"name": "Smite",
|
|
"description": "Call down holy light to smite your enemies",
|
|
"ability_type": "spell",
|
|
"base_power": 20,
|
|
"damage_type": "holy",
|
|
"scaling_stat": "wisdom",
|
|
"scaling_factor": 0.5,
|
|
"mana_cost": 10,
|
|
"cooldown": 0,
|
|
"effects_applied": [],
|
|
"is_aoe": false,
|
|
"target_count": 1
|
|
}
|
|
|
|
Errors:
|
|
404: Ability not found
|
|
"""
|
|
logger.info("Getting ability", ability_id=ability_id)
|
|
|
|
loader = get_ability_loader()
|
|
ability = loader.load_ability(ability_id)
|
|
|
|
if ability is None:
|
|
logger.warning("Ability not found", ability_id=ability_id)
|
|
return not_found_response(
|
|
message=f"Ability '{ability_id}' not found"
|
|
)
|
|
|
|
logger.info("Ability retrieved", ability_id=ability_id, name=ability.name)
|
|
|
|
return success_response(ability.to_dict())
|