all: generate json, not code

This includes modifying horsebot to use the generated JSON, as well as
moving the generator to another cmd/ directory.

Remove the generated code while we're here.
Koka tests still have to be updated, but it requires a JSON parser.
This commit is contained in:
2026-03-08 21:33:46 -04:00
parent 7ff271ff2d
commit 8632bb8c3c
60 changed files with 71 additions and 62322 deletions
-405
View File
@@ -1,405 +0,0 @@
//go:build ignore
package main
import (
"bufio"
"cmp"
"context"
_ "embed"
"encoding/json"
"errors"
"flag"
"fmt"
"log/slog"
"maps"
"os"
"os/signal"
"path/filepath"
"slices"
"golang.org/x/sync/errgroup"
"zombiezen.com/go/sqlite"
"zombiezen.com/go/sqlite/sqlitex"
"git.sunturtle.xyz/zephyr/horse/horse"
)
func main() {
var (
mdb string
out string
region string
)
flag.StringVar(&mdb, "mdb", os.ExpandEnv(`$USERPROFILE\AppData\LocalLow\Cygames\Umamusume\master\master.mdb`), "`path` to Umamusume master.mdb")
flag.StringVar(&out, "o", `horse`, "`dir`ectory for output files")
flag.StringVar(&region, "region", "global", "region the database is for (global, jp)")
flag.Parse()
slog.Info("open", slog.String("mdb", mdb))
db, err := sqlitex.NewPool(mdb, sqlitex.PoolOptions{Flags: sqlite.OpenReadOnly})
if err != nil {
slog.Error("opening mdb", slog.String("mdb", mdb), slog.Any("err", err))
os.Exit(1)
}
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
go func() {
<-ctx.Done()
stop()
}()
loadgroup, ctx1 := errgroup.WithContext(ctx)
charas := load(ctx1, loadgroup, db, "characters", characterSQL, func(s *sqlite.Stmt) horse.Character {
return horse.Character{
ID: horse.CharacterID(s.ColumnInt(0)),
Name: s.ColumnText(1),
}
})
aff := load(ctx1, loadgroup, db, "pair affinity", affinitySQL, func(s *sqlite.Stmt) horse.AffinityRelation {
return horse.AffinityRelation{
IDA: s.ColumnInt(0),
IDB: s.ColumnInt(1),
IDC: s.ColumnInt(2),
Affinity: s.ColumnInt(3),
}
})
umas := load(ctx1, loadgroup, db, "umas", umaSQL, func(s *sqlite.Stmt) horse.Uma {
return horse.Uma{
ID: horse.UmaID(s.ColumnInt(0)),
CharacterID: horse.CharacterID(s.ColumnInt(1)),
Name: s.ColumnText(2),
Variant: s.ColumnText(3),
Sprint: horse.AptitudeLevel(s.ColumnInt(4)),
Mile: horse.AptitudeLevel(s.ColumnInt(6)),
Medium: horse.AptitudeLevel(s.ColumnInt(7)),
Long: horse.AptitudeLevel(s.ColumnInt(8)),
Front: horse.AptitudeLevel(s.ColumnInt(9)),
Pace: horse.AptitudeLevel(s.ColumnInt(10)),
Late: horse.AptitudeLevel(s.ColumnInt(11)),
End: horse.AptitudeLevel(s.ColumnInt(12)),
Turf: horse.AptitudeLevel(s.ColumnInt(13)),
Dirt: horse.AptitudeLevel(s.ColumnInt(14)),
Unique: horse.SkillID(s.ColumnInt(15)),
Skill1: horse.SkillID(s.ColumnInt(16)),
Skill2: horse.SkillID(s.ColumnInt(17)),
Skill3: horse.SkillID(s.ColumnInt(18)),
SkillPL2: horse.SkillID(s.ColumnInt(19)),
SkillPL3: horse.SkillID(s.ColumnInt(20)),
SkillPL4: horse.SkillID(s.ColumnInt(21)),
SkillPL5: horse.SkillID(s.ColumnInt(22)),
}
})
sg := load(ctx1, loadgroup, db, "skill groups", skillGroupSQL, func(s *sqlite.Stmt) horse.SkillGroup {
return horse.SkillGroup{
ID: horse.SkillGroupID(s.ColumnInt(0)),
Skill1: horse.SkillID(s.ColumnInt(1)),
Skill2: horse.SkillID(s.ColumnInt(2)),
Skill3: horse.SkillID(s.ColumnInt(3)),
SkillBad: horse.SkillID(s.ColumnInt(4)),
}
})
skills := load(ctx1, loadgroup, db, "skills", skillSQL, func(s *sqlite.Stmt) horse.Skill {
return horse.Skill{
ID: horse.SkillID(s.ColumnInt(0)),
Name: s.ColumnText(1),
Description: s.ColumnText(2),
Group: horse.SkillGroupID(s.ColumnInt32(3)),
Rarity: int8(s.ColumnInt(5)),
GroupRate: int8(s.ColumnInt(6)),
GradeValue: s.ColumnInt32(7),
WitCheck: s.ColumnBool(8),
Activations: trimActivations([]horse.Activation{
{
Precondition: s.ColumnText(9),
Condition: s.ColumnText(10),
Duration: horse.TenThousandths(s.ColumnInt(11)),
DurScale: horse.DurScale(s.ColumnInt(12)),
Cooldown: horse.TenThousandths(s.ColumnInt(13)),
Abilities: trimAbilities([]horse.Ability{
{
Type: horse.AbilityType(s.ColumnInt(14)),
ValueUsage: horse.AbilityValueUsage(s.ColumnInt(15)),
Value: horse.TenThousandths(s.ColumnInt(16)),
Target: horse.AbilityTarget(s.ColumnInt(17)),
TargetValue: s.ColumnInt32(18),
},
{
Type: horse.AbilityType(s.ColumnInt(19)),
ValueUsage: horse.AbilityValueUsage(s.ColumnInt(20)),
Value: horse.TenThousandths(s.ColumnInt(21)),
Target: horse.AbilityTarget(s.ColumnInt(22)),
TargetValue: s.ColumnInt32(23),
},
{
Type: horse.AbilityType(s.ColumnInt(24)),
ValueUsage: horse.AbilityValueUsage(s.ColumnInt(25)),
Value: horse.TenThousandths(s.ColumnInt(26)),
Target: horse.AbilityTarget(s.ColumnInt(27)),
TargetValue: s.ColumnInt32(28),
},
}),
},
{
Precondition: s.ColumnText(29),
Condition: s.ColumnText(30),
Duration: horse.TenThousandths(s.ColumnInt(31)),
DurScale: horse.DurScale(s.ColumnInt(32)),
Cooldown: horse.TenThousandths(s.ColumnInt(33)),
Abilities: trimAbilities([]horse.Ability{
{
Type: horse.AbilityType(s.ColumnInt(34)),
ValueUsage: horse.AbilityValueUsage(s.ColumnInt(35)),
Value: horse.TenThousandths(s.ColumnInt(36)),
Target: horse.AbilityTarget(s.ColumnInt(37)),
TargetValue: s.ColumnInt32(38),
},
{
Type: horse.AbilityType(s.ColumnInt(39)),
ValueUsage: horse.AbilityValueUsage(s.ColumnInt(40)),
Value: horse.TenThousandths(s.ColumnInt(41)),
Target: horse.AbilityTarget(s.ColumnInt(42)),
TargetValue: s.ColumnInt32(43),
},
{
Type: horse.AbilityType(s.ColumnInt(44)),
ValueUsage: horse.AbilityValueUsage(s.ColumnInt(45)),
Value: horse.TenThousandths(s.ColumnInt(46)),
Target: horse.AbilityTarget(s.ColumnInt(47)),
TargetValue: s.ColumnInt32(48),
},
}),
},
}),
UniqueOwner: s.ColumnText(52), // TODO(zeph): should be id, not name
SPCost: s.ColumnInt(49),
IconID: s.ColumnInt(53),
}
})
races := load(ctx1, loadgroup, db, "races", raceSQL, func(s *sqlite.Stmt) horse.Race {
return horse.Race{
ID: horse.RaceID(s.ColumnInt(0)),
Name: s.ColumnText(1),
// TODO(zeph): grade
Thumbnail: s.ColumnInt(3),
Primary: horse.RaceID(s.ColumnInt(4)),
}
})
saddles := load(ctx1, loadgroup, db, "saddles", saddleSQL, func(s *sqlite.Stmt) horse.Saddle {
return horse.Saddle{
ID: horse.SaddleID(s.ColumnInt(0)),
Name: s.ColumnText(1),
Races: trimZeros(
horse.RaceID(s.ColumnInt(2)),
horse.RaceID(s.ColumnInt(3)),
horse.RaceID(s.ColumnInt(4)),
),
Type: horse.SaddleType(s.ColumnInt(5)),
Primary: horse.SaddleID(s.ColumnInt(6)),
}
})
scenarios := load(ctx1, loadgroup, db, "scenarios", scenarioSQL, func(s *sqlite.Stmt) horse.Scenario {
return horse.Scenario{
ID: horse.ScenarioID(s.ColumnInt(0)),
Name: s.ColumnText(1),
Title: s.ColumnText(2),
}
})
sparks := load(ctx1, loadgroup, db, "sparks", sparkSQL, func(s *sqlite.Stmt) horse.Spark {
return horse.Spark{
ID: horse.SparkID(s.ColumnInt(0)),
Name: s.ColumnText(1),
Description: s.ColumnText(2),
Group: horse.SparkGroupID(s.ColumnInt(3)),
Rarity: horse.SparkRarity(s.ColumnInt(4)),
Type: horse.SparkType(s.ColumnInt(5)),
// Effects filled in later.
}
})
sparkeffs := load(ctx1, loadgroup, db, "spark effects", sparkEffectSQL, func(s *sqlite.Stmt) SparkEffImm {
return SparkEffImm{
Group: horse.SparkGroupID(s.ColumnInt(0)),
Effect: s.ColumnInt(1),
Target: horse.SparkTarget(s.ColumnInt(2)),
Value1: s.ColumnInt32(3),
Value2: s.ColumnInt32(4),
}
})
if err := os.MkdirAll(filepath.Join(out, region), 0775); err != nil {
slog.Error("create output dir", slog.Any("err", err))
os.Exit(1)
}
writegroup, ctx2 := errgroup.WithContext(ctx)
writegroup.Go(func() error { return write(ctx2, out, region, "character.json", charas) })
writegroup.Go(func() error { return write(ctx2, out, region, "affinity.json", aff) })
writegroup.Go(func() error { return write(ctx2, out, region, "uma.json", umas) })
writegroup.Go(func() error { return write(ctx2, out, region, "skill-group.json", sg) })
writegroup.Go(func() error { return write(ctx2, out, region, "skill.json", skills) })
writegroup.Go(func() error { return write(ctx2, out, region, "race.json", races) })
writegroup.Go(func() error { return write(ctx2, out, region, "saddle.json", saddles) })
writegroup.Go(func() error { return write(ctx2, out, region, "scenario.json", scenarios) })
writegroup.Go(func() error { return write(ctx2, out, region, "spark.json", mergesparks(sparks, sparkeffs)) })
if err := writegroup.Wait(); err != nil {
slog.ErrorContext(ctx, "write", slog.Any("err", err))
os.Exit(1)
}
slog.InfoContext(ctx, "done")
}
var (
//go:embed sql/character.sql
characterSQL string
//go:embed sql/affinity.sql
affinitySQL string
//go:embed sql/uma.sql
umaSQL string
//go:embed sql/skill-group.sql
skillGroupSQL string
//go:embed sql/skill.sql
skillSQL string
//go:embed sql/race.sql
raceSQL string
//go:embed sql/saddle.sql
saddleSQL string
//go:embed sql/scenario.sql
scenarioSQL string
//go:embed sql/spark.sql
sparkSQL string
//go:embed sql/spark-effect.sql
sparkEffectSQL string
)
func load[T any](ctx context.Context, group *errgroup.Group, db *sqlitex.Pool, kind, sql string, row func(*sqlite.Stmt) T) func() ([]T, error) {
slog.InfoContext(ctx, "load", slog.String("kind", kind))
var r []T
group.Go(func() error {
conn, err := db.Take(ctx)
defer db.Put(conn)
if err != nil {
return fmt.Errorf("couldn't get connection for %s: %w", kind, err)
}
stmt, _, err := conn.PrepareTransient(sql)
if err != nil {
return fmt.Errorf("couldn't prepare statement for %s: %w", kind, err)
}
for {
ok, err := stmt.Step()
if err != nil {
return fmt.Errorf("error stepping %s: %w", kind, err)
}
if !ok {
break
}
r = append(r, row(stmt))
}
return nil
})
return func() ([]T, error) {
err := group.Wait()
if err == context.Canceled {
// After the first wait, all future ones return context.Canceled.
// We want to be able to wait any number of times, so hide it.
err = nil
}
return r, err
}
}
func write[T any](ctx context.Context, out, region, name string, v func() (T, error)) error {
p := filepath.Join(out, region, name)
r, err := v()
if err != nil {
return err
}
slog.InfoContext(ctx, "write", slog.String("path", p))
f, err := os.Create(p)
if err != nil {
return err
}
defer f.Close()
w := bufio.NewWriter(f)
enc := json.NewEncoder(w)
enc.SetEscapeHTML(false)
enc.SetIndent("", "\t")
err = enc.Encode(r)
err = errors.Join(err, w.Flush())
slog.InfoContext(ctx, "marshaled", slog.String("path", p))
return err
}
func mergesparks(sparks func() ([]horse.Spark, error), effs func() ([]SparkEffImm, error)) func() ([]horse.Spark, error) {
return func() ([]horse.Spark, error) {
sp, err := sparks()
if err != nil {
return nil, err
}
ef, err := effs()
if err != nil {
return nil, err
}
// Spark effects are sorted by group ID, but groups apply to multiple
// sparks, and we don't rely on sparks and groups being in the same order.
// It is possible to merge in linear time, but not worth the effort:
// n log n is fine since this is an AOT step.
for i := range sp {
k, ok := slices.BinarySearchFunc(ef, sp[i].Group, func(e SparkEffImm, v horse.SparkGroupID) int { return cmp.Compare(e.Group, v) })
if !ok {
panic(fmt.Errorf("mergesparks: no spark group for %+v", &sp[i]))
}
// Back up to the first effect in the group.
for k > 0 && ef[k-1].Group == sp[i].Group {
k--
}
// Map effect IDs to the lists of their effects.
m := make(map[int][]horse.SparkEffect)
for _, e := range ef[k:] {
if e.Group != sp[i].Group {
// Done with this group.
break
}
m[e.Effect] = append(m[e.Effect], horse.SparkEffect{Target: e.Target, Value1: e.Value1, Value2: e.Value2})
}
// Now get effects in order.
keys := slices.Sorted(maps.Keys(m))
sp[i].Effects = make([][]horse.SparkEffect, 0, len(keys))
for _, key := range keys {
sp[i].Effects = append(sp[i].Effects, m[key])
}
}
return sp, nil
}
}
type SparkEffImm struct {
Group horse.SparkGroupID
Effect int
Target horse.SparkTarget
Value1 int32
Value2 int32
}
func trimAbilities(s []horse.Ability) []horse.Ability {
for len(s) > 0 && s[len(s)-1].Type == 0 {
s = s[:len(s)-1]
}
return s
}
func trimActivations(s []horse.Activation) []horse.Activation {
for len(s) > 0 && s[len(s)-1].Condition == "" {
s = s[:len(s)-1]
}
return s
}
func trimZeros[T comparable](s ...T) []T {
var zero T
for len(s) > 0 && s[len(s)-1] == zero {
s = s[:len(s)-1]
}
return s
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-2014
View File
File diff suppressed because it is too large Load Diff
-913
View File
@@ -1,913 +0,0 @@
module horse/global/race
// Automatically generated with horsegen; DO NOT EDIT
import std/core/delayed
import std/core/vector
import std/core-extras
import std/data/rb-map
import horse/game-id
pub import horse/race
extern create-id-table(): vector<int>
c inline "int32_t arr[] = {1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1011,1012,1013,1014,1015,1016,1017,1018,1019,1020,1021,1022,1023,1024,1025,1026,1027,1028,1101,1102,1103,1104,1105,1106,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021,2022,2023,2024,2025,2026,2027,2028,2029,2030,2031,2032,2033,2034,2035,3001,3002,3003,3004,3005,3006,3007,3008,3009,3010,3011,3012,3013,3014,3015,3016,3017,3018,3019,3020,3021,3022,3023,3024,3025,3026,3027,3028,3029,3030,3031,3032,3033,3034,3035,3036,3037,3038,3039,3040,3041,3042,3043,3044,3045,3046,3047,3048,3049,3050,3051,3052,3053,3054,3055,3056,3057,3058,3059,3060,3061,3062,3063,3064,3065,3066,3067,3068,3069,3070,4001,4002,4003,4004,4005,4006,4007,4008,4009,4010,4011,4012,4013,4014,4015,4016,4017,4018,4019,4020,4021,4022,4023,4024,4025,4026,4027,4028,4030,4031,4032,4033,4035,4036,4037,4038,4039,4040,4041,4042,4043,4044,4045,4046,4047,4048,4049,4050,4051,4052,4053,4054,4055,4056,4057,4058,4059,4060,4061,4062,4063,4064,4065,4066,4068,4069,4070,4071,4072,4073,4074,4075,4076,4077,4078,4079,4080,4081,4082,4083,4084,4085,4086,4087,4088,4089,4090,4091,4092,4093,4094,4095,4096,4097,4098,4099,4100,4101,4102,4103,4104,4105,4106,4107,4108,4109,4110,4111,4112,4113,4114,4115,4116,4118,4119,4120,4121,4122,4123,4124,4501,4502,4503,4504,4505,4506,4507,4508,4509,4510,4511,4512,4513,4514,4515,4516,4517,4518,4519,4520,4521,4522,4523,4524,4525,4526,};\nkk_vector_from_cint32array(arr, (kk_ssize_t)285, kk_context())"
js inline "[1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1011,1012,1013,1014,1015,1016,1017,1018,1019,1020,1021,1022,1023,1024,1025,1026,1027,1028,1101,1102,1103,1104,1105,1106,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021,2022,2023,2024,2025,2026,2027,2028,2029,2030,2031,2032,2033,2034,2035,3001,3002,3003,3004,3005,3006,3007,3008,3009,3010,3011,3012,3013,3014,3015,3016,3017,3018,3019,3020,3021,3022,3023,3024,3025,3026,3027,3028,3029,3030,3031,3032,3033,3034,3035,3036,3037,3038,3039,3040,3041,3042,3043,3044,3045,3046,3047,3048,3049,3050,3051,3052,3053,3054,3055,3056,3057,3058,3059,3060,3061,3062,3063,3064,3065,3066,3067,3068,3069,3070,4001,4002,4003,4004,4005,4006,4007,4008,4009,4010,4011,4012,4013,4014,4015,4016,4017,4018,4019,4020,4021,4022,4023,4024,4025,4026,4027,4028,4030,4031,4032,4033,4035,4036,4037,4038,4039,4040,4041,4042,4043,4044,4045,4046,4047,4048,4049,4050,4051,4052,4053,4054,4055,4056,4057,4058,4059,4060,4061,4062,4063,4064,4065,4066,4068,4069,4070,4071,4072,4073,4074,4075,4076,4077,4078,4079,4080,4081,4082,4083,4084,4085,4086,4087,4088,4089,4090,4091,4092,4093,4094,4095,4096,4097,4098,4099,4100,4101,4102,4103,4104,4105,4106,4107,4108,4109,4110,4111,4112,4113,4114,4115,4116,4118,4119,4120,4121,4122,4123,4124,4501,4502,4503,4504,4505,4506,4507,4508,4509,4510,4511,4512,4513,4514,4515,4516,4517,4518,4519,4520,4521,4522,4523,4524,4525,4526,]"
// Vector of all race IDs in order for easy iterating.
pub val all = once(create-id-table)
val name2id = once()
var m: rbmap<string, int> := empty()
all().foreach() fn(id) m := m.set(Race-id(id).show, id)
m
// Get the race ID that has the given exact name.
// Alternate versions of races have an indication of their ID in their names.
// If no race matches the name, the result is an invalid ID.
pub fun from-name(name: string): race-id
Race-id(name2id().rb-map/lookup(name).default(0))
// Get the name for a race.
// Alternate versions of races have an indication of their ID in their names.
// If no race matches the ID, the result is the numeric ID.
pub fun show(r: race-id): string
match r.game-id
1001 -> "February Stakes"
1002 -> "Takamatsunomiya Kinen"
1003 -> "Osaka Hai"
1004 -> "Oka Sho"
1005 -> "Satsuki Sho"
1006 -> "Tenno Sho (Spring)"
1007 -> "NHK Mile Cup"
1008 -> "Victoria Mile"
1009 -> "Japanese Oaks"
1010 -> "Tokyo Yushun (Japanese Derby)"
1011 -> "Yasuda Kinen"
1012 -> "Takarazuka Kinen"
1013 -> "Sprinters Stakes"
1014 -> "Shuka Sho"
1015 -> "Kikuka Sho"
1016 -> "Tenno Sho (Autumn)"
1017 -> "Queen Elizabeth II Cup"
1018 -> "Mile Championship"
1019 -> "Japan Cup"
1020 -> "Champions Cup"
1021 -> "Hanshin Juvenile Fillies"
1022 -> "Asahi Hai Futurity Stakes"
1023 -> "Arima Kinen"
1024 -> "Hopeful Stakes"
1025 -> "Takarazuka Kinen" ++ " (Alternate 1025)"
1026 -> "Kikuka Sho" ++ " (Alternate 1026)"
1027 -> "Tenno Sho (Spring)" ++ " (Alternate 1027)"
1028 -> "Satsuki Sho" ++ " (Alternate 1028)"
1101 -> "Teio Sho"
1102 -> "Japan Dirt Derby"
1103 -> "JBC Ladies Classic"
1104 -> "JBC Sprint"
1105 -> "JBC Classic"
1106 -> "Tokyo Daishoten"
2001 -> "Nikkei Shinshun Hai"
2002 -> "Tokai Stakes"
2003 -> "American JCC"
2004 -> "Kyoto Kinen"
2005 -> "Nakayama Kinen"
2006 -> "Yayoi Sho"
2007 -> "Kinko Sho"
2008 -> "Fillies' Revue"
2009 -> "Hanshin Daishoten"
2010 -> "Spring Stakes"
2011 -> "Nikkei Sho"
2012 -> "Hanshin Umamusume Stakes"
2013 -> "New Zealand Trophy"
2014 -> "Milers Cup"
2015 -> "Flora Stakes"
2016 -> "Aoba Sho"
2017 -> "Kyoto Shimbun Hai"
2018 -> "Keio Hai Spring Cup"
2019 -> "Meguro Kinen"
2020 -> "Sapporo Kinen"
2021 -> "Centaur Stakes"
2022 -> "Rose Stakes"
2023 -> "St. Lite Kinen"
2024 -> "Kobe Shimbun Hai"
2025 -> "All Comers"
2026 -> "Mainichi Okan"
2027 -> "Kyoto Daishoten"
2028 -> "Fuchu Umamusume Stakes"
2029 -> "Swan Stakes"
2030 -> "Keio Hai Junior Stakes"
2031 -> "Copa Republica Argentina"
2032 -> "Daily Hai Junior Stakes"
2033 -> "Stayers Stakes"
2034 -> "Hanshin Cup"
2035 -> "Spring Stakes" ++ " (Alternate 2035)"
3001 -> "Kyoto Kimpai"
3002 -> "Nakayama Kimpai"
3003 -> "Shinzan Kinen"
3004 -> "Fairy Stakes"
3005 -> "Aichi Hai"
3006 -> "Keisei Hai"
3007 -> "Silk Road Stakes"
3008 -> "Negishi Stakes"
3009 -> "Kisaragi Sho"
3010 -> "Tokyo Shimbun Hai"
3011 -> "Queen Cup"
3012 -> "Kyodo News Hai"
3013 -> "Kyoto Umamusume Stakes"
3014 -> "Diamond Stakes"
3015 -> "Kokura Daishoten"
3016 -> "Arlington Cup"
3017 -> "Hankyu Hai"
3018 -> "Tulip Sho"
3019 -> "Ocean Stakes"
3020 -> "Nakayama Umamusume Stakes"
3021 -> "Falcon Stakes"
3022 -> "Flower Cup"
3023 -> "Mainichi Hai"
3024 -> "March Stakes"
3025 -> "Lord Derby Challenge Trophy"
3026 -> "Antares Stakes"
3027 -> "Fukushima Umamusume Stakes"
3028 -> "Niigata Daishoten"
3029 -> "Heian Stakes"
3030 -> "Naruo Kinen"
3031 -> "Mermaid Stakes"
3032 -> "Epsom Cup"
3033 -> "Unicorn Stakes"
3034 -> "Hakodate Sprint Stakes"
3035 -> "CBC Sho"
3036 -> "Radio Nikkei Sho"
3037 -> "Procyon Stakes"
3038 -> "Tanabata Sho"
3039 -> "Hakodate Kinen"
3040 -> "Chukyo Kinen"
3041 -> "Hakodate Junior Stakes"
3042 -> "Ibis Summer Dash"
3043 -> "Queen Stakes"
3044 -> "Kokura Kinen"
3045 -> "Leopard Stakes"
3046 -> "Sekiya Kinen"
3047 -> "Elm Stakes"
3048 -> "Kitakyushu Kinen"
3049 -> "Niigata Junior Stakes"
3050 -> "Keeneland Cup"
3051 -> "Sapporo Junior Stakes"
3052 -> "Kokura Junior Stakes"
3053 -> "Niigata Kinen"
3054 -> "Shion Stakes"
3055 -> "Keisei Hai Autumn Handicap"
3056 -> "Sirius Stakes"
3057 -> "Saudi Arabia Royal Cup"
3058 -> "Fuji Stakes"
3059 -> "Artemis Stakes"
3060 -> "Fantasy Stakes"
3061 -> "Miyako Stakes"
3062 -> "Musashino Stakes"
3063 -> "Fukushima Kinen"
3064 -> "Tokyo Sports Hai Junior Stakes"
3065 -> "Kyoto Junior Stakes"
3066 -> "Keihan Hai"
3067 -> "Challenge Cup"
3068 -> "Chunichi Shimbun Hai"
3069 -> "Capella Stakes"
3070 -> "Turquoise Stakes"
4001 -> "Manyo Stakes"
4002 -> "Junior Cup"
4003 -> "Yodo Tankyori Stakes"
4004 -> "Pollux Stakes"
4005 -> "January Stakes"
4006 -> "New Year Stakes"
4007 -> "Kobai Stakes"
4008 -> "Subaru Stakes"
4009 -> "Wakagoma Stakes"
4010 -> "Carbuncle Stakes"
4011 -> "Shirafuji Stakes"
4012 -> "Crocus Stakes"
4013 -> "Yamato Stakes"
4014 -> "Elfin Stakes"
4015 -> "Rakuyo Stakes"
4016 -> "Aldebaran Stakes"
4017 -> "Valentine Stakes"
4018 -> "Hyacinth Stakes"
4019 -> "Sobu Stakes"
4020 -> "Sumire Stakes"
4021 -> "Osakajo Stakes"
4022 -> "Polaris Stakes"
4023 -> "Nigawa Stakes"
4024 -> "Anemone Stakes"
4025 -> "Shoryu Stakes"
4026 -> "Kochi Stakes"
4027 -> "Wakaba Stakes"
4028 -> "Chiba Stakes"
4030 -> "Rokko Stakes"
4031 -> "Coral Stakes"
4032 -> "Marguerite Stakes"
4033 -> "Fukuryu Stakes"
4035 -> "Wasurenagusa Sho"
4036 -> "Keiyo Stakes"
4037 -> "Shunrai Stakes"
4038 -> "Fukushima Mimpo Hai"
4039 -> "Tachibana Stakes"
4040 -> "Oasis Stakes"
4041 -> "Tennozan Stakes"
4042 -> "Tango Stakes"
4043 -> "Sweetpea Stakes"
4044 -> "Tanigawadake Stakes"
4045 -> "Principal Stakes"
4046 -> "Metropolitan Stakes"
4047 -> "Kurama Stakes"
4048 -> "Brilliant Stakes"
4049 -> "Miyakooji Stakes"
4050 -> "Aoi Stakes"
4051 -> "Ritto Stakes"
4052 -> "Seiryu Stakes"
4053 -> "May Stakes"
4054 -> "Hosu Stakes"
4055 -> "Idaten Stakes"
4056 -> "Shirayuri Stakes"
4057 -> "Keyaki Stakes"
4058 -> "Azuchijo Stakes"
4059 -> "Akhalteke Stakes"
4060 -> "Tempozan Stakes"
4061 -> "Yonago Stakes"
4062 -> "Onuma Stakes"
4063 -> "Paradise Stakes"
4064 -> "Tomoe Sho"
4065 -> "Marine Stakes"
4066 -> "Meitetsu Hai"
4068 -> "Chukyo Junior Stakes"
4069 -> "Fukushima TV Open"
4070 -> "Dahlia Sho"
4071 -> "Sapporo Nikkei Open"
4072 -> "UHB Sho"
4073 -> "Aso Stakes"
4074 -> "Phoenix Sho"
4075 -> "Cosmos Sho"
4076 -> "NST Sho"
4077 -> "Clover Sho"
4078 -> "Himawari Sho"
4079 -> "BSN Sho"
4080 -> "Kokura Nikkei Open"
4081 -> "Toki Stakes"
4082 -> "Tancho Stakes"
4083 -> "Suzuran Sho"
4084 -> "Enif Stakes"
4085 -> "Nojigiku Stakes"
4086 -> "Radio Nippon Sho"
4087 -> "Kikyo Stakes"
4088 -> "Fuyo Stakes"
4089 -> "Canna Stakes"
4090 -> "Port Island Stakes"
4091 -> "Opal Stakes"
4092 -> "Green Channel Cup"
4093 -> "Momiji Stakes"
4094 -> "October Stakes"
4095 -> "Shinetsu Stakes"
4096 -> "Ivy Stakes"
4097 -> "Muromachi Stakes"
4098 -> "Brazil Cup"
4099 -> "Hagi Stakes"
4100 -> "Cassiopeia Stakes"
4101 -> "Lumiere Autumn Dash"
4102 -> "Oro Cup"
4103 -> "Fukushima Junior Stakes"
4104 -> "Andromeda Stakes"
4105 -> "Shimotsuki Stakes"
4106 -> "Fukushima Minyu Cup"
4107 -> "Capital Stakes"
4108 -> "Autumn Leaf Stakes"
4109 -> "Lapis Lazuli Stakes"
4110 -> "Shiwasu Stakes"
4111 -> "Rigel Stakes"
4112 -> "Tanzanite Stakes"
4113 -> "December Stakes"
4114 -> "Christmas Rose Stakes"
4115 -> "Galaxy Stakes"
4116 -> "Betelgeuse Stakes"
4118 -> "Kitakyushu Tankyori Stakes"
4119 -> "Azumakofuji Stakes"
4120 -> "Sleipnir Stakes"
4121 -> "Sannomiya Stakes"
4122 -> "Kanetsu Stakes"
4123 -> "Nagatsuki Stakes"
4124 -> "Uzumasa Stakes"
4501 -> "Aster Sho"
4502 -> "Saffron Sho"
4503 -> "Rindo Sho"
4504 -> "Shigiku Sho"
4505 -> "Platanus Sho"
4506 -> "Nadeshiko Sho"
4507 -> "Hyakunichiso Tokubetsu"
4508 -> "Kimmokusei Tokubetsu"
4509 -> "Oxalis Sho"
4510 -> "Kigiku Sho"
4511 -> "Mochinoki Sho"
4512 -> "Akamatsu Sho"
4513 -> "Shumeigiku Sho"
4514 -> "Cattleya Sho"
4515 -> "Begonia Sho"
4516 -> "Shiragiku Sho"
4517 -> "Habotan Sho"
4518 -> "Koyamaki Sho"
4519 -> "Manryo Sho"
4520 -> "Kuromatsu Sho"
4521 -> "Erica Sho"
4522 -> "Tsuwabuki Sho"
4523 -> "Hiiragi Sho"
4524 -> "Sazanka Sho"
4525 -> "Kantsubaki Sho"
4526 -> "Senryo Sho"
x -> "race " ++ x.show
// Get the grade for a race.
// If no race matches the ID, the result is Pre-OP.
pub fun grade(r: race-id): grade
match r.game-id
1001 -> G1
1002 -> G1
1003 -> G1
1004 -> G1
1005 -> G1
1006 -> G1
1007 -> G1
1008 -> G1
1009 -> G1
1010 -> G1
1011 -> G1
1012 -> G1
1013 -> G1
1014 -> G1
1015 -> G1
1016 -> G1
1017 -> G1
1018 -> G1
1019 -> G1
1020 -> G1
1021 -> G1
1022 -> G1
1023 -> G1
1024 -> G1
1025 -> G1
1026 -> G1
1027 -> G1
1028 -> G1
1101 -> G1
1102 -> G1
1103 -> G1
1104 -> G1
1105 -> G1
1106 -> G1
2001 -> G2
2002 -> G2
2003 -> G2
2004 -> G2
2005 -> G2
2006 -> G2
2007 -> G2
2008 -> G2
2009 -> G2
2010 -> G2
2011 -> G2
2012 -> G2
2013 -> G2
2014 -> G2
2015 -> G2
2016 -> G2
2017 -> G2
2018 -> G2
2019 -> G2
2020 -> G2
2021 -> G2
2022 -> G2
2023 -> G2
2024 -> G2
2025 -> G2
2026 -> G2
2027 -> G2
2028 -> G2
2029 -> G2
2030 -> G2
2031 -> G2
2032 -> G2
2033 -> G2
2034 -> G2
2035 -> G2
3001 -> G3
3002 -> G3
3003 -> G3
3004 -> G3
3005 -> G3
3006 -> G3
3007 -> G3
3008 -> G3
3009 -> G3
3010 -> G3
3011 -> G3
3012 -> G3
3013 -> G3
3014 -> G3
3015 -> G3
3016 -> G3
3017 -> G3
3018 -> G2
3019 -> G3
3020 -> G3
3021 -> G3
3022 -> G3
3023 -> G3
3024 -> G3
3025 -> G3
3026 -> G3
3027 -> G3
3028 -> G3
3029 -> G3
3030 -> G3
3031 -> G3
3032 -> G3
3033 -> G3
3034 -> G3
3035 -> G3
3036 -> G3
3037 -> G3
3038 -> G3
3039 -> G3
3040 -> G3
3041 -> G3
3042 -> G3
3043 -> G3
3044 -> G3
3045 -> G3
3046 -> G3
3047 -> G3
3048 -> G3
3049 -> G3
3050 -> G3
3051 -> G3
3052 -> G3
3053 -> G3
3054 -> G3
3055 -> G3
3056 -> G3
3057 -> G3
3058 -> G2
3059 -> G3
3060 -> G3
3061 -> G3
3062 -> G3
3063 -> G3
3064 -> G3
3065 -> G3
3066 -> G3
3067 -> G3
3068 -> G3
3069 -> G3
3070 -> G3
4001 -> OP
4002 -> OP
4003 -> OP
4004 -> OP
4005 -> OP
4006 -> OP
4007 -> OP
4008 -> OP
4009 -> OP
4010 -> OP
4011 -> OP
4012 -> OP
4013 -> OP
4014 -> OP
4015 -> OP
4016 -> OP
4017 -> OP
4018 -> OP
4019 -> OP
4020 -> OP
4021 -> OP
4022 -> OP
4023 -> OP
4024 -> OP
4025 -> OP
4026 -> OP
4027 -> OP
4028 -> OP
4030 -> OP
4031 -> OP
4032 -> OP
4033 -> OP
4035 -> OP
4036 -> OP
4037 -> OP
4038 -> OP
4039 -> OP
4040 -> OP
4041 -> OP
4042 -> OP
4043 -> OP
4044 -> OP
4045 -> OP
4046 -> OP
4047 -> OP
4048 -> OP
4049 -> OP
4050 -> G3
4051 -> OP
4052 -> OP
4053 -> OP
4054 -> OP
4055 -> OP
4056 -> OP
4057 -> OP
4058 -> OP
4059 -> OP
4060 -> OP
4061 -> OP
4062 -> OP
4063 -> OP
4064 -> OP
4065 -> OP
4066 -> OP
4068 -> OP
4069 -> OP
4070 -> OP
4071 -> OP
4072 -> OP
4073 -> OP
4074 -> OP
4075 -> OP
4076 -> OP
4077 -> OP
4078 -> OP
4079 -> OP
4080 -> OP
4081 -> OP
4082 -> OP
4083 -> OP
4084 -> OP
4085 -> OP
4086 -> OP
4087 -> OP
4088 -> OP
4089 -> OP
4090 -> OP
4091 -> OP
4092 -> OP
4093 -> OP
4094 -> OP
4095 -> OP
4096 -> OP
4097 -> OP
4098 -> OP
4099 -> OP
4100 -> OP
4101 -> OP
4102 -> OP
4103 -> OP
4104 -> OP
4105 -> OP
4106 -> OP
4107 -> OP
4108 -> OP
4109 -> OP
4110 -> OP
4111 -> OP
4112 -> OP
4113 -> OP
4114 -> OP
4115 -> OP
4116 -> OP
4118 -> OP
4119 -> OP
4120 -> OP
4121 -> OP
4122 -> OP
4123 -> OP
4124 -> OP
4501 -> Pre-OP
4502 -> Pre-OP
4503 -> Pre-OP
4504 -> Pre-OP
4505 -> Pre-OP
4506 -> Pre-OP
4507 -> Pre-OP
4508 -> Pre-OP
4509 -> Pre-OP
4510 -> Pre-OP
4511 -> Pre-OP
4512 -> Pre-OP
4513 -> Pre-OP
4514 -> Pre-OP
4515 -> Pre-OP
4516 -> Pre-OP
4517 -> Pre-OP
4518 -> Pre-OP
4519 -> Pre-OP
4520 -> Pre-OP
4521 -> Pre-OP
4522 -> Pre-OP
4523 -> Pre-OP
4524 -> Pre-OP
4525 -> Pre-OP
4526 -> Pre-OP
_ -> Pre-OP
// Get the thumbnail ID for a race.
// If no race matches the ID, the result is an invalid ID.
pub fun thumbnail(r: race-id): race-thumbnail-id
match r.game-id
1001 -> Race-thumbnail-id(1001)
1002 -> Race-thumbnail-id(1002)
1003 -> Race-thumbnail-id(1003)
1004 -> Race-thumbnail-id(1004)
1005 -> Race-thumbnail-id(1005)
1006 -> Race-thumbnail-id(1006)
1007 -> Race-thumbnail-id(1007)
1008 -> Race-thumbnail-id(1008)
1009 -> Race-thumbnail-id(1009)
1010 -> Race-thumbnail-id(1010)
1011 -> Race-thumbnail-id(1011)
1012 -> Race-thumbnail-id(1012)
1013 -> Race-thumbnail-id(1013)
1014 -> Race-thumbnail-id(1014)
1015 -> Race-thumbnail-id(1015)
1016 -> Race-thumbnail-id(1016)
1017 -> Race-thumbnail-id(1017)
1018 -> Race-thumbnail-id(1018)
1019 -> Race-thumbnail-id(1019)
1020 -> Race-thumbnail-id(1020)
1021 -> Race-thumbnail-id(1021)
1022 -> Race-thumbnail-id(1022)
1023 -> Race-thumbnail-id(1023)
1024 -> Race-thumbnail-id(1024)
1025 -> Race-thumbnail-id(1012)
1026 -> Race-thumbnail-id(1015)
1027 -> Race-thumbnail-id(1027)
1028 -> Race-thumbnail-id(1028)
1101 -> Race-thumbnail-id(1101)
1102 -> Race-thumbnail-id(1102)
1103 -> Race-thumbnail-id(1103)
1104 -> Race-thumbnail-id(1104)
1105 -> Race-thumbnail-id(1105)
1106 -> Race-thumbnail-id(1106)
2001 -> Race-thumbnail-id(2001)
2002 -> Race-thumbnail-id(2002)
2003 -> Race-thumbnail-id(2003)
2004 -> Race-thumbnail-id(2004)
2005 -> Race-thumbnail-id(2005)
2006 -> Race-thumbnail-id(2006)
2007 -> Race-thumbnail-id(2007)
2008 -> Race-thumbnail-id(2008)
2009 -> Race-thumbnail-id(2009)
2010 -> Race-thumbnail-id(2010)
2011 -> Race-thumbnail-id(2011)
2012 -> Race-thumbnail-id(2012)
2013 -> Race-thumbnail-id(2013)
2014 -> Race-thumbnail-id(2014)
2015 -> Race-thumbnail-id(2015)
2016 -> Race-thumbnail-id(2016)
2017 -> Race-thumbnail-id(2017)
2018 -> Race-thumbnail-id(2018)
2019 -> Race-thumbnail-id(2019)
2020 -> Race-thumbnail-id(2020)
2021 -> Race-thumbnail-id(2021)
2022 -> Race-thumbnail-id(2022)
2023 -> Race-thumbnail-id(2023)
2024 -> Race-thumbnail-id(2024)
2025 -> Race-thumbnail-id(2025)
2026 -> Race-thumbnail-id(2026)
2027 -> Race-thumbnail-id(2027)
2028 -> Race-thumbnail-id(2028)
2029 -> Race-thumbnail-id(2029)
2030 -> Race-thumbnail-id(2030)
2031 -> Race-thumbnail-id(2031)
2032 -> Race-thumbnail-id(2032)
2033 -> Race-thumbnail-id(2033)
2034 -> Race-thumbnail-id(2034)
2035 -> Race-thumbnail-id(2010)
3001 -> Race-thumbnail-id(3001)
3002 -> Race-thumbnail-id(3002)
3003 -> Race-thumbnail-id(3003)
3004 -> Race-thumbnail-id(3004)
3005 -> Race-thumbnail-id(3005)
3006 -> Race-thumbnail-id(3006)
3007 -> Race-thumbnail-id(3007)
3008 -> Race-thumbnail-id(3008)
3009 -> Race-thumbnail-id(3009)
3010 -> Race-thumbnail-id(3010)
3011 -> Race-thumbnail-id(3011)
3012 -> Race-thumbnail-id(3012)
3013 -> Race-thumbnail-id(3013)
3014 -> Race-thumbnail-id(3014)
3015 -> Race-thumbnail-id(3015)
3016 -> Race-thumbnail-id(3016)
3017 -> Race-thumbnail-id(3017)
3018 -> Race-thumbnail-id(3018)
3019 -> Race-thumbnail-id(3019)
3020 -> Race-thumbnail-id(3020)
3021 -> Race-thumbnail-id(3021)
3022 -> Race-thumbnail-id(3022)
3023 -> Race-thumbnail-id(3023)
3024 -> Race-thumbnail-id(3024)
3025 -> Race-thumbnail-id(3025)
3026 -> Race-thumbnail-id(3026)
3027 -> Race-thumbnail-id(3027)
3028 -> Race-thumbnail-id(3028)
3029 -> Race-thumbnail-id(3029)
3030 -> Race-thumbnail-id(3030)
3031 -> Race-thumbnail-id(3031)
3032 -> Race-thumbnail-id(3032)
3033 -> Race-thumbnail-id(3033)
3034 -> Race-thumbnail-id(3034)
3035 -> Race-thumbnail-id(3035)
3036 -> Race-thumbnail-id(3036)
3037 -> Race-thumbnail-id(3037)
3038 -> Race-thumbnail-id(3038)
3039 -> Race-thumbnail-id(3039)
3040 -> Race-thumbnail-id(3040)
3041 -> Race-thumbnail-id(3041)
3042 -> Race-thumbnail-id(3042)
3043 -> Race-thumbnail-id(3043)
3044 -> Race-thumbnail-id(3044)
3045 -> Race-thumbnail-id(3045)
3046 -> Race-thumbnail-id(3046)
3047 -> Race-thumbnail-id(3047)
3048 -> Race-thumbnail-id(3048)
3049 -> Race-thumbnail-id(3049)
3050 -> Race-thumbnail-id(3050)
3051 -> Race-thumbnail-id(3051)
3052 -> Race-thumbnail-id(3052)
3053 -> Race-thumbnail-id(3053)
3054 -> Race-thumbnail-id(3054)
3055 -> Race-thumbnail-id(3055)
3056 -> Race-thumbnail-id(3056)
3057 -> Race-thumbnail-id(3057)
3058 -> Race-thumbnail-id(3058)
3059 -> Race-thumbnail-id(3059)
3060 -> Race-thumbnail-id(3060)
3061 -> Race-thumbnail-id(3061)
3062 -> Race-thumbnail-id(3062)
3063 -> Race-thumbnail-id(3063)
3064 -> Race-thumbnail-id(3064)
3065 -> Race-thumbnail-id(3065)
3066 -> Race-thumbnail-id(3066)
3067 -> Race-thumbnail-id(3067)
3068 -> Race-thumbnail-id(3068)
3069 -> Race-thumbnail-id(3069)
3070 -> Race-thumbnail-id(3070)
4001 -> Race-thumbnail-id(4001)
4002 -> Race-thumbnail-id(4002)
4003 -> Race-thumbnail-id(4003)
4004 -> Race-thumbnail-id(4004)
4005 -> Race-thumbnail-id(4005)
4006 -> Race-thumbnail-id(4006)
4007 -> Race-thumbnail-id(4007)
4008 -> Race-thumbnail-id(4008)
4009 -> Race-thumbnail-id(4009)
4010 -> Race-thumbnail-id(4010)
4011 -> Race-thumbnail-id(4011)
4012 -> Race-thumbnail-id(4012)
4013 -> Race-thumbnail-id(4013)
4014 -> Race-thumbnail-id(4014)
4015 -> Race-thumbnail-id(4015)
4016 -> Race-thumbnail-id(4016)
4017 -> Race-thumbnail-id(4017)
4018 -> Race-thumbnail-id(4018)
4019 -> Race-thumbnail-id(4019)
4020 -> Race-thumbnail-id(4020)
4021 -> Race-thumbnail-id(4021)
4022 -> Race-thumbnail-id(4022)
4023 -> Race-thumbnail-id(4023)
4024 -> Race-thumbnail-id(4024)
4025 -> Race-thumbnail-id(4025)
4026 -> Race-thumbnail-id(4026)
4027 -> Race-thumbnail-id(4027)
4028 -> Race-thumbnail-id(4028)
4030 -> Race-thumbnail-id(4030)
4031 -> Race-thumbnail-id(4031)
4032 -> Race-thumbnail-id(4032)
4033 -> Race-thumbnail-id(4033)
4035 -> Race-thumbnail-id(4035)
4036 -> Race-thumbnail-id(4036)
4037 -> Race-thumbnail-id(4037)
4038 -> Race-thumbnail-id(4038)
4039 -> Race-thumbnail-id(4039)
4040 -> Race-thumbnail-id(4040)
4041 -> Race-thumbnail-id(4041)
4042 -> Race-thumbnail-id(4042)
4043 -> Race-thumbnail-id(4043)
4044 -> Race-thumbnail-id(4044)
4045 -> Race-thumbnail-id(4045)
4046 -> Race-thumbnail-id(4046)
4047 -> Race-thumbnail-id(4047)
4048 -> Race-thumbnail-id(4048)
4049 -> Race-thumbnail-id(4049)
4050 -> Race-thumbnail-id(4050)
4051 -> Race-thumbnail-id(4051)
4052 -> Race-thumbnail-id(4052)
4053 -> Race-thumbnail-id(4053)
4054 -> Race-thumbnail-id(4054)
4055 -> Race-thumbnail-id(4055)
4056 -> Race-thumbnail-id(4056)
4057 -> Race-thumbnail-id(4057)
4058 -> Race-thumbnail-id(4058)
4059 -> Race-thumbnail-id(4059)
4060 -> Race-thumbnail-id(4060)
4061 -> Race-thumbnail-id(4061)
4062 -> Race-thumbnail-id(4062)
4063 -> Race-thumbnail-id(4063)
4064 -> Race-thumbnail-id(4064)
4065 -> Race-thumbnail-id(4065)
4066 -> Race-thumbnail-id(4066)
4068 -> Race-thumbnail-id(4068)
4069 -> Race-thumbnail-id(4069)
4070 -> Race-thumbnail-id(4070)
4071 -> Race-thumbnail-id(4071)
4072 -> Race-thumbnail-id(4072)
4073 -> Race-thumbnail-id(4073)
4074 -> Race-thumbnail-id(4074)
4075 -> Race-thumbnail-id(4075)
4076 -> Race-thumbnail-id(4076)
4077 -> Race-thumbnail-id(4077)
4078 -> Race-thumbnail-id(4078)
4079 -> Race-thumbnail-id(4079)
4080 -> Race-thumbnail-id(4080)
4081 -> Race-thumbnail-id(4081)
4082 -> Race-thumbnail-id(4082)
4083 -> Race-thumbnail-id(4083)
4084 -> Race-thumbnail-id(4084)
4085 -> Race-thumbnail-id(4085)
4086 -> Race-thumbnail-id(4086)
4087 -> Race-thumbnail-id(4087)
4088 -> Race-thumbnail-id(4088)
4089 -> Race-thumbnail-id(4089)
4090 -> Race-thumbnail-id(4090)
4091 -> Race-thumbnail-id(4091)
4092 -> Race-thumbnail-id(4092)
4093 -> Race-thumbnail-id(4093)
4094 -> Race-thumbnail-id(4094)
4095 -> Race-thumbnail-id(4095)
4096 -> Race-thumbnail-id(4096)
4097 -> Race-thumbnail-id(4097)
4098 -> Race-thumbnail-id(4098)
4099 -> Race-thumbnail-id(4099)
4100 -> Race-thumbnail-id(4100)
4101 -> Race-thumbnail-id(4101)
4102 -> Race-thumbnail-id(4102)
4103 -> Race-thumbnail-id(4103)
4104 -> Race-thumbnail-id(4104)
4105 -> Race-thumbnail-id(4105)
4106 -> Race-thumbnail-id(4106)
4107 -> Race-thumbnail-id(4107)
4108 -> Race-thumbnail-id(4108)
4109 -> Race-thumbnail-id(4109)
4110 -> Race-thumbnail-id(4110)
4111 -> Race-thumbnail-id(4111)
4112 -> Race-thumbnail-id(4112)
4113 -> Race-thumbnail-id(4113)
4114 -> Race-thumbnail-id(4114)
4115 -> Race-thumbnail-id(4115)
4116 -> Race-thumbnail-id(4116)
4118 -> Race-thumbnail-id(4117)
4119 -> Race-thumbnail-id(4118)
4120 -> Race-thumbnail-id(4119)
4121 -> Race-thumbnail-id(4120)
4122 -> Race-thumbnail-id(4121)
4123 -> Race-thumbnail-id(4122)
4124 -> Race-thumbnail-id(4123)
4501 -> Race-thumbnail-id(4501)
4502 -> Race-thumbnail-id(4502)
4503 -> Race-thumbnail-id(4503)
4504 -> Race-thumbnail-id(4504)
4505 -> Race-thumbnail-id(4505)
4506 -> Race-thumbnail-id(4506)
4507 -> Race-thumbnail-id(4507)
4508 -> Race-thumbnail-id(4508)
4509 -> Race-thumbnail-id(4509)
4510 -> Race-thumbnail-id(4510)
4511 -> Race-thumbnail-id(4511)
4512 -> Race-thumbnail-id(4512)
4513 -> Race-thumbnail-id(4513)
4514 -> Race-thumbnail-id(4514)
4515 -> Race-thumbnail-id(4515)
4516 -> Race-thumbnail-id(4516)
4517 -> Race-thumbnail-id(4517)
4518 -> Race-thumbnail-id(4518)
4519 -> Race-thumbnail-id(4519)
4520 -> Race-thumbnail-id(4520)
4521 -> Race-thumbnail-id(4521)
4522 -> Race-thumbnail-id(4522)
4523 -> Race-thumbnail-id(4523)
4524 -> Race-thumbnail-id(4524)
4525 -> Race-thumbnail-id(4525)
4526 -> Race-thumbnail-id(4526)
_ -> Race-thumbnail-id(0)
// Get the primary ID for a race.
// For races which are the primary version, or if no race matches the given ID,
// the result is the input.
pub fun primary(r: race-id): race-id
match r.game-id
1025 -> Race-id(1012)
1026 -> Race-id(1015)
1027 -> Race-id(1006)
1028 -> Race-id(1005)
2035 -> Race-id(2010)
_ -> r
File diff suppressed because it is too large Load Diff
-518
View File
@@ -1,518 +0,0 @@
module horse/global/saddle
// Automatically generated with horsegen; DO NOT EDIT
import std/core/delayed
import std/core/vector
import std/core-extras
import horse/game-id
pub import horse/race
pub import horse/global/race
extern create-id-table(): vector<int>
c inline "int32_t arr[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,};\nkk_vector_from_cint32array(arr, (kk_ssize_t)155, kk_context())"
js inline "[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,]"
// Vector of all saddle IDs in order for easy iterating.
pub val all = once(create-id-table)
// Get the name for a saddle.
// Alternate versions of saddles have an indication of their ID in their names.
// If no saddle matches the ID, the result contains the numeric ID.
pub fun show(s: saddle-id): string
match s.game-id
1 -> "Classic Triple Crown"
2 -> "Senior Autumn Triple Crown"
3 -> "Triple Tiara"
4 -> "Senior Spring Triple Crown"
5 -> "Tenno Sweep"
6 -> "Dual Grand Prix"
7 -> "Dual Miles"
8 -> "Dual Sprints"
9 -> "Dual Dirts"
10 -> "Arima Kinen"
11 -> "Japan C."
12 -> "Japanese Derby"
13 -> "Tenno Sho (Spring)"
14 -> "Takarazuka Kinen"
15 -> "Tenno Sho (Autumn)"
16 -> "Kikuka Sho"
17 -> "Osaka Hai"
18 -> "Satsuki Sho"
19 -> "Japanese Oaks"
20 -> "Takamatsunomiya Kinen"
21 -> "Yasuda Kinen"
22 -> "Sprinters S."
23 -> "Mile Ch."
24 -> "Oka Sho"
25 -> "Victoria Mile"
26 -> "Queen Elizabeth II Cup"
27 -> "NHK Mile C."
28 -> "Shuka Sho"
29 -> "Champions C."
30 -> "February S."
31 -> "JBC Classic"
32 -> "Tokyo Daishoten"
33 -> "Asahi Hai F.S."
34 -> "Hopeful S."
35 -> "Hanshin J.F."
36 -> "Teio Sho"
37 -> "JBC Sprint"
38 -> "J.D. Derby"
39 -> "JBC L. Classic"
40 -> "Nikkei Shinshun Hai"
41 -> "Tokai S."
42 -> "American JCC"
43 -> "Kyoto Kinen"
44 -> "Nakayama Kinen"
45 -> "Yayoi Sho"
46 -> "Kinko Sho"
47 -> "Fillies' Revue"
48 -> "Hanshin Daishoten"
49 -> "Spring S."
50 -> "Nikkei Sho"
51 -> "Hanshin Umamusume S."
52 -> "New Zealand T."
53 -> "Yomiuri Milers C."
54 -> "Flora S."
55 -> "Aoba Sho"
56 -> "Kyoto Shimbun Hai"
57 -> "Keio Hai Spring C."
58 -> "Meguro Kinen"
59 -> "Sapporo Kinen"
60 -> "Centaur S."
61 -> "Rose S."
62 -> "St. Lite Kinen"
63 -> "Kobe Shimbun Hai"
64 -> "All Comers"
65 -> "Mainichi Okan"
66 -> "Kyoto Daishoten"
67 -> "Fuchu Umamusume S."
68 -> "Swan S."
69 -> "Keio Hai Junior S."
70 -> "Copa Republica Argentina"
71 -> "Daily Hai Junior S."
72 -> "Stayers S."
73 -> "Hanshin C."
74 -> "Kyoto Kimpai"
75 -> "Nakayama Kimpai"
76 -> "Shinzan Kinen"
77 -> "Fairy S."
78 -> "Aichi Hai"
79 -> "Keisei Hai"
80 -> "Silk Road S."
81 -> "Negishi S."
82 -> "Kisaragi Sho"
83 -> "Tokyo Shimbun Hai"
84 -> "Queen C."
85 -> "Kyodo News Hai"
86 -> "Kyoto Umamusume S."
87 -> "Diamond S."
88 -> "Kokura Daishoten"
89 -> "Arlington C."
90 -> "Hankyu Hai"
91 -> "Tulip Sho"
92 -> "Ocean S."
93 -> "Nakayama Umamusume S."
94 -> "Falcon S."
95 -> "Flower C."
96 -> "Mainichi Hai"
97 -> "March S."
98 -> "Lord Derby C.T."
99 -> "Antares S."
100 -> "Fukushima Umamusume S."
101 -> "Niigata Daishoten"
102 -> "Heian S."
103 -> "Naruo Kinen"
104 -> "Mermaid S."
105 -> "Epsom C."
106 -> "Unicorn S."
107 -> "Hakodate Sprint S."
108 -> "CBC Sho"
109 -> "Radio Nikkei Sho"
110 -> "Procyon S."
111 -> "Tanabata Sho"
112 -> "Hakodate Kinen"
113 -> "Chukyo Kinen"
114 -> "Hakodate Junior S."
115 -> "Ibis Summer D."
116 -> "Queen S."
117 -> "Kokura Kinen"
118 -> "Leopard S."
119 -> "Sekiya Kinen"
120 -> "Elm S."
121 -> "Kitakyushu Kinen"
122 -> "Niigata Junior S."
123 -> "Keeneland C."
124 -> "Sapporo Junior S."
125 -> "Kokura Junior S."
126 -> "Niigata Kinen"
127 -> "Shion S."
128 -> "Keisei Hai A.H."
129 -> "Sirius S."
130 -> "Saudi Arabia R.C."
131 -> "Fuji S."
132 -> "Artemis S."
133 -> "Fantasy S."
134 -> "Miyako S."
135 -> "Musashino S."
136 -> "Fukushima Kinen"
137 -> "Tokyo Sports Hai Junior S."
138 -> "Kyoto Junior S."
139 -> "Keihan Hai"
140 -> "Challenge C."
141 -> "Chunichi Shimbun Hai"
142 -> "Capella S."
143 -> "Turquoise S."
144 -> "Classic Triple Crown" ++ " (Alternate 144)"
145 -> "Senior Spring Triple Crown" ++ " (Alternate 145)"
146 -> "Dual Grand Prix" ++ " (Alternate 146)"
147 -> "Takarazuka Kinen" ++ " (Alternate 147)"
148 -> "Kikuka Sho" ++ " (Alternate 148)"
149 -> "Spring S." ++ " (Alternate 149)"
150 -> "Aoi S."
151 -> "Senior Spring Triple Crown" ++ " (Alternate 151)"
152 -> "Tenno Sweep" ++ " (Alternate 152)"
153 -> "Tenno Sho (Spring)" ++ " (Alternate 153)"
154 -> "Classic Triple Crown" ++ " (Alternate 154)"
155 -> "Satsuki Sho" ++ " (Alternate 155)"
x -> "saddle " ++ x.show
// Get the list of races that entitle a horse to a saddle.
// If no saddle matches the ID, the result is the empty list.
pub fun races(s: saddle-id): list<race-id>
match s.game-id
1 -> [Race-id(100501), Race-id(101001), Race-id(101501), ]
2 -> [Race-id(101601), Race-id(101901), Race-id(102301), ]
3 -> [Race-id(100401), Race-id(100901), Race-id(101401), ]
4 -> [Race-id(100301), Race-id(100601), Race-id(101201), ]
5 -> [Race-id(100601), Race-id(101601), ]
6 -> [Race-id(101201), Race-id(102301), ]
7 -> [Race-id(101101), Race-id(101801), ]
8 -> [Race-id(101301), Race-id(100201), ]
9 -> [Race-id(100101), Race-id(102001), ]
10 -> [Race-id(102301), ]
11 -> [Race-id(101901), ]
12 -> [Race-id(101001), ]
13 -> [Race-id(100601), ]
14 -> [Race-id(101201), ]
15 -> [Race-id(101601), ]
16 -> [Race-id(101501), ]
17 -> [Race-id(100301), ]
18 -> [Race-id(100501), ]
19 -> [Race-id(100901), ]
20 -> [Race-id(100201), ]
21 -> [Race-id(101101), ]
22 -> [Race-id(101301), ]
23 -> [Race-id(101801), ]
24 -> [Race-id(100401), ]
25 -> [Race-id(100801), ]
26 -> [Race-id(101701), ]
27 -> [Race-id(100701), ]
28 -> [Race-id(101401), ]
29 -> [Race-id(102001), ]
30 -> [Race-id(100101), ]
31 -> [Race-id(110501), ]
32 -> [Race-id(110601), ]
33 -> [Race-id(102201), ]
34 -> [Race-id(102401), ]
35 -> [Race-id(102101), ]
36 -> [Race-id(110101), ]
37 -> [Race-id(110401), ]
38 -> [Race-id(110201), ]
39 -> [Race-id(110301), ]
40 -> [Race-id(200101), ]
41 -> [Race-id(200201), ]
42 -> [Race-id(200301), ]
43 -> [Race-id(200401), ]
44 -> [Race-id(200501), ]
45 -> [Race-id(200601), ]
46 -> [Race-id(200701), ]
47 -> [Race-id(200801), ]
48 -> [Race-id(200901), ]
49 -> [Race-id(201001), ]
50 -> [Race-id(201101), ]
51 -> [Race-id(201201), ]
52 -> [Race-id(201301), ]
53 -> [Race-id(201401), ]
54 -> [Race-id(201501), ]
55 -> [Race-id(201601), ]
56 -> [Race-id(201701), ]
57 -> [Race-id(201801), ]
58 -> [Race-id(201901), ]
59 -> [Race-id(202001), ]
60 -> [Race-id(202101), ]
61 -> [Race-id(202201), ]
62 -> [Race-id(202301), ]
63 -> [Race-id(202401), ]
64 -> [Race-id(202501), ]
65 -> [Race-id(202601), ]
66 -> [Race-id(202701), ]
67 -> [Race-id(202801), ]
68 -> [Race-id(202901), ]
69 -> [Race-id(203001), ]
70 -> [Race-id(203101), ]
71 -> [Race-id(203201), ]
72 -> [Race-id(203301), ]
73 -> [Race-id(203401), ]
74 -> [Race-id(300101), ]
75 -> [Race-id(300201), ]
76 -> [Race-id(300301), ]
77 -> [Race-id(300401), ]
78 -> [Race-id(300501), ]
79 -> [Race-id(300601), ]
80 -> [Race-id(300701), ]
81 -> [Race-id(300801), ]
82 -> [Race-id(300901), ]
83 -> [Race-id(301001), ]
84 -> [Race-id(301101), ]
85 -> [Race-id(301201), ]
86 -> [Race-id(301301), ]
87 -> [Race-id(301401), ]
88 -> [Race-id(301501), ]
89 -> [Race-id(301601), ]
90 -> [Race-id(301701), ]
91 -> [Race-id(301801), ]
92 -> [Race-id(301901), ]
93 -> [Race-id(302001), ]
94 -> [Race-id(302101), ]
95 -> [Race-id(302201), ]
96 -> [Race-id(302301), ]
97 -> [Race-id(302401), ]
98 -> [Race-id(302501), ]
99 -> [Race-id(302601), ]
100 -> [Race-id(302701), ]
101 -> [Race-id(302801), ]
102 -> [Race-id(302901), ]
103 -> [Race-id(303001), ]
104 -> [Race-id(303101), ]
105 -> [Race-id(303201), ]
106 -> [Race-id(303301), ]
107 -> [Race-id(303401), ]
108 -> [Race-id(303501), ]
109 -> [Race-id(303601), ]
110 -> [Race-id(303701), ]
111 -> [Race-id(303801), ]
112 -> [Race-id(303901), ]
113 -> [Race-id(304001), ]
114 -> [Race-id(304101), ]
115 -> [Race-id(304201), ]
116 -> [Race-id(304301), ]
117 -> [Race-id(304401), ]
118 -> [Race-id(304501), ]
119 -> [Race-id(304601), ]
120 -> [Race-id(304701), ]
121 -> [Race-id(304801), ]
122 -> [Race-id(304901), ]
123 -> [Race-id(305001), ]
124 -> [Race-id(305101), ]
125 -> [Race-id(305201), ]
126 -> [Race-id(305301), ]
127 -> [Race-id(305401), ]
128 -> [Race-id(305501), ]
129 -> [Race-id(305601), ]
130 -> [Race-id(305701), ]
131 -> [Race-id(305801), ]
132 -> [Race-id(305901), ]
133 -> [Race-id(306001), ]
134 -> [Race-id(306101), ]
135 -> [Race-id(306201), ]
136 -> [Race-id(306301), ]
137 -> [Race-id(306401), ]
138 -> [Race-id(306501), ]
139 -> [Race-id(306601), ]
140 -> [Race-id(306701), ]
141 -> [Race-id(306801), ]
142 -> [Race-id(306901), ]
143 -> [Race-id(307001), ]
144 -> [Race-id(100501), Race-id(101001), Race-id(102601), ]
145 -> [Race-id(100301), Race-id(100601), Race-id(102501), ]
146 -> [Race-id(102501), Race-id(102301), ]
147 -> [Race-id(102501), ]
148 -> [Race-id(102601), ]
149 -> [Race-id(203501), ]
150 -> [Race-id(405001), ]
151 -> [Race-id(100301), Race-id(102701), Race-id(101201), ]
152 -> [Race-id(102701), Race-id(101601), ]
153 -> [Race-id(102701), ]
154 -> [Race-id(102801), Race-id(101001), Race-id(101501), ]
155 -> [Race-id(102801), ]
_ -> []
// Get a saddle's type.
// If no saddle matches the ID, the result is Honor.
pub fun saddle-type(s: saddle-id): saddle-type
match s.game-id
1 -> Honor
2 -> Honor
3 -> Honor
4 -> Honor
5 -> Honor
6 -> Honor
7 -> Honor
8 -> Honor
9 -> Honor
10 -> G1-Win
11 -> G1-Win
12 -> G1-Win
13 -> G1-Win
14 -> G1-Win
15 -> G1-Win
16 -> G1-Win
17 -> G1-Win
18 -> G1-Win
19 -> G1-Win
20 -> G1-Win
21 -> G1-Win
22 -> G1-Win
23 -> G1-Win
24 -> G1-Win
25 -> G1-Win
26 -> G1-Win
27 -> G1-Win
28 -> G1-Win
29 -> G1-Win
30 -> G1-Win
31 -> G1-Win
32 -> G1-Win
33 -> G1-Win
34 -> G1-Win
35 -> G1-Win
36 -> G1-Win
37 -> G1-Win
38 -> G1-Win
39 -> G1-Win
40 -> G2-Win
41 -> G2-Win
42 -> G2-Win
43 -> G2-Win
44 -> G2-Win
45 -> G2-Win
46 -> G2-Win
47 -> G2-Win
48 -> G2-Win
49 -> G2-Win
50 -> G2-Win
51 -> G2-Win
52 -> G2-Win
53 -> G2-Win
54 -> G2-Win
55 -> G2-Win
56 -> G2-Win
57 -> G2-Win
58 -> G2-Win
59 -> G2-Win
60 -> G2-Win
61 -> G2-Win
62 -> G2-Win
63 -> G2-Win
64 -> G2-Win
65 -> G2-Win
66 -> G2-Win
67 -> G2-Win
68 -> G2-Win
69 -> G2-Win
70 -> G2-Win
71 -> G2-Win
72 -> G2-Win
73 -> G2-Win
74 -> G3-Win
75 -> G3-Win
76 -> G3-Win
77 -> G3-Win
78 -> G3-Win
79 -> G3-Win
80 -> G3-Win
81 -> G3-Win
82 -> G3-Win
83 -> G3-Win
84 -> G3-Win
85 -> G3-Win
86 -> G3-Win
87 -> G3-Win
88 -> G3-Win
89 -> G3-Win
90 -> G3-Win
91 -> G2-Win
92 -> G3-Win
93 -> G3-Win
94 -> G3-Win
95 -> G3-Win
96 -> G3-Win
97 -> G3-Win
98 -> G3-Win
99 -> G3-Win
100 -> G3-Win
101 -> G3-Win
102 -> G3-Win
103 -> G3-Win
104 -> G3-Win
105 -> G3-Win
106 -> G3-Win
107 -> G3-Win
108 -> G3-Win
109 -> G3-Win
110 -> G3-Win
111 -> G3-Win
112 -> G3-Win
113 -> G3-Win
114 -> G3-Win
115 -> G3-Win
116 -> G3-Win
117 -> G3-Win
118 -> G3-Win
119 -> G3-Win
120 -> G3-Win
121 -> G3-Win
122 -> G3-Win
123 -> G3-Win
124 -> G3-Win
125 -> G3-Win
126 -> G3-Win
127 -> G3-Win
128 -> G3-Win
129 -> G3-Win
130 -> G3-Win
131 -> G2-Win
132 -> G3-Win
133 -> G3-Win
134 -> G3-Win
135 -> G3-Win
136 -> G3-Win
137 -> G3-Win
138 -> G3-Win
139 -> G3-Win
140 -> G3-Win
141 -> G3-Win
142 -> G3-Win
143 -> G3-Win
144 -> Honor
145 -> Honor
146 -> Honor
147 -> G1-Win
148 -> G1-Win
149 -> G2-Win
150 -> G3-Win
151 -> Honor
152 -> Honor
153 -> G1-Win
154 -> Honor
155 -> G1-Win
_ -> Honor
// Get the primary ID for a saddle.
// For saddles which are the primary version, or if no saddle matches the given ID,
// the result is the input.
pub fun primary(s: saddle-id): saddle-id
match s.game-id
144 -> Saddle-id(1)
145 -> Saddle-id(4)
146 -> Saddle-id(6)
147 -> Saddle-id(14)
148 -> Saddle-id(16)
149 -> Saddle-id(49)
151 -> Saddle-id(4)
152 -> Saddle-id(5)
153 -> Saddle-id(13)
154 -> Saddle-id(1)
155 -> Saddle-id(18)
_ -> s
-23
View File
@@ -1,23 +0,0 @@
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!",
},
}
-30
View File
@@ -1,30 +0,0 @@
module horse/global/scenario
// Automatically generated with horsegen; DO NOT EDIT
import std/core/delayed
import std/core/vector
import std/core-extras
import horse/game-id
extern create-id-table(): vector<int>
c inline "int32_t arr[] = {1,2,};\nkk_vector_from_cint32array(arr, (kk_ssize_t)2, kk_context())"
js inline "[1,2,]"
// Vector of all scenario IDs in order for easy iterating.
pub val all = once(create-id-table)
// 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
-13794
View File
File diff suppressed because it is too large Load Diff
-14417
View File
File diff suppressed because it is too large Load Diff
-13268
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
-1711
View File
File diff suppressed because it is too large Load Diff
-1571
View File
File diff suppressed because it is too large Load Diff
-27
View File
@@ -1,38 +1,11 @@
package horse_test
import (
"cmp"
"slices"
"strings"
"sync"
"testing"
"git.sunturtle.xyz/zephyr/horse/horse"
"git.sunturtle.xyz/zephyr/horse/horse/global"
)
var SortedSkills = sync.OnceValue(func() []horse.Skill {
skills := make([]horse.Skill, 0, len(global.AllSkills))
for _, v := range global.AllSkills {
skills = append(skills, v)
}
slices.SortFunc(skills, func(a, b horse.Skill) int { return cmp.Compare(a.ID, b.ID) })
return skills
})
func TestSkillStrings(t *testing.T) {
t.Parallel()
for _, s := range SortedSkills() {
for _, a := range s.Activations {
for _, abil := range a.Abilities {
if n := abil.Type.String(); strings.HasPrefix(n, "AbilityType(") {
t.Errorf("%v %s: %s", s.ID, s.Name, n)
}
}
}
}
}
func TestTenThousandthsString(t *testing.T) {
t.Parallel()
cases := []struct {
-60
View File
@@ -1,60 +0,0 @@
WITH pairs AS (
SELECT
a.id AS id_a,
b.id AS id_b
FROM chara_data a
JOIN chara_data b ON a.id < b.id
-- Exclude characters who have no succession relations defined.
WHERE a.id IN (SELECT chara_id FROM succession_relation_member)
AND b.id IN (SELECT chara_id FROM succession_relation_member)
), trios AS (
SELECT
a.id AS id_a,
b.id AS id_b,
c.id AS id_c
FROM chara_data a
JOIN chara_data b ON a.id < b.id
JOIN chara_data c ON a.id < c.id AND b.id < c.id
-- Exclude characters who have no succession relations defined.
WHERE a.id IN (SELECT chara_id FROM succession_relation_member)
AND b.id IN (SELECT chara_id FROM succession_relation_member)
AND c.id IN (SELECT chara_id FROM succession_relation_member)
), pair_relations AS (
SELECT
ra.relation_type,
ra.chara_id AS id_a,
rb.chara_id AS id_b
FROM succession_relation_member ra
JOIN succession_relation_member rb ON ra.relation_type = rb.relation_type
), trio_relations AS (
SELECT
ra.relation_type,
ra.chara_id AS id_a,
rb.chara_id AS id_b,
rc.chara_id AS id_c
FROM succession_relation_member ra
JOIN succession_relation_member rb ON ra.relation_type = rb.relation_type
JOIN succession_relation_member rc ON ra.relation_type = rc.relation_type
), affinity AS (
SELECT
pairs.*,
0 AS id_c,
SUM(IFNULL(relation_point, 0)) AS base_affinity
FROM pairs
LEFT JOIN pair_relations rp ON pairs.id_a = rp.id_a AND pairs.id_b = rp.id_b
LEFT JOIN succession_relation sr ON rp.relation_type = sr.relation_type
GROUP BY pairs.id_a, pairs.id_b
UNION ALL
SELECT
trios.*,
SUM(IFNULL(relation_point, 0)) AS base_affinity
FROM trios
LEFT JOIN trio_relations rt ON trios.id_a = rt.id_a AND trios.id_b = rt.id_b AND trios.id_c = rt.id_c
LEFT JOIN succession_relation sr ON rt.relation_type = sr.relation_type
GROUP BY trios.id_a, trios.id_b, trios.id_c
)
SELECT * FROM affinity
WHERE base_affinity != 0
ORDER BY id_a, id_b, id_c
-9
View File
@@ -1,9 +0,0 @@
SELECT
"index" AS "id",
"text" AS "name",
ROW_NUMBER() OVER (ORDER BY "index") - 1 AS "index"
FROM text_data
WHERE category = 6 AND "index" BETWEEN 1000 AND 1999
-- Exclude characters who have no succession relations defined.
AND "index" IN (SELECT chara_id FROM succession_relation_member)
ORDER BY "id"
-14
View File
@@ -1,14 +0,0 @@
WITH race_names AS (
SELECT "index" AS id, "text" AS name FROM text_data WHERE category = 33
)
SELECT
race.id,
race_names.name,
race.grade,
race.thumbnail_id,
MIN(race.id) OVER (PARTITION BY race_names.name) AS "primary",
ROW_NUMBER() OVER (PARTITION BY race_names.name ORDER BY race.id) - 1 AS "alternate"
FROM race
JOIN race_names ON race.id = race_names.id
WHERE race."group" = 1
ORDER BY race.id
-20
View File
@@ -1,20 +0,0 @@
WITH saddle_names AS (
SELECT "index" AS id, "text" AS name
FROM text_data
WHERE category = 111
)
SELECT
s.id,
n.name,
ri1.id AS race1,
IFNULL(ri2.id, 0) AS race2,
IFNULL(ri3.id, 0) AS race3,
s.win_saddle_type,
MIN(s.id) OVER (PARTITION BY n.name) AS "primary",
ROW_NUMBER() OVER (PARTITION BY n.name ORDER BY s.id) - 1 AS "alternate"
FROM single_mode_wins_saddle s
JOIN race_instance ri1 ON s.race_instance_id_1 = ri1.id
LEFT JOIN race_instance ri2 ON s.race_instance_id_2 = ri2.id
LEFT JOIN race_instance ri3 ON s.race_instance_id_3 = ri3.id
LEFT JOIN saddle_names n ON s.id = n.id
ORDER BY s.id
-17
View File
@@ -1,17 +0,0 @@
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
-15
View File
@@ -1,15 +0,0 @@
WITH skill_groups AS (
SELECT DISTINCT group_id FROM skill_data
)
SELECT
g.group_id,
IFNULL(s1.id, 0) AS skill1,
IFNULL(s2.id, 0) AS skill2,
IFNULL(s3.id, 0) AS skill3,
IFNULL(m1.id, 0) AS skill_bad
FROM skill_groups g
LEFT JOIN skill_data s1 ON g.group_id = s1.group_id AND s1.group_rate = 1
LEFT JOIN skill_data s2 ON g.group_id = s2.group_id AND s2.group_rate = 2
LEFT JOIN skill_data s3 ON g.group_id = s3.group_id AND s3.group_rate = 3
LEFT JOIN skill_data m1 ON g.group_id = m1.group_id AND m1.group_rate = -1
ORDER BY g.group_id
-98
View File
@@ -1,98 +0,0 @@
WITH skill_names AS (
SELECT
n."index" AS "id",
n."text" AS "name",
d."text" AS "description"
FROM text_data n
JOIN text_data d ON n."index" = d."index" AND n."category" = 47 AND d."category" = 48
), skill_groups AS (
SELECT
group_id,
name
FROM skill_data d
JOIN skill_names n ON d.id = n.id
WHERE group_rate = 1
), card_name AS (
SELECT
"index" AS "id",
"text" AS "name"
FROM text_data n
WHERE category = 4
), card_unique AS (
SELECT DISTINCT
ss.skill_id1 AS unique_id,
card_name.id AS owner_id,
card_name.name
FROM card_data card
JOIN card_name ON card.id = card_name.id
JOIN card_rarity_data rd ON card.id = rd.card_id
JOIN skill_set ss ON rd.skill_set = ss.id
)
SELECT
d.id,
n.name,
n.description,
IIF(d.unique_skill_id_1 = 0, d.group_id, ud.group_id) AS group_id,
CASE
WHEN g.name IS NOT NULL THEN g.name
WHEN d.unique_skill_id_1 != 0 THEN n.name
ELSE ''
END AS group_name,
d.rarity,
d.group_rate,
d.grade_value,
d.activate_lot,
d.precondition_1,
d.condition_1,
d.float_ability_time_1,
d.ability_time_usage_1,
d.float_cooldown_time_1,
d.ability_type_1_1,
d.ability_value_usage_1_1,
d.float_ability_value_1_1,
d.target_type_1_1,
d.target_value_1_1,
d.ability_type_1_2,
d.ability_value_usage_1_2,
d.float_ability_value_1_2,
d.target_type_1_2,
d.target_value_1_2,
d.ability_type_1_3,
d.ability_value_usage_1_3,
d.float_ability_value_1_3,
d.target_type_1_3,
d.target_value_1_3,
d.precondition_2,
d.condition_2,
d.float_ability_time_2,
d.ability_time_usage_2,
d.float_cooldown_time_2,
d.ability_type_2_1,
d.ability_value_usage_2_1,
d.float_ability_value_2_1,
d.target_type_2_1,
d.target_value_2_1,
d.ability_type_2_2,
d.ability_value_usage_2_2,
d.float_ability_value_2_2,
d.target_type_2_2,
d.target_value_2_2,
d.ability_type_2_3,
d.ability_value_usage_2_3,
d.float_ability_value_2_3,
d.target_type_2_3,
d.target_value_2_3,
IFNULL(p.need_skill_point, 0) AS sp_cost,
d.unique_skill_id_1,
COALESCE(u.owner_id, iu.owner_id, 0) AS unique_owner_id,
COALESCE(u.name, iu.name, '') AS unique_owner,
d.icon_id,
ROW_NUMBER() OVER (ORDER BY d.id) - 1 AS "index"
FROM skill_data d
JOIN skill_names n ON d.id = n.id
LEFT JOIN skill_data ud ON d.unique_skill_id_1 = ud.id
LEFT JOIN skill_groups g ON d.group_id = g.group_id
LEFT JOIN single_mode_skill_need_point p ON d.id = p.id
LEFT JOIN card_unique u ON d.id = u.unique_id
LEFT JOIN card_unique iu ON d.unique_skill_id_1 = iu.unique_id
ORDER BY d.id
-9
View File
@@ -1,9 +0,0 @@
SELECT
factor_group_id,
effect_id,
target_type,
value_1,
value_2
FROM succession_factor_effect
WHERE factor_group_id NOT IN (40001) -- exclude Carnival Bonus
ORDER BY factor_group_id, effect_id, id
-20
View File
@@ -1,20 +0,0 @@
WITH spark AS (
SELECT
n."index" AS "id",
n."text" AS "name",
d."text" AS "description"
FROM text_data n
LEFT JOIN text_data d ON n."index" = d."index" AND d."category" = 172
WHERE n.category = 147
)
SELECT
sf.factor_id,
spark.name,
spark.description,
sf.factor_group_id,
sf.rarity,
sf.factor_type
FROM spark
JOIN succession_factor sf ON spark.id = sf.factor_id
WHERE sf.factor_type != 7 -- exclude Carnival Bonus
ORDER BY sf.factor_id
-59
View File
@@ -1,59 +0,0 @@
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