10 KiB
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
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 statidx_item_stats_value- Range queries on stat valuesidx_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 Damagedamage_magical- Magical Damagedamage_ranged- Ranged Damage
Accuracy Stats:
accuracy_physical- Physical Accuracyaccuracy_magical- Magical Accuracyaccuracy_ranged- Ranged Accuracy
Resistance Stats:
resistance_physical- Physical Resistanceresistance_magical- Magical Resistanceresistance_ranged- Ranged Resistance
Health & Mana:
health- Healthmana- Manahealth_regen- Health Regenerationmana_regen- Mana Regeneration
Special Stats:
critical- Criticalhealing- Healingmovement_speed- Movement Speed
Enemy Type Damage:
critter_slaying- Damage against Crittersdamage_vs_beasts- Damage against Beastsdamage_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.statsvec and inserts each stat - Maps
StatTypeenum 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
-- 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
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
// 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
// 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
// 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
// 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):
-- 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):
-- 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:
-
Stat Ranges Table - For items with variable stats
CREATE TABLE item_stat_ranges ( item_id INTEGER, stat_type TEXT, min_value REAL, max_value REAL, PRIMARY KEY (item_id, stat_type) ); -
Derived Stats - Calculate total stats for equipment sets
-- 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; -
Stat Scaling - Track how stats scale with item level
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; -
Stat Categories - Group related stats
CREATE TABLE stat_categories ( stat_type TEXT PRIMARY KEY, category TEXT -- 'offense', 'defense', 'utility', etc. );
Verification
Run the verification script anytime:
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! 🎮