mdb: package for interacting with game's local database

This commit is contained in:
2026-06-02 12:39:58 -04:00
parent 96503e40f6
commit f40fea0ec5
28 changed files with 2906 additions and 3 deletions

152
mdb/skill.go Normal file
View File

@@ -0,0 +1,152 @@
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
}