230 lines
4.7 KiB
Go
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
|
|
}
|