🎒 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>
227 lines
No EOL
11 KiB
Python
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}") |