Compare commits
No commits in common. "3efefb66323df97bed434fbbca55f5d0e72f8700" and "5293da29219583fa41558087b55bee488681652d" have entirely different histories.
3efefb6632
...
5293da2921
6 changed files with 181 additions and 135 deletions
99
CLAUDE.md
99
CLAUDE.md
|
|
@ -311,101 +311,4 @@ python3 run_bot_debug.py
|
||||||
- Test thoroughly before pushing to production
|
- Test thoroughly before pushing to production
|
||||||
- Consider security implications for all user interactions
|
- Consider security implications for all user interactions
|
||||||
|
|
||||||
This documentation should be updated as the project evolves to maintain accuracy and usefulness for future development efforts.
|
This documentation should be updated as the project evolves to maintain accuracy and usefulness for future development efforts.
|
||||||
|
|
||||||
## 💌 Message for the Next Claude
|
|
||||||
|
|
||||||
Hello future Claude! 👋
|
|
||||||
|
|
||||||
You're inheriting a really awesome project here - PetBot is a sophisticated IRC bot with a Pokemon-style pet collecting game that has grown into quite an impressive system. Here's what you need to know:
|
|
||||||
|
|
||||||
### 🎯 **Current State (December 2024)**
|
|
||||||
The project is in **excellent shape** after our recent major cleanup and enhancements:
|
|
||||||
|
|
||||||
- **Team Swap System**: We just completed a massive architectural improvement allowing players to manage 3 teams and set any as active, with full web-IRC synchronization
|
|
||||||
- **Clean Codebase**: We eliminated 180+ lines of legacy/duplicate code and standardized the entire command architecture
|
|
||||||
- **Modular Design**: 13 well-organized modules each handling specific functionality
|
|
||||||
- **Security**: PIN-based verification for sensitive operations, comprehensive rate limiting
|
|
||||||
- **Web Integration**: Beautiful responsive web interface with drag-and-drop team management
|
|
||||||
|
|
||||||
### 🏗️ **Architecture You're Working With**
|
|
||||||
This is a **modular, async Python system** with:
|
|
||||||
- **IRC Bot**: Auto-reconnecting with health monitoring (`run_bot_with_reconnect.py`)
|
|
||||||
- **Web Server**: Built-in HTTP server with unified templates (`webserver.py`)
|
|
||||||
- **Database**: Async SQLite with comprehensive schema (`src/database.py`)
|
|
||||||
- **Game Engine**: Weather, spawns, battles, achievements (`src/game_engine.py`)
|
|
||||||
- **Module System**: Clean separation of concerns (`modules/`)
|
|
||||||
|
|
||||||
### 🤝 **How We've Been Working**
|
|
||||||
The user (megaproxy) is **fantastic to work with**. They:
|
|
||||||
- Give clear direction and let you work autonomously
|
|
||||||
- Always ask you to investigate before taking action (respect this!)
|
|
||||||
- Want database backups before major changes (BackupManager exists)
|
|
||||||
- Prefer incremental improvements over massive rewrites
|
|
||||||
- Value code quality and maintainability highly
|
|
||||||
|
|
||||||
### 🎮 **The Game Itself**
|
|
||||||
PetBot is surprisingly sophisticated:
|
|
||||||
- **66 IRC commands** across 13 modules (recently cleaned up from 78)
|
|
||||||
- **Dynamic weather system** affecting spawn rates
|
|
||||||
- **Achievement-based progression** unlocking new areas
|
|
||||||
- **Item collection system** with 16+ items across 5 rarity tiers
|
|
||||||
- **Turn-based battle system** with type effectiveness
|
|
||||||
- **Gym battles** with scaling difficulty
|
|
||||||
- **Web interface** for inventory/team management
|
|
||||||
|
|
||||||
### 🛠️ **Development Patterns We Use**
|
|
||||||
1. **Always use TodoWrite** for complex tasks (user loves seeing progress)
|
|
||||||
2. **Investigate first** - user wants analysis before action
|
|
||||||
3. **Backup before major DB changes** (`BackupManager` is your friend)
|
|
||||||
4. **Test thoroughly** - syntax check, imports, functionality
|
|
||||||
5. **Clean commit messages** with explanations
|
|
||||||
6. **Document in CLAUDE.md** as you learn
|
|
||||||
|
|
||||||
### 🔧 **Key Technical Patterns**
|
|
||||||
- **Command Redirection**: IRC commands often redirect to web interface for better UX
|
|
||||||
- **PIN Verification**: Sensitive operations (like team changes) use IRC-delivered PINs
|
|
||||||
- **State Management**: Active encounters/battles prevent concurrent actions
|
|
||||||
- **Async Everything**: Database, IRC, web server - all async/await
|
|
||||||
- **Error Handling**: Comprehensive try/catch with user-friendly messages
|
|
||||||
|
|
||||||
### 📂 **Important Files to Know**
|
|
||||||
- `start_petbot.sh` - One-command startup (handles venv, deps, everything)
|
|
||||||
- `config.py` - Central configuration (admin user, IRC settings, etc.)
|
|
||||||
- `CLAUDE.md` - This file! Keep it updated
|
|
||||||
- `run_bot_with_reconnect.py` - Main bot with reconnection + rate limiting
|
|
||||||
- `src/database.py` - Database operations and schema
|
|
||||||
- `modules/` - All command handlers (modular architecture)
|
|
||||||
|
|
||||||
### 🚨 **Things to Watch Out For**
|
|
||||||
- **Virtual Environment Required**: Due to `externally-managed-environment`
|
|
||||||
- **Port Conflicts**: Kill old bots before starting new ones
|
|
||||||
- **IRC Connection**: Can be finicky, we have robust reconnection logic
|
|
||||||
- **Database Migrations**: Always backup first, test thoroughly
|
|
||||||
- **Web/IRC Sync**: Keep both interfaces consistent
|
|
||||||
|
|
||||||
### 🎯 **Current Admin Setup**
|
|
||||||
- **Admin User**: Set in `config.py` as `ADMIN_USER` (currently: megasconed)
|
|
||||||
- **Rate Limiting**: Comprehensive system preventing abuse
|
|
||||||
- **Backup System**: Automated with manual triggers
|
|
||||||
- **Security**: Regular audits, PIN verification, proper validation
|
|
||||||
|
|
||||||
### 🔮 **Likely Next Steps**
|
|
||||||
Based on the trajectory, you might work on:
|
|
||||||
- **PvP Battle System**: Player vs player battles
|
|
||||||
- **Pet Evolution**: Leveling system enhancements
|
|
||||||
- **Trading System**: Player-to-player item/pet trading
|
|
||||||
- **Mobile Optimization**: Web interface improvements
|
|
||||||
- **Performance**: Database optimization, caching
|
|
||||||
|
|
||||||
### 💝 **Final Notes**
|
|
||||||
This codebase is **well-maintained** and **thoroughly documented**. The user cares deeply about code quality and the player experience. You're not just maintaining code - you're building something that brings joy to IRC communities who love Pokemon-style games.
|
|
||||||
|
|
||||||
**Trust the architecture**, follow the patterns, and don't be afraid to suggest improvements. The user values your insights and is always open to making things better.
|
|
||||||
|
|
||||||
You've got this! 🚀
|
|
||||||
|
|
||||||
*- Your predecessor Claude, who had a blast working on this project*
|
|
||||||
|
|
||||||
P.S. - The `./start_petbot.sh` script is magical - it handles everything. Use it!
|
|
||||||
P.P.S. - Always check `git status` before major changes. The user likes clean commits.
|
|
||||||
10
README.md
10
README.md
|
|
@ -184,16 +184,6 @@ Access the web dashboard at `http://petz.rdx4.com/`:
|
||||||
|
|
||||||
## 🐛 Recent Updates
|
## 🐛 Recent Updates
|
||||||
|
|
||||||
### v0.3.0 - Team Swap System & Architecture Cleanup
|
|
||||||
- ✅ **Active Team Architecture**: Complete redesign allowing any team (1-3) to be set as active
|
|
||||||
- ✅ **Web-IRC Synchronization**: IRC battles now use teams selected via web interface
|
|
||||||
- ✅ **Team Management Hub**: Enhanced web interface with "Make Active" buttons and team status
|
|
||||||
- ✅ **Database Migration**: New `active_teams` table for flexible team management
|
|
||||||
- ✅ **PIN Security**: Secure team changes with IRC-delivered PINs and verification
|
|
||||||
- ✅ **Command Architecture Cleanup**: Eliminated 12 duplicate commands and standardized admin system
|
|
||||||
- ✅ **Legacy Code Removal**: Cleaned up 180+ lines of redundant code across modules
|
|
||||||
- ✅ **Modular System Enhancement**: Improved separation of concerns and maintainability
|
|
||||||
|
|
||||||
### v0.2.0 - Item Collection System
|
### v0.2.0 - Item Collection System
|
||||||
- ✅ Complete item system with 16 unique items across 5 categories
|
- ✅ Complete item system with 16 unique items across 5 categories
|
||||||
- ✅ Item discovery during exploration (30% chance)
|
- ✅ Item discovery during exploration (30% chance)
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ class Admin(BaseModule):
|
||||||
"""Handles admin-only commands like reload"""
|
"""Handles admin-only commands like reload"""
|
||||||
|
|
||||||
def get_commands(self):
|
def get_commands(self):
|
||||||
return ["reload", "rate_stats", "rate_user", "rate_unban", "rate_reset", "weather", "setweather", "spawnevent", "startevent", "heal"]
|
return ["reload", "rate_stats", "rate_user", "rate_unban", "rate_reset", "weather", "setweather", "spawnevent", "startevent", "status", "uptime", "ping", "heal"]
|
||||||
|
|
||||||
async def handle_command(self, channel, nickname, command, args):
|
async def handle_command(self, channel, nickname, command, args):
|
||||||
if command == "reload":
|
if command == "reload":
|
||||||
|
|
@ -42,6 +42,12 @@ class Admin(BaseModule):
|
||||||
await self.cmd_spawnevent(channel, nickname, args)
|
await self.cmd_spawnevent(channel, nickname, args)
|
||||||
elif command == "startevent":
|
elif command == "startevent":
|
||||||
await self.cmd_startevent(channel, nickname, args)
|
await self.cmd_startevent(channel, nickname, args)
|
||||||
|
elif command == "status":
|
||||||
|
await self.cmd_status(channel, nickname)
|
||||||
|
elif command == "uptime":
|
||||||
|
await self.cmd_uptime(channel, nickname)
|
||||||
|
elif command == "ping":
|
||||||
|
await self.cmd_ping(channel, nickname)
|
||||||
elif command == "heal":
|
elif command == "heal":
|
||||||
await self.cmd_heal(channel, nickname)
|
await self.cmd_heal(channel, nickname)
|
||||||
|
|
||||||
|
|
@ -305,24 +311,18 @@ class Admin(BaseModule):
|
||||||
# Set weather for specific location
|
# Set weather for specific location
|
||||||
location_name = location_arg if len(args) == 2 else " ".join(args[:-1])
|
location_name = location_arg if len(args) == 2 else " ".join(args[:-1])
|
||||||
|
|
||||||
result = await self.database.set_weather_for_location(
|
success = await self.database.set_weather_for_location(
|
||||||
location_name, weather_type, end_time.isoformat(),
|
location_name, weather_type, end_time.isoformat(),
|
||||||
weather_config.get("spawn_modifier", 1.0),
|
weather_config.get("spawn_modifier", 1.0),
|
||||||
",".join(weather_config.get("affected_types", []))
|
",".join(weather_config.get("affected_types", []))
|
||||||
)
|
)
|
||||||
|
|
||||||
if result.get("success"):
|
if success:
|
||||||
self.send_message(channel,
|
self.send_message(channel,
|
||||||
f"🌤️ {nickname}: Set {weather_type} weather for {location_name}! "
|
f"🌤️ {nickname}: Set {weather_type} weather for {location_name}! "
|
||||||
f"Duration: {duration} minutes, Modifier: {weather_config.get('spawn_modifier', 1.0)}x")
|
f"Duration: {duration} minutes, Modifier: {weather_config.get('spawn_modifier', 1.0)}x")
|
||||||
|
|
||||||
# Announce weather change if it actually changed
|
|
||||||
if result.get("changed"):
|
|
||||||
await self.game_engine.announce_weather_change(
|
|
||||||
location_name, result.get("previous_weather"), weather_type, "admin"
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
self.send_message(channel, f"❌ {nickname}: Failed to set weather for '{location_name}'. {result.get('error', 'Location may not exist.')}")
|
self.send_message(channel, f"❌ {nickname}: Failed to set weather for '{location_name}'. Location may not exist.")
|
||||||
|
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
self.send_message(channel, f"{nickname}: ❌ Weather configuration file not found.")
|
self.send_message(channel, f"{nickname}: ❌ Weather configuration file not found.")
|
||||||
|
|
@ -409,6 +409,61 @@ class Admin(BaseModule):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.send_message(channel, f"{nickname}: ❌ Error starting event: {str(e)}")
|
self.send_message(channel, f"{nickname}: ❌ Error starting event: {str(e)}")
|
||||||
|
|
||||||
|
async def cmd_status(self, channel, nickname):
|
||||||
|
"""Show bot connection status (available to all users)"""
|
||||||
|
try:
|
||||||
|
# Check if connection manager exists
|
||||||
|
if hasattr(self.bot, 'connection_manager') and self.bot.connection_manager:
|
||||||
|
stats = self.bot.connection_manager.get_connection_stats()
|
||||||
|
connected = stats.get('connected', False)
|
||||||
|
state = stats.get('state', 'unknown')
|
||||||
|
|
||||||
|
status_emoji = "🟢" if connected else "🔴"
|
||||||
|
self.send_message(channel, f"{status_emoji} {nickname}: Bot status - {state.upper()}")
|
||||||
|
else:
|
||||||
|
self.send_message(channel, f"🟢 {nickname}: Bot is running")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.send_message(channel, f"{nickname}: ❌ Error getting status: {str(e)}")
|
||||||
|
|
||||||
|
async def cmd_uptime(self, channel, nickname):
|
||||||
|
"""Show bot uptime (available to all users)"""
|
||||||
|
try:
|
||||||
|
# Check if bot has startup time
|
||||||
|
if hasattr(self.bot, 'startup_time'):
|
||||||
|
import datetime
|
||||||
|
uptime = datetime.datetime.now() - self.bot.startup_time
|
||||||
|
days = uptime.days
|
||||||
|
hours, remainder = divmod(uptime.seconds, 3600)
|
||||||
|
minutes, seconds = divmod(remainder, 60)
|
||||||
|
|
||||||
|
if days > 0:
|
||||||
|
uptime_str = f"{days}d {hours}h {minutes}m"
|
||||||
|
elif hours > 0:
|
||||||
|
uptime_str = f"{hours}h {minutes}m"
|
||||||
|
else:
|
||||||
|
uptime_str = f"{minutes}m {seconds}s"
|
||||||
|
|
||||||
|
self.send_message(channel, f"⏱️ {nickname}: Bot uptime - {uptime_str}")
|
||||||
|
else:
|
||||||
|
self.send_message(channel, f"⏱️ {nickname}: Bot is running (uptime unknown)")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.send_message(channel, f"{nickname}: ❌ Error getting uptime: {str(e)}")
|
||||||
|
|
||||||
|
async def cmd_ping(self, channel, nickname):
|
||||||
|
"""Test bot responsiveness (available to all users)"""
|
||||||
|
try:
|
||||||
|
import time
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
|
# Simple responsiveness test
|
||||||
|
response_time = (time.time() - start_time) * 1000 # Convert to milliseconds
|
||||||
|
|
||||||
|
self.send_message(channel, f"🏓 {nickname}: Pong! Response time: {response_time:.1f}ms")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.send_message(channel, f"{nickname}: ❌ Error with ping: {str(e)}")
|
||||||
|
|
||||||
async def cmd_heal(self, channel, nickname):
|
async def cmd_heal(self, channel, nickname):
|
||||||
"""Heal active pets (available to all users with 1-hour cooldown)"""
|
"""Heal active pets (available to all users with 1-hour cooldown)"""
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,6 @@ from src.backup_manager import BackupManager, BackupScheduler
|
||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
|
|
||||||
# Add parent directory to path for config import
|
|
||||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
||||||
from config import ADMIN_USER
|
|
||||||
|
|
||||||
|
|
||||||
class BackupCommands(BaseModule):
|
class BackupCommands(BaseModule):
|
||||||
|
|
@ -59,7 +53,10 @@ class BackupCommands(BaseModule):
|
||||||
|
|
||||||
async def _is_admin(self, nickname):
|
async def _is_admin(self, nickname):
|
||||||
"""Check if user has admin privileges."""
|
"""Check if user has admin privileges."""
|
||||||
return nickname.lower() == ADMIN_USER.lower()
|
# This should be implemented based on your admin system
|
||||||
|
# For now, using a simple check - replace with actual admin verification
|
||||||
|
admin_users = ["admin", "megaproxy"] # Add your admin usernames
|
||||||
|
return nickname.lower() in admin_users
|
||||||
|
|
||||||
async def cmd_backup(self, channel, nickname, args):
|
async def cmd_backup(self, channel, nickname, args):
|
||||||
"""Create a manual backup."""
|
"""Create a manual backup."""
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,6 @@ from modules.base_module import BaseModule
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
|
|
||||||
# Add parent directory to path for config import
|
|
||||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
||||||
from config import ADMIN_USER
|
|
||||||
|
|
||||||
|
|
||||||
class ConnectionMonitor(BaseModule):
|
class ConnectionMonitor(BaseModule):
|
||||||
|
|
@ -192,7 +186,9 @@ class ConnectionMonitor(BaseModule):
|
||||||
|
|
||||||
async def _is_admin(self, nickname):
|
async def _is_admin(self, nickname):
|
||||||
"""Check if user has admin privileges."""
|
"""Check if user has admin privileges."""
|
||||||
return nickname.lower() == ADMIN_USER.lower()
|
# This should match the admin system in other modules
|
||||||
|
admin_users = ["admin", "megaproxy", "megasconed"]
|
||||||
|
return nickname.lower() in admin_users
|
||||||
|
|
||||||
async def get_connection_health(self):
|
async def get_connection_health(self):
|
||||||
"""Get connection health status for monitoring."""
|
"""Get connection health status for monitoring."""
|
||||||
|
|
|
||||||
111
src/bot.py
111
src/bot.py
|
|
@ -72,14 +72,119 @@ class PetBot:
|
||||||
await self.handle_command(connection, nickname, nickname, message)
|
await self.handle_command(connection, nickname, nickname, message)
|
||||||
|
|
||||||
async def handle_command(self, connection, target, nickname, message):
|
async def handle_command(self, connection, target, nickname, message):
|
||||||
# Command handling is now done by the modular system in run_bot_with_reconnect.py
|
command_parts = message[1:].split()
|
||||||
# This method is kept for backward compatibility but does nothing
|
if not command_parts:
|
||||||
pass
|
return
|
||||||
|
|
||||||
|
command = command_parts[0].lower()
|
||||||
|
args = command_parts[1:]
|
||||||
|
|
||||||
|
try:
|
||||||
|
if command == "help":
|
||||||
|
await self.cmd_help(connection, target, nickname)
|
||||||
|
elif command == "start":
|
||||||
|
await self.cmd_start(connection, target, nickname)
|
||||||
|
elif command == "catch":
|
||||||
|
await self.cmd_catch(connection, target, nickname, args)
|
||||||
|
elif command == "team":
|
||||||
|
await self.cmd_team(connection, target, nickname)
|
||||||
|
elif command == "wild":
|
||||||
|
await self.cmd_wild(connection, target, nickname, args)
|
||||||
|
elif command == "battle":
|
||||||
|
await self.cmd_battle(connection, target, nickname, args)
|
||||||
|
elif command == "stats":
|
||||||
|
await self.cmd_stats(connection, target, nickname, args)
|
||||||
|
else:
|
||||||
|
await self.send_message(connection, target, f"{nickname}: Unknown command. Use !help for available commands.")
|
||||||
|
except Exception as e:
|
||||||
|
await self.send_message(connection, target, f"{nickname}: Error processing command: {str(e)}")
|
||||||
|
|
||||||
async def send_message(self, connection, target, message):
|
async def send_message(self, connection, target, message):
|
||||||
connection.privmsg(target, message)
|
connection.privmsg(target, message)
|
||||||
await asyncio.sleep(0.5)
|
await asyncio.sleep(0.5)
|
||||||
|
|
||||||
|
async def cmd_help(self, connection, target, nickname):
|
||||||
|
help_text = [
|
||||||
|
"Available commands:",
|
||||||
|
"!start - Begin your pet journey",
|
||||||
|
"!catch <location> - Try to catch a pet in a location",
|
||||||
|
"!team - View your active pets",
|
||||||
|
"!wild <location> - See what pets are in an area",
|
||||||
|
"!battle <player> - Challenge another player",
|
||||||
|
"!stats [pet_name] - View pet or player stats"
|
||||||
|
]
|
||||||
|
for line in help_text:
|
||||||
|
await self.send_message(connection, target, line)
|
||||||
|
|
||||||
|
async def cmd_start(self, connection, target, nickname):
|
||||||
|
player = await self.database.get_player(nickname)
|
||||||
|
if player:
|
||||||
|
await self.send_message(connection, target, f"{nickname}: You already have an account! Use !team to see your pets.")
|
||||||
|
return
|
||||||
|
|
||||||
|
player_id = await self.database.create_player(nickname)
|
||||||
|
starter_pet = await self.game_engine.give_starter_pet(player_id)
|
||||||
|
|
||||||
|
await self.send_message(connection, target,
|
||||||
|
f"{nickname}: Welcome to the world of pets! You received a {starter_pet['species_name']}!")
|
||||||
|
|
||||||
|
async def cmd_catch(self, connection, target, nickname, args):
|
||||||
|
if not args:
|
||||||
|
await self.send_message(connection, target, f"{nickname}: Specify a location to catch pets in!")
|
||||||
|
return
|
||||||
|
|
||||||
|
location_name = " ".join(args)
|
||||||
|
player = await self.database.get_player(nickname)
|
||||||
|
if not player:
|
||||||
|
await self.send_message(connection, target, f"{nickname}: Use !start to begin your journey first!")
|
||||||
|
return
|
||||||
|
|
||||||
|
result = await self.game_engine.attempt_catch(player["id"], location_name)
|
||||||
|
await self.send_message(connection, target, f"{nickname}: {result}")
|
||||||
|
|
||||||
|
async def cmd_team(self, connection, target, nickname):
|
||||||
|
player = await self.database.get_player(nickname)
|
||||||
|
if not player:
|
||||||
|
await self.send_message(connection, target, f"{nickname}: Use !start to begin your journey first!")
|
||||||
|
return
|
||||||
|
|
||||||
|
pets = await self.database.get_player_pets(player["id"], active_only=True)
|
||||||
|
if not pets:
|
||||||
|
await self.send_message(connection, target, f"{nickname}: You don't have any active pets! Use !catch to find some.")
|
||||||
|
return
|
||||||
|
|
||||||
|
team_info = []
|
||||||
|
for pet in pets:
|
||||||
|
name = pet["nickname"] or pet["species_name"]
|
||||||
|
team_info.append(f"{name} (Lv.{pet['level']}) - {pet['hp']}/{pet['max_hp']} HP")
|
||||||
|
|
||||||
|
await self.send_message(connection, target, f"{nickname}'s team: " + " | ".join(team_info))
|
||||||
|
|
||||||
|
async def cmd_wild(self, connection, target, nickname, args):
|
||||||
|
if not args:
|
||||||
|
await self.send_message(connection, target, f"{nickname}: Specify a location to explore!")
|
||||||
|
return
|
||||||
|
|
||||||
|
location_name = " ".join(args)
|
||||||
|
wild_pets = await self.game_engine.get_location_spawns(location_name)
|
||||||
|
|
||||||
|
if wild_pets:
|
||||||
|
pet_list = ", ".join([pet["name"] for pet in wild_pets])
|
||||||
|
await self.send_message(connection, target, f"Wild pets in {location_name}: {pet_list}")
|
||||||
|
else:
|
||||||
|
await self.send_message(connection, target, f"{nickname}: No location found called '{location_name}'")
|
||||||
|
|
||||||
|
async def cmd_battle(self, connection, target, nickname, args):
|
||||||
|
await self.send_message(connection, target, f"{nickname}: Battle system coming soon!")
|
||||||
|
|
||||||
|
async def cmd_stats(self, connection, target, nickname, args):
|
||||||
|
player = await self.database.get_player(nickname)
|
||||||
|
if not player:
|
||||||
|
await self.send_message(connection, target, f"{nickname}: Use !start to begin your journey first!")
|
||||||
|
return
|
||||||
|
|
||||||
|
await self.send_message(connection, target,
|
||||||
|
f"{nickname}: Level {player['level']} | {player['experience']} XP | ${player['money']}")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
bot = PetBot()
|
bot = PetBot()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue