230 lines
4.7 KiB
Go
230 lines
4.7 KiB
Go
package spells
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
nigiri "git.sharkk.net/Sharkk/Nigiri"
|
|
)
|
|
|
|
// Spell represents a spell in the game
|
|
type Spell struct {
|
|
ID int `json:"id"`
|
|
Name string `json:"name" db:"required,unique"`
|
|
MP int `json:"mp" db:"index"`
|
|
Attribute int `json:"attribute"`
|
|
Type int `json:"type" db:"index"`
|
|
}
|
|
|
|
// SpellType constants for spell types
|
|
const (
|
|
TypeHealing = 1
|
|
TypeHurt = 2
|
|
TypeSleep = 3
|
|
TypeAttackBoost = 4
|
|
TypeDefenseBoost = 5
|
|
)
|
|
|
|
// Global store
|
|
var store *nigiri.BaseStore[Spell]
|
|
var db *nigiri.Collection
|
|
|
|
// Init sets up the Nigiri store and indices
|
|
func Init(collection *nigiri.Collection) {
|
|
db = collection
|
|
store = nigiri.NewBaseStore[Spell]()
|
|
|
|
// Register custom indices
|
|
store.RegisterIndex("byType", nigiri.BuildIntGroupIndex(func(s *Spell) int {
|
|
return s.Type
|
|
}))
|
|
|
|
store.RegisterIndex("byName", nigiri.BuildCaseInsensitiveLookupIndex(func(s *Spell) string {
|
|
return s.Name
|
|
}))
|
|
|
|
store.RegisterIndex("byMP", nigiri.BuildIntGroupIndex(func(s *Spell) int {
|
|
return s.MP
|
|
}))
|
|
|
|
store.RegisterIndex("allByTypeMP", nigiri.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
|
|
}))
|
|
|
|
store.RebuildIndices()
|
|
}
|
|
|
|
// GetStore returns the spells store
|
|
func GetStore() *nigiri.BaseStore[Spell] {
|
|
if store == nil {
|
|
panic("spells store not initialized - call Initialize first")
|
|
}
|
|
return store
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// CRUD operations
|
|
func (s *Spell) Save() error {
|
|
if s.ID == 0 {
|
|
id, err := store.Create(s)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
s.ID = id
|
|
return nil
|
|
}
|
|
return store.Update(s.ID, s)
|
|
}
|
|
|
|
func (s *Spell) Delete() error {
|
|
store.Remove(s.ID)
|
|
return nil
|
|
}
|
|
|
|
// Insert with ID assignment
|
|
func (s *Spell) Insert() error {
|
|
id, err := store.Create(s)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
s.ID = id
|
|
return nil
|
|
}
|
|
|
|
// Query functions
|
|
func Find(id int) (*Spell, error) {
|
|
spell, exists := store.Find(id)
|
|
if !exists {
|
|
return nil, fmt.Errorf("spell with ID %d not found", id)
|
|
}
|
|
return spell, nil
|
|
}
|
|
|
|
func All() ([]*Spell, error) {
|
|
return store.AllSorted("allByTypeMP"), nil
|
|
}
|
|
|
|
func ByType(spellType int) ([]*Spell, error) {
|
|
return store.GroupByIndex("byType", spellType), nil
|
|
}
|
|
|
|
func ByMaxMP(maxMP int) ([]*Spell, error) {
|
|
return store.FilterByIndex("allByTypeMP", func(s *Spell) bool {
|
|
return s.MP <= maxMP
|
|
}), nil
|
|
}
|
|
|
|
func ByTypeAndMaxMP(spellType, maxMP int) ([]*Spell, error) {
|
|
return store.FilterByIndex("allByTypeMP", func(s *Spell) bool {
|
|
return s.Type == spellType && s.MP <= maxMP
|
|
}), nil
|
|
}
|
|
|
|
func ByName(name string) (*Spell, error) {
|
|
spell, exists := store.LookupByIndex("byName", strings.ToLower(name))
|
|
if !exists {
|
|
return nil, fmt.Errorf("spell with name '%s' not found", name)
|
|
}
|
|
return spell, nil
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// 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
|
|
}
|