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 skill-group.sql var skillGroupSQL string //go:embed skill.sql var skillSQL 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 IconID int Index int } type SkillActivation struct { Precondition string Condition string Duration float64 Cooldown float64 Abilities [3]SkillAbility } type SkillAbility struct { Type int ValueUsage int Value float64 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.ColumnFloat(11), Cooldown: stmt.ColumnFloat(12), Abilities: [3]SkillAbility{ { Type: stmt.ColumnInt(13), ValueUsage: stmt.ColumnInt(14), Value: stmt.ColumnFloat(15), Target: stmt.ColumnInt(16), TargetValue: stmt.ColumnInt(17), }, { Type: stmt.ColumnInt(18), ValueUsage: stmt.ColumnInt(19), Value: stmt.ColumnFloat(20), Target: stmt.ColumnInt(21), TargetValue: stmt.ColumnInt(22), }, { Type: stmt.ColumnInt(23), ValueUsage: stmt.ColumnInt(24), Value: stmt.ColumnFloat(25), Target: stmt.ColumnInt(26), TargetValue: stmt.ColumnInt(27), }, }, }, { Precondition: stmt.ColumnText(28), Condition: stmt.ColumnText(29), Duration: stmt.ColumnFloat(30), Cooldown: stmt.ColumnFloat(31), Abilities: [3]SkillAbility{ { Type: stmt.ColumnInt(32), ValueUsage: stmt.ColumnInt(33), Value: stmt.ColumnFloat(34), Target: stmt.ColumnInt(35), TargetValue: stmt.ColumnInt(36), }, { Type: stmt.ColumnInt(37), ValueUsage: stmt.ColumnInt(38), Value: stmt.ColumnFloat(39), Target: stmt.ColumnInt(40), TargetValue: stmt.ColumnInt(41), }, { Type: stmt.ColumnInt(42), ValueUsage: stmt.ColumnInt(43), Value: stmt.ColumnFloat(44), Target: stmt.ColumnInt(45), TargetValue: stmt.ColumnInt(46), }, }, }, }, SPCost: stmt.ColumnInt(47), InheritID: stmt.ColumnInt(48), IconID: stmt.ColumnInt(49), Index: stmt.ColumnInt(50), } r = append(r, s) } return r, nil }