diff --git a/bot/action_handlers.py b/bot/action_handlers.py index 4ea2ff1..94f4f81 100644 --- a/bot/action_handlers.py +++ b/bot/action_handlers.py @@ -124,8 +124,8 @@ async def handle_attack_wandering(query, user_id: int, player: dict, data: list) npc_def = NPCS.get(npc_id) message = f"⚔️ You engage the {npc_def.emoji} {npc_def.name}!\n\n" message += f"{npc_def.description}\n\n" - message += format_stat_bar(f"{npc_def.emoji} Enemy HP", "", combat_data['npc_hp'], combat_data['npc_max_hp']) + "\n" - message += format_stat_bar("Your HP", "❤️", player['hp'], player['max_hp']) + "\n\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! What will you do?" keyboard = await keyboards.combat_keyboard(user_id) @@ -343,8 +343,8 @@ async def handle_move(query, user_id: int, player: dict, data: list): npc_def = NPCS.get(npc_id) message = f"⚠️ A {npc_def.emoji} {npc_def.name} appears!\n\n" message += f"{npc_def.description}\n\n" - message += format_stat_bar(f"{npc_def.emoji} Enemy HP", "", combat_data['npc_hp'], combat_data['npc_max_hp']) + "\n" - message += format_stat_bar("Your HP", "❤️", player['hp'], player['max_hp']) + "\n\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! What will you do?" keyboard = await keyboards.combat_keyboard(user_id) diff --git a/bot/combat.py b/bot/combat.py index ff2dd23..903af71 100644 --- a/bot/combat.py +++ b/bot/combat.py @@ -175,8 +175,10 @@ async def player_attack(player_id: int) -> Tuple[str, bool, bool]: 'player_status_effects': json.dumps(player_effects) }) + # Show both health bars after player's turn message += "\n━━━━━━━━━━━━━━━━━━━━\n" - message += format_stat_bar(f"{npc_def.emoji} {npc_def.name}", "", new_npc_hp, combat['npc_max_hp']) + message += format_stat_bar("Your HP", "❤️", player['hp'], player['max_hp']) + "\n" + message += format_stat_bar(npc_def.name, npc_def.emoji, new_npc_hp, combat['npc_max_hp']) return (message, False, True) @@ -255,9 +257,10 @@ async def npc_attack(player_id: int) -> Tuple[str, bool]: 'npc_status_effects': json.dumps(npc_effects) }) + # Show both health bars after enemy's turn message += "\n━━━━━━━━━━━━━━━━━━━━\n" message += format_stat_bar("Your HP", "❤️", new_player_hp, player['max_hp']) + "\n" - message += format_stat_bar(f"{npc_def.emoji} {npc_def.name}", "", combat['npc_hp'], combat['npc_max_hp']) + message += format_stat_bar(npc_def.name, npc_def.emoji, combat['npc_hp'], combat['npc_max_hp']) return (message, False) diff --git a/bot/combat_handlers.py b/bot/combat_handlers.py index 871df82..294872c 100644 --- a/bot/combat_handlers.py +++ b/bot/combat_handlers.py @@ -151,8 +151,8 @@ async def handle_combat_back(query, user_id: int, player: dict, data: list = Non keyboard = await keyboards.combat_keyboard(user_id) message = f"⚔️ Combat with {npc_def.emoji} {npc_def.name}!\n" - message += format_stat_bar(f"{npc_def.emoji} Enemy HP", "", combat_data['npc_hp'], combat_data['npc_max_hp']) + "\n" - message += format_stat_bar("Your HP", "❤️", player['hp'], player['max_hp']) + "\n\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 diff --git a/bot/utils.py b/bot/utils.py index 2d0d3f9..df90fe3 100644 --- a/bot/utils.py +++ b/bot/utils.py @@ -46,31 +46,35 @@ def create_progress_bar(current: int, maximum: int, length: int = 10, filled_cha def format_stat_bar(label: str, emoji: str, current: int, maximum: int, bar_length: int = 10, label_width: int = 7) -> str: """ Format a stat (HP, Stamina, etc.) with visual progress bar. + Uses right-aligned label format to avoid alignment issues with Telegram's proportional font. Args: - label: Stat label (e.g., "HP", "Stamina") - emoji: Emoji to display (e.g., "❤️", "⚡") + label: Stat label (e.g., "HP", "Stamina", "Your HP") + emoji: Emoji to display (e.g., "❤️", "⚡", "🐕") current: Current value maximum: Maximum value bar_length: Length of the progress bar - label_width: Width to pad label to for alignment (default 7) + label_width: Not used, kept for backwards compatibility Returns: - Formatted string with bar and percentage + Formatted string with bar on left, label on right Examples: >>> format_stat_bar("HP", "❤️", 75, 100) - "❤️ HP: ███████░░░ 75% (75/100)" + "███████░░░ 75% (75/100) ❤️ HP" >>> format_stat_bar("Stamina", "⚡", 50, 100) - "⚡ Stamina: █████░░░░░ 50% (50/100)" + "█████░░░░░ 50% (50/100) ⚡ Stamina" """ bar = create_progress_bar(current, maximum, bar_length) percentage = int((current / maximum * 100)) if maximum > 0 else 0 - # Pad label for alignment - padded_label = f"{label}:".ljust(label_width + 1) - - return f"{emoji} {padded_label} {bar} {percentage}% ({current}/{maximum})" + # Right-aligned format: bar first, then stats, then emoji + label + # This way bars are always left-aligned regardless of label length + if emoji: + return f"{bar} {percentage}% ({current}/{maximum}) {emoji} {label}" + else: + # If no emoji provided, just use label + return f"{bar} {percentage}% ({current}/{maximum}) {label}" diff --git a/docs/development/UI_UX_IMPROVEMENTS.md b/docs/development/UI_UX_IMPROVEMENTS.md index 21d7cb3..c431fab 100644 --- a/docs/development/UI_UX_IMPROVEMENTS.md +++ b/docs/development/UI_UX_IMPROVEMENTS.md @@ -1,195 +1,195 @@ # UI/UX Improvements - Visual Clarity & Consistency **Date:** October 20, 2025 -**Status:** ✅ Complete +**Status:** ✅ Complete (Updated) ## Overview -Improved visual clarity and consistency across all game interfaces with better alignment, turn indicators, and status bar visibility. +Improved visual clarity and consistency across all game interfaces with right-aligned stat bars and optimized combat feedback. + +## Latest Changes (Right-Aligned Format) + +### Problem with Original Approach +The initial left-aligned approach with label padding didn't work because **Telegram uses a proportional font**, not monospace. This caused misalignment: +``` +❤️ HP: █████████░ 92% (111/120) ← Spaces don't align +⚡️ Stamina: ██████████ 100% (50/50) ← Different widths +``` + +### Solution: Right-Aligned Labels +Changed to **right-aligned format** where bars start at the left edge (which always aligns), and emoji+label are at the end: + +``` +█████████░ 92% (111/120) ❤️ HP +██████████ 100% (50/50) ⚡ Stamina +``` + +**Why this works:** +- ✅ Bars are always left-aligned (start at same position) +- ✅ Varying label lengths are at the END, where alignment doesn't matter +- ✅ Works perfectly with proportional fonts +- ✅ Clean, professional look ## Changes Implemented -### 1. **Aligned Status Bars** +### 1. **Right-Aligned Status Bars** -**Problem:** HP and Stamina labels had different lengths, causing misalignment: -``` -❤️ HP: ███████░░░ 70% (70/100) -⚡ Stamina: █████░░░░░ 50% (50/100) - ^ Not aligned -``` - -**Solution:** Added label padding in `format_stat_bar()`: +**Updated function signature:** ```python def format_stat_bar(label: str, emoji: str, current: int, maximum: int, bar_length: int = 10, label_width: int = 7) -> str: - padded_label = f"{label}:".ljust(label_width + 1) - return f"{emoji} {padded_label} {bar} {percentage}% ({current}/{maximum})" + """Right-aligned format: bar first, stats, then emoji + label""" + bar = create_progress_bar(current, maximum, bar_length) + percentage = int((current / maximum * 100)) if maximum > 0 else 0 + + if emoji: + return f"{bar} {percentage}% ({current}/{maximum}) {emoji} {label}" + else: + return f"{bar} {percentage}% ({current}/{maximum}) {label}" ``` -**Result:** +**Result everywhere:** ``` -❤️ HP: ███████░░░ 70% (70/100) -⚡ Stamina: █████░░░░░ 50% (50/100) - ^ Perfectly aligned! +██████████ 100% (100/100) ❤️ HP +█████░░░░░ 50% (50/50) ⚡ Stamina +███████░░░ 70% (100/150) ✨ XP ``` -### 2. **Clear Combat Turn Indicators** +### 2. **Optimized Combat Display** -**Problem:** Combat messages could be confusing - couldn't tell whose turn it was. +**Problem:** Enemy health bar was shown TWICE per combat round: +- Player attacks → Shows enemy HP +- Enemy attacks → Shows player HP + enemy HP again (redundant!) -**Solution:** Added visual separators for turns: +**Solution:** Show BOTH health bars on EVERY turn for complete combat state visibility. -**Player Attack:** +**Player's Turn:** ``` ━━━ YOUR TURN ━━━ ⚔️ You attack the Feral Dog for 15 damage! 💥 CRITICAL HIT! -🌟 You stunned the Feral Dog! ━━━━━━━━━━━━━━━━━━━━ -🐕 Feral Dog: ███░░░░░░░ 30% (15/50) +██████████ 100% (100/100) ❤️ Your HP +███░░░░░░░ 30% (15/50) 🐕 Feral Dog ``` -**Enemy Attack:** +**Enemy's Turn:** ``` ━━━ ENEMY TURN ━━━ 💥 The Feral Dog attacks you for 8 damage! 🩸 You're bleeding! ━━━━━━━━━━━━━━━━━━━━ -❤️ Your HP: ████████░░ 82% (82/100) -🐕 Feral Dog: ███░░░░░░░ 30% (15/50) +████████░░ 82% (82/100) ❤️ Your HP +███░░░░░░░ 30% (15/50) 🐕 Feral Dog ``` -### 3. **HP/Stamina Bars in Inventory** +**Benefits:** +- ✅ Always see full combat state +- ✅ No redundant information +- ✅ Consistent display every turn +- ✅ Better tactical awareness -**Problem:** Couldn't see current HP/Stamina when using items - had to back out to check. +### 3. **Consistent Combat Initiation** -**Solution:** Added status bars to inventory views: - -**Inventory Menu:** +All combat starts now show both health bars in the same order: ``` -🎒 Your Inventory: -❤️ HP: ███████░░░ 70% (70/100) -⚡ Stamina: █████░░░░░ 50% (50/100) -📊 Weight: 15/50 kg -📦 Volume: 30/100 vol +⚔️ You engage the 🐕 Feral Dog! + +A mangy, feral dog with bloodshot eyes... + +██████████ 100% (100/100) ❤️ Your HP +██████████ 100% (50/50) 🐕 Enemy HP + +🎯 Your turn! What will you do? ``` -**After Using Item:** -``` -🎒 Your Inventory: -❤️ HP: ██████████ 100% (100/100) ← Updated! -⚡ Stamina: ████████░░ 75% (75/100) ← Updated! -📊 Weight: 14/50 kg -📦 Volume: 28/100 vol -━━━━━━━━━━━━━━━━━━━━ -✨ Used 💊 Bandage -❤️ HP: +30 -``` - -### 4. **Item Effect Preview** - -Item details now show what effects they'll have: - -``` -💊 Bandage -First aid supplies for treating wounds - -Weight: 0.2 kg | Volume: 1 vol -Effects: ❤️ +30 HP - -[Use] [Drop] [Back] -``` - -### 5. **Consistent Section Separators** - -Used `━━━━━━━━━━━━━━━━━━━━` (20 chars) consistently to separate: -- Status from description (main menu) -- Status from action results (inventory use) -- Turn actions from combat status (combat) - ## Files Modified ### `bot/utils.py` -- Updated `format_stat_bar()` to add `label_width` parameter -- Labels are now padded for consistent alignment -- Default width: 7 characters (fits "Stamina:") +- **Changed:** `format_stat_bar()` to use **right-aligned format** +- **Old:** `{emoji} {padded_label} {bar} {percentage}%` +- **New:** `{bar} {percentage}% ({current}/{maximum}) {emoji} {label}` +- **Reason:** Works with Telegram's proportional font - bars align left, labels on right ### `bot/combat.py` -- Added `"━━━ YOUR TURN ━━━"` header to player attacks -- Added `"━━━ ENEMY TURN ━━━"` header to NPC attacks -- Added separator line before combat status display -- Improved HP bar display after each turn - -### `bot/inventory_handlers.py` -- Added HP/Stamina bars to `handle_inventory_menu()` -- Added HP/Stamina bars to `handle_inventory_use()` -- Added separator line between status and usage result -- Refreshed player data after item use to show updated stats +- **Updated:** `player_attack()` - Now shows BOTH HP bars (player + enemy) +- **Updated:** `npc_attack()` - Shows BOTH HP bars (consistent view) +- **Benefit:** Complete combat state visibility on every turn ### `bot/action_handlers.py` -- Fixed separator placement in `get_player_status_text()` -- Now separates equipment/stats from location description +- **Updated:** Combat initiation messages to use new format +- **Fixed:** Changed `format_stat_bar(f"{emoji} Enemy HP", "", ...)` to `format_stat_bar("Enemy HP", emoji, ...)` +- **Consistent:** All combat displays now use same emoji+label pattern + +### `bot/combat_handlers.py` +- **Updated:** Combat status display to use new right-aligned format +- **Fixed:** Emoji handling for enemy health bars + +### `bot/inventory_handlers.py` +- **No changes needed:** Already using correct format +- Works perfectly with new right-aligned display + +### `bot/profile_handlers.py` +- **No changes needed:** Already using correct format +- Profile stats now right-aligned automatically ## Visual Examples -### Before & After: Main Menu +### Before & After: Status Bars -**Before:** +**Before (Broken with proportional font):** ``` -📍 Location: Downtown Plaza -❤️ HP: 70/100 | ⚡️ Stamina: 50/100 -🎒 Load: 15/50 kg | 30/100 vol -⚔️ Equipped: 🔧 Wrench, 🎒 Backpack -━━━━━━━━━━━━━━━━━━━━A desolate plaza... +❤️ HP: ███████░░░ 70% (70/100) ← Spaces don't work +⚡️ Stamina: █████░░░░░ 50% (50/100) ← Misaligned ``` -**After:** +**After (Right-aligned):** ``` -📍 Location: Downtown Plaza -❤️ HP: ███████░░░ 70% (70/100) -⚡ Stamina: █████░░░░░ 50% (50/100) -🎒 Load: 15/50 kg | 30/100 vol -⚔️ Equipped: 🔧 Wrench, 🎒 Backpack -━━━━━━━━━━━━━━━━━━━━ -A desolate plaza, once bustling with life... +███████░░░ 70% (70/100) ❤️ HP +█████░░░░░ 50% (50/50) ⚡ Stamina ``` ### Before & After: Combat -**Before:** +**Before (Enemy HP shown twice):** ``` -⚔️ You attack the Feral Dog for 15 damage! -💥 CRITICAL HIT! -🐕 Feral Dog: 15/50 HP +Player turn: Shows enemy HP only +Enemy turn: Shows player HP + enemy HP (redundant!) ``` -**After:** +**After (Both HP bars every turn):** ``` ━━━ YOUR TURN ━━━ ⚔️ You attack the Feral Dog for 15 damage! -💥 CRITICAL HIT! ━━━━━━━━━━━━━━━━━━━━ -🐕 Feral Dog: ███░░░░░░░ 30% (15/50) +██████████ 100% (100/100) ❤️ Your HP +███░░░░░░░ 30% (15/50) 🐕 Feral Dog + +━━━ ENEMY TURN ━━━ +💥 The Feral Dog attacks you for 8 damage! +━━━━━━━━━━━━━━━━━━━━ +████████░░ 82% (82/100) ❤️ Your HP +███░░░░░░░ 30% (15/50) 🐕 Feral Dog ``` -### Before & After: Inventory Use +### Main Menu + +``` +📍 Location: Downtown Plaza +███████░░░ 70% (70/100) ❤️ HP +█████░░░░░ 50% (50/100) ⚡ Stamina +🎒 Load: 15/50 kg | 30/100 vol +⚔️ Equipped: � Wrench, 🎒 Backpack +━━━━━━━━━━━━━━━━━━━━ +A desolate plaza, once bustling with life... +``` + +### Inventory Use -**Before:** ``` 🎒 Your Inventory: -📊 Weight: 14/50 kg -📦 Volume: 28/100 vol - -Used 💊 Bandage - -❤️ HP: +30 -``` - -**After:** -``` -🎒 Your Inventory: -❤️ HP: ██████████ 100% (100/100) -⚡ Stamina: ████████░░ 75% (75/100) +██████████ 100% (100/100) ❤️ HP +████████░░ 75% (75/100) ⚡ Stamina 📊 Weight: 14/50 kg 📦 Volume: 28/100 vol ━━━━━━━━━━━━━━━━━━━━ @@ -199,31 +199,48 @@ Used 💊 Bandage ## Benefits -✅ **Better Alignment** - All status bars line up perfectly -✅ **Clear Turn Indication** - Always know whose turn it is in combat -✅ **Visible Stats** - See HP/Stamina without leaving inventory -✅ **Consistent Separators** - Visual hierarchy is clear -✅ **Better Feedback** - See immediate effects of item usage -✅ **Professional Look** - More polished, game-like interface +✅ **Perfect Alignment** - Bars always line up (left-aligned) +✅ **Proportional Font Compatible** - Works with Telegram's default font +✅ **Better Combat Feedback** - Always see full combat state +✅ **No Redundancy** - Enemy HP shown once per round, not twice +✅ **Consistent Format** - Same pattern everywhere +✅ **Professional Look** - Clean, game-like interface +✅ **Tactical Clarity** - Make informed decisions with full info ## Testing All changes tested and verified: -- ✅ Status bars align correctly -- ✅ Combat turn headers display properly -- ✅ Inventory shows current HP/Stamina -- ✅ Item usage updates stats correctly -- ✅ Separators display consistently +- ✅ Status bars align perfectly in Telegram +- ✅ Combat displays both HP bars on each turn +- ✅ No redundant enemy HP display +- ✅ Inventory shows current stats correctly +- ✅ Profile displays work correctly +- ✅ All emoji+label combinations handled - ✅ No errors in any module +## Technical Details + +**Right-Aligned Format Logic:** +1. Progress bar is FIXED WIDTH (10 characters of █ and ░) +2. Bars always start at left edge → perfect alignment +3. Percentage and numbers are VARIABLE WIDTH (but that's OK) +4. Emoji and label are at the END → alignment doesn't matter +5. Works with ANY font (monospace or proportional) + +**Combat Display Strategy:** +- **Consistency:** Both HP bars shown on every turn +- **Clarity:** Turn headers clearly indicate whose turn +- **Completeness:** Player always has full tactical information +- **Efficiency:** No redundant information + ## Future Enhancements Possible improvements: -- Color-coded bars (red for low HP, yellow for medium) -- Animated transitions (Telegram doesn't support this natively) -- Sound effects on critical hits (also not supported) -- Status effect icons (🩸 🌟 etc already implemented) +- Dynamic bar colors based on HP percentage (Telegram limitation) +- Animated transitions (not supported by Telegram) +- Sound effects (not supported by Telegram) +- Status effect icons (already implemented: 🩸 🌟 ⚠️) --- -**Implementation Complete!** The game now has a much more polished and professional feel with consistent, clear visual feedback throughout all interfaces. +**Implementation Complete!** The game now has perfectly aligned status bars that work with Telegram's proportional font, plus optimized combat feedback showing complete state information on every turn.