# EverQuest II Loot System This package implements a comprehensive loot generation and management system for the EverQuest II server emulator, converted from the original C++ implementation. ## Overview The loot system handles: - **Loot Generation**: Probability-based item and coin generation from configurable loot tables - **Treasure Chests**: Physical chest spawns with tier-appropriate appearances - **Global Loot**: Level, race, and zone-based loot assignments - **Loot Distribution**: Group loot methods and player rights management - **Database Integration**: Persistent loot table and assignment storage - **Client Communication**: Version-specific packet building for loot windows ## Architecture ### Core Components #### LootDatabase (`database.go`) - Manages all database operations for loot tables, drops, and assignments - Caches loot data in memory for performance - Supports real-time updates and reloading #### LootManager (`manager.go`) - Central coordinator for loot generation and chest management - Implements probability-based loot algorithms - Handles treasure chest lifecycle and cleanup #### ChestService (`chest.go`) - Manages treasure chest interactions (view, loot, disarm, lockpick) - Validates player permissions and positioning - Integrates with player and zone services #### LootPacketBuilder (`packets.go`) - Builds client-specific packets for loot communication - Supports multiple client versions (v1 through v60114+) - Handles loot window updates and interaction responses #### LootSystem (`integration.go`) - High-level integration layer combining all components - Provides simplified API for common operations - Manages system lifecycle and configuration ### Data Structures #### LootTable ```go type LootTable struct { ID int32 // Unique table identifier Name string // Descriptive name MinCoin int32 // Minimum coin drop MaxCoin int32 // Maximum coin drop MaxLootItems int16 // Maximum items per loot LootDropProbability float32 // Chance for loot to drop (0-100%) CoinProbability float32 // Chance for coins to drop (0-100%) Drops []*LootDrop // Individual item drops } ``` #### LootDrop ```go type LootDrop struct { LootTableID int32 // Parent table ID ItemID int32 // Item to drop ItemCharges int16 // Item stack size/charges EquipItem bool // Auto-equip item Probability float32 // Drop chance (0-100%) NoDropQuestCompletedID int32 // Required quest completion } ``` #### TreasureChest ```go type TreasureChest struct { ID int32 // Unique chest ID SpawnID int32 // Source spawn ID ZoneID int32 // Zone location X, Y, Z float32 // Position coordinates Heading float32 // Orientation AppearanceID int32 // Visual appearance LootResult *LootResult // Contained items and coins Created time.Time // Creation timestamp LootRights []uint32 // Players with access rights IsDisarmable bool // Can be disarmed IsLocked bool // Requires lockpicking } ``` ## Database Schema ### Core Tables #### loottable ```sql CREATE TABLE loottable ( id INTEGER PRIMARY KEY, name TEXT, mincoin INTEGER DEFAULT 0, maxcoin INTEGER DEFAULT 0, maxlootitems INTEGER DEFAULT 6, lootdrop_probability REAL DEFAULT 100.0, coin_probability REAL DEFAULT 50.0 ); ``` #### lootdrop ```sql CREATE TABLE lootdrop ( loot_table_id INTEGER, item_id INTEGER, item_charges INTEGER DEFAULT 1, equip_item INTEGER DEFAULT 0, probability REAL DEFAULT 100.0, no_drop_quest_completed_id INTEGER DEFAULT 0 ); ``` #### spawn_loot ```sql CREATE TABLE spawn_loot ( spawn_id INTEGER, loottable_id INTEGER ); ``` #### loot_global ```sql CREATE TABLE loot_global ( type TEXT, -- 'level', 'race', or 'zone' loot_table INTEGER, -- Target loot table ID value1 INTEGER, -- Min level, race ID, or zone ID value2 INTEGER, -- Max level (for level type) value3 INTEGER, -- Loot tier value4 INTEGER -- Reserved ); ``` ## Usage Examples ### Basic Setup ```go // Create loot system config := &LootSystemConfig{ DatabaseConnection: db, ItemMasterList: itemMasterList, PlayerService: playerService, ZoneService: zoneService, ClientService: clientService, ItemPacketBuilder: itemPacketBuilder, StartCleanupTimer: true, } lootSystem, err := NewLootSystem(config) if err != nil { log.Fatal(err) } ``` ### Generate Loot and Create Chest ```go // Create loot context context := &LootContext{ PlayerLevel: 25, PlayerRace: 1, ZoneID: 100, KillerID: playerID, GroupMembers: []uint32{playerID}, CompletedQuests: playerQuests, LootMethod: GroupLootMethodFreeForAll, } // Generate loot and create chest chest, err := lootSystem.GenerateAndCreateChest( spawnID, zoneID, x, y, z, heading, context) if err != nil { log.Printf("Failed to create loot chest: %v", err) } ``` ### Handle Player Loot Interaction ```go // Player opens chest err := lootSystem.ShowChestToPlayer(chestID, playerID) // Player loots specific item err = lootSystem.HandlePlayerLootInteraction( chestID, playerID, ChestInteractionLoot, itemUniqueID) // Player loots everything err = lootSystem.HandlePlayerLootInteraction( chestID, playerID, ChestInteractionLootAll, 0) ``` ### Create Loot Tables ```go // Create a simple loot table items := []QuickLootItem{ {ItemID: 1001, Charges: 1, Probability: 100.0, AutoEquip: false}, {ItemID: 1002, Charges: 5, Probability: 50.0, AutoEquip: false}, {ItemID: 1003, Charges: 1, Probability: 25.0, AutoEquip: true}, } err := lootSystem.CreateQuickLootTable( tableID, "Orc Warrior Loot", items, 10, 50, 3) // Assign to spawns spawnIDs := []int32{2001, 2002, 2003} err = lootSystem.AssignLootToSpawns(tableID, spawnIDs) ``` ## Chest Appearances Chest appearance is automatically selected based on the highest tier item: | Tier Range | Appearance | Chest Type | |------------|------------|------------| | 1-2 (Common-Uncommon) | 4034 | Small Chest | | 3-4 (Treasured-Rare) | 5864 | Treasure Chest | | 5-6 (Legendary-Fabled) | 5865 | Ornate Chest | | 7+ (Mythical+) | 4015 | Exquisite Chest | ## Loot Generation Algorithm 1. **Table Selection**: Get loot tables assigned to spawn + applicable global tables 2. **Drop Probability**: Roll against `lootdrop_probability` to determine if loot drops 3. **Coin Generation**: If `coin_probability` succeeds, generate random coins between min/max 4. **Item Processing**: For each loot drop: - Check quest requirements - Roll against item probability - Generate item instance with specified charges - Stop when `maxlootitems` reached 5. **Chest Creation**: If items qualify (tier >= Common), create treasure chest ## Global Loot System Global loot provides automatic loot assignment based on: ### Level-Based Loot ```go err := lootSystem.CreateGlobalLevelLoot(10, 20, tableID, LootTierCommon) ``` ### Race-Based Loot ```sql INSERT INTO loot_global (type, loot_table, value1, value2) VALUES ('race', 100, 1, 0); -- Human racial loot ``` ### Zone-Based Loot ```sql INSERT INTO loot_global (type, loot_table, value1, value2) VALUES ('zone', 200, 150, 0); -- Zone 150 specific loot ``` ## Group Loot Methods The system supports various loot distribution methods: - **Free For All**: Anyone can loot anything - **Round Robin**: Items distributed in turn order - **Master Looter**: Designated player distributes loot - **Need/Greed**: Players roll need or greed for items - **Lotto**: Random distribution for high-tier items ## Statistics and Monitoring ```go // Get comprehensive statistics stats, err := lootSystem.GetSystemStatistics() // Check loot generation stats genStats := lootSystem.Manager.GetStatistics() fmt.Printf("Total loots: %d, Average items per loot: %.2f", genStats.TotalLoots, genStats.AverageItemsPerLoot) ``` ## Validation and Debugging ```go // Validate all items in loot tables exist errors := lootSystem.ValidateItemsInLootTables() for _, err := range errors { fmt.Printf("Validation error: %s\n", err.Description) } // Preview potential loot without generating preview, err := lootSystem.GetLootPreview(spawnID, context) fmt.Printf("Possible items: %d, Coin range: %d-%d", len(preview.PossibleItems), preview.MinCoins, preview.MaxCoins) ``` ## Performance Considerations - **Memory Caching**: All loot tables are cached in memory for fast access - **Prepared Statements**: Database queries use prepared statements for efficiency - **Concurrent Safety**: All operations are thread-safe with proper mutex usage - **Cleanup Timers**: Automatic cleanup of expired chests prevents memory leaks - **Batch Operations**: Support for bulk loot table and spawn assignments ## Client Version Compatibility The packet building system supports multiple EverQuest II client versions: - **Version 1**: Basic loot display (oldest clients) - **Version 373**: Added item type and icon support - **Version 546**: Enhanced item appearance data - **Version 1193**: Heirloom and no-trade flags - **Version 60114**: Full modern feature set with adornments ## Migration from C++ This Go implementation maintains full compatibility with the original C++ EQ2EMu loot system: - **Database Schema**: Identical table structure and data - **Loot Algorithms**: Same probability calculations and item selection - **Chest Logic**: Equivalent chest appearance and interaction rules - **Global Loot**: Compatible global loot table processing - **Packet Format**: Maintains client protocol compatibility ## Testing Comprehensive test suite covers: - Loot generation algorithms - Database operations - Chest interactions - Packet building - Statistics tracking - Performance benchmarks Run tests with: ```bash go test ./internal/items/loot/... ``` ## Configuration Key configuration constants in `constants.go`: - `DefaultMaxLootItems`: Maximum items per loot (default: 6) - `ChestDespawnTime`: Empty chest despawn time (5 minutes) - `ChestCleanupTime`: Force cleanup time (10 minutes) - `LootTierCommon`: Minimum tier for chest creation ## Error Handling The system provides detailed error reporting for: - Missing loot tables or items - Invalid player permissions - Database connection issues - Packet building failures - Chest interaction violations All errors are logged with appropriate prefixes (`[LOOT]`, `[CHEST]`, `[LOOT-DB]`) for easy debugging.