package mdb import ( "context" _ "embed" "fmt" "strconv" "strings" "zombiezen.com/go/sqlite" "zombiezen.com/go/sqlite/sqlitex" "git.sunturtle.xyz/zephyr/horse" ) var ( //go:embed sql/skill-group.sql skillGroupSQL string //go:embed sql/skill.sql skillSQL string ) // SkillGroups retrieves all skill groups. func SkillGroups(ctx context.Context, db *sqlitex.Pool) ([]horse.SkillGroup, error) { return load(ctx, db, nil, skillGroupSQL, func(s *sqlite.Stmt) horse.SkillGroup { return horse.SkillGroup{ ID: horse.SkillGroupID(s.ColumnInt(0)), Skill1: horse.SkillID(s.ColumnInt(1)), Skill2: horse.SkillID(s.ColumnInt(2)), Skill3: horse.SkillID(s.ColumnInt(3)), SkillBad: horse.SkillID(s.ColumnInt(4)), } }) } // Skills retrieves all skills. func Skills(ctx context.Context, db *sqlitex.Pool) ([]horse.Skill, error) { return load(ctx, db, nil, skillSQL, func(s *sqlite.Stmt) horse.Skill { return horse.Skill{ ID: horse.SkillID(s.ColumnInt(0)), Name: s.ColumnText(1), Description: s.ColumnText(2), Group: horse.SkillGroupID(s.ColumnInt32(3)), Rarity: int8(s.ColumnInt(5)), GroupRate: int8(s.ColumnInt(6)), GradeValue: s.ColumnInt32(7), WitCheck: s.ColumnBool(8), Activations: trimActivations([]horse.Activation{ { Precondition: s.ColumnText(9), Condition: s.ColumnText(10), Duration: horse.TenThousandths(s.ColumnInt(11)), DurScale: horse.DurScale(s.ColumnInt(12)), Cooldown: horse.TenThousandths(s.ColumnInt(13)), Abilities: trimAbilities([]horse.Ability{ { Type: horse.AbilityType(s.ColumnInt(14)), ValueUsage: horse.AbilityValueUsage(s.ColumnInt(15)), Value: horse.TenThousandths(s.ColumnInt(16)), Target: horse.AbilityTarget(s.ColumnInt(17)), TargetValue: s.ColumnInt32(18), }, { Type: horse.AbilityType(s.ColumnInt(19)), ValueUsage: horse.AbilityValueUsage(s.ColumnInt(20)), Value: horse.TenThousandths(s.ColumnInt(21)), Target: horse.AbilityTarget(s.ColumnInt(22)), TargetValue: s.ColumnInt32(23), }, { Type: horse.AbilityType(s.ColumnInt(24)), ValueUsage: horse.AbilityValueUsage(s.ColumnInt(25)), Value: horse.TenThousandths(s.ColumnInt(26)), Target: horse.AbilityTarget(s.ColumnInt(27)), TargetValue: s.ColumnInt32(28), }, }), }, { Precondition: s.ColumnText(29), Condition: s.ColumnText(30), Duration: horse.TenThousandths(s.ColumnInt(31)), DurScale: horse.DurScale(s.ColumnInt(32)), Cooldown: horse.TenThousandths(s.ColumnInt(33)), Abilities: trimAbilities([]horse.Ability{ { Type: horse.AbilityType(s.ColumnInt(34)), ValueUsage: horse.AbilityValueUsage(s.ColumnInt(35)), Value: horse.TenThousandths(s.ColumnInt(36)), Target: horse.AbilityTarget(s.ColumnInt(37)), TargetValue: s.ColumnInt32(38), }, { Type: horse.AbilityType(s.ColumnInt(39)), ValueUsage: horse.AbilityValueUsage(s.ColumnInt(40)), Value: horse.TenThousandths(s.ColumnInt(41)), Target: horse.AbilityTarget(s.ColumnInt(42)), TargetValue: s.ColumnInt32(43), }, { Type: horse.AbilityType(s.ColumnInt(44)), ValueUsage: horse.AbilityValueUsage(s.ColumnInt(45)), Value: horse.TenThousandths(s.ColumnInt(46)), Target: horse.AbilityTarget(s.ColumnInt(47)), TargetValue: s.ColumnInt32(48), }, }), }, }), UniqueOwner: s.ColumnText(52), // TODO(zeph): should be id, not name Tags: parseTags(s.ColumnText(54)), SPCost: s.ColumnInt(49), IconID: s.ColumnInt(53), } }) } func parseTags(s string) []uint16 { r := make([]uint16, 0, 8) for s != "" { t, u, _ := strings.Cut(s, "/") s = u v, err := strconv.ParseUint(t, 10, 16) if err != nil { panic(fmt.Errorf("parsing skill tags: %w", err)) } r = append(r, uint16(v)) } return trimZeros(r...) } func trimAbilities(s []horse.Ability) []horse.Ability { for len(s) > 0 && s[len(s)-1].Type == 0 { s = s[:len(s)-1] } return s } func trimActivations(s []horse.Activation) []horse.Activation { for len(s) > 0 && s[len(s)-1].Condition == "" { s = s[:len(s)-1] } return s } func trimZeros[T comparable](s ...T) []T { var zero T for len(s) > 0 && s[len(s)-1] == zero { s = s[:len(s)-1] } return s }