339 lines
12 KiB
Python
339 lines
12 KiB
Python
"""
|
|
Inventory-related action handlers.
|
|
"""
|
|
import logging
|
|
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
|
|
from . import 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
|
|
from .api_client import api_client
|
|
await query.answer()
|
|
|
|
# Get inventory from API
|
|
inv_result = await api_client.get_inventory(player['id'])
|
|
inventory_items = inv_result.get('inventory', [])
|
|
current_weight, current_volume = logic.calculate_inventory_load(inventory_items)
|
|
max_weight, max_volume = logic.get_player_capacity(inventory_items, player)
|
|
|
|
text = "<b>🎒 Your Inventory:</b>\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 += "\n<i>Your inventory is empty.</i>"
|
|
|
|
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.
|
|
|
|
Note: item_db_id is the inventory row id from the API response.
|
|
We need to get the full inventory and find the item by id.
|
|
"""
|
|
from .api_client import api_client
|
|
|
|
await query.answer()
|
|
item_db_id = int(data[1])
|
|
|
|
# Get inventory from API
|
|
inv_result = await api_client.get_inventory(user_id)
|
|
inventory_items = inv_result.get('inventory', [])
|
|
|
|
# Find the specific item
|
|
item = next((i for i in inventory_items if i['id'] == item_db_id), None)
|
|
if not item:
|
|
await query.answer("Item not found in inventory", show_alert=True)
|
|
return
|
|
|
|
emoji = item.get('emoji', '❔')
|
|
|
|
# Build item details text
|
|
text = f"{emoji} <b>{item.get('name', 'Unknown')}</b>\n"
|
|
|
|
description = item.get('description')
|
|
if description:
|
|
text += f"<i>{description}</i>\n\n"
|
|
else:
|
|
text += "\n"
|
|
|
|
text += f"<b>Weight:</b> {item.get('weight', 0)} kg | <b>Volume:</b> {item.get('volume', 0)} vol\n"
|
|
|
|
# Add weapon stats if applicable
|
|
if item.get('type') == 'weapon':
|
|
text += f"<b>Damage:</b> {item.get('damage_min', 0)}-{item.get('damage_max', 0)}\n"
|
|
|
|
# Add consumable effects if applicable
|
|
if item.get('type') == 'consumable':
|
|
effects = []
|
|
if item.get('hp_restore'):
|
|
effects.append(f"❤️ +{item.get('hp_restore')} HP")
|
|
if item.get('stamina_restore'):
|
|
effects.append(f"⚡ +{item.get('stamina_restore')} Stamina")
|
|
if effects:
|
|
text += f"<b>Effects:</b> {', '.join(effects)}\n"
|
|
|
|
# Add equipped status
|
|
if item.get('is_equipped'):
|
|
text += "\n✅ <b>Currently Equipped</b>"
|
|
|
|
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, 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
|
|
from .api_client import api_client
|
|
|
|
item_db_id = int(data[1])
|
|
|
|
# Get inventory from API to find the item
|
|
inv_result = await api_client.get_inventory(user_id)
|
|
inventory_items = inv_result.get('inventory', [])
|
|
item = next((i for i in inventory_items if i['id'] == item_db_id), None)
|
|
|
|
if not item:
|
|
await query.answer("Item not found.", show_alert=False)
|
|
return
|
|
|
|
if item.get('type') != 'consumable':
|
|
await query.answer("This item cannot be used.", show_alert=False)
|
|
return
|
|
|
|
await query.answer()
|
|
|
|
# Use the API to use the item
|
|
result = await api_client.use_item(user_id, item['item_id'])
|
|
|
|
if not result.get('success'):
|
|
await query.answer(result.get('message', 'Failed to use item'), show_alert=True)
|
|
return
|
|
|
|
# Refresh player data to get updated stats
|
|
player = await api_client.get_player_by_id(user_id)
|
|
|
|
# Get updated inventory
|
|
inv_result = await api_client.get_inventory(user_id)
|
|
inventory_items = inv_result.get('inventory', [])
|
|
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 = "<b>🎒 Your Inventory:</b>\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 from API response
|
|
text += result.get('message', 'Item used.')
|
|
|
|
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."""
|
|
from .api_client import api_client
|
|
|
|
item_db_id = int(data[1])
|
|
drop_amount_str = data[2] if len(data) > 2 else None
|
|
|
|
# Get inventory to find the item
|
|
inv_result = await api_client.get_inventory(user_id)
|
|
inventory_items = inv_result.get('inventory', [])
|
|
item = next((i for i in inventory_items if i['id'] == item_db_id), None)
|
|
|
|
if not item:
|
|
await query.answer("Item not found.", show_alert=False)
|
|
return
|
|
|
|
# Determine how much to drop
|
|
if drop_amount_str is None or drop_amount_str == "all":
|
|
drop_amount = item['quantity']
|
|
else:
|
|
drop_amount = min(int(drop_amount_str), item['quantity'])
|
|
|
|
# Use API to drop item
|
|
result = await api_client.drop_item(user_id, item['item_id'], drop_amount)
|
|
|
|
if result.get('success'):
|
|
await query.answer(result.get('message', f"Dropped {drop_amount}x {item['name']}"), show_alert=False)
|
|
else:
|
|
await query.answer(result.get('message', 'Failed to drop item'), show_alert=True)
|
|
return
|
|
|
|
# Get updated inventory
|
|
inv_result = await api_client.get_inventory(user_id)
|
|
inventory_items = inv_result.get('inventory', [])
|
|
current_weight, current_volume = logic.calculate_inventory_load(inventory_items)
|
|
max_weight, max_volume = logic.get_player_capacity(inventory_items, player)
|
|
|
|
text = "<b>🎒 Your Inventory:</b>\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."""
|
|
from .api_client import api_client
|
|
|
|
item_db_id = int(data[1])
|
|
|
|
# Get inventory to find the item
|
|
inv_result = await api_client.get_inventory(user_id)
|
|
inventory_items = inv_result.get('inventory', [])
|
|
item = next((i for i in inventory_items if i['id'] == item_db_id), None)
|
|
|
|
if not item:
|
|
await query.answer("Item not found.", show_alert=False)
|
|
return
|
|
|
|
if not item.get('equippable'):
|
|
await query.answer("This item cannot be equipped.", show_alert=False)
|
|
return
|
|
|
|
# Use API to equip item
|
|
result = await api_client.equip_item(user_id, item['item_id'])
|
|
|
|
if not result.get('success'):
|
|
await query.answer(result.get('message', 'Failed to equip item'), show_alert=True)
|
|
return
|
|
|
|
await query.answer(result.get('message', f"Equipped {item['name']}!"), show_alert=False)
|
|
|
|
# Refresh the item view
|
|
emoji = item.get('emoji', '❔')
|
|
text = f"{emoji} <b>{item.get('name', 'Unknown')}</b>\n"
|
|
|
|
description = item.get('description')
|
|
if description:
|
|
text += f"<i>{description}</i>\n\n"
|
|
else:
|
|
text += "\n"
|
|
|
|
text += f"<b>Weight:</b> {item.get('weight', 0)} kg | <b>Volume:</b> {item.get('volume', 0)} vol\n"
|
|
|
|
if item.get('type') == 'weapon':
|
|
text += f"<b>Damage:</b> {item.get('damage_min', 0)}-{item.get('damage_max', 0)}\n"
|
|
|
|
text += "\n✅ <b>Currently Equipped</b>"
|
|
|
|
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, True, item['quantity']
|
|
),
|
|
image_path=location_image
|
|
)
|
|
|
|
|
|
async def handle_inventory_unequip(query, user_id: int, player: dict, data: list):
|
|
"""Unequip an item."""
|
|
from .api_client import api_client
|
|
|
|
item_db_id = int(data[1])
|
|
|
|
# Get inventory to find the item
|
|
inv_result = await api_client.get_inventory(user_id)
|
|
inventory_items = inv_result.get('inventory', [])
|
|
item = next((i for i in inventory_items if i['id'] == item_db_id), None)
|
|
|
|
if not item:
|
|
await query.answer("Item not found.", show_alert=False)
|
|
return
|
|
|
|
# Use API to unequip item
|
|
result = await api_client.unequip_item(user_id, item['item_id'])
|
|
|
|
if not result.get('success'):
|
|
await query.answer(result.get('message', 'Failed to unequip item'), show_alert=True)
|
|
return
|
|
|
|
await query.answer(result.get('message', f"Unequipped {item['name']}."), show_alert=False)
|
|
|
|
# Refresh the item view
|
|
emoji = item.get('emoji', '❔')
|
|
text = f"{emoji} <b>{item.get('name', 'Unknown')}</b>\n"
|
|
|
|
description = item.get('description')
|
|
if description:
|
|
text += f"<i>{description}</i>\n\n"
|
|
else:
|
|
text += "\n"
|
|
|
|
text += f"<b>Weight:</b> {item.get('weight', 0)} kg | <b>Volume:</b> {item.get('volume', 0)} vol\n"
|
|
|
|
if item.get('type') == 'weapon':
|
|
text += f"<b>Damage:</b> {item.get('damage_min', 0)}-{item.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, False, item['quantity']
|
|
),
|
|
image_path=location_image
|
|
)
|