Implement pet nicknames system - database, IRC command, validation

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
megaproxy 2025-07-14 16:57:41 +01:00
parent 4de0c1a124
commit 3098be7f36
3 changed files with 101 additions and 2 deletions

View file

@ -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 <pet_id> <name> 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

View file

@ -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!")
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 <pet> <new_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']}")

View file

@ -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
}