180 lines
5.5 KiB
Go
180 lines
5.5 KiB
Go
package ground_spawn
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"eq2emu/internal/common"
|
|
"eq2emu/internal/database"
|
|
"zombiezen.com/go/sqlite"
|
|
)
|
|
|
|
// MasterList manages all ground spawns using the generic base
|
|
type MasterList struct {
|
|
*common.MasterList[int32, *GroundSpawn]
|
|
}
|
|
|
|
// NewMasterList creates a new ground spawn master list
|
|
func NewMasterList() *MasterList {
|
|
return &MasterList{
|
|
MasterList: common.NewMasterList[int32, *GroundSpawn](),
|
|
}
|
|
}
|
|
|
|
// AddGroundSpawn adds a ground spawn to the master list
|
|
func (ml *MasterList) AddGroundSpawn(gs *GroundSpawn) bool {
|
|
return ml.MasterList.Add(gs)
|
|
}
|
|
|
|
// GetGroundSpawn retrieves a ground spawn by ID
|
|
func (ml *MasterList) GetGroundSpawn(groundSpawnID int32) *GroundSpawn {
|
|
return ml.MasterList.Get(groundSpawnID)
|
|
}
|
|
|
|
// RemoveGroundSpawn removes a ground spawn by ID
|
|
func (ml *MasterList) RemoveGroundSpawn(groundSpawnID int32) bool {
|
|
return ml.MasterList.Remove(groundSpawnID)
|
|
}
|
|
|
|
// GetByZone returns all ground spawns in a specific zone
|
|
func (ml *MasterList) GetByZone(zoneID int32) []*GroundSpawn {
|
|
return ml.MasterList.Filter(func(gs *GroundSpawn) bool {
|
|
return gs.ZoneID == zoneID
|
|
})
|
|
}
|
|
|
|
// GetBySkill returns all ground spawns that require a specific skill
|
|
func (ml *MasterList) GetBySkill(skill string) []*GroundSpawn {
|
|
return ml.MasterList.Filter(func(gs *GroundSpawn) bool {
|
|
return gs.CollectionSkill == skill
|
|
})
|
|
}
|
|
|
|
// GetAvailableSpawns returns all harvestable ground spawns
|
|
func (ml *MasterList) GetAvailableSpawns() []*GroundSpawn {
|
|
return ml.MasterList.Filter(func(gs *GroundSpawn) bool {
|
|
return gs.IsAvailable()
|
|
})
|
|
}
|
|
|
|
// GetDepletedSpawns returns all depleted ground spawns
|
|
func (ml *MasterList) GetDepletedSpawns() []*GroundSpawn {
|
|
return ml.MasterList.Filter(func(gs *GroundSpawn) bool {
|
|
return gs.IsDepleted()
|
|
})
|
|
}
|
|
|
|
// LoadFromDatabase loads all ground spawns from database
|
|
func (ml *MasterList) LoadFromDatabase(db *database.Database) error {
|
|
if db.GetType() == database.SQLite {
|
|
return ml.loadFromSQLite(db)
|
|
}
|
|
return ml.loadFromMySQL(db)
|
|
}
|
|
|
|
func (ml *MasterList) loadFromSQLite(db *database.Database) error {
|
|
return db.ExecTransient(`
|
|
SELECT id, groundspawn_id, name, collection_skill, number_harvests,
|
|
attempts_per_harvest, randomize_heading, respawn_time,
|
|
x, y, z, heading, zone_id, grid_id
|
|
FROM ground_spawns
|
|
ORDER BY groundspawn_id
|
|
`, func(stmt *sqlite.Stmt) error {
|
|
gs := &GroundSpawn{
|
|
ID: stmt.ColumnInt32(0),
|
|
GroundSpawnID: stmt.ColumnInt32(1),
|
|
Name: stmt.ColumnText(2),
|
|
CollectionSkill: stmt.ColumnText(3),
|
|
NumberHarvests: int8(stmt.ColumnInt32(4)),
|
|
AttemptsPerHarvest: int8(stmt.ColumnInt32(5)),
|
|
RandomizeHeading: stmt.ColumnBool(6),
|
|
RespawnTime: stmt.ColumnInt32(7),
|
|
X: float32(stmt.ColumnFloat(8)),
|
|
Y: float32(stmt.ColumnFloat(9)),
|
|
Z: float32(stmt.ColumnFloat(10)),
|
|
Heading: float32(stmt.ColumnFloat(11)),
|
|
ZoneID: stmt.ColumnInt32(12),
|
|
GridID: stmt.ColumnInt32(13),
|
|
db: db,
|
|
isNew: false,
|
|
IsAlive: true,
|
|
CurrentHarvests: int8(stmt.ColumnInt32(4)), // Initialize to max harvests
|
|
HarvestEntries: make([]*HarvestEntry, 0),
|
|
HarvestItems: make([]*HarvestEntryItem, 0),
|
|
}
|
|
|
|
// Load harvest data for this ground spawn
|
|
if err := gs.loadHarvestData(); err != nil {
|
|
return fmt.Errorf("failed to load harvest data for ground spawn %d: %w", gs.GroundSpawnID, err)
|
|
}
|
|
|
|
ml.MasterList.Add(gs)
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func (ml *MasterList) loadFromMySQL(db *database.Database) error {
|
|
rows, err := db.Query(`
|
|
SELECT id, groundspawn_id, name, collection_skill, number_harvests,
|
|
attempts_per_harvest, randomize_heading, respawn_time,
|
|
x, y, z, heading, zone_id, grid_id
|
|
FROM ground_spawns
|
|
ORDER BY groundspawn_id
|
|
`)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to query ground spawns: %w", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
for rows.Next() {
|
|
gs := &GroundSpawn{
|
|
db: db,
|
|
isNew: false,
|
|
IsAlive: true,
|
|
HarvestEntries: make([]*HarvestEntry, 0),
|
|
HarvestItems: make([]*HarvestEntryItem, 0),
|
|
}
|
|
|
|
err := rows.Scan(&gs.ID, &gs.GroundSpawnID, &gs.Name, &gs.CollectionSkill,
|
|
&gs.NumberHarvests, &gs.AttemptsPerHarvest, &gs.RandomizeHeading,
|
|
&gs.RespawnTime, &gs.X, &gs.Y, &gs.Z, &gs.Heading, &gs.ZoneID, &gs.GridID)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to scan ground spawn: %w", err)
|
|
}
|
|
|
|
// Initialize current harvests to max
|
|
gs.CurrentHarvests = gs.NumberHarvests
|
|
|
|
// Load harvest data for this ground spawn
|
|
if err := gs.loadHarvestData(); err != nil {
|
|
return fmt.Errorf("failed to load harvest data for ground spawn %d: %w", gs.GroundSpawnID, err)
|
|
}
|
|
|
|
ml.MasterList.Add(gs)
|
|
}
|
|
|
|
return rows.Err()
|
|
}
|
|
|
|
// GetStatistics returns statistics about the ground spawn system
|
|
func (ml *MasterList) GetStatistics() *Statistics {
|
|
availableSpawns := len(ml.GetAvailableSpawns())
|
|
|
|
// Count by zone
|
|
zoneMap := make(map[int32]int)
|
|
skillMap := make(map[string]int64)
|
|
|
|
ml.MasterList.ForEach(func(id int32, gs *GroundSpawn) {
|
|
zoneMap[gs.ZoneID]++
|
|
skillMap[gs.CollectionSkill]++
|
|
})
|
|
|
|
return &Statistics{
|
|
TotalHarvests: 0, // Would need to be tracked separately
|
|
SuccessfulHarvests: 0, // Would need to be tracked separately
|
|
RareItemsHarvested: 0, // Would need to be tracked separately
|
|
SkillUpsGenerated: 0, // Would need to be tracked separately
|
|
HarvestsBySkill: skillMap,
|
|
ActiveGroundSpawns: availableSpawns,
|
|
GroundSpawnsByZone: zoneMap,
|
|
}
|
|
} |