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