""" Inventory-related action handlers. """ import logging from telegram import InlineKeyboardButton, InlineKeyboardMarkup from . import database, keyboards, logic from data.world_loader import game_world from data.items import ITEMS logger = logging.getLogger(__name__) async def handle_inventory_menu(query, user_id: int, player: dict, data: list = None): """Display player inventory with item management options.""" from .utils import format_stat_bar await query.answer() inventory_items = await database.get_inventory(user_id) current_weight, current_volume = logic.calculate_inventory_load(inventory_items) max_weight, max_volume = logic.get_player_capacity(inventory_items, player) text = "šŸŽ’ Your Inventory:\n" text += f"{format_stat_bar('HP', 'ā¤ļø', player['hp'], player['max_hp'])}\n" text += f"{format_stat_bar('Stamina', '⚔', player['stamina'], player['max_stamina'])}\n" text += f"šŸ“Š Weight: {current_weight}/{max_weight} kg\n" text += f"šŸ“¦ Volume: {current_volume}/{max_volume} vol\n" if not inventory_items: text += "\nYour inventory is empty." location = game_world.get_location(player['location_id']) location_image = location.image_path if location else None from .handlers import send_or_edit_with_image await send_or_edit_with_image( query, text=text, reply_markup=keyboards.inventory_keyboard(inventory_items), image_path=location_image ) async def handle_inventory_item(query, user_id: int, player: dict, data: list): """Show details for a specific inventory item.""" await query.answer() item_db_id = int(data[1]) item = await database.get_inventory_item(item_db_id) item_def = ITEMS.get(item['item_id'], {}) emoji = item_def.get('emoji', 'ā”') # Build item details text text = f"{emoji} {item_def.get('name', 'Unknown')}\n" description = item_def.get('description') if description: text += f"{description}\n\n" else: text += "\n" text += f"Weight: {item_def.get('weight', 0)} kg | Volume: {item_def.get('volume', 0)} vol\n" # Add weapon stats if applicable if item_def.get('type') == 'weapon': text += f"Damage: {item_def.get('damage_min', 0)}-{item_def.get('damage_max', 0)}\n" # Add consumable effects if applicable if item_def.get('type') == 'consumable': effects = [] if item_def.get('hp_restore'): effects.append(f"ā¤ļø +{item_def.get('hp_restore')} HP") if item_def.get('stamina_restore'): effects.append(f"⚔ +{item_def.get('stamina_restore')} Stamina") if effects: text += f"Effects: {', '.join(effects)}\n" # Add equipped status if item.get('is_equipped'): text += "\nāœ… Currently Equipped" location = game_world.get_location(player['location_id']) location_image = location.image_path if location else None from .handlers import send_or_edit_with_image await send_or_edit_with_image( query, text=text, reply_markup=keyboards.inventory_item_actions_keyboard( item_db_id, item_def, item.get('is_equipped', False), item['quantity'] ), image_path=location_image ) async def handle_inventory_use(query, user_id: int, player: dict, data: list): """Use a consumable item from inventory.""" from .utils import format_stat_bar item_db_id = int(data[1]) item = await database.get_inventory_item(item_db_id) if not item: await query.answer("Item not found.", show_alert=False) return item_def = ITEMS.get(item['item_id'], {}) if item_def.get('type') != 'consumable': await query.answer("This item cannot be used.", show_alert=False) return await query.answer() # Apply item effects result_parts = [] updates = {} if 'hp_restore' in item_def: hp_gain = item_def['hp_restore'] new_hp = min(player['max_hp'], player['hp'] + hp_gain) actual_gain = new_hp - player['hp'] updates['hp'] = new_hp if actual_gain > 0: result_parts.append(f"ā¤ļø HP: +{actual_gain}") else: result_parts.append(f"ā¤ļø HP: Already at maximum!") if 'stamina_restore' in item_def: stamina_gain = item_def['stamina_restore'] new_stamina = min(player['max_stamina'], player['stamina'] + stamina_gain) actual_gain = new_stamina - player['stamina'] updates['stamina'] = new_stamina if actual_gain > 0: result_parts.append(f"⚔ Stamina: +{actual_gain}") else: result_parts.append(f"⚔ Stamina: Already at maximum!") if updates: await database.update_player(user_id, updates) # Refresh player data to get updated stats player = await database.get_player(user_id) # Remove one item from inventory if item['quantity'] > 1: await database.update_inventory_item(item['id'], quantity=item['quantity'] - 1) else: await database.remove_item_from_inventory(item['id']) # Show updated inventory inventory_items = await database.get_inventory(user_id) current_weight, current_volume = logic.calculate_inventory_load(inventory_items) max_weight, max_volume = logic.get_player_capacity(inventory_items, player) # Build status section with HP/Stamina bars text = "šŸŽ’ Your Inventory:\n" text += f"{format_stat_bar('HP', 'ā¤ļø', player['hp'], player['max_hp'])}\n" text += f"{format_stat_bar('Stamina', '⚔', player['stamina'], player['max_stamina'])}\n" text += f"šŸ“Š Weight: {current_weight}/{max_weight} kg\n" text += f"šŸ“¦ Volume: {current_volume}/{max_volume} vol\n" text += "━━━━━━━━━━━━━━━━━━━━\n" # Build result message emoji = item_def.get('emoji', 'ā”') text += f"✨ Used {emoji} {item_def.get('name')}\n" if result_parts: text += "\n".join(result_parts) else: text += "No effect." location = game_world.get_location(player['location_id']) location_image = location.image_path if location else None from .handlers import send_or_edit_with_image await send_or_edit_with_image( query, text=text, reply_markup=keyboards.inventory_keyboard(inventory_items), image_path=location_image ) async def handle_inventory_drop(query, user_id: int, player: dict, data: list): """Drop an item from inventory to the world.""" item_db_id = int(data[1]) drop_amount_str = data[2] if len(data) > 2 else None item = await database.get_inventory_item(item_db_id) if not item: await query.answer("Item not found.", show_alert=False) return item_def = ITEMS.get(item['item_id'], {}) # Determine how much to drop if drop_amount_str is None or drop_amount_str == "all": await database.drop_item_to_world(item['item_id'], item['quantity'], player['location_id']) await database.remove_item_from_inventory(item['id'], quantity=item['quantity']) await query.answer(f"You dropped all {item['quantity']}x {item_def.get('name')}.", show_alert=False) else: drop_amount = int(drop_amount_str) if drop_amount >= item['quantity']: await database.drop_item_to_world(item['item_id'], item['quantity'], player['location_id']) await database.remove_item_from_inventory(item['id'], quantity=item['quantity']) await query.answer(f"You dropped all {item['quantity']}x {item_def.get('name')}.", show_alert=False) else: await database.drop_item_to_world(item['item_id'], drop_amount, player['location_id']) await database.update_inventory_item(item['id'], quantity=item['quantity'] - drop_amount) await query.answer(f"You dropped {drop_amount}x {item_def.get('name')}.", show_alert=False) inventory_items = await database.get_inventory(user_id) current_weight, current_volume = logic.calculate_inventory_load(inventory_items) max_weight, max_volume = logic.get_player_capacity(inventory_items, player) text = "šŸŽ’ Your Inventory:\n" text += f"šŸ“Š Weight: {current_weight}/{max_weight} kg\n" text += f"šŸ“¦ Volume: {current_volume}/{max_volume} vol\n\n" if not inventory_items: text += "It's empty." location = game_world.get_location(player['location_id']) location_image = location.image_path if location else None from .handlers import send_or_edit_with_image await send_or_edit_with_image( query, text=text, reply_markup=keyboards.inventory_keyboard(inventory_items), image_path=location_image ) async def handle_inventory_equip(query, user_id: int, player: dict, data: list): """Equip an item from inventory.""" item_db_id = int(data[1]) item = await database.get_inventory_item(item_db_id) if not item: await query.answer("Item not found.", show_alert=False) return item_def = ITEMS.get(item['item_id'], {}) item_slot = item_def.get('slot') if not item_slot: await query.answer("This item cannot be equipped.", show_alert=False) return # Unequip any item in the same slot inventory_items = await database.get_inventory(user_id) for inv_item in inventory_items: if inv_item.get('is_equipped'): inv_item_def = ITEMS.get(inv_item['item_id'], {}) if inv_item_def.get('slot') == item_slot: await database.update_inventory_item(inv_item['id'], is_equipped=False) # If equipping from a stack, split the stack if item['quantity'] > 1: await database.update_inventory_item(item_db_id, quantity=item['quantity'] - 1) new_item_id = await database.add_equipped_item_to_inventory(user_id, item['item_id']) await query.answer(f"Equipped {item_def.get('name')}!", show_alert=False) item = await database.get_inventory_item(new_item_id) item_db_id = new_item_id else: await database.update_inventory_item(item_db_id, is_equipped=True) await query.answer(f"Equipped {item_def.get('name')}!", show_alert=False) item = await database.get_inventory_item(item_db_id) # Refresh the item view emoji = item_def.get('emoji', 'ā”') text = f"{emoji} {item_def.get('name', 'Unknown')}\n" description = item_def.get('description') if description: text += f"{description}\n\n" else: text += "\n" text += f"Weight: {item_def.get('weight', 0)} kg | Volume: {item_def.get('volume', 0)} vol\n" if item_def.get('type') == 'weapon': text += f"Damage: {item_def.get('damage_min', 0)}-{item_def.get('damage_max', 0)}\n" text += "\nāœ… Currently Equipped" location = game_world.get_location(player['location_id']) location_image = location.image_path if location else None from .handlers import send_or_edit_with_image await send_or_edit_with_image( query, text=text, reply_markup=keyboards.inventory_item_actions_keyboard( item_db_id, item_def, True, item['quantity'] ), image_path=location_image ) async def handle_inventory_unequip(query, user_id: int, player: dict, data: list): """Unequip an item.""" item_db_id = int(data[1]) item = await database.get_inventory_item(item_db_id) if not item: await query.answer("Item not found.", show_alert=False) return item_def = ITEMS.get(item['item_id'], {}) # Check if there's an existing unequipped stack inventory_items = await database.get_inventory(user_id) existing_stack = None for inv_item in inventory_items: if (inv_item['item_id'] == item['item_id'] and not inv_item.get('is_equipped') and inv_item['id'] != item_db_id): existing_stack = inv_item break if existing_stack: # Merge into existing stack await database.update_inventory_item(existing_stack['id'], quantity=existing_stack['quantity'] + 1) await database.remove_item_from_inventory(item_db_id) await query.answer(f"Unequipped {item_def.get('name')}.", show_alert=False) item = await database.get_inventory_item(existing_stack['id']) item_db_id = existing_stack['id'] else: # Just unequip await database.update_inventory_item(item_db_id, is_equipped=False) await query.answer(f"Unequipped {item_def.get('name')}.", show_alert=False) item = await database.get_inventory_item(item_db_id) # Refresh the item view emoji = item_def.get('emoji', 'ā”') text = f"{emoji} {item_def.get('name', 'Unknown')}\n" description = item_def.get('description') if description: text += f"{description}\n\n" else: text += "\n" text += f"Weight: {item_def.get('weight', 0)} kg | Volume: {item_def.get('volume', 0)} vol\n" if item_def.get('type') == 'weapon': text += f"Damage: {item_def.get('damage_min', 0)}-{item_def.get('damage_max', 0)}\n" location = game_world.get_location(player['location_id']) location_image = location.image_path if location else None from .handlers import send_or_edit_with_image await send_or_edit_with_image( query, text=text, reply_markup=keyboards.inventory_item_actions_keyboard( item_db_id, item_def, False, item['quantity'] ), image_path=location_image )