Petbot/modules/exploration.py
megaproxy db144da24f Add complete item collection system (v0.2.0)
🎒 Item Collection System:
- 16 unique items across 5 categories (healing, battle, rare, location, special)
- Rarity tiers: Common, Uncommon, Rare, Epic, Legendary with symbols
- 30% chance to find items during exploration
- Location-specific items (shells, mushrooms, crystals, runes)
- Inventory management with \!inventory and \!use commands
- Web interface integration showing player inventories
- Consumable items: healing potions, battle boosters, lucky charms

🔧 Technical Updates:
- Added items and player_inventory database tables
- New Inventory module for item management
- Updated game engine with item discovery system
- Enhanced web interface with inventory display
- Item initialization from config/items.json

🆕 New Commands:
- \!inventory / \!inv / \!items - View collected items by category
- \!use <item name> - Use consumable items on active pets

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-14 00:19:57 +01:00

227 lines
No EOL
11 KiB
Python

#!/usr/bin/env python3
"""Exploration commands module for PetBot"""
from .base_module import BaseModule
class Exploration(BaseModule):
"""Handles exploration, travel, location, weather, and wild commands"""
def get_commands(self):
return ["explore", "travel", "location", "where", "weather", "wild", "catch", "capture"]
async def handle_command(self, channel, nickname, command, args):
if command == "explore":
await self.cmd_explore(channel, nickname)
elif command == "travel":
await self.cmd_travel(channel, nickname, args)
elif command in ["location", "where"]:
await self.cmd_location(channel, nickname)
elif command == "weather":
await self.cmd_weather(channel, nickname)
elif command == "wild":
await self.cmd_wild(channel, nickname, args)
elif command in ["catch", "capture"]:
await self.cmd_catch(channel, nickname)
async def cmd_explore(self, channel, nickname):
"""Explore current location"""
player = await self.require_player(channel, nickname)
if not player:
return
encounter = await self.game_engine.explore_location(player["id"])
if encounter["type"] == "error":
self.send_message(channel, f"{nickname}: {encounter['message']}")
elif encounter["type"] == "empty":
self.send_message(channel, f"🔍 {nickname}: {encounter['message']}")
elif encounter["type"] == "item_found":
self.send_message(channel, f"{nickname}: {encounter['message']}")
elif encounter["type"] == "encounter":
# Store the encounter for potential catching
self.bot.active_encounters[player["id"]] = encounter["pet"]
pet = encounter["pet"]
type_str = pet["type1"]
if pet["type2"]:
type_str += f"/{pet['type2']}"
self.send_message(channel,
f"🐾 {nickname}: A wild Level {pet['level']} {pet['species_name']} ({type_str}) appeared in {encounter['location']}!")
self.send_message(channel, f"Choose your action: !battle to fight it, or !catch to try catching it directly!")
async def cmd_travel(self, channel, nickname, args):
"""Travel to a different location"""
if not args:
self.send_message(channel, f"{nickname}: Specify where to travel! Available: Starter Town, Whispering Woods, Electric Canyon, Crystal Caves, Frozen Tundra, Dragon's Peak")
return
player = await self.require_player(channel, nickname)
if not player:
return
destination = " ".join(args).title() # Normalize to Title Case
location = await self.database.get_location_by_name(destination)
if not location:
self.send_message(channel, f"{nickname}: '{destination}' is not a valid location!")
return
# Check if player can access this location
missing_requirements = await self.database.get_missing_location_requirements(player["id"], location["id"])
if missing_requirements:
# Build specific message about required achievements
if len(missing_requirements) == 1:
achievement = missing_requirements[0]
self.send_message(channel, f"{nickname}: You cannot access {destination} yet! Required achievement: '{achievement['name']}' - {achievement['description']}")
else:
achievement_names = [f"'{req['name']}'" for req in missing_requirements]
self.send_message(channel, f"{nickname}: You cannot access {destination} yet! Required achievements: {', '.join(achievement_names)}. Use !achievements to see progress.")
return
# Clear any active encounters when traveling
if player["id"] in self.bot.active_encounters:
del self.bot.active_encounters[player["id"]]
await self.database.update_player_location(player["id"], location["id"])
# Show weather info
weather = await self.database.get_location_weather(location["id"])
weather_msg = ""
if weather:
weather_patterns = getattr(self.game_engine, 'weather_patterns', {})
weather_info = weather_patterns.get("weather_types", {}).get(weather["weather_type"], {})
weather_desc = weather_info.get("description", f"{weather['weather_type']} weather")
weather_msg = f" Weather: {weather['weather_type']} - {weather_desc}"
self.send_message(channel, f"🗺️ {nickname}: You traveled to {destination}. {location['description']}{weather_msg}")
async def cmd_location(self, channel, nickname):
"""Show current location"""
player = await self.require_player(channel, nickname)
if not player:
return
location = await self.database.get_player_location(player["id"])
if location:
self.send_message(channel, f"📍 {nickname}: You are currently in {location['name']}. {location['description']}")
else:
self.send_message(channel, f"{nickname}: You seem to be lost! Contact an admin.")
async def cmd_weather(self, channel, nickname):
"""Show current weather"""
player = await self.require_player(channel, nickname)
if not player:
return
location = await self.database.get_player_location(player["id"])
if not location:
self.send_message(channel, f"{nickname}: You seem to be lost!")
return
weather = await self.database.get_location_weather(location["id"])
if weather:
weather_patterns = getattr(self.game_engine, 'weather_patterns', {})
weather_info = weather_patterns.get("weather_types", {}).get(weather["weather_type"], {})
weather_desc = weather_info.get("description", f"{weather['weather_type']} weather")
self.send_message(channel, f"🌤️ {nickname}: Current weather in {location['name']}: {weather['weather_type']}")
self.send_message(channel, f"Effect: {weather_desc}")
else:
self.send_message(channel, f"🌤️ {nickname}: The weather in {location['name']} is calm with no special effects.")
async def cmd_wild(self, channel, nickname, args):
"""Show wild pets in location (defaults to current)"""
player = await self.require_player(channel, nickname)
if not player:
return
if args:
# Specific location requested
location_name = " ".join(args).title()
else:
# Default to current location
current_location = await self.database.get_player_location(player["id"])
if not current_location:
self.send_message(channel, f"{nickname}: You seem to be lost!")
return
location_name = current_location["name"]
wild_pets = await self.game_engine.get_location_spawns(location_name)
if wild_pets:
pet_list = ", ".join([pet["name"] for pet in wild_pets])
self.send_message(channel, f"🌿 Wild pets in {location_name}: {pet_list}")
else:
self.send_message(channel, f"{nickname}: No location found called '{location_name}'")
async def cmd_catch(self, channel, nickname):
"""Catch a pet during exploration or battle"""
player = await self.require_player(channel, nickname)
if not player:
return
# Check if player is in an active battle
active_battle = await self.game_engine.battle_engine.get_active_battle(player["id"])
if active_battle:
# Catching during battle
wild_pet = active_battle["wild_pet"]
current_hp = active_battle["wild_hp"]
max_hp = wild_pet["max_hp"]
# Calculate catch rate based on remaining HP (lower HP = higher catch rate)
hp_percentage = current_hp / max_hp
base_catch_rate = 0.3 # Lower base rate than direct catch
hp_bonus = (1.0 - hp_percentage) * 0.5 # Up to 50% bonus for low HP
final_catch_rate = min(0.9, base_catch_rate + hp_bonus) # Cap at 90%
import random
if random.random() < final_catch_rate:
# Successful catch during battle
result = await self.game_engine.attempt_catch_current_location(player["id"], wild_pet)
# End the battle
await_result = await self.game_engine.battle_engine.end_battle(player["id"], "caught")
# Check for achievements
type_achievements = await self.game_engine.check_and_award_achievements(player["id"], "catch_type", "")
total_achievements = await self.game_engine.check_and_award_achievements(player["id"], "catch_total", "")
all_achievements = type_achievements + total_achievements
if all_achievements:
for achievement in all_achievements:
self.send_message(channel, f"🏆 {nickname}: Achievement unlocked: {achievement['name']}! {achievement['description']}")
# Remove encounter
if player["id"] in self.bot.active_encounters:
del self.bot.active_encounters[player["id"]]
self.send_message(channel, f"🎯 {nickname}: Caught the {wild_pet['species_name']} during battle! (HP: {current_hp}/{max_hp})")
else:
# Failed catch - battle continues
catch_percentage = int(final_catch_rate * 100)
self.send_message(channel, f"🎯 {nickname}: The {wild_pet['species_name']} broke free! ({catch_percentage}% catch rate) Battle continues!")
return
# Regular exploration catch (not in battle)
if player["id"] not in self.bot.active_encounters:
self.send_message(channel, f"{nickname}: You need to !explore first to find a pet, or be in battle to catch!")
return
target_pet = self.bot.active_encounters[player["id"]]
result = await self.game_engine.attempt_catch_current_location(player["id"], target_pet)
# Check for achievements after successful catch
if "Success!" in result:
type_achievements = await self.game_engine.check_and_award_achievements(player["id"], "catch_type", "")
total_achievements = await self.game_engine.check_and_award_achievements(player["id"], "catch_total", "")
all_achievements = type_achievements + total_achievements
if all_achievements:
for achievement in all_achievements:
self.send_message(channel, f"🏆 {nickname}: Achievement unlocked: {achievement['name']}! {achievement['description']}")
# Remove the encounter regardless of success
del self.bot.active_encounters[player["id"]]
self.send_message(channel, f"🎯 {nickname}: {result}")