horsegen: generate umas

This commit is contained in:
2026-02-26 19:02:49 -05:00
parent 3fa30903cd
commit 7972bab46c
13 changed files with 3747 additions and 15 deletions

View File

@@ -159,7 +159,23 @@ func ExecSparks(t *template.Template, region string, kk, g io.Writer, sparks []S
return err
}
const wordSeps = " ,!?/-+();#○☆♡'=♪∀゚∴"
func ExecUmas(t *template.Template, region string, kk, g io.Writer, umas []Uma) error {
data := struct {
Region string
Umas []Uma
UmaCount int
}{region, umas, len(umas)}
var err error
if kk != nil {
err = errors.Join(err, t.ExecuteTemplate(kk, "koka-uma", &data))
}
if g != nil {
err = errors.Join(err, t.ExecuteTemplate(g, "go-uma", &data))
}
return err
}
const wordSeps = " ,!?/-+();#○☆♡'=♪∀゚∴[]:"
var (
kkReplace = func() *strings.Replacer {

View File

@@ -17,6 +17,9 @@ 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
@@ -541,3 +544,70 @@ func SparkEffects(ctx context.Context, db *sqlitex.Pool) (map[int]map[int][]Spar
}
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
}

View File

@@ -55,6 +55,7 @@ func main() {
scens []Scenario
sparks []Spark
sparkeff map[int]map[int][]SparkEffect
umas []Uma
)
eg.Go(func() error {
slog.Info("get characters")
@@ -116,6 +117,12 @@ func main() {
sparkeff = r
return err
})
eg.Go(func() error {
slog.Info("get umas")
r, err := Umas(ctx, db)
umas = r
return err
})
if err := eg.Wait(); err != nil {
slog.Error("load", slog.Any("err", err))
os.Exit(1)
@@ -199,6 +206,18 @@ func main() {
slog.Info("write sparks")
return ExecSparks(t, region, kf, gf, sparks, sparkeff)
})
eg.Go(func() error {
kf, err := os.Create(filepath.Join(out, region, "uma.kk"))
if err != nil {
return err
}
gf, err := os.Create(filepath.Join(out, region, "uma.go"))
if err != nil {
return err
}
slog.Info("write umas")
return ExecUmas(t, region, kf, gf, umas)
})
if err := eg.Wait(); err != nil {
slog.Error("generate", slog.Any("err", err))
os.Exit(1)

42
horsegen/uma.go.template Normal file
View File

@@ -0,0 +1,42 @@
{{- define "go-uma" -}}
package {{ $.Region }}
// Automatically generated with horsegen; DO NOT EDIT
import . "git.sunturtle.xyz/zephyr/horse/horse"
const (
{{- range $uma := $.Umas }}
{{ goenum $uma.CharacterName }}{{ goenum $uma.Variant }} UmaID = {{ $uma.ID }} // {{ $uma.Name }}
{{- end }}
)
var AllUmas = map[UmaID]Uma{
{{- range $uma := $.Umas }}
{{ goenum $uma.CharacterName }}{{ goenum $uma.Variant }}: {
ID: {{ $uma.ID }},
CharacterID: {{ $uma.CharacterID }},
Name: {{ printf "%q" $uma.Name }},
Variant: {{ printf "%q" $uma.Variant }},
Sprint: {{ $uma.Sprint }},
Mile: {{ $uma.Mile }},
Medium: {{ $uma.Medium }},
Long: {{ $uma.Long }},
Front: {{ $uma.Front }},
Pace: {{ $uma.Pace }},
Late: {{ $uma.Late }},
End: {{ $uma.End }},
Turf: {{ $uma.Turf }},
Dirt: {{ $uma.Dirt }},
Unique: {{ $uma.UniqueID }},
Skill1: {{ $uma.Skill1 }},
Skill2: {{ $uma.Skill2 }},
Skill3: {{ $uma.Skill3 }},
SkillPL2: {{ $uma.SkillPL2 }},
SkillPL3: {{ $uma.SkillPL3 }},
SkillPL4: {{ $uma.SkillPL4 }},
SkillPL5: {{ $uma.SkillPL5 }},
},
{{- end }}
}
{{ end }}

221
horsegen/uma.kk.template Normal file
View File

@@ -0,0 +1,221 @@
{{- define "koka-uma" -}}
module horse/{{ $.Region }}/uma
// Automatically generated with horsegen; DO NOT EDIT
import std/core/delayed
import std/core/vector
import std/core-extras
import horse/game-id
import horse/movement
pub import horse/uma
extern create-id-table(): vector<int>
c inline "int32_t arr[] = { {{- range $uma := $.Umas }}{{ $uma.ID }},{{ end -}} };\nkk_vector_from_cint32array(arr, (kk_ssize_t){{ $.UmaCount }}, kk_context())"
js inline "[{{ range $uma := $.Umas }}{{ $uma.ID }},{{ end }}]"
// Vector of all Uma IDs in order for easy iterating.
val vall = once(create-id-table)
// Get the name for an Uma.
// The name includes the costume variant, e.g. `[Special Dreamer] Special Week`.
// If no Uma matches the ID, the result contains the numeric ID.
pub fun show(uma: uma-id): string
match uma.game-id
{{- range $uma := $.Umas }}
{{ $uma.ID }} -> {{ printf "%q" $uma.Name }}
{{- end }}
x -> "uma " ++ x.show
// Get the costume variant for an Uma, e.g. `[Special Dreamer]`.
// If no Uma matches the ID, the result contains the numeric ID.
pub fun variant(uma: uma-id): string
match uma.game-id
{{- range $uma := $.Umas }}
{{ $uma.ID }} -> {{ printf "%q" $uma.Variant }}
{{- end }}
x -> "uma " ++ x.show
// Get the character ID for an Uma.
// If no Uma matches the ID, the result is an invalid ID.
pub fun character-id(uma: uma-id): character-id
match uma.game-id
{{- range $uma := $.Umas }}
{{ $uma.ID }} -> Character-id({{ $uma.CharacterID }})
{{- end }}
_ -> Character-id(0)
// Get the sprint aptitude for an Uma.
// If no Uma matches the ID, the result is G.
pub fun sprint(uma: uma-id): aptitude-level
match uma.game-id
{{- range $uma := $.Umas }}
{{ $uma.ID }} -> {{ template "koka-aptitude-level" $uma.Sprint }}
{{- end }}
_ -> G
// Get the mile aptitude for an Uma.
// If no Uma matches the ID, the result is G.
pub fun mile(uma: uma-id): aptitude-level
match uma.game-id
{{- range $uma := $.Umas }}
{{ $uma.ID }} -> {{ template "koka-aptitude-level" $uma.Mile }}
{{- end }}
_ -> G
// Get the medium aptitude for an Uma.
// If no Uma matches the ID, the result is G.
pub fun medium(uma: uma-id): aptitude-level
match uma.game-id
{{- range $uma := $.Umas }}
{{ $uma.ID }} -> {{ template "koka-aptitude-level" $uma.Medium }}
{{- end }}
_ -> G
// Get the long aptitude for an Uma.
// If no Uma matches the ID, the result is G.
pub fun long(uma: uma-id): aptitude-level
match uma.game-id
{{- range $uma := $.Umas }}
{{ $uma.ID }} -> {{ template "koka-aptitude-level" $uma.Long }}
{{- end }}
_ -> G
// Get the front runner aptitude for an Uma.
// If no Uma matches the ID, the result is G.
pub fun front-runner(uma: uma-id): aptitude-level
match uma.game-id
{{- range $uma := $.Umas }}
{{ $uma.ID }} -> {{ template "koka-aptitude-level" $uma.Front }}
{{- end }}
_ -> G
// Get the pace chaser aptitude for an Uma.
// If no Uma matches the ID, the result is G.
pub fun pace-chaser(uma: uma-id): aptitude-level
match uma.game-id
{{- range $uma := $.Umas }}
{{ $uma.ID }} -> {{ template "koka-aptitude-level" $uma.Pace }}
{{- end }}
_ -> G
// Get the late surger aptitude for an Uma.
// If no Uma matches the ID, the result is G.
pub fun late-surger(uma: uma-id): aptitude-level
match uma.game-id
{{- range $uma := $.Umas }}
{{ $uma.ID }} -> {{ template "koka-aptitude-level" $uma.Late }}
{{- end }}
_ -> G
// Get the end closer aptitude for an Uma.
// If no Uma matches the ID, the result is G.
pub fun end-closer(uma: uma-id): aptitude-level
match uma.game-id
{{- range $uma := $.Umas }}
{{ $uma.ID }} -> {{ template "koka-aptitude-level" $uma.End }}
{{- end }}
_ -> G
// Get the turf aptitude for an Uma.
// If no Uma matches the ID, the result is G.
pub fun turf(uma: uma-id): aptitude-level
match uma.game-id
{{- range $uma := $.Umas }}
{{ $uma.ID }} -> {{ template "koka-aptitude-level" $uma.Turf }}
{{- end }}
_ -> G
// Get the dirt aptitude for an Uma.
// If no Uma matches the ID, the result is G.
pub fun dirt(uma: uma-id): aptitude-level
match uma.game-id
{{- range $uma := $.Umas }}
{{ $uma.ID }} -> {{ template "koka-aptitude-level" $uma.Dirt }}
{{- end }}
_ -> G
// Get the unique skill for an Uma.
// If no Uma matches the ID, the result is an invalid ID.
pub fun unique(uma: uma-id): skill-id
match uma.game-id
{{- range $uma := $.Umas }}
{{ $uma.ID }} -> Skill-id({{ $uma.UniqueID }})
{{- end }}
_ -> Skill-id(0)
// Get the first built-in skill for an Uma.
// If no Uma matches the ID, the result is an invalid ID.
pub fun skill1(uma: uma-id): skill-id
match uma.game-id
{{- range $uma := $.Umas }}
{{ $uma.ID }} -> Skill-id({{ $uma.Skill1 }})
{{- end }}
_ -> Skill-id(0)
// Get the second built-in skill for an Uma.
// If no Uma matches the ID, the result is an invalid ID.
pub fun skill2(uma: uma-id): skill-id
match uma.game-id
{{- range $uma := $.Umas }}
{{ $uma.ID }} -> Skill-id({{ $uma.Skill2 }})
{{- end }}
_ -> Skill-id(0)
// Get the third built-in skill for an Uma.
// If no Uma matches the ID, the result is an invalid ID.
pub fun skill3(uma: uma-id): skill-id
match uma.game-id
{{- range $uma := $.Umas }}
{{ $uma.ID }} -> Skill-id({{ $uma.Skill3 }})
{{- end }}
_ -> Skill-id(0)
// Get the potential level 2 skill for an Uma.
// If no Uma matches the ID, the result is an invalid ID.
pub fun skill-pl2(uma: uma-id): skill-id
match uma.game-id
{{- range $uma := $.Umas }}
{{ $uma.ID }} -> Skill-id({{ $uma.SkillPL2 }})
{{- end }}
_ -> Skill-id(0)
// Get the potential level 3 skill for an Uma.
// If no Uma matches the ID, the result is an invalid ID.
pub fun skill-pl3(uma: uma-id): skill-id
match uma.game-id
{{- range $uma := $.Umas }}
{{ $uma.ID }} -> Skill-id({{ $uma.SkillPL3 }})
{{- end }}
_ -> Skill-id(0)
// Get the potential level 4 skill for an Uma.
// If no Uma matches the ID, the result is an invalid ID.
pub fun skill-pl4(uma: uma-id): skill-id
match uma.game-id
{{- range $uma := $.Umas }}
{{ $uma.ID }} -> Skill-id({{ $uma.SkillPL4 }})
{{- end }}
_ -> Skill-id(0)
// Get the potential level 5 skill for an Uma.
// If no Uma matches the ID, the result is an invalid ID.
pub fun skill-pl5(uma: uma-id): skill-id
match uma.game-id
{{- range $uma := $.Umas }}
{{ $uma.ID }} -> Skill-id({{ $uma.SkillPL5 }})
{{- end }}
_ -> Skill-id(0)
{{ end }}
{{- define "koka-aptitude-level" -}}
{{- if eq . 1 -}} G
{{- else if eq . 2 -}} F
{{- else if eq . 3 -}} E
{{- else if eq . 4 -}} D
{{- else if eq . 5 -}} C
{{- else if eq . 6 -}} B
{{- else if eq . 7 -}} A
{{- else if eq . 8 -}} S
{{- else -}} ??? aptitude={{ . }}
{{- end -}}
{{- end -}}

59
horsegen/uma.sql Normal file
View File

@@ -0,0 +1,59 @@
WITH uma_name AS (
SELECT "index" AS id, "text" AS name
FROM text_data
WHERE category = 4
), uma_variant AS (
SELECT "index" AS id, "text" AS variant
FROM text_data
WHERE category = 5
), chara_name AS (
SELECT "index" AS id, "text" AS name
FROM text_data
WHERE category = 6
), skills AS (
SELECT
uma.id,
s.skill_id,
s.need_rank,
ROW_NUMBER() OVER (PARTITION BY s.available_skill_set_id, s.need_rank) AS idx
FROM card_data uma
LEFT JOIN available_skill_set s ON uma.available_skill_set_id = s.available_skill_set_id
)
SELECT
uma.card_id,
card_data.chara_id,
n.name,
v.variant,
c.name AS chara_name,
uma.proper_distance_short,
uma.proper_distance_mile,
uma.proper_distance_middle,
uma.proper_distance_long,
uma.proper_running_style_nige,
uma.proper_running_style_senko,
uma.proper_running_style_sashi,
uma.proper_running_style_oikomi,
uma.proper_ground_turf,
uma.proper_ground_dirt,
su.skill_id1 AS unique_skill,
s1.skill_id AS skill1,
s2.skill_id AS skill2,
s3.skill_id AS skill3,
sp2.skill_id AS skill_pl2,
sp3.skill_id AS skill_pl3,
sp4.skill_id AS skill_pl4,
sp5.skill_id AS skill_pl5
FROM card_data
JOIN card_rarity_data uma ON card_data.id = uma.card_id
JOIN chara_name c ON card_data.chara_id = c.id
JOIN skill_set su ON uma.skill_set = su.id
JOIN skills s1 ON uma.card_id = s1.id AND s1.need_rank = 0 AND s1.idx = 1
JOIN skills s2 ON uma.card_id = s2.id AND s2.need_rank = 0 AND s2.idx = 2
JOIN skills s3 ON uma.card_id = s3.id AND s3.need_rank = 0 AND s3.idx = 3
JOIN skills sp2 ON uma.card_id = sp2.id AND sp2.need_rank = 2
JOIN skills sp3 ON uma.card_id = sp3.id AND sp3.need_rank = 3
JOIN skills sp4 ON uma.card_id = sp4.id AND sp4.need_rank = 4
JOIN skills sp5 ON uma.card_id = sp5.id AND sp5.need_rank = 5
LEFT JOIN uma_name n ON uma.card_id = n.id
LEFT JOIN uma_variant v ON uma.card_id = v.id
WHERE uma.rarity = 5