Add visual progress bars and refactor handler modules
- 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
This commit is contained in:
298
docs/development/BOT_MODULE.md
Normal file
298
docs/development/BOT_MODULE.md
Normal file
@@ -0,0 +1,298 @@
|
||||
# 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 functions
|
||||
- **`database.py`** - Database operations and queries
|
||||
- **`keyboards.py`** - Telegram keyboard layouts
|
||||
- **`logic.py`** - Game logic and calculations
|
||||
- **`combat.py`** (17KB) - Combat system implementation
|
||||
- **`spawn_manager.py`** - Enemy spawning system
|
||||
- **`utils.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 display
|
||||
- `handle_inspect_area()` - Inspect locations
|
||||
- `handle_attack_wandering()` - Attack wandering enemies
|
||||
- `handle_inspect_interactable()` - Inspect objects
|
||||
- `handle_action()` - Perform actions
|
||||
- `handle_main_menu()` - Main menu navigation
|
||||
- `handle_move_menu()` - Movement menu
|
||||
- `handle_move()` - Travel between locations
|
||||
|
||||
#### **`inventory_handlers.py`** (13KB, 355 lines)
|
||||
Inventory management system
|
||||
- `handle_inventory_menu()` - Show inventory
|
||||
- `handle_inventory_item()` - Item details
|
||||
- `handle_inventory_use()` - Use consumables
|
||||
- `handle_inventory_drop()` - Drop items
|
||||
- `handle_inventory_equip()` - Equip gear
|
||||
- `handle_inventory_unequip()` - Unequip gear
|
||||
|
||||
#### **`pickup_handlers.py`** (5.1KB, 135 lines)
|
||||
Item collection from world
|
||||
- `handle_pickup_menu()` - Pickup options
|
||||
- `handle_pickup()` - Pick up items
|
||||
|
||||
#### **`combat_handlers.py`** (6.3KB, 171 lines)
|
||||
Combat action handlers
|
||||
- `handle_combat_attack()` - Attack enemy
|
||||
- `handle_combat_flee()` - Flee combat
|
||||
- `handle_combat_use_item_menu()` - Combat items menu
|
||||
- `handle_combat_use_item()` - Use item in combat
|
||||
- `handle_combat_back()` - Return to combat menu
|
||||
|
||||
#### **`profile_handlers.py`** (6.0KB, 147 lines)
|
||||
Character progression
|
||||
- `handle_profile()` - View profile
|
||||
- `handle_spend_points_menu()` - Stat points menu
|
||||
- `handle_spend_point()` - Allocate stat points
|
||||
|
||||
#### **`corpse_handlers.py`** (8.2KB, 234 lines)
|
||||
Looting system
|
||||
- `handle_loot_player_corpse()` - Loot player corpses
|
||||
- `handle_take_corpse_item()` - Take items from player corpse
|
||||
- `handle_scavenge_npc_corpse()` - Scavenge NPC corpses
|
||||
- `handle_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:
|
||||
|
||||
```python
|
||||
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:
|
||||
```python
|
||||
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`:
|
||||
```python
|
||||
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
|
||||
```python
|
||||
# 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
|
||||
```python
|
||||
from .your_handlers import handle_new_action
|
||||
```
|
||||
|
||||
### Step 3: Add Route
|
||||
```python
|
||||
# In button_handler()
|
||||
elif action_type == "new_action":
|
||||
await handle_new_action(query, user_id, player, data)
|
||||
```
|
||||
|
||||
### Step 4: Create Keyboard Button
|
||||
```python
|
||||
# In keyboards.py
|
||||
InlineKeyboardButton(
|
||||
"New Action",
|
||||
callback_data="new_action:param1:param2"
|
||||
)
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
### Manual Testing
|
||||
1. Start the bot: `python main.py`
|
||||
2. Send `/start` to the bot
|
||||
3. Test each button action
|
||||
4. Check logs for errors
|
||||
|
||||
### Unit Testing (Future)
|
||||
```python
|
||||
# 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:
|
||||
```python
|
||||
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
|
||||
```python
|
||||
# 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.py`
|
||||
- `backups/handlers.py.old`
|
||||
|
||||
All functionality preserved, just reorganized into modules.
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
1. **Type Hints** - Add proper type annotations
|
||||
2. **Unit Tests** - Test coverage for all handlers
|
||||
3. **Decorators** - Common validations (requires_combat, requires_stamina)
|
||||
4. **Base Classes** - Handler base class with common functionality
|
||||
5. **Event System** - Decouple actions from responses
|
||||
|
||||
## Contributing
|
||||
|
||||
When adding new features:
|
||||
1. Choose the appropriate handler module (or create new one)
|
||||
2. Follow the existing pattern
|
||||
3. Add docstrings
|
||||
4. Log important actions
|
||||
5. Handle errors gracefully
|
||||
6. Update this documentation
|
||||
|
||||
## Questions?
|
||||
|
||||
See also:
|
||||
- `REFACTORING_NOTES.md` - Refactoring details
|
||||
- `HANDLER_REFACTORING_SUMMARY.md` - Before/after comparison
|
||||
- `README.md` - Project overview
|
||||
Reference in New Issue
Block a user