- Implement visual HP/Stamina/XP bars using Unicode characters (██░) - Refactor handlers.py (1308 → 377 lines) into specialized modules: * action_handlers.py - World interaction and status display * inventory_handlers.py - Inventory management * combat_handlers.py - Combat actions * profile_handlers.py - Character stats with visual bars * corpse_handlers.py - Looting system * pickup_handlers.py - Item collection - Add utility functions: create_progress_bar(), format_stat_bar() - Organize all documentation into docs/ structure - Create comprehensive documentation index with navigation - Add UI examples showing before/after visual improvements
7.5 KiB
7.5 KiB
Bot Module Documentation
Overview
The bot module contains all the Telegram bot logic for "Echoes of the Ashes" RPG game.
Module Structure
Core Modules
handlers.py(14KB) - Main message router and utility functionsdatabase.py- Database operations and querieskeyboards.py- Telegram keyboard layoutslogic.py- Game logic and calculationscombat.py(17KB) - Combat system implementationspawn_manager.py- Enemy spawning systemutils.py- Utility functions and decorators
Handler Modules (Refactored)
Organized by functionality for better maintainability:
action_handlers.py (14KB, 367 lines)
World interaction and inspection
get_player_status_text()- Player status displayhandle_inspect_area()- Inspect locationshandle_attack_wandering()- Attack wandering enemieshandle_inspect_interactable()- Inspect objectshandle_action()- Perform actionshandle_main_menu()- Main menu navigationhandle_move_menu()- Movement menuhandle_move()- Travel between locations
inventory_handlers.py (13KB, 355 lines)
Inventory management system
handle_inventory_menu()- Show inventoryhandle_inventory_item()- Item detailshandle_inventory_use()- Use consumableshandle_inventory_drop()- Drop itemshandle_inventory_equip()- Equip gearhandle_inventory_unequip()- Unequip gear
pickup_handlers.py (5.1KB, 135 lines)
Item collection from world
handle_pickup_menu()- Pickup optionshandle_pickup()- Pick up items
combat_handlers.py (6.3KB, 171 lines)
Combat action handlers
handle_combat_attack()- Attack enemyhandle_combat_flee()- Flee combathandle_combat_use_item_menu()- Combat items menuhandle_combat_use_item()- Use item in combathandle_combat_back()- Return to combat menu
profile_handlers.py (6.0KB, 147 lines)
Character progression
handle_profile()- View profilehandle_spend_points_menu()- Stat points menuhandle_spend_point()- Allocate stat points
corpse_handlers.py (8.2KB, 234 lines)
Looting system
handle_loot_player_corpse()- Loot player corpseshandle_take_corpse_item()- Take items from player corpsehandle_scavenge_npc_corpse()- Scavenge NPC corpseshandle_scavenge_corpse_item()- Take items from NPC corpse
Architecture
Message Flow
Telegram Update
↓
main.py (Application setup)
↓
handlers.py::button_handler (Router)
↓
Specialized Handler (action_handlers, combat_handlers, etc.)
↓
database.py (Data operations)
↓
keyboards.py (UI response)
↓
Response to User
Handler Pattern
All handlers follow a consistent pattern:
async def handle_action(query, user_id: int, player: dict, data: list = None):
"""
Handle specific action.
Args:
query: Telegram callback query object
user_id: Telegram user ID
player: Player data dict
data: Optional list of parameters from callback_data
"""
# 1. Validate input
# 2. Perform action
# 3. Update database
# 4. Send response with send_or_edit_with_image()
Shared Utilities
send_or_edit_with_image()
Central function for sending/editing messages with images:
await send_or_edit_with_image(
query,
text="Message text",
reply_markup=keyboard,
image_path="/path/to/image.png" # Optional
)
Features:
- Smooth image transitions
- Image caching for performance
- Automatic fallback to text-only
- Edit vs. send detection
Design Principles
1. Separation of Concerns
Each module handles a specific domain:
- Handlers → User interaction
- Database → Data persistence
- Logic → Game rules
- Combat → Battle mechanics
2. Single Responsibility
Each function has one clear purpose:
- ✅
handle_inventory_use()- Use items - ✅
handle_combat_attack()- Attack in combat - ❌
One giant function that does everything
3. Consistency
All handlers:
- Accept same parameter pattern
- Use async/await
- Handle errors gracefully
- Log important actions
4. Error Handling
Centralized in button_handler:
try:
await handle_specific_action(...)
except Exception as e:
logger.error(f"Error: {e}", exc_info=True)
await query.answer("An error occurred.", show_alert=True)
Adding New Handlers
Step 1: Create Handler Function
# In appropriate *_handlers.py module
async def handle_new_action(query, user_id: int, player: dict, data: list):
"""Handle new action."""
await query.answer()
# Your logic here
from .handlers import send_or_edit_with_image
await send_or_edit_with_image(
query,
text="Action result",
reply_markup=some_keyboard()
)
Step 2: Import in handlers.py
from .your_handlers import handle_new_action
Step 3: Add Route
# In button_handler()
elif action_type == "new_action":
await handle_new_action(query, user_id, player, data)
Step 4: Create Keyboard Button
# In keyboards.py
InlineKeyboardButton(
"New Action",
callback_data="new_action:param1:param2"
)
Testing
Manual Testing
- Start the bot:
python main.py - Send
/startto the bot - Test each button action
- Check logs for errors
Unit Testing (Future)
# tests/test_handlers.py
async def test_handle_inventory_use():
result = await handle_inventory_use(
mock_query,
user_id=123,
player=mock_player,
data=['inventory_use', '1']
)
assert result is not None
Performance Considerations
Image Caching
Images are cached after first upload:
cached_file_id = await database.get_cached_image(image_path)
if not cached_file_id:
# Upload and cache
await database.cache_image(image_path, file_id)
Database Queries
- Use indexed lookups (user_id, location_id)
- Batch operations where possible
- Async all the way
Memory
- Don't store large objects in memory
- Use database for persistence
- Clean up old data periodically
Debugging
Enable Debug Logging
# In main.py
logging.basicConfig(
level=logging.DEBUG, # Change from INFO
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
Common Issues
Issue: Handler not being called
- Check callback_data format:
"action_type:param1:param2" - Verify route exists in
button_handler() - Check import statement
Issue: Image not showing
- Verify image path exists
- Check image cache
- Look for upload errors in logs
Issue: Database errors
- Check player exists
- Verify foreign key relationships
- Look at database schema
Migration Guide
From Old handlers.py
Old code in backup files:
backups/handlers_original.pybackups/handlers.py.old
All functionality preserved, just reorganized into modules.
Future Enhancements
- Type Hints - Add proper type annotations
- Unit Tests - Test coverage for all handlers
- Decorators - Common validations (requires_combat, requires_stamina)
- Base Classes - Handler base class with common functionality
- Event System - Decouple actions from responses
Contributing
When adding new features:
- Choose the appropriate handler module (or create new one)
- Follow the existing pattern
- Add docstrings
- Log important actions
- Handle errors gracefully
- Update this documentation
Questions?
See also:
REFACTORING_NOTES.md- Refactoring detailsHANDLER_REFACTORING_SUMMARY.md- Before/after comparisonREADME.md- Project overview