horsegen: also generate go

This commit is contained in:
2026-01-14 12:18:54 -05:00
parent be41389006
commit c9a7e15f89
10 changed files with 16896 additions and 21 deletions

View File

@@ -2,6 +2,7 @@ package main
import (
"embed"
"errors"
"fmt"
"io"
"regexp"
@@ -10,7 +11,7 @@ import (
"unicode"
)
//go:embed character.kk.template skill.kk.template
//go:embed character.kk.template skill.kk.template character.go.template skill.go.template
var templates embed.FS
// LoadTemplates sets up templates to render game data to source code.
@@ -18,12 +19,14 @@ func LoadTemplates() (*template.Template, error) {
t := template.New("root")
t.Funcs(template.FuncMap{
"kkenum": kkenum,
"goenum": goenum,
})
return t.ParseFS(templates, "*")
}
// ExecCharacterKK renders the Koka character module to w.
func ExecCharacterKK(t *template.Template, w io.Writer, c []NamedID[Character], pairs, trios []AffinityRelation) error {
// ExecCharacter renders the Koka character module to kk and the Go character file to g.
// If either is nil, it is skipped.
func ExecCharacter(t *template.Template, kk, g io.Writer, c []NamedID[Character], pairs, trios []AffinityRelation) error {
if len(pairs) != len(c)*len(c) {
return fmt.Errorf("there are %d pairs but there must be %d for %d characters", len(pairs), len(c)*len(c), len(c))
}
@@ -58,13 +61,20 @@ func ExecCharacterKK(t *template.Template, w io.Writer, c []NamedID[Character],
Count int
MaxID int
}{c, pairs, trios, pm, tm, len(c), maxid}
return t.ExecuteTemplate(w, "koka-character", &data)
var err error
if kk != nil {
err = errors.Join(t.ExecuteTemplate(kk, "koka-character", &data))
}
if g != nil {
err = errors.Join(t.ExecuteTemplate(g, "go-character", &data))
}
return err
}
func ExecSkillKK(t *template.Template, w io.Writer, g []NamedID[SkillGroup], s []Skill) error {
m := make(map[int][]Skill, len(g))
u := make(map[int]int, len(g))
for _, t := range s {
func ExecSkill(t *template.Template, kk, g io.Writer, groups []NamedID[SkillGroup], skills []Skill) error {
m := make(map[int][]Skill, len(groups))
u := make(map[int]int, len(groups))
for _, t := range skills {
m[t.GroupID] = append(m[t.GroupID], t)
if t.Rarity >= 4 {
// Add inheritable uniques to u so we can add inherited versions to groups.
@@ -72,7 +82,7 @@ func ExecSkillKK(t *template.Template, w io.Writer, g []NamedID[SkillGroup], s [
}
}
// Now that u is set up, iterate through again and add in inherited skills.
for _, t := range s {
for _, t := range skills {
if t.InheritID != 0 {
m[u[t.InheritID]] = append(m[u[t.InheritID]], t)
}
@@ -81,8 +91,15 @@ func ExecSkillKK(t *template.Template, w io.Writer, g []NamedID[SkillGroup], s [
Groups []NamedID[SkillGroup]
Skills []Skill
Related map[int][]Skill
}{g, s, m}
return t.ExecuteTemplate(w, "koka-skill", &data)
}{groups, skills, m}
var err error
if kk != nil {
err = errors.Join(t.ExecuteTemplate(kk, "koka-skill", &data))
}
if g != nil {
err = errors.Join(t.ExecuteTemplate(g, "go-skill-data", &data))
}
return err
}
func ExecSkillGroupKK(t *template.Template, w io.Writer, g []NamedID[SkillGroup], s []Skill) error {
@@ -93,7 +110,7 @@ func ExecSkillGroupKK(t *template.Template, w io.Writer, g []NamedID[SkillGroup]
return t.ExecuteTemplate(w, "koka-skill-group", &data)
}
const replaceDash = " ,!?/+();#○☆♡'=♪∀゚∴"
const wordSeps = " ,!?/-+();#○☆♡'=♪∀゚∴"
var (
kkReplace = func() *strings.Replacer {
@@ -111,13 +128,33 @@ var (
"×", "x",
"◎", "Lv2",
}
for _, c := range replaceDash {
for _, c := range wordSeps {
r = append(r, string(c), "-")
}
return strings.NewReplacer(r...)
}()
kkMultidash = regexp.MustCompile(`-+`)
kkDashNonletter = regexp.MustCompile(`-[^A-Za-z]`)
goReplace = func() *strings.Replacer {
r := []string{
"Triple 7s", "TripleSevens",
"1,500,000 CC", "OneMillionCC",
"15,000,000 CC", "FifteenMillionCC",
"1st", "First",
"♡ 3D Nail Art", "NailArt",
".", "",
"&", "And",
"'s", "s",
"∞", "Infinity",
"×", "X",
"◎", "Lv2",
}
for _, c := range wordSeps {
r = append(r, string(c), "")
}
return strings.NewReplacer(r...)
}()
)
func kkenum(name string) string {
@@ -144,3 +181,14 @@ func kkenum(name string) string {
}
return name
}
func goenum(name string) string {
// go names are a bit more lax, so we need fewer checks
orig := name
name = goReplace.Replace(name)
if len(name) == 0 {
panic(fmt.Errorf("%q became empty as Go enum variant", orig))
}
name = strings.ToUpper(name[:1]) + name[1:]
return name
}