230 lines
4.7 KiB
Go

package spells
import (
"dk/internal/store"
"fmt"
"strings"
)
// Spell represents a spell in the game
type Spell struct {
ID int `json:"id"`
Name string `json:"name"`
MP int `json:"mp"`
Attribute int `json:"attribute"`
Type int `json:"type"`
}
func (s *Spell) Save() error {
return GetStore().UpdateWithRebuild(s.ID, s)
}
func (s *Spell) Delete() error {
GetStore().RemoveWithRebuild(s.ID)
return nil
}
// Creates a new Spell with sensible defaults
func New() *Spell {
return &Spell{
Name: "",
MP: 5, // Default MP cost
Attribute: 10, // Default attribute value
Type: TypeHealing, // Default to healing spell
}
}
// Validate checks if spell has valid values
func (s *Spell) Validate() error {
if s.Name == "" {
return fmt.Errorf("spell name cannot be empty")
}
if s.MP < 0 {
return fmt.Errorf("spell MP cannot be negative")
}
if s.Attribute < 0 {
return fmt.Errorf("spell Attribute cannot be negative")
}
if s.Type < TypeHealing || s.Type > TypeDefenseBoost {
return fmt.Errorf("invalid spell type: %d", s.Type)
}
return nil
}
// SpellType constants for spell types
const (
TypeHealing = 1
TypeHurt = 2
TypeSleep = 3
TypeAttackBoost = 4
TypeDefenseBoost = 5
)
// SpellStore with enhanced BaseStore
type SpellStore struct {
*store.BaseStore[Spell]
}
// Global store with singleton pattern
var GetStore = store.NewSingleton(func() *SpellStore {
ss := &SpellStore{BaseStore: store.NewBaseStore[Spell]()}
// Register indices
ss.RegisterIndex("byType", store.BuildIntGroupIndex(func(s *Spell) int {
return s.Type
}))
ss.RegisterIndex("byName", store.BuildCaseInsensitiveLookupIndex(func(s *Spell) string {
return s.Name
}))
ss.RegisterIndex("byMP", store.BuildIntGroupIndex(func(s *Spell) int {
return s.MP
}))
ss.RegisterIndex("allByTypeMP", store.BuildSortedListIndex(func(a, b *Spell) bool {
if a.Type != b.Type {
return a.Type < b.Type
}
if a.MP != b.MP {
return a.MP < b.MP
}
return a.ID < b.ID
}))
return ss
})
// Enhanced CRUD operations
func (ss *SpellStore) AddSpell(spell *Spell) error {
return ss.AddWithRebuild(spell.ID, spell)
}
func (ss *SpellStore) RemoveSpell(id int) {
ss.RemoveWithRebuild(id)
}
func (ss *SpellStore) UpdateSpell(spell *Spell) error {
return ss.UpdateWithRebuild(spell.ID, spell)
}
// Data persistence
func LoadData(dataPath string) error {
ss := GetStore()
return ss.BaseStore.LoadData(dataPath)
}
func SaveData(dataPath string) error {
ss := GetStore()
return ss.BaseStore.SaveData(dataPath)
}
// Query functions using enhanced store
func Find(id int) (*Spell, error) {
ss := GetStore()
spell, exists := ss.Find(id)
if !exists {
return nil, fmt.Errorf("spell with ID %d not found", id)
}
return spell, nil
}
func All() ([]*Spell, error) {
ss := GetStore()
return ss.AllSorted("allByTypeMP"), nil
}
func ByType(spellType int) ([]*Spell, error) {
ss := GetStore()
return ss.GroupByIndex("byType", spellType), nil
}
func ByMaxMP(maxMP int) ([]*Spell, error) {
ss := GetStore()
return ss.FilterByIndex("allByTypeMP", func(s *Spell) bool {
return s.MP <= maxMP
}), nil
}
func ByTypeAndMaxMP(spellType, maxMP int) ([]*Spell, error) {
ss := GetStore()
return ss.FilterByIndex("allByTypeMP", func(s *Spell) bool {
return s.Type == spellType && s.MP <= maxMP
}), nil
}
func ByName(name string) (*Spell, error) {
ss := GetStore()
spell, exists := ss.LookupByIndex("byName", strings.ToLower(name))
if !exists {
return nil, fmt.Errorf("spell with name '%s' not found", name)
}
return spell, nil
}
// Insert with ID assignment
func (s *Spell) Insert() error {
ss := GetStore()
if s.ID == 0 {
s.ID = ss.GetNextID()
}
return ss.AddSpell(s)
}
// Helper methods
func (s *Spell) IsHealing() bool {
return s.Type == TypeHealing
}
func (s *Spell) IsHurt() bool {
return s.Type == TypeHurt
}
func (s *Spell) IsSleep() bool {
return s.Type == TypeSleep
}
func (s *Spell) IsAttackBoost() bool {
return s.Type == TypeAttackBoost
}
func (s *Spell) IsDefenseBoost() bool {
return s.Type == TypeDefenseBoost
}
func (s *Spell) TypeName() string {
switch s.Type {
case TypeHealing:
return "Healing"
case TypeHurt:
return "Hurt"
case TypeSleep:
return "Sleep"
case TypeAttackBoost:
return "Attack Boost"
case TypeDefenseBoost:
return "Defense Boost"
default:
return "Unknown"
}
}
func (s *Spell) CanCast(availableMP int) bool {
return availableMP >= s.MP
}
func (s *Spell) Efficiency() float64 {
if s.MP == 0 {
return 0
}
return float64(s.Attribute) / float64(s.MP)
}
func (s *Spell) IsOffensive() bool {
return s.Type == TypeHurt || s.Type == TypeSleep
}
func (s *Spell) IsSupport() bool {
return s.Type == TypeHealing || s.Type == TypeAttackBoost || s.Type == TypeDefenseBoost
}