- 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
299 lines
7.5 KiB
Markdown
299 lines
7.5 KiB
Markdown
# 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
|