- Updated gym challenge to automatically search in player's current location first - Made gym search case-insensitive (forest guardian, Forest Guardian, FOREST GUARDIAN all work) - Added helpful error messages showing available gyms in current location - Updated gym info command to also prioritize current location and be case-insensitive - Added get_gym_by_name_in_location() database method for location-specific searches - Improved user experience by removing need to travel between locations to challenge gyms Fixes: \!gym challenge forest guardian now works correctly 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
280 lines
No EOL
12 KiB
Python
280 lines
No EOL
12 KiB
Python
#!/usr/bin/env python3
|
|
"""Gym battle module for PetBot"""
|
|
|
|
from .base_module import BaseModule
|
|
|
|
class GymBattles(BaseModule):
|
|
"""Handles gym challenges, battles, and badge tracking"""
|
|
|
|
def get_commands(self):
|
|
return ["gym"]
|
|
|
|
async def handle_command(self, channel, nickname, command, args):
|
|
if command == "gym":
|
|
if not args:
|
|
await self.cmd_gym_list(channel, nickname)
|
|
elif args[0] == "list":
|
|
await self.cmd_gym_list_all(channel, nickname)
|
|
elif args[0] == "challenge":
|
|
await self.cmd_gym_challenge(channel, nickname, args[1:])
|
|
elif args[0] == "info":
|
|
await self.cmd_gym_info(channel, nickname, args[1:])
|
|
elif args[0] == "status":
|
|
await self.cmd_gym_status(channel, nickname)
|
|
else:
|
|
await self.cmd_gym_list(channel, nickname)
|
|
|
|
async def cmd_gym_list(self, channel, nickname):
|
|
"""List gyms in current location"""
|
|
player = await self.require_player(channel, nickname)
|
|
if not player:
|
|
return
|
|
|
|
# Get player's current location
|
|
location = await self.database.get_player_location(player["id"])
|
|
if not location:
|
|
self.send_message(channel, f"{nickname}: You are not in a valid location!")
|
|
return
|
|
|
|
# Get gyms in current location
|
|
gyms = await self.database.get_gyms_in_location(location["id"], player["id"])
|
|
|
|
if not gyms:
|
|
self.send_message(channel, f"🏛️ {nickname}: No gyms found in {location['name']}.")
|
|
return
|
|
|
|
self.send_message(channel, f"🏛️ Gyms in {location['name']}:")
|
|
|
|
for gym in gyms:
|
|
victories = gym.get("victories", 0)
|
|
if victories == 0:
|
|
status = "Not challenged"
|
|
difficulty = "Beginner"
|
|
else:
|
|
status = f"{victories} victories"
|
|
difficulty = f"Level {victories + 1}"
|
|
|
|
badge_icon = gym["badge_icon"]
|
|
leader = gym["leader_name"]
|
|
theme = gym["theme"]
|
|
|
|
self.send_message(channel,
|
|
f" {badge_icon} {gym['name']} - Leader: {leader} ({theme})")
|
|
self.send_message(channel,
|
|
f" Status: {status} | Next difficulty: {difficulty}")
|
|
|
|
self.send_message(channel,
|
|
f"💡 Use '!gym challenge \"<gym name>\"' to battle!")
|
|
|
|
async def cmd_gym_list_all(self, channel, nickname):
|
|
"""List all gyms across all locations"""
|
|
player = await self.require_player(channel, nickname)
|
|
if not player:
|
|
return
|
|
|
|
# Get all locations and their gyms
|
|
all_locations = await self.database.get_all_locations()
|
|
|
|
self.send_message(channel, f"🗺️ {nickname}: All Gym Locations:")
|
|
|
|
total_badges = 0
|
|
for location in all_locations:
|
|
gyms = await self.database.get_gyms_in_location(location["id"], player["id"])
|
|
|
|
if gyms:
|
|
for gym in gyms:
|
|
victories = gym.get("victories", 0)
|
|
status_icon = "✅" if victories > 0 else "❌"
|
|
if victories > 0:
|
|
total_badges += 1
|
|
|
|
self.send_message(channel,
|
|
f" {status_icon} {location['name']}: {gym['name']} ({gym['theme']}) - {victories} victories")
|
|
|
|
self.send_message(channel, f"🏆 Total badges earned: {total_badges}")
|
|
|
|
async def cmd_gym_challenge(self, channel, nickname, args):
|
|
"""Challenge a gym"""
|
|
if not args:
|
|
self.send_message(channel, f"{nickname}: Specify a gym to challenge! Example: !gym challenge \"Forest Guardian\"")
|
|
return
|
|
|
|
player = await self.require_player(channel, nickname)
|
|
if not player:
|
|
return
|
|
|
|
# Get player's current location first
|
|
location = await self.database.get_player_location(player["id"])
|
|
if not location:
|
|
self.send_message(channel, f"{nickname}: You are not in a valid location! Use !travel to go somewhere first.")
|
|
return
|
|
|
|
gym_name = " ".join(args).strip('"')
|
|
|
|
# Look for gym in player's current location (case-insensitive)
|
|
gym = await self.database.get_gym_by_name_in_location(gym_name, location["id"])
|
|
if not gym:
|
|
# List available gyms in current location for helpful error message
|
|
available_gyms = await self.database.get_gyms_in_location(location["id"])
|
|
if available_gyms:
|
|
gym_list = ", ".join([f'"{g["name"]}"' for g in available_gyms])
|
|
self.send_message(channel, f"{nickname}: No gym named '{gym_name}' found in {location['name']}! Available gyms: {gym_list}")
|
|
else:
|
|
self.send_message(channel, f"{nickname}: No gyms found in {location['name']}! Try traveling to a different location.")
|
|
return
|
|
|
|
# Check if player has active pets
|
|
active_pets = await self.database.get_active_pets(player["id"])
|
|
if not active_pets:
|
|
self.send_message(channel, f"{nickname}: You need at least one active pet to challenge a gym! Use !activate <pet> first.")
|
|
return
|
|
|
|
# Get player's gym progress
|
|
progress = await self.database.get_player_gym_progress(player["id"], gym["id"])
|
|
difficulty_level = (progress["victories"] if progress else 0) + 1
|
|
difficulty_multiplier = 1.0 + (difficulty_level - 1) * 0.2 # 20% increase per victory
|
|
|
|
# Start gym battle
|
|
await self.start_gym_battle(channel, nickname, player, gym, difficulty_level, difficulty_multiplier)
|
|
|
|
async def start_gym_battle(self, channel, nickname, player, gym, difficulty_level, difficulty_multiplier):
|
|
"""Start a gym battle"""
|
|
# Get gym team with scaling
|
|
gym_team = await self.database.get_gym_team(gym["id"], difficulty_multiplier)
|
|
|
|
if not gym_team:
|
|
self.send_message(channel, f"{nickname}: {gym['name']} gym has no team configured!")
|
|
return
|
|
|
|
# Display battle start
|
|
badge_icon = gym["badge_icon"]
|
|
leader = gym["leader_name"]
|
|
difficulty_name = f"Level {difficulty_level}" if difficulty_level > 1 else "Beginner"
|
|
|
|
self.send_message(channel,
|
|
f"🏛️ {nickname} challenges the {gym['name']} gym!")
|
|
self.send_message(channel,
|
|
f"{badge_icon} Leader {leader}: \"Welcome to my {gym['theme']}-type gym! Let's see what you've got!\"")
|
|
self.send_message(channel,
|
|
f"⚔️ Difficulty: {difficulty_name} ({len(gym_team)} pets)")
|
|
|
|
# For now, simulate battle result (we'll implement actual battle mechanics later)
|
|
import random
|
|
|
|
# Simple win/loss calculation based on player's active pets
|
|
active_pets = await self.database.get_active_pets(player["id"])
|
|
player_strength = sum(pet["level"] * (pet["attack"] + pet["defense"]) for pet in active_pets)
|
|
gym_strength = sum(pet["level"] * (pet["attack"] + pet["defense"]) for pet in gym_team)
|
|
|
|
# Add some randomness but favor player slightly for now
|
|
win_chance = min(0.85, max(0.15, player_strength / (gym_strength * 0.8)))
|
|
|
|
if random.random() < win_chance:
|
|
await self.handle_gym_victory(channel, nickname, player, gym, difficulty_level)
|
|
else:
|
|
await self.handle_gym_defeat(channel, nickname, gym, difficulty_level)
|
|
|
|
async def handle_gym_victory(self, channel, nickname, player, gym, difficulty_level):
|
|
"""Handle gym battle victory"""
|
|
# Record victory in database
|
|
result = await self.database.record_gym_victory(player["id"], gym["id"])
|
|
|
|
badge_icon = gym["badge_icon"]
|
|
leader = gym["leader_name"]
|
|
|
|
self.send_message(channel, f"🎉 {nickname} defeats the {gym['name']} gym!")
|
|
|
|
if result["is_first_victory"]:
|
|
# First time victory - award badge
|
|
self.send_message(channel,
|
|
f"{badge_icon} Leader {leader}: \"Impressive! You've earned the {gym['badge_name']}!\"")
|
|
self.send_message(channel,
|
|
f"🏆 {nickname} earned the {gym['badge_name']} {badge_icon}!")
|
|
|
|
# Award bonus rewards for first victory
|
|
money_reward = 500 + (difficulty_level * 100)
|
|
exp_reward = 200 + (difficulty_level * 50)
|
|
else:
|
|
# Repeat victory
|
|
self.send_message(channel,
|
|
f"{badge_icon} Leader {leader}: \"Well fought! Your skills keep improving!\"")
|
|
|
|
money_reward = 200 + (difficulty_level * 50)
|
|
exp_reward = 100 + (difficulty_level * 25)
|
|
|
|
# Award rewards (we'll implement this when we have currency/exp systems)
|
|
victories = result["victories"]
|
|
next_difficulty = result["next_difficulty"]
|
|
|
|
self.send_message(channel,
|
|
f"💰 Rewards: ${money_reward} | 🌟 {exp_reward} EXP")
|
|
self.send_message(channel,
|
|
f"📊 {gym['name']} record: {victories} victories | Next challenge: Level {next_difficulty}")
|
|
|
|
async def handle_gym_defeat(self, channel, nickname, gym, difficulty_level):
|
|
"""Handle gym battle defeat"""
|
|
badge_icon = gym["badge_icon"]
|
|
leader = gym["leader_name"]
|
|
|
|
self.send_message(channel, f"💥 {nickname} was defeated by the {gym['name']} gym!")
|
|
self.send_message(channel,
|
|
f"{badge_icon} Leader {leader}: \"Good battle! Train more and come back stronger!\"")
|
|
self.send_message(channel,
|
|
f"💡 Tip: Level up your pets, get better items, or try a different strategy!")
|
|
|
|
async def cmd_gym_info(self, channel, nickname, args):
|
|
"""Get detailed information about a gym"""
|
|
if not args:
|
|
self.send_message(channel, f"{nickname}: Specify a gym name! Example: !gym info \"Forest Guardian\"")
|
|
return
|
|
|
|
player = await self.require_player(channel, nickname)
|
|
if not player:
|
|
return
|
|
|
|
gym_name = " ".join(args).strip('"')
|
|
|
|
# First try to find gym in player's current location
|
|
location = await self.database.get_player_location(player["id"])
|
|
gym = None
|
|
|
|
if location:
|
|
gym = await self.database.get_gym_by_name_in_location(gym_name, location["id"])
|
|
|
|
# If not found in current location, search globally
|
|
if not gym:
|
|
gym = await self.database.get_gym_by_name(gym_name)
|
|
|
|
if not gym:
|
|
self.send_message(channel, f"{nickname}: Gym '{gym_name}' not found!")
|
|
return
|
|
|
|
# Get gym team info
|
|
gym_team = await self.database.get_gym_team(gym["id"])
|
|
|
|
badge_icon = gym["badge_icon"]
|
|
|
|
self.send_message(channel, f"🏛️ {gym['name']} Gym Information:")
|
|
self.send_message(channel, f"📍 Location: {gym['location_name']}")
|
|
self.send_message(channel, f"👤 Leader: {gym['leader_name']}")
|
|
self.send_message(channel, f"🎯 Theme: {gym['theme']}-type")
|
|
self.send_message(channel, f"📝 {gym['description']}")
|
|
self.send_message(channel, f"🏆 Badge: {gym['badge_name']} {badge_icon}")
|
|
|
|
if gym_team:
|
|
self.send_message(channel, f"⚔️ Team ({len(gym_team)} pets):")
|
|
for pet in gym_team:
|
|
type_str = pet["type1"]
|
|
if pet["type2"]:
|
|
type_str += f"/{pet['type2']}"
|
|
self.send_message(channel,
|
|
f" • Level {pet['level']} {pet['species_name']} ({type_str})")
|
|
|
|
async def cmd_gym_status(self, channel, nickname):
|
|
"""Show player's overall gym progress"""
|
|
player = await self.require_player(channel, nickname)
|
|
if not player:
|
|
return
|
|
|
|
# This will show a summary - for detailed view they can use !gym list
|
|
self.send_message(channel, f"🏆 {nickname}: Use !gym list to see all gym progress, or check your profile at: http://petz.rdx4.com/player/{nickname}") |