413 lines
10 KiB
Markdown
413 lines
10 KiB
Markdown
# Item Stats in Database - Implementation Summary
|
|
|
|
## ✅ Completed Successfully
|
|
|
|
Successfully added normalized item stats storage to the database for efficient querying and filtering.
|
|
|
|
---
|
|
|
|
## What Was Added
|
|
|
|
### 1. Database Migration: `add_item_stats`
|
|
|
|
**New Table: `item_stats`**
|
|
```sql
|
|
CREATE TABLE item_stats (
|
|
item_id INTEGER NOT NULL,
|
|
stat_type TEXT NOT NULL,
|
|
value REAL NOT NULL, -- Float/REAL for precise stat values
|
|
PRIMARY KEY (item_id, stat_type),
|
|
FOREIGN KEY (item_id) REFERENCES items(id) ON DELETE CASCADE
|
|
);
|
|
```
|
|
|
|
**Indexes Created:**
|
|
- `idx_item_stats_stat_type` - Find all items with a specific stat
|
|
- `idx_item_stats_value` - Range queries on stat values
|
|
- `idx_item_stats_type_value` - Combined queries (type + value range)
|
|
|
|
**Composite Primary Key:**
|
|
- `(item_id, stat_type)` - Ensures each item can only have one value per stat type
|
|
- Prevents duplicate stats for the same item
|
|
|
|
### 2. Supported Stat Types
|
|
|
|
All 20 stat types from the game:
|
|
|
|
**Damage Stats:**
|
|
- `damage_physical` - Physical Damage
|
|
- `damage_magical` - Magical Damage
|
|
- `damage_ranged` - Ranged Damage
|
|
|
|
**Accuracy Stats:**
|
|
- `accuracy_physical` - Physical Accuracy
|
|
- `accuracy_magical` - Magical Accuracy
|
|
- `accuracy_ranged` - Ranged Accuracy
|
|
|
|
**Resistance Stats:**
|
|
- `resistance_physical` - Physical Resistance
|
|
- `resistance_magical` - Magical Resistance
|
|
- `resistance_ranged` - Ranged Resistance
|
|
|
|
**Health & Mana:**
|
|
- `health` - Health
|
|
- `mana` - Mana
|
|
- `health_regen` - Health Regeneration
|
|
- `mana_regen` - Mana Regeneration
|
|
|
|
**Special Stats:**
|
|
- `critical` - Critical
|
|
- `healing` - Healing
|
|
- `movement_speed` - Movement Speed
|
|
|
|
**Enemy Type Damage:**
|
|
- `critter_slaying` - Damage against Critters
|
|
- `damage_vs_beasts` - Damage against Beasts
|
|
- `damage_vs_undead` - Damage against Undead
|
|
|
|
### 3. Code Changes
|
|
|
|
**`src/databases/item_database.rs`**
|
|
- Updated `save_to_db_with_images()` to also save stats
|
|
- Iterates through `item.stats` vec and inserts each stat
|
|
- Maps `StatType` enum to string representation
|
|
- Uses same transaction as item and recipe saving
|
|
|
|
---
|
|
|
|
## Results from Test Data
|
|
|
|
### Statistics
|
|
|
|
```
|
|
✅ Total stat entries: 84
|
|
📊 Most common stats:
|
|
- health: 20 items
|
|
- resistance_magical: 9 items
|
|
- resistance_physical: 9 items
|
|
- accuracy_magical: 7 items
|
|
- mana: 7 items
|
|
- mana_regen: 7 items
|
|
```
|
|
|
|
### Example Items with Stats
|
|
|
|
**The Bad Ring (ID: 73)** - 12 stats (testing item)
|
|
- All stats maxed at 1000 (accuracy, damage, health, mana, resistances)
|
|
|
|
**Ring of the High Mage (ID: 394)** - 5 stats
|
|
- Health: 50
|
|
- Mana: 50
|
|
- Mana Regen: 2
|
|
- Magical Resistance: 35
|
|
- Physical Resistance: 15
|
|
|
|
**Crown of the Tyrant** - High health bonus
|
|
- Health: 100
|
|
|
|
---
|
|
|
|
## Usage Examples
|
|
|
|
### SQL Queries
|
|
|
|
```sql
|
|
-- Find all items with health bonuses
|
|
SELECT i.id, i.name, s.value as health
|
|
FROM items i
|
|
JOIN item_stats s ON i.id = s.item_id
|
|
WHERE s.stat_type = 'health'
|
|
ORDER BY s.value DESC;
|
|
|
|
-- Find weapons with high physical damage
|
|
SELECT i.id, i.name, s.value as damage
|
|
FROM items i
|
|
JOIN item_stats s ON i.id = s.item_id
|
|
WHERE i.item_type = 'weapon'
|
|
AND s.stat_type = 'damage_physical'
|
|
AND s.value > 50
|
|
ORDER BY s.value DESC;
|
|
|
|
-- Find items with multiple resistance types
|
|
SELECT i.id, i.name, COUNT(*) as resistance_count
|
|
FROM items i
|
|
JOIN item_stats s ON i.id = s.item_id
|
|
WHERE s.stat_type LIKE 'resistance_%'
|
|
GROUP BY i.id, i.name
|
|
HAVING COUNT(*) >= 2;
|
|
|
|
-- Find balanced items (have both offense and defense)
|
|
SELECT i.id, i.name
|
|
FROM items i
|
|
WHERE EXISTS (
|
|
SELECT 1 FROM item_stats
|
|
WHERE item_id = i.id AND stat_type LIKE 'damage_%'
|
|
)
|
|
AND EXISTS (
|
|
SELECT 1 FROM item_stats
|
|
WHERE item_id = i.id AND stat_type LIKE 'resistance_%'
|
|
);
|
|
|
|
-- Get all stats for a specific item
|
|
SELECT stat_type, value
|
|
FROM item_stats
|
|
WHERE item_id = 394
|
|
ORDER BY stat_type;
|
|
|
|
-- Find items within a stat range
|
|
SELECT i.name, s.value
|
|
FROM items i
|
|
JOIN item_stats s ON i.id = s.item_id
|
|
WHERE s.stat_type = 'health'
|
|
AND s.value BETWEEN 50 AND 100;
|
|
```
|
|
|
|
### Rust Queries
|
|
|
|
```rust
|
|
use diesel::prelude::*;
|
|
use cursebreaker_parser::schema::{items, item_stats};
|
|
|
|
// Find items with high health
|
|
let high_health_items = item_stats::table
|
|
.inner_join(items::table)
|
|
.filter(item_stats::stat_type.eq("health"))
|
|
.filter(item_stats::value.gt(100.0))
|
|
.select((items::name, item_stats::value))
|
|
.load::<(String, f32)>(&mut conn)?;
|
|
|
|
// Get all stats for an item
|
|
let item_id = 394;
|
|
let stats = item_stats::table
|
|
.filter(item_stats::item_id.eq(item_id))
|
|
.select((item_stats::stat_type, item_stats::value))
|
|
.load::<(String, f32)>(&mut conn)?;
|
|
```
|
|
|
|
---
|
|
|
|
## Web API Examples
|
|
|
|
For your interactive map and wiki:
|
|
|
|
### 1. Filter Items by Stat
|
|
|
|
```rust
|
|
// GET /api/items?stat=health&min=50&max=100
|
|
pub async fn filter_items_by_stat(
|
|
stat: String,
|
|
min: f32,
|
|
max: f32,
|
|
) -> Result<Vec<Item>> {
|
|
let items = item_stats::table
|
|
.inner_join(items::table)
|
|
.filter(item_stats::stat_type.eq(stat))
|
|
.filter(item_stats::value.between(min, max))
|
|
.select(items::all_columns)
|
|
.load(&mut conn)?;
|
|
|
|
Ok(items)
|
|
}
|
|
```
|
|
|
|
### 2. Item Comparison Tool
|
|
|
|
```rust
|
|
// GET /api/items/compare?ids=394,340,179
|
|
pub async fn compare_items(item_ids: Vec<i32>) -> Result<ItemComparison> {
|
|
let stats = item_stats::table
|
|
.filter(item_stats::item_id.eq_any(item_ids))
|
|
.load::<(i32, String, f32)>(&mut conn)?;
|
|
|
|
// Group by item and return comparison table
|
|
Ok(build_comparison(stats))
|
|
}
|
|
```
|
|
|
|
### 3. Best Items for Stat
|
|
|
|
```rust
|
|
// GET /api/items/best?stat=damage_physical&limit=10
|
|
pub async fn best_items_for_stat(
|
|
stat: String,
|
|
limit: i64,
|
|
) -> Result<Vec<ItemWithStat>> {
|
|
let items = item_stats::table
|
|
.inner_join(items::table)
|
|
.filter(item_stats::stat_type.eq(stat))
|
|
.order_by(item_stats::value.desc())
|
|
.limit(limit)
|
|
.select((items::all_columns, item_stats::value))
|
|
.load(&mut conn)?;
|
|
|
|
Ok(items)
|
|
}
|
|
```
|
|
|
|
### 4. Item Build Suggestions
|
|
|
|
```rust
|
|
// GET /api/builds?focus=mage
|
|
pub async fn suggest_build(focus: String) -> Result<Build> {
|
|
// For mage build: high mana, mana_regen, magical damage/accuracy
|
|
let stats_to_prioritize = match focus.as_str() {
|
|
"mage" => vec!["mana", "mana_regen", "damage_magical", "accuracy_magical"],
|
|
"warrior" => vec!["health", "damage_physical", "resistance_physical"],
|
|
"archer" => vec!["damage_ranged", "accuracy_ranged", "critical"],
|
|
_ => vec![]
|
|
};
|
|
|
|
// Find best items for each slot with those stats
|
|
// ...
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Benefits
|
|
|
|
✅ **Efficient Filtering** - Query items by stat without parsing JSON
|
|
✅ **Range Queries** - Find items within stat value ranges
|
|
✅ **Comparative Analysis** - Easy item comparisons
|
|
✅ **Build Optimization** - Find best items for specific builds
|
|
✅ **Indexed** - Fast queries on stat types and values
|
|
✅ **Normalized** - No data duplication, consistent values
|
|
✅ **Type-Safe** - Composite PK prevents duplicate stats
|
|
|
|
---
|
|
|
|
## Performance Considerations
|
|
|
|
### Query Optimization
|
|
|
|
**Fast Queries** (uses indexes):
|
|
```sql
|
|
-- Single stat lookup
|
|
WHERE stat_type = 'health' -- Uses idx_item_stats_stat_type
|
|
|
|
-- Range query
|
|
WHERE value > 50 -- Uses idx_item_stats_value
|
|
|
|
-- Combined
|
|
WHERE stat_type = 'health' AND value > 50 -- Uses idx_item_stats_type_value
|
|
```
|
|
|
|
**Slower Queries** (may need optimization):
|
|
```sql
|
|
-- Multiple stat requirements (requires multiple joins)
|
|
-- Consider caching or denormalizing for frequently accessed combinations
|
|
```
|
|
|
|
### Storage Impact
|
|
|
|
- 84 stat entries currently
|
|
- Average ~3-4 stats per item with stats
|
|
- Minimal storage: ~8 bytes per entry (int + text + float)
|
|
- Total: < 1 KB for current data
|
|
|
|
As more items with stats are added, storage remains efficient due to normalization.
|
|
|
|
---
|
|
|
|
## Wiki Feature Ideas
|
|
|
|
### 1. Item Comparison Tool
|
|
Show side-by-side comparison of multiple items with all their stats.
|
|
|
|
### 2. Best-in-Slot Lists
|
|
- Best weapons for physical damage
|
|
- Best armor for magical resistance
|
|
- Best accessories for health/mana
|
|
|
|
### 3. Build Guides
|
|
- "Mage Build" - show items with high mana/magical stats
|
|
- "Tank Build" - show items with high health/resistances
|
|
- "DPS Build" - show items with high damage/critical
|
|
|
|
### 4. Stat Distribution Charts
|
|
- Visualize stat value distributions
|
|
- Show which stats are rare vs common
|
|
- Identify stat "sweet spots"
|
|
|
|
### 5. Upgrade Paths
|
|
- Show progression of items by stat values
|
|
- "From 50 health → 100 health → 150 health"
|
|
|
|
---
|
|
|
|
## Future Enhancements
|
|
|
|
### Optional Additions:
|
|
|
|
1. **Stat Ranges Table** - For items with variable stats
|
|
```sql
|
|
CREATE TABLE item_stat_ranges (
|
|
item_id INTEGER,
|
|
stat_type TEXT,
|
|
min_value REAL,
|
|
max_value REAL,
|
|
PRIMARY KEY (item_id, stat_type)
|
|
);
|
|
```
|
|
|
|
2. **Derived Stats** - Calculate total stats for equipment sets
|
|
```sql
|
|
-- Sum up stats across multiple equipped items
|
|
SELECT stat_type, SUM(value) as total
|
|
FROM item_stats
|
|
WHERE item_id IN (/* equipped item IDs */)
|
|
GROUP BY stat_type;
|
|
```
|
|
|
|
3. **Stat Scaling** - Track how stats scale with item level
|
|
```sql
|
|
SELECT i.level, AVG(s.value) as avg_damage
|
|
FROM items i
|
|
JOIN item_stats s ON i.id = s.item_id
|
|
WHERE s.stat_type = 'damage_physical'
|
|
GROUP BY i.level;
|
|
```
|
|
|
|
4. **Stat Categories** - Group related stats
|
|
```sql
|
|
CREATE TABLE stat_categories (
|
|
stat_type TEXT PRIMARY KEY,
|
|
category TEXT -- 'offense', 'defense', 'utility', etc.
|
|
);
|
|
```
|
|
|
|
---
|
|
|
|
## Verification
|
|
|
|
Run the verification script anytime:
|
|
```bash
|
|
cargo run --bin verify-stats
|
|
```
|
|
|
|
Shows:
|
|
- Total stat entries
|
|
- Breakdown by stat type
|
|
- Items with most stats
|
|
- Example queries (high damage, health bonuses)
|
|
|
|
---
|
|
|
|
## Ready for Production
|
|
|
|
Your item stats are now:
|
|
- ✅ Stored in normalized table
|
|
- ✅ Efficiently queryable
|
|
- ✅ Properly indexed
|
|
- ✅ Ready for filtering and comparison
|
|
- ✅ Available for build optimization
|
|
- ✅ Perfect for wiki features
|
|
|
|
The database now contains complete item data with:
|
|
- ✅ Metadata (type, level, price, etc.)
|
|
- ✅ Images (3 sizes, WebP)
|
|
- ✅ Crafting recipes (normalized)
|
|
- ✅ **Stats (normalized, queryable)**
|
|
|
|
Your interactive map and wiki have everything needed for a rich item browsing experience! 🎮
|