""" Main handlers for the Telegram bot. This module contains the core button callback routing. All other functionality is organized in separate modules: - action_handlers.py - World interaction handlers - inventory_handlers.py - Inventory management - combat_handlers.py - Combat actions - profile_handlers.py - Character stats - corpse_handlers.py - Looting system - pickup_handlers.py - Item collection - message_utils.py - Message sending/editing utilities - commands.py - Slash command handlers """ import logging from telegram import Update from telegram.ext import ContextTypes from .message_utils import send_or_edit_with_image # Import organized action handlers from .action_handlers import ( handle_inspect_area, handle_attack_wandering, handle_inspect_interactable, handle_action, handle_main_menu, handle_move_menu, handle_move ) from .inventory_handlers import ( handle_inventory_menu, handle_inventory_item, handle_inventory_use, handle_inventory_drop, handle_inventory_equip, handle_inventory_unequip ) from .pickup_handlers import ( handle_pickup_menu, handle_pickup ) from .combat_handlers import ( handle_combat_attack, handle_combat_flee, handle_combat_use_item_menu, handle_combat_use_item, handle_combat_back ) from .profile_handlers import ( handle_profile, handle_spend_points_menu, handle_spend_point ) from .corpse_handlers import ( handle_loot_player_corpse, handle_take_corpse_item, handle_scavenge_npc_corpse, handle_scavenge_corpse_item ) # Import command handlers (for main.py to register) from .commands import start, export_map, spawn_stats logger = logging.getLogger(__name__) # ============================================================================ # HANDLER REGISTRY # ============================================================================ # Map of action types to their handler functions # All handlers have signature: async def handle_*(query, user_id, player, data=None) HANDLER_MAP = { # Inspection & World Interaction 'inspect_area': handle_inspect_area, 'inspect_area_menu': handle_inspect_area, 'attack_wandering': handle_attack_wandering, 'inspect': handle_inspect_interactable, 'action': handle_action, # Navigation & Menu 'main_menu': handle_main_menu, 'move_menu': handle_move_menu, 'move': handle_move, # Profile & Stats 'profile': handle_profile, 'spend_points_menu': handle_spend_points_menu, 'spend_point': handle_spend_point, # Inventory Management 'inventory_menu': handle_inventory_menu, 'inventory_item': handle_inventory_item, 'inventory_use': handle_inventory_use, 'inventory_drop': handle_inventory_drop, 'inventory_equip': handle_inventory_equip, 'inventory_unequip': handle_inventory_unequip, # Item Pickup 'pickup_menu': handle_pickup_menu, 'pickup': handle_pickup, # Combat Actions 'combat_attack': handle_combat_attack, 'combat_flee': handle_combat_flee, 'combat_use_item_menu': handle_combat_use_item_menu, 'combat_use_item': handle_combat_use_item, 'combat_back': handle_combat_back, # Corpse Looting 'loot_player_corpse': handle_loot_player_corpse, 'take_corpse_item': handle_take_corpse_item, 'scavenge_npc_corpse': handle_scavenge_npc_corpse, 'scavenge_corpse_item': handle_scavenge_corpse_item, } # ============================================================================ # BUTTON CALLBACK ROUTER # ============================================================================ async def button_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: """ Main router for button callbacks. Delegates to specific handler functions based on action type. All handlers have a unified signature: (query, user_id, player, data=None) Note: user_id passed to handlers is actually the player's unique DB id (not telegram_id) """ from .api_client import api_client query = update.callback_query telegram_id = query.from_user.id data = query.data.split(':') action_type = data[0] # Get player by telegram_id and translate to unique id player = await api_client.get_player(telegram_id) if not player or player['is_dead']: await query.answer() await send_or_edit_with_image( query, text="💀 Your journey has ended. You died in the wasteland. Create a new character with /start to begin again.", reply_markup=None ) return # From now on, use player's unique database id user_id = player['id'] # Check if player is in combat - restrict most actions combat = await api_client.get_combat(user_id) allowed_in_combat = { 'combat_attack', 'combat_flee', 'combat_use_item_menu', 'combat_use_item', 'combat_back', 'no_op' } if combat and action_type not in allowed_in_combat: await query.answer("You're in combat! Focus on the fight!", show_alert=False) return # Route to appropriate handler if action_type == 'no_op': await query.answer() return handler = HANDLER_MAP.get(action_type) if handler: try: await handler(query, user_id, player, data) except Exception as e: logger.error(f"Error handling button action {action_type}: {e}", exc_info=True) await query.answer("An error occurred. Please try again.", show_alert=True) else: logger.warning(f"Unknown action type: {action_type}") await query.answer("Unknown action", show_alert=False)