From 8fb29a953c82a0093df44623331c4f2e9db42fcc Mon Sep 17 00:00:00 2001 From: Branden J Brown Date: Tue, 10 Feb 2026 21:04:12 -0500 Subject: [PATCH] horsegen: generate scenarios since sparks use them --- doc/README.md | 1 + horse/game-id.kk | 3 + horse/global/scenario.go | 23 ++++++ horse/global/scenario.kk | 38 ++++++++++ horse/race.go | 9 +++ horse/spark.kk | 135 ++-------------------------------- horsegen/gen.go | 15 ++++ horsegen/load.go | 40 ++++++++++ horsegen/main.go | 23 +++++- horsegen/scenario.go.template | 23 ++++++ horsegen/scenario.kk.template | 45 ++++++++++++ horsegen/scenario.sql | 17 +++++ 12 files changed, 243 insertions(+), 129 deletions(-) create mode 100644 horse/global/scenario.go create mode 100644 horse/global/scenario.kk create mode 100644 horsegen/scenario.go.template create mode 100644 horsegen/scenario.kk.template create mode 100644 horsegen/scenario.sql diff --git a/doc/README.md b/doc/README.md index 8e882d2..fab6de7 100644 --- a/doc/README.md +++ b/doc/README.md @@ -12,6 +12,7 @@ This file is my notes from exploring the database. - 147 is spark names, 172 is spark descriptions - 33 is race names by race id, 28 is race names by race instance id, 31 is race courses, 111 is saddle names - 65 is player titles, 66 is title descriptions - ties with honor_data? +- 119 is scenario full titles (e.g. The Beginning: URA Finale), 120 is scenario descriptions, 237 is scenario names (e.g. URA Finale) # succession factor (sparks) diff --git a/horse/game-id.kk b/horse/game-id.kk index 5cdd902..c6b05a3 100644 --- a/horse/game-id.kk +++ b/horse/game-id.kk @@ -7,6 +7,9 @@ alias game-id = int // Specific game ID types. // I've already made mistakes with ID categories and I haven't even committed this file yet. +pub struct scenario-id + game-id: game-id + // Game ID for characters. // Generally numbers in the range 1000-9999. pub struct character-id diff --git a/horse/global/scenario.go b/horse/global/scenario.go new file mode 100644 index 0000000..cd86309 --- /dev/null +++ b/horse/global/scenario.go @@ -0,0 +1,23 @@ +package global + +// Automatically generated with horsegen; DO NOT EDIT + +import . "git.sunturtle.xyz/zephyr/horse/horse" + +const ( + ScenarioURAFinale ScenarioID = 1 // URA Finale + ScenarioUnityCup ScenarioID = 2 // Unity Cup +) + +var AllScenarios = map[ScenarioID]Scenario{ + ScenarioURAFinale: { + ID: 1, + Name: "URA Finale", + Title: "The Beginning: URA Finale", + }, + ScenarioUnityCup: { + ID: 2, + Name: "Unity Cup", + Title: "Unity Cup: Shine On, Team Spirit!", + }, +} diff --git a/horse/global/scenario.kk b/horse/global/scenario.kk new file mode 100644 index 0000000..663a6b3 --- /dev/null +++ b/horse/global/scenario.kk @@ -0,0 +1,38 @@ +module horse/global/scenario + +// Automatically generated with horsegen; DO NOT EDIT + +import horse/game-id + +// Enumeration of all scenarios for type-safe programming. +pub type scenario + URA-Finale + Unity-Cup + +// Get the scenario ID for a scenario. +pub fun scenario-id(s: scenario): scenario-id + match s + URA-Finale -> Scenario-id(1) + Unity-Cup -> Scenario-id(2) + +// List of all scenarios in ID order for easy iterating. +pub val all = [ + URA-Finale, + Unity-Cup, +] + +// Get the name for a scenario. +// If no scenario matches the ID, the result contains the numeric ID. +pub fun show(s: scenario-id): string + match s.game-id + 1 -> "URA Finale" + 2 -> "Unity Cup" + x -> "scenario " ++ x.show + +// Get the full title for a scenario, e.g. "The Beginning: URA Finale". +// If no scenario matches the ID, the result contains the numeric ID. +pub fun title(s: scenario-id): string + match s.game-id + 1 -> "The Beginning: URA Finale" + 2 -> "Unity Cup: Shine On, Team Spirit!" + x -> "scenario " ++ x.show diff --git a/horse/race.go b/horse/race.go index 374b2e4..2438ed1 100644 --- a/horse/race.go +++ b/horse/race.go @@ -35,3 +35,12 @@ const ( SaddleTypeG2 SaddleTypeG1 ) + +type ScenarioID int8 + +// Scenario is metadata about a career scenario. +type Scenario struct { + ID ScenarioID + Name string + Title string +} diff --git a/horse/spark.kk b/horse/spark.kk index 8327d8d..f54b8ac 100644 --- a/horse/spark.kk +++ b/horse/spark.kk @@ -1,13 +1,14 @@ module horse/spark -// A single spark. -// Parameterized by the spark type: stat, aptitude, unique, race, or skill. -pub struct spark - kind: a - level: level +import horse/game-id -pub fun spark/show(spark: spark, level-fancy: string = "*", ?kind: (a) -> string): string - kind(spark.kind) ++ " " ++ spark.level.show ++ level-fancy +pub type spark + Stat(s: stat, l: level) + Aptitude(a: aptitude, l: level) + Unique(s: skill-id, l: level) + Race(r: race-id, l: level) + Skill(s: skill-id, l: level) + Scenario(s: scenario-id, l: level) pub type level One @@ -64,123 +65,3 @@ pub fun aptitude/show(this : aptitude): string Pace-Chaser -> "Pace Chaser" Late-Surger -> "Late Surger" End-Closer -> "End Closer" - -// Unique (green) spark. -// TODO: decide this representation; strings? umas? probably depends on skills generally -pub type unique - -pub fun unique/show(this: unique): string - "TODO(zeph): unique skills" - -// Race, skill, and scenario (white) sparks. -pub type generic - February-Stakes - Takamatsunomiya-Kinen - Osaka-Hai - Oka-Sho - Satsuki-Sho - Tenno-Sho-Spring - NHK-Mile-Cup - Victoria-Mile - Japanese-Oaks - Japanese-Derby - Yasuda-Kinen - Takarazuka-Kinen - Sprinters-Stakes - Shuka-Sho - Kikuka-Sho - Tenno-Sho-Autumn - Queen-Elizabeth-II-Cup - Mile-Championship - Japan-Cup - Champions-Cup - Hanshin-Juvenile-Fillies - Asahi-Hai-Futurity-Stakes - Arima-Kinen - Hopeful-Stakes - Tokyo-Daishoten - JBC-Classic - JBC-Sprint - JBC-Ladies-Classic - Japan-Dirt-Derby - Teio-Sho - Skill(skill: string) - URA-Finale - Unity-Cup - -// Automatically generated. -// Equality comparison of the `generic` type. -pub fun generic/(==)(this : generic, other : generic) : e bool - match (this, other) - (February-Stakes, February-Stakes) -> True - (Takamatsunomiya-Kinen, Takamatsunomiya-Kinen) -> True - (Osaka-Hai, Osaka-Hai) -> True - (Oka-Sho, Oka-Sho) -> True - (Satsuki-Sho, Satsuki-Sho) -> True - (Tenno-Sho-Spring, Tenno-Sho-Spring) -> True - (NHK-Mile-Cup, NHK-Mile-Cup) -> True - (Victoria-Mile, Victoria-Mile) -> True - (Japanese-Oaks, Japanese-Oaks) -> True - (Japanese-Derby, Japanese-Derby) -> True - (Yasuda-Kinen, Yasuda-Kinen) -> True - (Takarazuka-Kinen, Takarazuka-Kinen) -> True - (Sprinters-Stakes, Sprinters-Stakes) -> True - (Shuka-Sho, Shuka-Sho) -> True - (Kikuka-Sho, Kikuka-Sho) -> True - (Tenno-Sho-Autumn, Tenno-Sho-Autumn) -> True - (Queen-Elizabeth-II-Cup, Queen-Elizabeth-II-Cup) -> True - (Mile-Championship, Mile-Championship) -> True - (Japan-Cup, Japan-Cup) -> True - (Champions-Cup, Champions-Cup) -> True - (Hanshin-Juvenile-Fillies, Hanshin-Juvenile-Fillies) -> True - (Asahi-Hai-Futurity-Stakes, Asahi-Hai-Futurity-Stakes) -> True - (Arima-Kinen, Arima-Kinen) -> True - (Hopeful-Stakes, Hopeful-Stakes) -> True - (Tokyo-Daishoten, Tokyo-Daishoten) -> True - (JBC-Classic, JBC-Classic) -> True - (JBC-Sprint, JBC-Sprint) -> True - (JBC-Ladies-Classic, JBC-Ladies-Classic) -> True - (Japan-Dirt-Derby, Japan-Dirt-Derby) -> True - (Teio-Sho, Teio-Sho) -> True - (Skill(skill), Skill(skill')) -> skill == skill' - (URA-Finale, URA-Finale) -> True - (Unity-Cup, Unity-Cup) -> True - (_, _) -> False - -// Automatically generated. -// Shows a string representation of the `generic` type. -pub fun generic/show(this : generic) : e string - match this - February-Stakes -> "February Stakes" - Takamatsunomiya-Kinen -> "Takamatsunomiya Kinen" - Osaka-Hai -> "Osaka Hai" - Oka-Sho -> "Oka Sho" - Satsuki-Sho -> "Satsuki Sho" - Tenno-Sho-Spring -> "Tenno Sho Spring" - NHK-Mile-Cup -> "NHK Mile Cup" - Victoria-Mile -> "Victoria Mile" - Japanese-Oaks -> "Japanese Oaks" - Japanese-Derby -> "Japanese Derby" - Yasuda-Kinen -> "Yasuda Kinen" - Takarazuka-Kinen -> "Takarazuka Kinen" - Sprinters-Stakes -> "Sprinters Stakes" - Shuka-Sho -> "Shuka Sho" - Kikuka-Sho -> "Kikuka Sho" - Tenno-Sho-Autumn -> "Tenno Sho Autumn" - Queen-Elizabeth-II-Cup -> "Queen Elizabeth II Cup" - Mile-Championship -> "Mile Championship" - Japan-Cup -> "Japan Cup" - Champions-Cup -> "Champions Cup" - Hanshin-Juvenile-Fillies -> "Hanshin Juvenile Fillies" - Asahi-Hai-Futurity-Stakes -> "Asahi Hai Futurity Stakes" - Arima-Kinen -> "Arima Kinen" - Hopeful-Stakes -> "Hopeful Stakes" - Tokyo-Daishoten -> "Tokyo Daishoten" - JBC-Classic -> "JBC Classic" - JBC-Sprint -> "JBC Sprint" - JBC-Ladies-Classic -> "JBC Ladies Classic" - Japan-Dirt-Derby -> "Japan Dirt Derby" - Teio-Sho -> "Teio Sho" - Skill(skill) -> skill.show - URA-Finale -> "URA Finale" - Unity-Cup -> "Unity Cup" diff --git a/horsegen/gen.go b/horsegen/gen.go index d0e9106..215c9c5 100644 --- a/horsegen/gen.go +++ b/horsegen/gen.go @@ -123,6 +123,21 @@ func ExecSaddle(t *template.Template, region string, kk, g io.Writer, saddles [] return err } +func ExecScenario(t *template.Template, region string, kk, g io.Writer, scen []Scenario) error { + data := struct { + Region string + Scenarios []Scenario + }{region, scen} + var err error + if kk != nil { + err = errors.Join(err, t.ExecuteTemplate(kk, "koka-scenario", &data)) + } + if g != nil { + err = errors.Join(err, t.ExecuteTemplate(g, "go-scenario", &data)) + } + return err +} + const wordSeps = " ,!?/-+();#○☆♡'=♪∀゚∴" var ( diff --git a/horsegen/load.go b/horsegen/load.go index 5412d14..dfb3441 100644 --- a/horsegen/load.go +++ b/horsegen/load.go @@ -29,6 +29,9 @@ var raceSQL string //go:embed saddle.sql var saddleSQL string +//go:embed scenario.sql +var scenarioSQL string + type ( Character struct{} SkillGroup struct{} @@ -407,3 +410,40 @@ func Saddles(ctx context.Context, db *sqlitex.Pool) ([]Saddle, error) { } 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 +} diff --git a/horsegen/main.go b/horsegen/main.go index 39e0cc5..178f79c 100644 --- a/horsegen/main.go +++ b/horsegen/main.go @@ -52,6 +52,7 @@ func main() { skills []Skill races []Race saddles []Saddle + scens []Scenario ) eg.Go(func() error { slog.Info("get characters") @@ -91,8 +92,14 @@ func main() { }) eg.Go(func() error { slog.Info("get saddles") - s, err := Saddles(ctx, db) - saddles = s + r, err := Saddles(ctx, db) + saddles = r + return err + }) + eg.Go(func() error { + slog.Info("get scenarios") + r, err := Scenarios(ctx, db) + scens = r return err }) if err := eg.Wait(); err != nil { @@ -154,6 +161,18 @@ func main() { slog.Info("write saddles") return ExecSaddle(t, region, kf, gf, saddles) }) + eg.Go(func() error { + kf, err := os.Create(filepath.Join(out, region, "scenario.kk")) + if err != nil { + return err + } + gf, err := os.Create(filepath.Join(out, region, "scenario.go")) + if err != nil { + return err + } + slog.Info("write scenarios") + return ExecScenario(t, region, kf, gf, scens) + }) if err := eg.Wait(); err != nil { slog.Error("generate", slog.Any("err", err)) os.Exit(1) diff --git a/horsegen/scenario.go.template b/horsegen/scenario.go.template new file mode 100644 index 0000000..21fad59 --- /dev/null +++ b/horsegen/scenario.go.template @@ -0,0 +1,23 @@ +{{- define "go-scenario" -}} +package {{ $.Region }} + +// Automatically generated with horsegen; DO NOT EDIT + +import . "git.sunturtle.xyz/zephyr/horse/horse" + +const ( + {{- range $s := $.Scenarios }} + Scenario{{ goenum $s.Name }} ScenarioID = {{ $s.ID }} // {{ $s.Name }} + {{- end }} +) + +var AllScenarios = map[ScenarioID]Scenario{ + {{- range $s := $.Scenarios }} + Scenario{{ goenum $s.Name }}: { + ID: {{ $s.ID }}, + Name: {{ printf "%q" $s.Name }}, + Title: {{ printf "%q" $s.Title }}, + }, + {{- end }} +} +{{ end }} \ No newline at end of file diff --git a/horsegen/scenario.kk.template b/horsegen/scenario.kk.template new file mode 100644 index 0000000..ef4716e --- /dev/null +++ b/horsegen/scenario.kk.template @@ -0,0 +1,45 @@ +{{- define "koka-scenario" -}} +module horse/{{ $.Region }}/scenario + +// Automatically generated with horsegen; DO NOT EDIT + +import horse/game-id + +// Enumeration of all scenarios for type-safe programming. +pub type scenario + {{- range $s := $.Scenarios }} + {{ kkenum $s.Name }} + {{- end }} + +// Get the scenario ID for a scenario. +pub fun scenario-id(s: scenario): scenario-id + match s + {{- range $s := $.Scenarios }} + {{ kkenum $s.Name }} -> Scenario-id({{ $s.ID }}) + {{- end }} + +// List of all scenarios in ID order for easy iterating. +pub val all = [ + {{- range $s := $.Scenarios }} + {{ kkenum $s.Name }}, + {{- end }} +] + +// Get the name for a scenario. +// If no scenario matches the ID, the result contains the numeric ID. +pub fun show(s: scenario-id): string + match s.game-id + {{- range $s := $.Scenarios }} + {{ $s.ID }} -> {{ printf "%q" $s.Name }} + {{- end }} + x -> "scenario " ++ x.show + +// Get the full title for a scenario, e.g. "The Beginning: URA Finale". +// If no scenario matches the ID, the result contains the numeric ID. +pub fun title(s: scenario-id): string + match s.game-id + {{- range $s := $.Scenarios }} + {{ $s.ID }} -> {{ printf "%q" $s.Title }} + {{- end }} + x -> "scenario " ++ x.show +{{ end }} diff --git a/horsegen/scenario.sql b/horsegen/scenario.sql new file mode 100644 index 0000000..f802651 --- /dev/null +++ b/horsegen/scenario.sql @@ -0,0 +1,17 @@ +WITH scenario_name AS ( + SELECT "index" AS id, "text" AS name + FROM text_data + WHERE category = 237 +), scenario_title AS ( + SELECT "index" AS id, "text" AS title + FROM text_data + WHERE category = 119 +) +SELECT + sc.id, + n.name, + t.title +FROM single_mode_scenario sc + JOIN scenario_name n ON sc.id = n.id + JOIN scenario_title t ON sc.id = t.id +ORDER BY sc.id