From 3098be7f36a8c33301f8511f4e42f27442080c2b Mon Sep 17 00:00:00 2001 From: megaproxy Date: Mon, 14 Jul 2025 16:57:41 +0100 Subject: [PATCH] Implement pet nicknames system - database, IRC command, validation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- PROJECT_STATUS.md | 31 +++++++++++++++++++++++++++++ modules/pet_management.py | 30 ++++++++++++++++++++++++++-- src/database.py | 42 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+), 2 deletions(-) diff --git a/PROJECT_STATUS.md b/PROJECT_STATUS.md index 2bcd51b..da8c2dc 100644 --- a/PROJECT_STATUS.md +++ b/PROJECT_STATUS.md @@ -32,6 +32,37 @@ ## 🔄 Current Todo List +### Planned Next Features (In Priority Order) + +#### Phase 1: Pet Nicknames System +- [ ] **Database Schema** - Add nickname column to player_pets table +- [ ] **IRC Commands** - Add !nickname command +- [ ] **Web Interface** - Display nicknames on player profiles +- [ ] **Validation** - Ensure appropriate nickname length/content limits + +#### Phase 2: Team Builder Tool (Secure PIN System) +- [ ] **Web Team Editor** - Interface for modifying pet teams +- [ ] **PIN Generation** - Create unique verification codes for each request +- [ ] **Temporary Storage** - Hold pending team changes until PIN validation +- [ ] **IRC PIN Delivery** - PM verification codes to players +- [ ] **PIN Validation** - Web form to enter and confirm codes +- [ ] **Database Updates** - Apply team changes only after successful PIN verification +- [ ] **Security Cleanup** - Clear expired PINs and pending requests + +**Secure Technical Flow:** +``` +Web: Save Team → Generate PIN → Store Pending Changes → IRC: PM PIN + ↓ +Web: Enter PIN → Validate PIN → Apply Database Changes → Clear Request +``` +*Critical: No database changes until PIN verification succeeds* + +#### Phase 3: Auto-Battle Mode +- [ ] **Auto-Battle Logic** - Automated pet combat in current location +- [ ] **PM Notifications** - Send results to player via private message +- [ ] **Flood Control** - 5-second delays between battles, wins/losses only +- [ ] **Stop Mechanism** - Commands to start/stop auto-battle mode + ### Low Priority - [ ] **Enhanced Petdex Filtering** - Add search by type, evolution chains, rarity filters diff --git a/modules/pet_management.py b/modules/pet_management.py index cd6d040..26ffb25 100644 --- a/modules/pet_management.py +++ b/modules/pet_management.py @@ -7,7 +7,7 @@ class PetManagement(BaseModule): """Handles team, pets, and future pet management commands""" def get_commands(self): - return ["team", "pets", "activate", "deactivate", "swap"] + return ["team", "pets", "activate", "deactivate", "swap", "nickname"] async def handle_command(self, channel, nickname, command, args): if command == "team": @@ -20,6 +20,8 @@ class PetManagement(BaseModule): await self.cmd_deactivate(channel, nickname, args) elif command == "swap": await self.cmd_swap(channel, nickname, args) + elif command == "nickname": + await self.cmd_nickname(channel, nickname, args) async def cmd_team(self, channel, nickname): """Show active pets (channel display)""" @@ -158,4 +160,28 @@ class PetManagement(BaseModule): self.send_message(channel, f"{nickname}: Pet swap completed!") else: self.send_pm(nickname, f"❌ {result['error']}") - self.send_message(channel, f"{nickname}: Pet swap failed - check PM for details!") \ No newline at end of file + self.send_message(channel, f"{nickname}: Pet swap failed - check PM for details!") + + async def cmd_nickname(self, channel, nickname, args): + """Set a nickname for a pet""" + if len(args) < 2: + self.send_message(channel, f"{nickname}: Usage: !nickname ") + self.send_message(channel, f"Example: !nickname Charmander Flamey") + return + + player = await self.require_player(channel, nickname) + if not player: + return + + # Split args into pet identifier and new nickname + pet_identifier = args[0] + new_nickname = " ".join(args[1:]) + + result = await self.database.set_pet_nickname(player["id"], pet_identifier, new_nickname) + + if result["success"]: + old_name = result["old_name"] + new_name = result["new_nickname"] + self.send_message(channel, f"✨ {nickname}: {old_name} is now nicknamed '{new_name}'!") + else: + self.send_message(channel, f"❌ {nickname}: {result['error']}") \ No newline at end of file diff --git a/src/database.py b/src/database.py index 42aeec8..2ab484b 100644 --- a/src/database.py +++ b/src/database.py @@ -1316,4 +1316,46 @@ class Database: "total_encounters": total_encounters, "total_species": total_species, "completion_percentage": round(completion_percentage, 1) + } + + async def set_pet_nickname(self, player_id: int, pet_identifier: str, nickname: str) -> Dict: + """Set a nickname for a pet. Returns result dict.""" + # Validate nickname + if not nickname.strip(): + return {"success": False, "error": "Nickname cannot be empty"} + + nickname = nickname.strip() + if len(nickname) > 20: + return {"success": False, "error": "Nickname must be 20 characters or less"} + + # Basic content validation + if any(char in nickname for char in ['<', '>', '&', '"', "'"]): + return {"success": False, "error": "Nickname contains invalid characters"} + + async with aiosqlite.connect(self.db_path) as db: + db.row_factory = aiosqlite.Row + + # Find pet by current nickname or species name + cursor = await db.execute(""" + SELECT p.*, ps.name as species_name + FROM pets p + JOIN pet_species ps ON p.species_id = ps.id + WHERE p.player_id = ? + AND (p.nickname = ? OR ps.name = ?) + LIMIT 1 + """, (player_id, pet_identifier, pet_identifier)) + + pet = await cursor.fetchone() + if not pet: + return {"success": False, "error": f"Pet '{pet_identifier}' not found"} + + # Update nickname + await db.execute("UPDATE pets SET nickname = ? WHERE id = ?", (nickname, pet["id"])) + await db.commit() + + return { + "success": True, + "pet": dict(pet), + "old_name": pet["nickname"] or pet["species_name"], + "new_nickname": nickname } \ No newline at end of file