Add complete item collection system (v0.2.0)

🎒 Item Collection System:
- 16 unique items across 5 categories (healing, battle, rare, location, special)
- Rarity tiers: Common, Uncommon, Rare, Epic, Legendary with symbols
- 30% chance to find items during exploration
- Location-specific items (shells, mushrooms, crystals, runes)
- Inventory management with \!inventory and \!use commands
- Web interface integration showing player inventories
- Consumable items: healing potions, battle boosters, lucky charms

🔧 Technical Updates:
- Added items and player_inventory database tables
- New Inventory module for item management
- Updated game engine with item discovery system
- Enhanced web interface with inventory display
- Item initialization from config/items.json

🆕 New Commands:
- \!inventory / \!inv / \!items - View collected items by category
- \!use <item name> - Use consumable items on active pets

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
megaproxy 2025-07-14 00:19:57 +01:00
parent e0edcb391a
commit db144da24f
13 changed files with 952 additions and 22 deletions

View file

@ -186,6 +186,33 @@ class Database:
)
""")
await db.execute("""
CREATE TABLE IF NOT EXISTS items (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT UNIQUE NOT NULL,
description TEXT NOT NULL,
category TEXT NOT NULL,
rarity TEXT NOT NULL,
effect TEXT,
effect_value INTEGER DEFAULT 0,
consumable BOOLEAN DEFAULT TRUE,
sell_value INTEGER DEFAULT 0
)
""")
await db.execute("""
CREATE TABLE IF NOT EXISTS player_inventory (
id INTEGER PRIMARY KEY AUTOINCREMENT,
player_id INTEGER NOT NULL,
item_id INTEGER NOT NULL,
quantity INTEGER DEFAULT 1,
obtained_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (player_id) REFERENCES players (id),
FOREIGN KEY (item_id) REFERENCES items (id),
UNIQUE(player_id, item_id)
)
""")
await db.commit()
async def get_player(self, nickname: str) -> Optional[Dict]:
@ -519,4 +546,144 @@ class Database:
"pet2": dict(pet2),
"pet1_now": "active" if not pet1["is_active"] else "storage",
"pet2_now": "active" if not pet2["is_active"] else "storage"
}
}
# Item and Inventory Methods
async def add_item_to_inventory(self, player_id: int, item_name: str, quantity: int = 1) -> bool:
"""Add an item to player's inventory"""
async with aiosqlite.connect(self.db_path) as db:
# Get item ID
cursor = await db.execute("SELECT id FROM items WHERE name = ?", (item_name,))
item = await cursor.fetchone()
if not item:
return False
item_id = item[0]
# Check if player already has this item
cursor = await db.execute(
"SELECT quantity FROM player_inventory WHERE player_id = ? AND item_id = ?",
(player_id, item_id)
)
existing = await cursor.fetchone()
if existing:
# Update quantity
new_quantity = existing[0] + quantity
await db.execute(
"UPDATE player_inventory SET quantity = ? WHERE player_id = ? AND item_id = ?",
(new_quantity, player_id, item_id)
)
else:
# Insert new item
await db.execute(
"INSERT INTO player_inventory (player_id, item_id, quantity) VALUES (?, ?, ?)",
(player_id, item_id, quantity)
)
await db.commit()
return True
async def get_player_inventory(self, player_id: int) -> List[Dict]:
"""Get all items in player's inventory"""
async with aiosqlite.connect(self.db_path) as db:
db.row_factory = aiosqlite.Row
cursor = await db.execute("""
SELECT i.name, i.description, i.category, i.rarity, i.effect,
i.effect_value, pi.quantity, pi.obtained_at
FROM player_inventory pi
JOIN items i ON pi.item_id = i.id
WHERE pi.player_id = ?
ORDER BY i.rarity DESC, i.name ASC
""", (player_id,))
rows = await cursor.fetchall()
return [dict(row) for row in rows]
async def use_item(self, player_id: int, item_name: str) -> Dict:
"""Use an item from inventory"""
async with aiosqlite.connect(self.db_path) as db:
# Get item details
db.row_factory = aiosqlite.Row
cursor = await db.execute("""
SELECT i.*, pi.quantity
FROM items i
JOIN player_inventory pi ON i.id = pi.item_id
WHERE pi.player_id = ? AND i.name = ?
""", (player_id, item_name))
item = await cursor.fetchone()
if not item:
return {"success": False, "error": "Item not found in inventory"}
if item["quantity"] <= 0:
return {"success": False, "error": "No items of this type available"}
# Remove one from inventory if consumable
if item["consumable"]:
if item["quantity"] == 1:
await db.execute(
"DELETE FROM player_inventory WHERE player_id = ? AND item_id = ?",
(player_id, item["id"])
)
else:
await db.execute(
"UPDATE player_inventory SET quantity = quantity - 1 WHERE player_id = ? AND item_id = ?",
(player_id, item["id"])
)
await db.commit()
return {
"success": True,
"item": dict(item),
"effect": item["effect"],
"effect_value": item["effect_value"]
}
async def initialize_items(self):
"""Initialize items from config file"""
import json
try:
with open("config/items.json", "r") as f:
items_data = json.load(f)
except FileNotFoundError:
print("Items config file not found")
return
async with aiosqlite.connect(self.db_path) as db:
# Clear existing items
await db.execute("DELETE FROM items")
# Add all items from config
for category_items in items_data.values():
if category_items and isinstance(category_items, list):
for item in category_items:
if "id" in item: # Valid item entry
sell_value = 0
if item.get("effect") == "sell_value":
sell_value = item.get("effect_value", 0)
await db.execute("""
INSERT OR REPLACE INTO items
(id, name, description, category, rarity, effect, effect_value, sell_value)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
""", (
item["id"],
item["name"],
item["description"],
item["category"],
item["rarity"],
item.get("effect", "none"),
item.get("effect_value", 0),
sell_value
))
await db.commit()
print("Items initialized from config")
async def update_pet_hp(self, pet_id: int, new_hp: int) -> bool:
"""Update a pet's current HP"""
async with aiosqlite.connect(self.db_path) as db:
await db.execute("UPDATE pets SET hp = ? WHERE id = ?", (new_hp, pet_id))
await db.commit()
return True