package spells import ( "fmt" "dk/internal/database" ) // Spell represents a spell in the game type Spell struct { ID int Type int Name string Lore string Icon string MP int Power int } // SpellType constants for spell types const ( TypeHeal = 0 TypeDamage = 1 TypeSleep = 2 TypeUberAttack = 3 TypeUberDefense = 4 ) // New creates a new Spell with sensible defaults func New() *Spell { return &Spell{ Type: TypeHeal, Name: "", Lore: "", Icon: "", MP: 5, Power: 10, } } // 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.Power < 0 { return fmt.Errorf("spell Power cannot be negative") } if s.Type < TypeHeal || s.Type > TypeUberDefense { return fmt.Errorf("invalid spell type: %d", s.Type) } return nil } // CRUD operations func (s *Spell) Delete() error { return database.Exec("DELETE FROM spells WHERE id = %d", s.ID) } func (s *Spell) Insert() error { id, err := database.Insert("spells", s, "ID") if err != nil { return err } s.ID = int(id) return nil } // Query functions func Find(id int) (*Spell, error) { var spell Spell err := database.Get(&spell, "SELECT * FROM spells WHERE id = %d", id) if err != nil { return nil, fmt.Errorf("spell with ID %d not found", id) } return &spell, nil } func All() ([]*Spell, error) { var spells []*Spell err := database.Select(&spells, "SELECT * FROM spells ORDER BY type ASC, mp ASC, id ASC") return spells, err } func ByType(spellType int) ([]*Spell, error) { var spells []*Spell err := database.Select(&spells, "SELECT * FROM spells WHERE type = %d ORDER BY mp ASC, id ASC", spellType) return spells, err } func ByMaxMP(maxMP int) ([]*Spell, error) { var spells []*Spell err := database.Select(&spells, "SELECT * FROM spells WHERE mp <= %d ORDER BY type ASC, mp ASC, id ASC", maxMP) return spells, err } func ByTypeAndMaxMP(spellType, maxMP int) ([]*Spell, error) { var spells []*Spell err := database.Select(&spells, "SELECT * FROM spells WHERE type = %d AND mp <= %d ORDER BY mp ASC, id ASC", spellType, maxMP) return spells, err } func ByName(name string) (*Spell, error) { var spell Spell err := database.Get(&spell, "SELECT * FROM spells WHERE name = %s COLLATE NOCASE", name) if err != nil { return nil, fmt.Errorf("spell with name '%s' not found", name) } return &spell, nil } // Spell unlock functions func UnlocksForClassAtLevel(classID, level int) ([]*Spell, error) { var spells []*Spell query := ` SELECT s.* FROM spells s JOIN spell_unlocks u ON s.id = u.spell_id WHERE u.class_id = %d AND u.level = %d ORDER BY s.type ASC, s.mp ASC, s.id ASC` err := database.Select(&spells, query, classID, level) return spells, err } func UserSpells(userID int) ([]*Spell, error) { var spells []*Spell query := ` SELECT s.* FROM spells s JOIN user_spells us ON s.id = us.spell_id WHERE us.user_id = %d ORDER BY s.type ASC, s.mp ASC, s.id ASC` err := database.Select(&spells, query, userID) return spells, err } func UserHealingSpells(userID int) ([]*Spell, error) { var spells []*Spell query := ` SELECT s.* FROM spells s JOIN user_spells us ON s.id = us.spell_id WHERE us.user_id = %d AND s.type = 0 ORDER BY s.mp ASC, s.id ASC` err := database.Select(&spells, query, userID) return spells, err } func GrantSpell(userID, spellID int) error { return database.Exec("INSERT OR IGNORE INTO user_spells (user_id, spell_id) VALUES (%d, %d)", userID, spellID) } func GrantSpells(userID int, spellIDs []int) error { return database.Transaction(func() error { for _, spellID := range spellIDs { if err := GrantSpell(userID, spellID); err != nil { return err } } return nil }) } func HasSpell(userID, spellID int) bool { var count int err := database.Get(&count, "SELECT COUNT(*) FROM user_spells WHERE user_id = %d AND spell_id = %d", userID, spellID) return err == nil && count > 0 } // Helper methods func (s *Spell) IsHeal() bool { return s.Type == TypeHeal } func (s *Spell) IsDamage() bool { return s.Type == TypeDamage } func (s *Spell) IsSleep() bool { return s.Type == TypeSleep } func (s *Spell) IsUberAttack() bool { return s.Type == TypeUberAttack } func (s *Spell) IsUberDefense() bool { return s.Type == TypeUberDefense } func (s *Spell) TypeName() string { switch s.Type { case TypeHeal: return "Heal" case TypeDamage: return "Damage" case TypeSleep: return "Sleep" case TypeUberAttack: return "Uber Attack" case TypeUberDefense: return "Uber Defense" 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.Power) / float64(s.MP) } func (s *Spell) IsOffensive() bool { return s.Type == TypeDamage || s.Type == TypeSleep } func (s *Spell) IsSupport() bool { return s.Type == TypeHeal || s.Type == TypeUberAttack || s.Type == TypeUberDefense }