Files
echoes-of-the-ash/bot/combat_handlers.py
Joan c78c902b82 UI/UX: Fix alignment with right-aligned stat bars + optimize combat display
BREAKING: Changed format_stat_bar() to right-aligned format
- Bars now left-aligned, emoji+label on right
- Works with Telegram's proportional font (spaces don't work)
- Format: {bar} {percentage}% ({current}/{max}) {emoji} {label}

Combat improvements:
- Show BOTH HP bars on every turn (player + enemy)
- Eliminates redundant enemy HP display
- Better tactical awareness with complete state info

Files modified:
- bot/utils.py: Right-aligned format_stat_bar()
- bot/combat.py: Both HP bars on player/enemy turns
- bot/action_handlers.py: Fixed emoji handling
- bot/combat_handlers.py: Updated combat status display
- docs/development/UI_UX_IMPROVEMENTS.md: Complete documentation

Example output:
██████████ 100% (100/100) ❤️ Your HP
███░░░░░░░ 30% (15/50) 🐕 Feral Dog
2025-10-20 12:58:41 +02:00

165 lines
6.0 KiB
Python

"""
Combat-related action handlers.
"""
import logging
from . import database, keyboards
from .utils import format_stat_bar
from data.world_loader import game_world
logger = logging.getLogger(__name__)
async def handle_combat_attack(query, user_id: int, player: dict, data: list = None):
"""Handle player attack action in combat."""
from bot import combat
await query.answer()
message, npc_died, turn_ended = await combat.player_attack(user_id)
if npc_died:
# Combat ended - return to main menu
location = game_world.get_location(player['location_id'])
location_image = location.image_path if location else None
from .handlers import send_or_edit_with_image
await send_or_edit_with_image(
query,
text=message,
reply_markup=keyboards.main_menu_keyboard(),
image_path=location_image
)
elif turn_ended:
# NPC's turn - auto-attack
npc_message, player_died = await combat.npc_attack(user_id)
message += "\n\n" + npc_message
if player_died:
from .handlers import send_or_edit_with_image
await send_or_edit_with_image(query, text=message, reply_markup=None)
else:
combat_data = await database.get_combat(user_id)
if combat_data:
from data.npcs import NPCS
npc_def = NPCS.get(combat_data['npc_id'])
keyboard = await keyboards.combat_keyboard(user_id)
from .handlers import send_or_edit_with_image
await send_or_edit_with_image(
query,
text=message,
reply_markup=keyboard,
image_path=npc_def.image_url if npc_def else None
)
else:
await query.answer(message, show_alert=False)
async def handle_combat_flee(query, user_id: int, player: dict, data: list = None):
"""Handle flee attempt from combat."""
from bot import combat
await query.answer()
message, fled, turn_ended = await combat.flee_attempt(user_id)
if fled:
# Successfully fled - return to main menu
location = game_world.get_location(player['location_id'])
location_image = location.image_path if location else None
from .handlers import send_or_edit_with_image
await send_or_edit_with_image(
query,
text=message,
reply_markup=keyboards.main_menu_keyboard(),
image_path=location_image
)
elif turn_ended:
# Failed to flee - NPC attacks
npc_message, player_died = await combat.npc_attack(user_id)
message += "\n\n" + npc_message
if player_died:
from .handlers import send_or_edit_with_image
await send_or_edit_with_image(query, text=message, reply_markup=None)
else:
combat_data = await database.get_combat(user_id)
if combat_data:
from data.npcs import NPCS
npc_def = NPCS.get(combat_data['npc_id'])
keyboard = await keyboards.combat_keyboard(user_id)
from .handlers import send_or_edit_with_image
await send_or_edit_with_image(
query,
text=message,
reply_markup=keyboard,
image_path=npc_def.image_url if npc_def else None
)
else:
await query.answer(message, show_alert=False)
async def handle_combat_use_item_menu(query, user_id: int, player: dict, data: list = None):
"""Show menu of usable items during combat."""
await query.answer()
async def handle_combat_use_item(query, user_id: int, player: dict, data: list):
"""Use an item during combat."""
from bot import combat
item_db_id = int(data[1])
message, turn_ended = await combat.use_item_in_combat(user_id, item_db_id)
await query.answer(message, show_alert=False)
if turn_ended:
# NPC's turn
npc_message, player_died = await combat.npc_attack(user_id)
if player_died:
from .handlers import send_or_edit_with_image
await send_or_edit_with_image(
query,
text=message + "\n\n" + npc_message,
reply_markup=None
)
else:
combat_data = await database.get_combat(user_id)
if combat_data:
from data.npcs import NPCS
npc_def = NPCS.get(combat_data['npc_id'])
keyboard = await keyboards.combat_keyboard(user_id)
full_message = message + "\n\n" + npc_message + "\n\n🎯 Your turn!"
from .handlers import send_or_edit_with_image
await send_or_edit_with_image(
query,
text=full_message,
reply_markup=keyboard,
image_path=npc_def.image_url if npc_def else None
)
async def handle_combat_back(query, user_id: int, player: dict, data: list = None):
"""Return to combat menu from item selection."""
await query.answer()
combat_data = await database.get_combat(user_id)
if combat_data:
from data.npcs import NPCS
npc_def = NPCS.get(combat_data['npc_id'])
keyboard = await keyboards.combat_keyboard(user_id)
message = f"⚔️ Combat with {npc_def.emoji} {npc_def.name}!\n"
message += format_stat_bar("Your HP", "❤️", player['hp'], player['max_hp']) + "\n"
message += format_stat_bar("Enemy HP", npc_def.emoji, combat_data['npc_hp'], combat_data['npc_max_hp']) + "\n\n"
message += "🎯 Your turn!" if combat_data['turn'] == 'player' else "⏳ Enemy's turn..."
from .handlers import send_or_edit_with_image
await send_or_edit_with_image(
query,
text=message,
reply_markup=keyboard,
image_path=npc_def.image_url if npc_def else None
)