package main import ( "context" _ "embed" "fmt" "zombiezen.com/go/sqlite/sqlitex" ) //go:embed character.sql var characterSQL string //go:embed character.affinity2.sql var characterAffinity2SQL string //go:embed character.affinity3.sql var characterAffinity3SQL string //go:embed uma.sql var umaSQL string //go:embed skill-group.sql var skillGroupSQL string //go:embed skill.sql var skillSQL string //go:embed race.sql var raceSQL string //go:embed saddle.sql var saddleSQL string //go:embed scenario.sql var scenarioSQL string //go:embed spark.sql var sparkSQL string //go:embed spark-effect.sql var sparkEffectSQL string type ( Character struct{} SkillGroup struct{} ) type NamedID[T any] struct { // Disallow conversions between NamedID types. _ [0]*T ID int Name string // For internal use, the index of the identity, when it's needed. // We don't show this in public API, but it lets us use vectors for lookups. Index int } func Characters(ctx context.Context, db *sqlitex.Pool) ([]NamedID[Character], error) { conn, err := db.Take(ctx) defer db.Put(conn) if err != nil { return nil, fmt.Errorf("couldn't get connection for characters: %w", err) } stmt, _, err := conn.PrepareTransient(characterSQL) if err != nil { return nil, fmt.Errorf("couldn't prepare statement for characters: %w", err) } defer stmt.Finalize() var r []NamedID[Character] for { ok, err := stmt.Step() if err != nil { return nil, fmt.Errorf("error stepping characters: %w", err) } if !ok { break } c := NamedID[Character]{ ID: stmt.ColumnInt(0), Name: stmt.ColumnText(1), Index: stmt.ColumnInt(2), } r = append(r, c) } return r, nil } type AffinityRelation struct { IDA int NameA string IDB int NameB string IDC int NameC string Affinity int } func CharacterPairs(ctx context.Context, db *sqlitex.Pool) ([]AffinityRelation, error) { conn, err := db.Take(ctx) defer db.Put(conn) if err != nil { return nil, fmt.Errorf("couldn't get connection for character pairs: %w", err) } stmt, _, err := conn.PrepareTransient(characterAffinity2SQL) if err != nil { return nil, fmt.Errorf("couldn't prepare statement for character pairs: %w", err) } defer stmt.Finalize() var r []AffinityRelation for { ok, err := stmt.Step() if err != nil { return nil, fmt.Errorf("error stepping character pairs: %w", err) } if !ok { break } p := AffinityRelation{ IDA: stmt.ColumnInt(0), NameA: stmt.ColumnText(1), IDB: stmt.ColumnInt(2), NameB: stmt.ColumnText(3), Affinity: stmt.ColumnInt(4), } r = append(r, p) } return r, nil } func CharacterTrios(ctx context.Context, db *sqlitex.Pool) ([]AffinityRelation, error) { conn, err := db.Take(ctx) defer db.Put(conn) if err != nil { return nil, fmt.Errorf("couldn't get connection for character trios: %w", err) } stmt, _, err := conn.PrepareTransient(characterAffinity3SQL) if err != nil { return nil, fmt.Errorf("couldn't prepare statement for character trios: %w", err) } defer stmt.Finalize() var r []AffinityRelation for { ok, err := stmt.Step() if err != nil { return nil, fmt.Errorf("error stepping character trios: %w", err) } if !ok { break } p := AffinityRelation{ IDA: stmt.ColumnInt(0), NameA: stmt.ColumnText(1), IDB: stmt.ColumnInt(2), NameB: stmt.ColumnText(3), IDC: stmt.ColumnInt(4), NameC: stmt.ColumnText(5), Affinity: stmt.ColumnInt(6), } r = append(r, p) } return r, nil } func SkillGroups(ctx context.Context, db *sqlitex.Pool) ([]NamedID[SkillGroup], error) { conn, err := db.Take(ctx) defer db.Put(conn) if err != nil { return nil, fmt.Errorf("couldn't get connection for skill groups: %w", err) } stmt, _, err := conn.PrepareTransient(skillGroupSQL) if err != nil { return nil, fmt.Errorf("couldn't prepare statement for skill groups: %w", err) } defer stmt.Finalize() var r []NamedID[SkillGroup] for { ok, err := stmt.Step() if err != nil { return nil, fmt.Errorf("error stepping skill groups: %w", err) } if !ok { break } g := NamedID[SkillGroup]{ ID: stmt.ColumnInt(0), Name: stmt.ColumnText(1), } r = append(r, g) } return r, nil } type Skill struct { ID int Name string Description string GroupID int GroupName string Rarity int GroupRate int GradeValue int WitCheck bool Activations [2]SkillActivation SPCost int InheritID int UniqueOwnerID int UniqueOwner string IconID int Index int } type SkillActivation struct { Precondition string Condition string Duration int DurScale int Cooldown int Abilities [3]SkillAbility } type SkillAbility struct { Type int ValueUsage int Value int Target int TargetValue int } func Skills(ctx context.Context, db *sqlitex.Pool) ([]Skill, error) { conn, err := db.Take(ctx) defer db.Put(conn) if err != nil { return nil, fmt.Errorf("couldn't get connection for skills: %w", err) } stmt, _, err := conn.PrepareTransient(skillSQL) if err != nil { return nil, fmt.Errorf("couldn't prepare statement for skills: %w", err) } defer stmt.Finalize() var r []Skill for { ok, err := stmt.Step() if err != nil { return nil, fmt.Errorf("error stepping skills: %w", err) } if !ok { break } s := Skill{ ID: stmt.ColumnInt(0), Name: stmt.ColumnText(1), Description: stmt.ColumnText(2), GroupID: stmt.ColumnInt(3), GroupName: stmt.ColumnText(4), Rarity: stmt.ColumnInt(5), GroupRate: stmt.ColumnInt(6), GradeValue: stmt.ColumnInt(7), WitCheck: stmt.ColumnInt(8) != 0, Activations: [2]SkillActivation{ { Precondition: stmt.ColumnText(9), Condition: stmt.ColumnText(10), Duration: stmt.ColumnInt(11), DurScale: stmt.ColumnInt(12), Cooldown: stmt.ColumnInt(13), Abilities: [3]SkillAbility{ { Type: stmt.ColumnInt(14), ValueUsage: stmt.ColumnInt(15), Value: stmt.ColumnInt(16), Target: stmt.ColumnInt(17), TargetValue: stmt.ColumnInt(18), }, { Type: stmt.ColumnInt(19), ValueUsage: stmt.ColumnInt(20), Value: stmt.ColumnInt(21), Target: stmt.ColumnInt(22), TargetValue: stmt.ColumnInt(23), }, { Type: stmt.ColumnInt(24), ValueUsage: stmt.ColumnInt(25), Value: stmt.ColumnInt(26), Target: stmt.ColumnInt(27), TargetValue: stmt.ColumnInt(28), }, }, }, { Precondition: stmt.ColumnText(29), Condition: stmt.ColumnText(30), Duration: stmt.ColumnInt(31), DurScale: stmt.ColumnInt(32), Cooldown: stmt.ColumnInt(33), Abilities: [3]SkillAbility{ { Type: stmt.ColumnInt(34), ValueUsage: stmt.ColumnInt(35), Value: stmt.ColumnInt(36), Target: stmt.ColumnInt(37), TargetValue: stmt.ColumnInt(38), }, { Type: stmt.ColumnInt(39), ValueUsage: stmt.ColumnInt(40), Value: stmt.ColumnInt(41), Target: stmt.ColumnInt(42), TargetValue: stmt.ColumnInt(43), }, { Type: stmt.ColumnInt(44), ValueUsage: stmt.ColumnInt(45), Value: stmt.ColumnInt(46), Target: stmt.ColumnInt(47), TargetValue: stmt.ColumnInt(48), }, }, }, }, SPCost: stmt.ColumnInt(49), InheritID: stmt.ColumnInt(50), UniqueOwnerID: stmt.ColumnInt(51), UniqueOwner: stmt.ColumnText(52), IconID: stmt.ColumnInt(53), Index: stmt.ColumnInt(54), } r = append(r, s) } return r, nil } type Race struct { ID int Name string Grade int ThumbnailID int Primary int Alternate int } func Races(ctx context.Context, db *sqlitex.Pool) ([]Race, error) { conn, err := db.Take(ctx) defer db.Put(conn) if err != nil { return nil, fmt.Errorf("couldn't get connection for races: %w", err) } stmt, _, err := conn.PrepareTransient(raceSQL) if err != nil { return nil, fmt.Errorf("couldn't prepare statement for races: %w", err) } defer stmt.Finalize() var r []Race for { ok, err := stmt.Step() if err != nil { return nil, fmt.Errorf("error stepping races: %w", err) } if !ok { break } race := Race{ ID: stmt.ColumnInt(0), Name: stmt.ColumnText(1), Grade: stmt.ColumnInt(2), ThumbnailID: stmt.ColumnInt(3), Primary: stmt.ColumnInt(4), Alternate: stmt.ColumnInt(5), } r = append(r, race) } return r, nil } type Saddle struct { ID int Name string Races [3]int Type int Primary int Alternate int } func Saddles(ctx context.Context, db *sqlitex.Pool) ([]Saddle, error) { conn, err := db.Take(ctx) defer db.Put(conn) if err != nil { return nil, fmt.Errorf("couldn't get connection for saddles: %w", err) } stmt, _, err := conn.PrepareTransient(saddleSQL) if err != nil { return nil, fmt.Errorf("couldn't prepare statement for saddles: %w", err) } defer stmt.Finalize() var r []Saddle for { ok, err := stmt.Step() if err != nil { return nil, fmt.Errorf("error stepping saddles: %w", err) } if !ok { break } s := Saddle{ ID: stmt.ColumnInt(0), Name: stmt.ColumnText(1), Races: [3]int{stmt.ColumnInt(2), stmt.ColumnInt(3), stmt.ColumnInt(4)}, Type: stmt.ColumnInt(5), Primary: stmt.ColumnInt(6), Alternate: stmt.ColumnInt(7), } r = append(r, s) } return r, nil } type Scenario struct { ID int Name string Title string } func Scenarios(ctx context.Context, db *sqlitex.Pool) ([]Scenario, error) { conn, err := db.Take(ctx) defer db.Put(conn) if err != nil { return nil, fmt.Errorf("couldn't get connection for scenario: %w", err) } stmt, _, err := conn.PrepareTransient(scenarioSQL) if err != nil { return nil, fmt.Errorf("couldn't prepare statement for scenario: %w", err) } defer stmt.Finalize() var r []Scenario for { ok, err := stmt.Step() if err != nil { return nil, fmt.Errorf("error stepping scenarios: %w", err) } if !ok { break } s := Scenario{ ID: stmt.ColumnInt(0), Name: stmt.ColumnText(1), Title: stmt.ColumnText(2), } r = append(r, s) } return r, nil } type Spark struct { ID int Name string Description string Group int Rarity int Type int } type SparkEffect struct { Target int Value1 int Value2 int } func Sparks(ctx context.Context, db *sqlitex.Pool) ([]Spark, error) { conn, err := db.Take(ctx) defer db.Put(conn) if err != nil { return nil, fmt.Errorf("couldn't get connection for sparks: %w", err) } stmt, _, err := conn.PrepareTransient(sparkSQL) if err != nil { return nil, fmt.Errorf("couldn't prepare statement for sparks: %w", err) } defer stmt.Finalize() var r []Spark for { ok, err := stmt.Step() if err != nil { return nil, fmt.Errorf("error stepping sparks: %w", err) } if !ok { break } s := Spark{ ID: stmt.ColumnInt(0), Name: stmt.ColumnText(1), Description: stmt.ColumnText(2), Group: stmt.ColumnInt(3), Rarity: stmt.ColumnInt(4), Type: stmt.ColumnInt(5), } r = append(r, s) } return r, nil } func SparkEffects(ctx context.Context, db *sqlitex.Pool) (map[int]map[int][]SparkEffect, error) { conn, err := db.Take(ctx) defer db.Put(conn) if err != nil { return nil, fmt.Errorf("couldn't get connection for spark effects: %w", err) } stmt, _, err := conn.PrepareTransient(sparkEffectSQL) if err != nil { return nil, fmt.Errorf("couldn't prepare statement for spark effects: %w", err) } defer stmt.Finalize() r := make(map[int]map[int][]SparkEffect) for { ok, err := stmt.Step() if err != nil { return nil, fmt.Errorf("error stepping spark effects: %w", err) } if !ok { break } group := stmt.ColumnInt(0) eff := stmt.ColumnInt(1) s := SparkEffect{ Target: stmt.ColumnInt(2), Value1: stmt.ColumnInt(3), Value2: stmt.ColumnInt(4), } if r[group] == nil { r[group] = make(map[int][]SparkEffect) } r[group][eff] = append(r[group][eff], s) } return r, nil } type Uma struct { ID int CharacterID int Name string Variant string CharacterName string Sprint, Mile, Medium, Long int Front, Pace, Late, End int Turf, Dirt int UniqueID int Skill1, Skill2, Skill3 int SkillPL2, SkillPL3, SkillPL4, SkillPL5 int } func Umas(ctx context.Context, db *sqlitex.Pool) ([]Uma, error) { conn, err := db.Take(ctx) defer db.Put(conn) if err != nil { return nil, fmt.Errorf("couldn't get connection for umas: %w", err) } stmt, _, err := conn.PrepareTransient(umaSQL) if err != nil { return nil, fmt.Errorf("couldn't prepare statement for umas: %w", err) } defer stmt.Finalize() var r []Uma for { ok, err := stmt.Step() if err != nil { return nil, fmt.Errorf("error stepping umas: %w", err) } if !ok { break } uma := Uma{ ID: stmt.ColumnInt(0), CharacterID: stmt.ColumnInt(1), Name: stmt.ColumnText(2), Variant: stmt.ColumnText(3), CharacterName: stmt.ColumnText(4), Sprint: stmt.ColumnInt(5), Mile: stmt.ColumnInt(6), Medium: stmt.ColumnInt(7), Long: stmt.ColumnInt(8), Front: stmt.ColumnInt(9), Pace: stmt.ColumnInt(10), Late: stmt.ColumnInt(11), End: stmt.ColumnInt(12), Turf: stmt.ColumnInt(13), Dirt: stmt.ColumnInt(14), UniqueID: stmt.ColumnInt(15), Skill1: stmt.ColumnInt(16), Skill2: stmt.ColumnInt(17), Skill3: stmt.ColumnInt(18), SkillPL2: stmt.ColumnInt(19), SkillPL3: stmt.ColumnInt(20), SkillPL4: stmt.ColumnInt(21), SkillPL5: stmt.ColumnInt(22), } r = append(r, uma) } return r, nil }