package monsters import ( "fmt" nigiri "git.sharkk.net/Sharkk/Nigiri" ) // Monster represents a monster in the game type Monster struct { ID int `json:"id"` Name string `json:"name" db:"required"` MaxHP int `json:"max_hp"` MaxDmg int `json:"max_dmg"` Armor int `json:"armor"` Level int `json:"level" db:"index"` MaxExp int `json:"max_exp"` MaxGold int `json:"max_gold"` Immune int `json:"immune" db:"index"` } // Immunity constants const ( ImmuneNone = 0 ImmuneHurt = 1 ImmuneSleep = 2 ) // Global store var store *nigiri.BaseStore[Monster] // Init sets up the Nigiri store and indices func Init(collection *nigiri.Collection) { store = nigiri.NewBaseStore[Monster]() // Register custom indices store.RegisterIndex("byLevel", nigiri.BuildIntGroupIndex(func(m *Monster) int { return m.Level })) store.RegisterIndex("byImmunity", nigiri.BuildIntGroupIndex(func(m *Monster) int { return m.Immune })) store.RegisterIndex("allByLevel", nigiri.BuildSortedListIndex(func(a, b *Monster) bool { if a.Level == b.Level { return a.ID < b.ID } return a.Level < b.Level })) store.RebuildIndices() } // GetStore returns the monsters store func GetStore() *nigiri.BaseStore[Monster] { if store == nil { panic("monsters store not initialized - call Initialize first") } return store } // Creates a new Monster with sensible defaults func New() *Monster { return &Monster{ Name: "", MaxHP: 10, MaxDmg: 5, Armor: 0, Level: 1, MaxExp: 10, MaxGold: 5, Immune: ImmuneNone, } } // Validate checks if monster has valid values func (m *Monster) Validate() error { if m.Name == "" { return fmt.Errorf("monster name cannot be empty") } if m.MaxHP < 1 { return fmt.Errorf("monster MaxHP must be at least 1") } if m.Level < 1 { return fmt.Errorf("monster Level must be at least 1") } if m.Immune < ImmuneNone || m.Immune > ImmuneSleep { return fmt.Errorf("invalid immunity type: %d", m.Immune) } return nil } // CRUD operations func (m *Monster) Save() error { if m.ID == 0 { id, err := store.Create(m) if err != nil { return err } m.ID = id return nil } return store.Update(m.ID, m) } func (m *Monster) Delete() error { store.Remove(m.ID) return nil } // Insert with ID assignment func (m *Monster) Insert() error { id, err := store.Create(m) if err != nil { return err } m.ID = id return nil } // Query functions func Find(id int) (*Monster, error) { monster, exists := store.Find(id) if !exists { return nil, fmt.Errorf("monster with ID %d not found", id) } return monster, nil } func All() ([]*Monster, error) { return store.AllSorted("allByLevel"), nil } func ByLevel(level int) ([]*Monster, error) { return store.GroupByIndex("byLevel", level), nil } func ByLevelRange(minLevel, maxLevel int) ([]*Monster, error) { var result []*Monster for level := minLevel; level <= maxLevel; level++ { monsters := store.GroupByIndex("byLevel", level) result = append(result, monsters...) } return result, nil } func ByImmunity(immunityType int) ([]*Monster, error) { return store.GroupByIndex("byImmunity", immunityType), nil } // Helper methods func (m *Monster) IsHurtImmune() bool { return m.Immune == ImmuneHurt } func (m *Monster) IsSleepImmune() bool { return m.Immune == ImmuneSleep } func (m *Monster) HasImmunity() bool { return m.Immune != ImmuneNone } func (m *Monster) ImmunityName() string { switch m.Immune { case ImmuneNone: return "None" case ImmuneHurt: return "Hurt Spells" case ImmuneSleep: return "Sleep Spells" default: return "Unknown" } } func (m *Monster) DifficultyRating() float64 { if m.Level == 0 { return 0 } return float64(m.MaxHP+m.MaxDmg+m.Armor) / float64(m.Level) } func (m *Monster) ExpPerHP() float64 { if m.MaxHP == 0 { return 0 } return float64(m.MaxExp) / float64(m.MaxHP) } func (m *Monster) GoldPerHP() float64 { if m.MaxHP == 0 { return 0 } return float64(m.MaxGold) / float64(m.MaxHP) } // Legacy compatibility functions (will be removed later) func LoadData(dataPath string) error { // No longer needed - Nigiri handles this return nil } func SaveData(dataPath string) error { // No longer needed - Nigiri handles this return nil }