#!/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 # Handle various input formats and normalize location names destination_input = " ".join(args).lower() # Map common variations to exact location names location_mappings = { "starter town": "Starter Town", "whispering woods": "Whispering Woods", "electric canyon": "Electric Canyon", "crystal caves": "Crystal Caves", "frozen tundra": "Frozen Tundra", "dragon's peak": "Dragon's Peak", "dragons peak": "Dragon's Peak", "dragon peak": "Dragon's Peak", "dragons-peak": "Dragon's Peak" } destination = location_mappings.get(destination_input) if not destination: # Fall back to title case if no mapping found destination = " ".join(args).title() 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}")