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:
parent
4de0c1a124
commit
3098be7f36
3 changed files with 101 additions and 2 deletions
|
|
@ -32,6 +32,37 @@
|
||||||
|
|
||||||
## 🔄 Current Todo List
|
## 🔄 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
|
### Low Priority
|
||||||
- [ ] **Enhanced Petdex Filtering** - Add search by type, evolution chains, rarity filters
|
- [ ] **Enhanced Petdex Filtering** - Add search by type, evolution chains, rarity filters
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ class PetManagement(BaseModule):
|
||||||
"""Handles team, pets, and future pet management commands"""
|
"""Handles team, pets, and future pet management commands"""
|
||||||
|
|
||||||
def get_commands(self):
|
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):
|
async def handle_command(self, channel, nickname, command, args):
|
||||||
if command == "team":
|
if command == "team":
|
||||||
|
|
@ -20,6 +20,8 @@ class PetManagement(BaseModule):
|
||||||
await self.cmd_deactivate(channel, nickname, args)
|
await self.cmd_deactivate(channel, nickname, args)
|
||||||
elif command == "swap":
|
elif command == "swap":
|
||||||
await self.cmd_swap(channel, nickname, args)
|
await self.cmd_swap(channel, nickname, args)
|
||||||
|
elif command == "nickname":
|
||||||
|
await self.cmd_nickname(channel, nickname, args)
|
||||||
|
|
||||||
async def cmd_team(self, channel, nickname):
|
async def cmd_team(self, channel, nickname):
|
||||||
"""Show active pets (channel display)"""
|
"""Show active pets (channel display)"""
|
||||||
|
|
@ -158,4 +160,28 @@ class PetManagement(BaseModule):
|
||||||
self.send_message(channel, f"{nickname}: Pet swap completed!")
|
self.send_message(channel, f"{nickname}: Pet swap completed!")
|
||||||
else:
|
else:
|
||||||
self.send_pm(nickname, f"❌ {result['error']}")
|
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']}")
|
||||||
|
|
@ -1316,4 +1316,46 @@ class Database:
|
||||||
"total_encounters": total_encounters,
|
"total_encounters": total_encounters,
|
||||||
"total_species": total_species,
|
"total_species": total_species,
|
||||||
"completion_percentage": round(completion_percentage, 1)
|
"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
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue