Compare commits
2 Commits
5540bb2c4e
...
8632bb8c3c
| Author | SHA1 | Date | |
|---|---|---|---|
| 8632bb8c3c | |||
| 7ff271ff2d |
+63
-5
@@ -3,6 +3,8 @@ package main
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
@@ -20,11 +22,14 @@ import (
|
||||
"github.com/disgoorg/disgo/rest"
|
||||
|
||||
"git.sunturtle.xyz/zephyr/horse/horse"
|
||||
"git.sunturtle.xyz/zephyr/horse/horse/global"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var (
|
||||
// data options
|
||||
skillsFile string
|
||||
skillGroupsFile string
|
||||
// discord bot options
|
||||
tokenFile string
|
||||
// http api options
|
||||
addr string
|
||||
@@ -34,6 +39,8 @@ func main() {
|
||||
level slog.Level
|
||||
textfmt string
|
||||
)
|
||||
flag.StringVar(&skillsFile, "skills", "", "json `file` containing skill data")
|
||||
flag.StringVar(&skillGroupsFile, "skill-groups", "", "json `file` containing skill group data")
|
||||
flag.StringVar(&tokenFile, "token", "", "`file` containing the Discord bot token")
|
||||
flag.StringVar(&addr, "http", "", "`address` to bind HTTP API server")
|
||||
flag.StringVar(&route, "route", "/interactions/callback", "`path` to serve HTTP API calls")
|
||||
@@ -54,6 +61,14 @@ func main() {
|
||||
}
|
||||
slog.SetDefault(slog.New(lh))
|
||||
|
||||
byID, byName, err := loadSkills(skillsFile)
|
||||
groups, err2 := loadSkillGroups(skillGroupsFile)
|
||||
if err = errors.Join(err, err2); err != nil {
|
||||
slog.Error("loading data", slog.Any("err", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
skillsByID, skillsByName, skillGroupMap = byID, byName, groups
|
||||
|
||||
token, err := os.ReadFile(tokenFile)
|
||||
if err != nil {
|
||||
slog.Error("reading token", slog.Any("err", err))
|
||||
@@ -133,16 +148,59 @@ var commands = []discord.ApplicationCommandCreate{
|
||||
},
|
||||
}
|
||||
|
||||
// TODO(zeph): these globals could go away, but there's a bit of ceremony to doing that
|
||||
var (
|
||||
skillsByID map[horse.SkillID]horse.Skill
|
||||
skillsByName map[string]horse.SkillID
|
||||
skillGroupMap map[horse.SkillGroupID]horse.SkillGroup
|
||||
)
|
||||
|
||||
func loadSkills(file string) (map[horse.SkillID]horse.Skill, map[string]horse.SkillID, error) {
|
||||
b, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
var skills []horse.Skill
|
||||
if err := json.Unmarshal(b, &skills); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
byID := make(map[horse.SkillID]horse.Skill, len(skills))
|
||||
byName := make(map[string]horse.SkillID, len(skills))
|
||||
for _, s := range skills {
|
||||
byID[s.ID] = s
|
||||
byName[s.Name] = s.ID
|
||||
}
|
||||
slog.Info("loaded skills", slog.Int("count", len(skills)))
|
||||
return byID, byName, nil
|
||||
}
|
||||
|
||||
func loadSkillGroups(file string) (map[horse.SkillGroupID]horse.SkillGroup, error) {
|
||||
b, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var groups []horse.SkillGroup
|
||||
if err := json.Unmarshal(b, &groups); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m := make(map[horse.SkillGroupID]horse.SkillGroup, len(groups))
|
||||
for _, s := range groups {
|
||||
m[s.ID] = s
|
||||
}
|
||||
slog.Info("loaded skill groups", slog.Int("count", len(groups)))
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func skillHandler(data discord.SlashCommandInteractionData, e *handler.CommandEvent) error {
|
||||
q := data.String("query")
|
||||
id, err := strconv.ParseInt(q, 10, 32)
|
||||
if err == nil {
|
||||
// note inverted condition; this is when we have an id
|
||||
id = int64(global.AllSkills[horse.SkillID(id)].ID)
|
||||
id = int64(skillsByID[horse.SkillID(id)].ID)
|
||||
}
|
||||
if id == 0 {
|
||||
// Either we weren't given a number or the number doesn't match any skill ID.
|
||||
v := global.SkillNameToID[q]
|
||||
v := skillsByName[q]
|
||||
if v == 0 {
|
||||
// No such skill.
|
||||
m := discord.MessageCreate{
|
||||
@@ -155,7 +213,7 @@ func skillHandler(data discord.SlashCommandInteractionData, e *handler.CommandEv
|
||||
}
|
||||
// TODO(zeph): search conditions and effects, give a list
|
||||
m := discord.MessageCreate{
|
||||
Components: []discord.LayoutComponent{RenderSkill(horse.SkillID(id), global.AllSkills, global.SkillGroups)},
|
||||
Components: []discord.LayoutComponent{RenderSkill(horse.SkillID(id), skillsByID, skillGroupMap)},
|
||||
Flags: discord.MessageFlagIsComponentsV2,
|
||||
}
|
||||
return e.CreateMessage(m)
|
||||
@@ -177,7 +235,7 @@ func skillButton(data discord.ButtonInteractionData, e *handler.ComponentEvent)
|
||||
return e.CreateMessage(m)
|
||||
}
|
||||
m := discord.MessageUpdate{
|
||||
Components: &[]discord.LayoutComponent{RenderSkill(horse.SkillID(id), global.AllSkills, global.SkillGroups)},
|
||||
Components: &[]discord.LayoutComponent{RenderSkill(horse.SkillID(id), skillsByID, skillGroupMap)},
|
||||
}
|
||||
return e.UpdateMessage(m)
|
||||
}
|
||||
|
||||
@@ -9,10 +9,9 @@ import (
|
||||
|
||||
"git.sunturtle.xyz/zephyr/horse/cmd/horsebot/autocomplete"
|
||||
"git.sunturtle.xyz/zephyr/horse/horse"
|
||||
"git.sunturtle.xyz/zephyr/horse/horse/global"
|
||||
)
|
||||
|
||||
func RenderSkill(id horse.SkillID, all map[horse.SkillID]horse.Skill, groups map[int32][4]horse.SkillID) discord.ContainerComponent {
|
||||
func RenderSkill(id horse.SkillID, all map[horse.SkillID]horse.Skill, groups map[horse.SkillGroupID]horse.SkillGroup) discord.ContainerComponent {
|
||||
s, ok := all[id]
|
||||
if !ok {
|
||||
return discord.NewContainer(discord.NewTextDisplayf("invalid skill ID %v made it to RenderSkill", id))
|
||||
@@ -95,7 +94,8 @@ func RenderSkill(id horse.SkillID, all map[horse.SkillID]horse.Skill, groups map
|
||||
l := discord.NewTextDisplayf("%s ・ SP cost %d ・ Grade value %d ・ [Conditions on GameTora](https://gametora.com/umamusume/skill-condition-viewer?skill=%d)", skilltype, s.SPCost, s.GradeValue, s.ID)
|
||||
r.Components = append(r.Components, discord.NewSmallSeparator(), l)
|
||||
rel := make([]horse.Skill, 0, 4)
|
||||
for _, id := range groups[s.Group] {
|
||||
group := groups[s.Group]
|
||||
for _, id := range [...]horse.SkillID{group.Skill1, group.Skill2, group.Skill3, group.SkillBad} {
|
||||
if id != 0 {
|
||||
rel = append(rel, all[id])
|
||||
}
|
||||
@@ -135,8 +135,8 @@ func isDebuff(s horse.Skill) bool {
|
||||
|
||||
var skillGlobalAuto = sync.OnceValue(func() *autocomplete.Set[discord.AutocompleteChoice] {
|
||||
var set autocomplete.Set[discord.AutocompleteChoice]
|
||||
for _, id := range global.OrderedSkills {
|
||||
s := global.AllSkills[id]
|
||||
// NOTE(zeph): we're using global variables here
|
||||
for _, s := range skillsByID {
|
||||
set.Add(s.Name, discord.AutocompleteChoiceString{Name: s.Name, Value: s.Name})
|
||||
if s.UniqueOwner != "" {
|
||||
if s.Rarity >= 3 {
|
||||
|
||||
@@ -0,0 +1,403 @@
|
||||
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(®ion, "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
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
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
|
||||
@@ -0,0 +1,15 @@
|
||||
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
|
||||
@@ -6,4 +6,4 @@ SELECT
|
||||
value_2
|
||||
FROM succession_factor_effect
|
||||
WHERE factor_group_id NOT IN (40001) -- exclude Carnival Bonus
|
||||
ORDER BY factor_group_id, effect_id, target_type
|
||||
ORDER BY factor_group_id, effect_id, id
|
||||
@@ -1,13 +0,0 @@
|
||||
package main
|
||||
|
||||
import "os"
|
||||
|
||||
//go:generate go run ./horsegen
|
||||
//go:generate go generate ./horse/...
|
||||
//go:generate go fmt ./...
|
||||
//go:generate go test ./...
|
||||
|
||||
func main() {
|
||||
os.Stderr.WriteString("go generate, not go run\n")
|
||||
os.Exit(2)
|
||||
}
|
||||
@@ -5,7 +5,7 @@ go 1.25.5
|
||||
require (
|
||||
github.com/disgoorg/disgo v0.19.0-rc.15
|
||||
github.com/junegunn/fzf v0.67.0
|
||||
golang.org/x/sync v0.14.0
|
||||
golang.org/x/sync v0.20.0
|
||||
zombiezen.com/go/sqlite v1.4.2
|
||||
)
|
||||
|
||||
|
||||
@@ -40,8 +40,8 @@ golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5Z
|
||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8=
|
||||
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
||||
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
|
||||
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
|
||||
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
|
||||
+9
-2
@@ -3,10 +3,17 @@ package horse
|
||||
type CharacterID int16
|
||||
|
||||
type Character struct {
|
||||
ID CharacterID
|
||||
Name string
|
||||
ID CharacterID `json:"chara_id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func (c Character) String() string {
|
||||
return c.Name
|
||||
}
|
||||
|
||||
type AffinityRelation struct {
|
||||
IDA int `json:"chara_a"`
|
||||
IDB int `json:"chara_b"`
|
||||
IDC int `json:"chara_c,omitzero"`
|
||||
Affinity int `json:"affinity"`
|
||||
}
|
||||
|
||||
+114126
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,214 @@
|
||||
[
|
||||
{
|
||||
"chara_id": 1001,
|
||||
"name": "Special Week"
|
||||
},
|
||||
{
|
||||
"chara_id": 1002,
|
||||
"name": "Silence Suzuka"
|
||||
},
|
||||
{
|
||||
"chara_id": 1003,
|
||||
"name": "Tokai Teio"
|
||||
},
|
||||
{
|
||||
"chara_id": 1004,
|
||||
"name": "Maruzensky"
|
||||
},
|
||||
{
|
||||
"chara_id": 1005,
|
||||
"name": "Fuji Kiseki"
|
||||
},
|
||||
{
|
||||
"chara_id": 1006,
|
||||
"name": "Oguri Cap"
|
||||
},
|
||||
{
|
||||
"chara_id": 1007,
|
||||
"name": "Gold Ship"
|
||||
},
|
||||
{
|
||||
"chara_id": 1008,
|
||||
"name": "Vodka"
|
||||
},
|
||||
{
|
||||
"chara_id": 1009,
|
||||
"name": "Daiwa Scarlet"
|
||||
},
|
||||
{
|
||||
"chara_id": 1010,
|
||||
"name": "Taiki Shuttle"
|
||||
},
|
||||
{
|
||||
"chara_id": 1011,
|
||||
"name": "Grass Wonder"
|
||||
},
|
||||
{
|
||||
"chara_id": 1012,
|
||||
"name": "Hishi Amazon"
|
||||
},
|
||||
{
|
||||
"chara_id": 1013,
|
||||
"name": "Mejiro McQueen"
|
||||
},
|
||||
{
|
||||
"chara_id": 1014,
|
||||
"name": "El Condor Pasa"
|
||||
},
|
||||
{
|
||||
"chara_id": 1015,
|
||||
"name": "T.M. Opera O"
|
||||
},
|
||||
{
|
||||
"chara_id": 1016,
|
||||
"name": "Narita Brian"
|
||||
},
|
||||
{
|
||||
"chara_id": 1017,
|
||||
"name": "Symboli Rudolf"
|
||||
},
|
||||
{
|
||||
"chara_id": 1018,
|
||||
"name": "Air Groove"
|
||||
},
|
||||
{
|
||||
"chara_id": 1019,
|
||||
"name": "Agnes Digital"
|
||||
},
|
||||
{
|
||||
"chara_id": 1020,
|
||||
"name": "Seiun Sky"
|
||||
},
|
||||
{
|
||||
"chara_id": 1021,
|
||||
"name": "Tamamo Cross"
|
||||
},
|
||||
{
|
||||
"chara_id": 1022,
|
||||
"name": "Fine Motion"
|
||||
},
|
||||
{
|
||||
"chara_id": 1023,
|
||||
"name": "Biwa Hayahide"
|
||||
},
|
||||
{
|
||||
"chara_id": 1024,
|
||||
"name": "Mayano Top Gun"
|
||||
},
|
||||
{
|
||||
"chara_id": 1025,
|
||||
"name": "Manhattan Cafe"
|
||||
},
|
||||
{
|
||||
"chara_id": 1026,
|
||||
"name": "Mihono Bourbon"
|
||||
},
|
||||
{
|
||||
"chara_id": 1027,
|
||||
"name": "Mejiro Ryan"
|
||||
},
|
||||
{
|
||||
"chara_id": 1028,
|
||||
"name": "Hishi Akebono"
|
||||
},
|
||||
{
|
||||
"chara_id": 1030,
|
||||
"name": "Rice Shower"
|
||||
},
|
||||
{
|
||||
"chara_id": 1032,
|
||||
"name": "Agnes Tachyon"
|
||||
},
|
||||
{
|
||||
"chara_id": 1033,
|
||||
"name": "Admire Vega"
|
||||
},
|
||||
{
|
||||
"chara_id": 1034,
|
||||
"name": "Inari One"
|
||||
},
|
||||
{
|
||||
"chara_id": 1035,
|
||||
"name": "Winning Ticket"
|
||||
},
|
||||
{
|
||||
"chara_id": 1037,
|
||||
"name": "Eishin Flash"
|
||||
},
|
||||
{
|
||||
"chara_id": 1038,
|
||||
"name": "Curren Chan"
|
||||
},
|
||||
{
|
||||
"chara_id": 1039,
|
||||
"name": "Kawakami Princess"
|
||||
},
|
||||
{
|
||||
"chara_id": 1040,
|
||||
"name": "Gold City"
|
||||
},
|
||||
{
|
||||
"chara_id": 1041,
|
||||
"name": "Sakura Bakushin O"
|
||||
},
|
||||
{
|
||||
"chara_id": 1044,
|
||||
"name": "Sweep Tosho"
|
||||
},
|
||||
{
|
||||
"chara_id": 1045,
|
||||
"name": "Super Creek"
|
||||
},
|
||||
{
|
||||
"chara_id": 1046,
|
||||
"name": "Smart Falcon"
|
||||
},
|
||||
{
|
||||
"chara_id": 1048,
|
||||
"name": "Tosen Jordan"
|
||||
},
|
||||
{
|
||||
"chara_id": 1050,
|
||||
"name": "Narita Taishin"
|
||||
},
|
||||
{
|
||||
"chara_id": 1051,
|
||||
"name": "Nishino Flower"
|
||||
},
|
||||
{
|
||||
"chara_id": 1052,
|
||||
"name": "Haru Urara"
|
||||
},
|
||||
{
|
||||
"chara_id": 1056,
|
||||
"name": "Matikanefukukitaru"
|
||||
},
|
||||
{
|
||||
"chara_id": 1058,
|
||||
"name": "Meisho Doto"
|
||||
},
|
||||
{
|
||||
"chara_id": 1059,
|
||||
"name": "Mejiro Dober"
|
||||
},
|
||||
{
|
||||
"chara_id": 1060,
|
||||
"name": "Nice Nature"
|
||||
},
|
||||
{
|
||||
"chara_id": 1061,
|
||||
"name": "King Halo"
|
||||
},
|
||||
{
|
||||
"chara_id": 1068,
|
||||
"name": "Kitasan Black"
|
||||
},
|
||||
{
|
||||
"chara_id": 1069,
|
||||
"name": "Sakura Chiyono O"
|
||||
},
|
||||
{
|
||||
"chara_id": 1071,
|
||||
"name": "Mejiro Ardan"
|
||||
}
|
||||
]
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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!",
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
[
|
||||
{
|
||||
"scenario_id": 1,
|
||||
"name": "URA Finale",
|
||||
"title": "The Beginning: URA Finale"
|
||||
},
|
||||
{
|
||||
"scenario_id": 2,
|
||||
"name": "Unity Cup",
|
||||
"title": "Unity Cup: Shine On, Team Spirit!"
|
||||
}
|
||||
]
|
||||
@@ -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
|
||||
File diff suppressed because it is too large
Load Diff
-13794
File diff suppressed because it is too large
Load Diff
+15756
File diff suppressed because it is too large
Load Diff
-14417
File diff suppressed because it is too large
Load Diff
-13268
File diff suppressed because it is too large
Load Diff
+35564
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
-1711
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
-1571
File diff suppressed because it is too large
Load Diff
+12
-12
@@ -4,26 +4,26 @@ type RaceID int32
|
||||
|
||||
// Race is the internal data about a race.
|
||||
type Race struct {
|
||||
ID RaceID
|
||||
Name string
|
||||
Thumbnail int
|
||||
ID RaceID `json:"race_id"`
|
||||
Name string `json:"name"`
|
||||
Thumbnail int `json:"thumbnail"`
|
||||
// Some careers contain unusual versions of races, e.g. Tenno Sho (Spring)
|
||||
// in Hanshin instead of Kyoto for Narita Taishin and Biwa Hayahide.
|
||||
// For such races, this field holds the normal race ID.
|
||||
Primary RaceID
|
||||
Primary RaceID `json:"primary"`
|
||||
}
|
||||
|
||||
type SaddleID int32
|
||||
|
||||
// Saddle is the internal data about a race win saddle.
|
||||
type Saddle struct {
|
||||
ID SaddleID
|
||||
Name string
|
||||
Races []RaceID
|
||||
Type SaddleType
|
||||
ID SaddleID `json:"saddle_id"`
|
||||
Name string `json:"name"`
|
||||
Races []RaceID `json:"races"`
|
||||
Type SaddleType `json:"type"`
|
||||
// Saddles that involve alternate races are themselves alternate.
|
||||
// For such saddles, this field holds the normal saddle ID.
|
||||
Primary SaddleID
|
||||
Primary SaddleID `json:"primary"`
|
||||
}
|
||||
|
||||
type SaddleType int8
|
||||
@@ -40,7 +40,7 @@ type ScenarioID int8
|
||||
|
||||
// Scenario is metadata about a career scenario.
|
||||
type Scenario struct {
|
||||
ID ScenarioID
|
||||
Name string
|
||||
Title string
|
||||
ID ScenarioID `json:"scenario_id"`
|
||||
Name string `json:"name"`
|
||||
Title string `json:"title"`
|
||||
}
|
||||
|
||||
+46
-23
@@ -27,37 +27,37 @@ func (x TenThousandths) String() string {
|
||||
|
||||
// Skill is the internal data about a skill.
|
||||
type Skill struct {
|
||||
ID SkillID
|
||||
Name string
|
||||
Description string
|
||||
Group int32
|
||||
Rarity int8
|
||||
GroupRate int8
|
||||
GradeValue int32
|
||||
WitCheck bool
|
||||
Activations []Activation
|
||||
UniqueOwner string
|
||||
SPCost int
|
||||
IconID int
|
||||
ID SkillID `json:"skill_id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Group SkillGroupID `json:"group"`
|
||||
Rarity int8 `json:"rarity"`
|
||||
GroupRate int8 `json:"group_rate"`
|
||||
GradeValue int32 `json:"grade_value,omitzero"`
|
||||
WitCheck bool `json:"wit_check"`
|
||||
Activations []Activation `json:"activations"`
|
||||
UniqueOwner string `json:"unique_owner,omitzero"`
|
||||
SPCost int `json:"sp_cost,omitzero"`
|
||||
IconID int `json:"icon_id"`
|
||||
}
|
||||
|
||||
// Activation is the parameters controlling when a skill activates.
|
||||
type Activation struct {
|
||||
Precondition string
|
||||
Condition string
|
||||
Duration TenThousandths
|
||||
DurScale DurScale
|
||||
Cooldown TenThousandths
|
||||
Abilities []Ability
|
||||
Precondition string `json:"precondition,omitzero"`
|
||||
Condition string `json:"condition"`
|
||||
Duration TenThousandths `json:"duration,omitzero"`
|
||||
DurScale DurScale `json:"dur_scale,omitzero"`
|
||||
Cooldown TenThousandths `json:"cooldown,omitzero"`
|
||||
Abilities []Ability `json:"abilities"`
|
||||
}
|
||||
|
||||
// Ability is an individual effect applied by a skill.
|
||||
type Ability struct {
|
||||
Type AbilityType
|
||||
ValueUsage AbilityValueUsage
|
||||
Value TenThousandths
|
||||
Target AbilityTarget
|
||||
TargetValue int32
|
||||
Type AbilityType `json:"type"`
|
||||
ValueUsage AbilityValueUsage `json:"value_usage"`
|
||||
Value TenThousandths `json:"value"`
|
||||
Target AbilityTarget `json:"target"`
|
||||
TargetValue int32 `json:"target_value"`
|
||||
}
|
||||
|
||||
func (a Ability) String() string {
|
||||
@@ -202,3 +202,26 @@ const (
|
||||
TargetCharacter AbilityTarget = 22 // specific character
|
||||
TargetTriggering AbilityTarget = 23 // whosoever triggered this skill
|
||||
)
|
||||
|
||||
type SkillGroupID int32
|
||||
|
||||
// SkillGroup is a group of skills which are alternate versions of each other.
|
||||
//
|
||||
// Any of the skill IDs in a group may be zero, indicating that there is no
|
||||
// skill with the corresponding group rate.
|
||||
// Some skill groups contain only Skill2 or SkillBad, while others may have all
|
||||
// four skills.
|
||||
type SkillGroup struct {
|
||||
ID SkillGroupID `json:"skill_group"`
|
||||
// Skill1 is the base version of the skill, either a common (white) skill
|
||||
// or an Uma's own unique.
|
||||
Skill1 SkillID `json:"skill1,omitzero"`
|
||||
// Skill2 is the first upgraded version of the skill: a rare (gold)
|
||||
// skill, a double circle skill, or an inherited unique skill.
|
||||
Skill2 SkillID `json:"skill2,omitzero"`
|
||||
// Skill3 is the highest upgraded version, a gold version of a skill with
|
||||
// a double circle version.
|
||||
Skill3 SkillID `json:"skill3,omitzero"`
|
||||
// SkillBad is a negative (purple) skill.
|
||||
SkillBad SkillID `json:"skill_bad,omitzero"`
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
+10
-10
@@ -6,13 +6,13 @@ type (
|
||||
)
|
||||
|
||||
type Spark struct {
|
||||
ID SparkID
|
||||
Name string
|
||||
Description string
|
||||
Group SparkGroupID
|
||||
Rarity SparkRarity
|
||||
Type SparkType
|
||||
Effects [][]SparkEffect
|
||||
ID SparkID `json:"spark_id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Group SparkGroupID `json:"spark_group"`
|
||||
Rarity SparkRarity `json:"rarity"`
|
||||
Type SparkType `json:"type"`
|
||||
Effects [][]SparkEffect `json:"effects"`
|
||||
}
|
||||
|
||||
type SparkType int8
|
||||
@@ -46,9 +46,9 @@ func (r SparkRarity) String() string {
|
||||
}
|
||||
|
||||
type SparkEffect struct {
|
||||
Target SparkTarget
|
||||
Value1 int32
|
||||
Value2 int32
|
||||
Target SparkTarget `json:"target"`
|
||||
Value1 int32 `json:"value1,omitzero"`
|
||||
Value2 int32 `json:"value2,omitzero"`
|
||||
}
|
||||
|
||||
type SparkTarget int8
|
||||
|
||||
+22
-10
@@ -3,18 +3,30 @@ package horse
|
||||
type UmaID int32
|
||||
|
||||
type Uma struct {
|
||||
ID UmaID
|
||||
CharacterID CharacterID
|
||||
Name string
|
||||
Variant string
|
||||
ID UmaID `json:"chara_card_id"`
|
||||
CharacterID CharacterID `json:"chara_id"`
|
||||
Name string `json:"name"`
|
||||
Variant string `json:"variant"`
|
||||
|
||||
Sprint, Mile, Medium, Long AptitudeLevel
|
||||
Front, Pace, Late, End AptitudeLevel
|
||||
Turf, Dirt AptitudeLevel
|
||||
Sprint AptitudeLevel `json:"sprint"`
|
||||
Mile AptitudeLevel `json:"mile"`
|
||||
Medium AptitudeLevel `json:"medium"`
|
||||
Long AptitudeLevel `json:"long"`
|
||||
Front AptitudeLevel `json:"front"`
|
||||
Pace AptitudeLevel `json:"pace"`
|
||||
Late AptitudeLevel `json:"late"`
|
||||
End AptitudeLevel `json:"end"`
|
||||
Turf AptitudeLevel `json:"turf"`
|
||||
Dirt AptitudeLevel `json:"dirt"`
|
||||
|
||||
Unique SkillID
|
||||
Skill1, Skill2, Skill3 SkillID
|
||||
SkillPL2, SkillPL3, SkillPL4, SkillPL5 SkillID
|
||||
Unique SkillID `json:"unique"`
|
||||
Skill1 SkillID `json:"skill1"`
|
||||
Skill2 SkillID `json:"skill2"`
|
||||
Skill3 SkillID `json:"skill3"`
|
||||
SkillPL2 SkillID `json:"skill_pl2"`
|
||||
SkillPL3 SkillID `json:"skill_pl3"`
|
||||
SkillPL4 SkillID `json:"skill_pl4"`
|
||||
SkillPL5 SkillID `json:"skill_pl5"`
|
||||
}
|
||||
|
||||
type AptitudeLevel int8
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
# gen
|
||||
|
||||
Go tool to generate the Koka source code from the game's SQLite database.
|
||||
|
||||
Code is generated using Go templates.
|
||||
Templates use a `kkenum` function which converts a name `Mr. C.B.` to a Koka enumerant name `Mr-CB`.
|
||||
@@ -1,44 +0,0 @@
|
||||
WITH uma_names AS (
|
||||
SELECT
|
||||
"index" AS "id",
|
||||
"text" AS "name"
|
||||
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)
|
||||
), pairs AS (
|
||||
SELECT
|
||||
a.id AS id_a,
|
||||
a.name AS name_a,
|
||||
b.id AS id_b,
|
||||
b.name AS name_b
|
||||
FROM uma_names a
|
||||
JOIN uma_names b ON a.id != b.id -- exclude reflexive cases
|
||||
), relation_pairs 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
|
||||
), affinity AS (
|
||||
SELECT
|
||||
pairs.*,
|
||||
SUM(IFNULL(relation_point, 0)) AS base_affinity
|
||||
FROM pairs
|
||||
LEFT JOIN relation_pairs 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
|
||||
-- Reflexive cases.
|
||||
SELECT
|
||||
uma_names.id AS id_a,
|
||||
uma_names.name AS name_a,
|
||||
uma_names.id AS id_b,
|
||||
uma_names.name AS name_b,
|
||||
0 AS base_affinity
|
||||
FROM uma_names
|
||||
)
|
||||
SELECT * FROM affinity
|
||||
ORDER BY id_a, id_b
|
||||
@@ -1,87 +0,0 @@
|
||||
WITH uma_names AS (
|
||||
SELECT
|
||||
"index" AS "id",
|
||||
"text" AS "name"
|
||||
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)
|
||||
), trios AS (
|
||||
SELECT
|
||||
a.id AS id_a,
|
||||
a.name AS name_a,
|
||||
b.id AS id_b,
|
||||
b.name AS name_b,
|
||||
c.id AS id_c,
|
||||
c.name AS name_c
|
||||
FROM uma_names a
|
||||
JOIN uma_names b ON a.id != b.id -- exclude pairwise reflexive cases
|
||||
JOIN uma_names c ON a.id != c.id AND b.id != c.id
|
||||
), relation_trios 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
|
||||
trios.*,
|
||||
SUM(IFNULL(relation_point, 0)) AS base_affinity
|
||||
FROM trios
|
||||
LEFT JOIN relation_trios 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
|
||||
|
||||
UNION ALL
|
||||
-- A = B = C
|
||||
SELECT
|
||||
n.id AS id_a,
|
||||
n.name AS name_a,
|
||||
n.id AS id_b,
|
||||
n.name AS name_b,
|
||||
n.id AS id_c,
|
||||
n.name AS name_c,
|
||||
0 AS base_affinity
|
||||
FROM uma_names n
|
||||
|
||||
UNION ALL
|
||||
-- A = B
|
||||
SELECT
|
||||
n.id AS id_a,
|
||||
n.name AS name_a,
|
||||
n.id AS id_a,
|
||||
n.name AS id_b,
|
||||
m.id AS id_c,
|
||||
m.name AS name_c,
|
||||
0 AS base_affinity
|
||||
FROM uma_names n JOIN uma_names m ON n.id != m.id
|
||||
|
||||
UNION ALL
|
||||
-- A = C
|
||||
SELECT
|
||||
n.id AS id_a,
|
||||
n.name AS name_a,
|
||||
m.id AS id_a,
|
||||
m.name AS id_b,
|
||||
n.id AS id_c,
|
||||
n.name AS name_c,
|
||||
0 AS base_affinity
|
||||
FROM uma_names n JOIN uma_names m ON n.id != m.id
|
||||
|
||||
UNION ALL
|
||||
-- B = C
|
||||
SELECT
|
||||
m.id AS id_a,
|
||||
m.name AS name_a,
|
||||
n.id AS id_a,
|
||||
n.name AS id_b,
|
||||
n.id AS id_c,
|
||||
n.name AS name_c,
|
||||
0 AS base_affinity
|
||||
FROM uma_names n JOIN uma_names m ON n.id != m.id
|
||||
)
|
||||
SELECT * FROM affinity
|
||||
ORDER BY id_a, id_b, id_c
|
||||
@@ -1,72 +0,0 @@
|
||||
{{ define "go-character" -}}
|
||||
package {{ $.Region }}
|
||||
|
||||
// Automatically generated with horsegen; DO NOT EDIT
|
||||
|
||||
import . "git.sunturtle.xyz/zephyr/horse/horse"
|
||||
|
||||
const (
|
||||
{{- range $c := $.Characters }}
|
||||
Character{{ goenum $c.Name }} CharacterID = {{ $c.ID }} // {{ $c.Name }}
|
||||
{{- end }}
|
||||
)
|
||||
|
||||
var OrderedCharacters = [...]CharacterID{
|
||||
{{- range $c := $.Characters }}
|
||||
Character{{ goenum $c.Name }},
|
||||
{{- end }}
|
||||
}
|
||||
|
||||
var Characters = map[CharacterID]Character{
|
||||
{{- range $c := $.Characters }}
|
||||
Character{{ goenum $c.Name }}: {ID: {{ $c.ID }}, Name: {{ printf "%q" $c.Name -}} },
|
||||
{{- end }}
|
||||
}
|
||||
|
||||
var CharacterNameToID = map[string]CharacterID{
|
||||
{{- range $c := $.Characters }}
|
||||
{{ printf "%q" $c.Name }}: {{ $c.ID }},
|
||||
{{- end }}
|
||||
}
|
||||
|
||||
var pairAffinity = []int8{
|
||||
{{- range $a := $.Characters -}}
|
||||
{{- range $b := $.Characters -}}
|
||||
{{- index $.PairMaps $a.ID $b.ID -}},
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
}
|
||||
|
||||
var trioAffinity = []int8{
|
||||
{{- range $a := $.Characters -}}
|
||||
{{- range $b := $.Characters -}}
|
||||
{{- range $c := $.Characters -}}
|
||||
{{- index $.TrioMaps $a.ID $b.ID $c.ID -}},
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
}
|
||||
|
||||
func PairAffinity(a, b CharacterID) int {
|
||||
if _, ok := Characters[a]; !ok {
|
||||
return 0
|
||||
}
|
||||
if _, ok := Characters[b]; !ok {
|
||||
return 0
|
||||
}
|
||||
return int(pairAffinity[a*{{ $.CharaCount }} + b])
|
||||
}
|
||||
|
||||
func TrioAffinity(a, b, c CharacterID) int {
|
||||
if _, ok := Characters[a]; !ok {
|
||||
return 0
|
||||
}
|
||||
if _, ok := Characters[b]; !ok {
|
||||
return 0
|
||||
}
|
||||
if _, ok := Characters[c]; !ok {
|
||||
return 0
|
||||
}
|
||||
return int(trioAffinity[a*{{ $.CharaCount }}*{{ $.CharaCount }} + b*{{ $.CharaCount }} + c])
|
||||
}
|
||||
{{ end }}
|
||||
@@ -1,94 +0,0 @@
|
||||
{{ define "koka-character" -}}
|
||||
module horse/{{ $.Region }}/character
|
||||
|
||||
// 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/character
|
||||
|
||||
extern create-id-table(): vector<int>
|
||||
c inline "int32_t arr[] = { {{- range $chara := $.Characters }}{{ $chara.ID }},{{ end -}} };\nkk_vector_from_cint32array(arr, (kk_ssize_t){{ $.CharaCount }}, kk_context())"
|
||||
js inline "[{{ range $chara := $.Characters }}{{ $chara.ID }},{{ end }}]"
|
||||
// Vector of all character ID values 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(Character-id(id).show, id)
|
||||
m
|
||||
|
||||
// Get the character ID that has the given exact name.
|
||||
// If no character matches the name, the result is an invalid ID.
|
||||
pub fun from-name(name: string): character-id
|
||||
Character-id(name2id().rb-map/lookup(name).default(0))
|
||||
|
||||
// Get the name for a character.
|
||||
// If no character matches the ID, the result is the numeric ID.
|
||||
pub fun show(c: character-id): string
|
||||
match c.game-id
|
||||
{{- range $chara := $.Characters }}
|
||||
{{ $chara.ID }} -> {{ printf "%q" $chara.Name }}
|
||||
{{- end }}
|
||||
x -> "character " ++ x.show
|
||||
|
||||
fun character/index(c: character-id): int
|
||||
match c.game-id
|
||||
{{- range $chara := $.Characters }}
|
||||
{{ $chara.ID }} -> {{ $chara.Index }}
|
||||
{{- end }}
|
||||
_ -> -99999999
|
||||
|
||||
// Create the table of all pair affinities.
|
||||
// The affinity is the value at a.index*count + b.index.
|
||||
extern global/create-pair-table(): vector<int>
|
||||
c inline "int32_t arr[] = {
|
||||
{{- range $a := $.Characters }}
|
||||
{{- range $b := $.Characters }}
|
||||
{{- index $.PairMaps $a.ID $b.ID }},
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
};\nkk_vector_from_cint32array(arr, (kk_ssize_t){{ $.CharaCount }} * (kk_ssize_t){{ $.CharaCount }}, kk_context())"
|
||||
js inline "[
|
||||
{{- range $a := $.Characters }}
|
||||
{{- range $b := $.Characters }}
|
||||
{{- index $.PairMaps $a.ID $b.ID }},
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
]"
|
||||
val global/pair-table = global/create-pair-table()
|
||||
|
||||
// Base affinity between a pair using the global ruleset.
|
||||
pub fun global/pair-affinity(a: character-id, b: character-id): int
|
||||
global/pair-table.at(a.index * {{ $.CharaCount }} + b.index).default(0)
|
||||
|
||||
// Create the table of all trio affinities.
|
||||
// The affinity is the value at a.index*count*count + b.index*count + c.index.
|
||||
extern global/create-trio-table(): vector<int>
|
||||
c inline "int32_t arr[] = {
|
||||
{{- range $a := $.Characters }}
|
||||
{{- range $b := $.Characters }}
|
||||
{{- range $c := $.Characters }}
|
||||
{{- index $.TrioMaps $a.ID $b.ID $c.ID }},
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
};\nkk_vector_from_cint32array(arr, (kk_ssize_t){{ $.CharaCount }} * (kk_ssize_t){{ $.CharaCount }} * (kk_ssize_t){{ $.CharaCount }}, kk_context())"
|
||||
js inline "[
|
||||
{{- range $a := $.Characters }}
|
||||
{{- range $b := $.Characters }}
|
||||
{{- range $c := $.Characters }}
|
||||
{{- index $.TrioMaps $a.ID $b.ID $c.ID }},
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
]"
|
||||
val global/trio-table = global/create-trio-table()
|
||||
|
||||
// Base affinity for a trio using the global ruleset.
|
||||
pub fun global/trio-affinity(a: character-id, b: character-id, c: character-id): int
|
||||
global/trio-table.at(a.index * {{ $.CharaCount }} * {{ $.CharaCount }} + b.index * {{ $.CharaCount }} + c.index).default(0)
|
||||
{{ end }}
|
||||
-263
@@ -1,263 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"regexp"
|
||||
"strings"
|
||||
"text/template"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
//go:embed *.template
|
||||
var templates embed.FS
|
||||
|
||||
// LoadTemplates sets up templates to render game data to source code.
|
||||
func LoadTemplates() (*template.Template, error) {
|
||||
t := template.New("root")
|
||||
t.Funcs(template.FuncMap{
|
||||
"kkenum": kkenum,
|
||||
"goenum": goenum,
|
||||
})
|
||||
return t.ParseFS(templates, "*")
|
||||
}
|
||||
|
||||
// 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, region string, 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))
|
||||
}
|
||||
if len(trios) != len(c)*len(c)*len(c) {
|
||||
return fmt.Errorf("there are %d trios but there must be %d for %d characters", len(trios), len(c)*len(c)*len(c), len(c))
|
||||
}
|
||||
|
||||
maxid := 0
|
||||
pm := make(map[int]map[int]int, len(c))
|
||||
tm := make(map[int]map[int]map[int]int, len(c))
|
||||
for _, u := range c {
|
||||
maxid = max(maxid, u.ID)
|
||||
pm[u.ID] = make(map[int]int, len(c))
|
||||
tm[u.ID] = make(map[int]map[int]int, len(c))
|
||||
for _, v := range c {
|
||||
tm[u.ID][v.ID] = make(map[int]int, len(c))
|
||||
}
|
||||
}
|
||||
for _, p := range pairs {
|
||||
pm[p.IDA][p.IDB] = p.Affinity
|
||||
}
|
||||
for _, t := range trios {
|
||||
tm[t.IDA][t.IDB][t.IDC] = t.Affinity
|
||||
}
|
||||
|
||||
data := struct {
|
||||
Region string
|
||||
Characters []NamedID[Character]
|
||||
Pairs []AffinityRelation
|
||||
Trios []AffinityRelation
|
||||
PairMaps map[int]map[int]int
|
||||
TrioMaps map[int]map[int]map[int]int
|
||||
CharaCount int
|
||||
MaxID int
|
||||
}{region, c, pairs, trios, pm, tm, len(c), maxid}
|
||||
var err error
|
||||
if kk != nil {
|
||||
err = errors.Join(err, t.ExecuteTemplate(kk, "koka-character", &data))
|
||||
}
|
||||
if g != nil {
|
||||
err = errors.Join(err, t.ExecuteTemplate(g, "go-character", &data))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func ExecSkill(t *template.Template, region string, kk, g io.Writer, groups []NamedID[SkillGroup], skills []Skill) error {
|
||||
m := make(map[int][]Skill, len(groups))
|
||||
for _, t := range skills {
|
||||
m[t.GroupID] = append(m[t.GroupID], t)
|
||||
}
|
||||
data := struct {
|
||||
Region string
|
||||
Groups []NamedID[SkillGroup]
|
||||
Skills []Skill
|
||||
Related map[int][]Skill
|
||||
SkillCount int
|
||||
}{region, groups, skills, m, len(skills)}
|
||||
var err error
|
||||
if kk != nil {
|
||||
err = errors.Join(err, t.ExecuteTemplate(kk, "koka-skill", &data))
|
||||
}
|
||||
if g != nil {
|
||||
err = errors.Join(err, t.ExecuteTemplate(g, "go-skill-data", &data))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func ExecRace(t *template.Template, region string, kk, g io.Writer, races []Race) error {
|
||||
data := struct {
|
||||
Region string
|
||||
Races []Race
|
||||
RaceCount int
|
||||
}{region, races, len(races)}
|
||||
var err error
|
||||
if kk != nil {
|
||||
err = errors.Join(err, t.ExecuteTemplate(kk, "koka-race", &data))
|
||||
}
|
||||
if g != nil {
|
||||
err = errors.Join(err, t.ExecuteTemplate(g, "go-race", &data))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func ExecSaddle(t *template.Template, region string, kk, g io.Writer, saddles []Saddle) error {
|
||||
data := struct {
|
||||
Region string
|
||||
Saddles []Saddle
|
||||
SaddleCount int
|
||||
}{region, saddles, len(saddles)}
|
||||
var err error
|
||||
if kk != nil {
|
||||
err = errors.Join(err, t.ExecuteTemplate(kk, "koka-saddle", &data))
|
||||
}
|
||||
if g != nil {
|
||||
err = errors.Join(err, t.ExecuteTemplate(g, "go-saddle", &data))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func ExecScenario(t *template.Template, region string, kk, g io.Writer, scen []Scenario) error {
|
||||
data := struct {
|
||||
Region string
|
||||
Scenarios []Scenario
|
||||
ScenarioCount int
|
||||
}{region, scen, len(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
|
||||
}
|
||||
|
||||
func ExecSparks(t *template.Template, region string, kk, g io.Writer, sparks []Spark, effects map[int]map[int][]SparkEffect) error {
|
||||
data := struct {
|
||||
Region string
|
||||
Sparks []Spark
|
||||
SparkEffects map[int]map[int][]SparkEffect
|
||||
SparkCount int
|
||||
}{region, sparks, effects, len(sparks)}
|
||||
var err error
|
||||
if kk != nil {
|
||||
err = errors.Join(err, t.ExecuteTemplate(kk, "koka-spark", &data))
|
||||
}
|
||||
if g != nil {
|
||||
err = errors.Join(err, t.ExecuteTemplate(g, "go-spark", &data))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
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 {
|
||||
r := []string{
|
||||
"Triple 7s", "Triple-Sevens", // hard to replace with the right thing automatically
|
||||
"1,500,000 CC", "One-Million-CC",
|
||||
"15,000,000 CC", "Fifteen-Million-CC",
|
||||
"1st", "First",
|
||||
"114th", "Hundred-Fourteenth",
|
||||
"♡ 3D Nail Art", "Nail-Art",
|
||||
".", "",
|
||||
"\u2019", "",
|
||||
"&", "-and-",
|
||||
"'s", "s",
|
||||
"ó", "o",
|
||||
"∞", "Infinity",
|
||||
"\u00d7", "x",
|
||||
"◎", "Lv2",
|
||||
}
|
||||
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",
|
||||
".", "",
|
||||
"\u2019", "",
|
||||
"&", "And",
|
||||
"'s", "s",
|
||||
"∞", "Infinity",
|
||||
"\u00d7", "X",
|
||||
"◎", "Lv2",
|
||||
}
|
||||
for _, c := range wordSeps {
|
||||
r = append(r, string(c), "")
|
||||
}
|
||||
return strings.NewReplacer(r...)
|
||||
}()
|
||||
)
|
||||
|
||||
func kkenum(name string) string {
|
||||
orig := name
|
||||
name = kkReplace.Replace(name)
|
||||
name = kkMultidash.ReplaceAllLiteralString(name, "-")
|
||||
name = strings.Trim(name, "-")
|
||||
if len(name) == 0 {
|
||||
panic(fmt.Errorf("%q became empty as Koka enum variant", orig))
|
||||
}
|
||||
name = strings.ToUpper(name[:1]) + name[1:]
|
||||
if !unicode.IsLetter(rune(name[0])) {
|
||||
//lint:ignore ST1005 proper name
|
||||
panic(fmt.Errorf("Koka enum variant %q (from %q) starts with a non-letter", name, orig))
|
||||
}
|
||||
for _, c := range name {
|
||||
if c > 127 {
|
||||
// Koka does not allow non-ASCII characters in source code.
|
||||
// Don't proceed if we've missed one.
|
||||
panic(fmt.Errorf("non-ASCII character %q (%[1]U) in Koka enum variant %q (from %q)", c, name, orig))
|
||||
}
|
||||
}
|
||||
if kkDashNonletter.MatchString(name) {
|
||||
panic(fmt.Errorf("non-letter character after a dash in Koka enum variant %q (from %q)", name, orig))
|
||||
}
|
||||
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
|
||||
}
|
||||
@@ -1,613 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
|
||||
"zombiezen.com/go/sqlite/sqlitex"
|
||||
)
|
||||
|
||||
//go:embed character.sql
|
||||
var characterSQL string
|
||||
|
||||
//go:embed character.affinity2.sql
|
||||
var characterAffinity2SQL string
|
||||
|
||||
//go:embed character.affinity3.sql
|
||||
var characterAffinity3SQL string
|
||||
|
||||
//go:embed uma.sql
|
||||
var umaSQL string
|
||||
|
||||
//go:embed skill-group.sql
|
||||
var skillGroupSQL string
|
||||
|
||||
//go:embed skill.sql
|
||||
var skillSQL string
|
||||
|
||||
//go:embed race.sql
|
||||
var raceSQL string
|
||||
|
||||
//go:embed saddle.sql
|
||||
var saddleSQL string
|
||||
|
||||
//go:embed scenario.sql
|
||||
var scenarioSQL string
|
||||
|
||||
//go:embed spark.sql
|
||||
var sparkSQL string
|
||||
|
||||
//go:embed spark-effect.sql
|
||||
var sparkEffectSQL string
|
||||
|
||||
type (
|
||||
Character struct{}
|
||||
SkillGroup struct{}
|
||||
)
|
||||
|
||||
type NamedID[T any] struct {
|
||||
// Disallow conversions between NamedID types.
|
||||
_ [0]*T
|
||||
|
||||
ID int
|
||||
Name string
|
||||
// For internal use, the index of the identity, when it's needed.
|
||||
// We don't show this in public API, but it lets us use vectors for lookups.
|
||||
Index int
|
||||
}
|
||||
|
||||
func Characters(ctx context.Context, db *sqlitex.Pool) ([]NamedID[Character], error) {
|
||||
conn, err := db.Take(ctx)
|
||||
defer db.Put(conn)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't get connection for characters: %w", err)
|
||||
}
|
||||
stmt, _, err := conn.PrepareTransient(characterSQL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't prepare statement for characters: %w", err)
|
||||
}
|
||||
defer stmt.Finalize()
|
||||
|
||||
var r []NamedID[Character]
|
||||
for {
|
||||
ok, err := stmt.Step()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error stepping characters: %w", err)
|
||||
}
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
c := NamedID[Character]{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Name: stmt.ColumnText(1),
|
||||
Index: stmt.ColumnInt(2),
|
||||
}
|
||||
r = append(r, c)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
type AffinityRelation struct {
|
||||
IDA int
|
||||
NameA string
|
||||
IDB int
|
||||
NameB string
|
||||
IDC int
|
||||
NameC string
|
||||
Affinity int
|
||||
}
|
||||
|
||||
func CharacterPairs(ctx context.Context, db *sqlitex.Pool) ([]AffinityRelation, error) {
|
||||
conn, err := db.Take(ctx)
|
||||
defer db.Put(conn)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't get connection for character pairs: %w", err)
|
||||
}
|
||||
stmt, _, err := conn.PrepareTransient(characterAffinity2SQL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't prepare statement for character pairs: %w", err)
|
||||
}
|
||||
defer stmt.Finalize()
|
||||
|
||||
var r []AffinityRelation
|
||||
for {
|
||||
ok, err := stmt.Step()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error stepping character pairs: %w", err)
|
||||
}
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
p := AffinityRelation{
|
||||
IDA: stmt.ColumnInt(0),
|
||||
NameA: stmt.ColumnText(1),
|
||||
IDB: stmt.ColumnInt(2),
|
||||
NameB: stmt.ColumnText(3),
|
||||
Affinity: stmt.ColumnInt(4),
|
||||
}
|
||||
r = append(r, p)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func CharacterTrios(ctx context.Context, db *sqlitex.Pool) ([]AffinityRelation, error) {
|
||||
conn, err := db.Take(ctx)
|
||||
defer db.Put(conn)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't get connection for character trios: %w", err)
|
||||
}
|
||||
stmt, _, err := conn.PrepareTransient(characterAffinity3SQL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't prepare statement for character trios: %w", err)
|
||||
}
|
||||
defer stmt.Finalize()
|
||||
|
||||
var r []AffinityRelation
|
||||
for {
|
||||
ok, err := stmt.Step()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error stepping character trios: %w", err)
|
||||
}
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
p := AffinityRelation{
|
||||
IDA: stmt.ColumnInt(0),
|
||||
NameA: stmt.ColumnText(1),
|
||||
IDB: stmt.ColumnInt(2),
|
||||
NameB: stmt.ColumnText(3),
|
||||
IDC: stmt.ColumnInt(4),
|
||||
NameC: stmt.ColumnText(5),
|
||||
Affinity: stmt.ColumnInt(6),
|
||||
}
|
||||
r = append(r, p)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func SkillGroups(ctx context.Context, db *sqlitex.Pool) ([]NamedID[SkillGroup], error) {
|
||||
conn, err := db.Take(ctx)
|
||||
defer db.Put(conn)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't get connection for skill groups: %w", err)
|
||||
}
|
||||
stmt, _, err := conn.PrepareTransient(skillGroupSQL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't prepare statement for skill groups: %w", err)
|
||||
}
|
||||
defer stmt.Finalize()
|
||||
|
||||
var r []NamedID[SkillGroup]
|
||||
for {
|
||||
ok, err := stmt.Step()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error stepping skill groups: %w", err)
|
||||
}
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
g := NamedID[SkillGroup]{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Name: stmt.ColumnText(1),
|
||||
}
|
||||
r = append(r, g)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
type Skill struct {
|
||||
ID int
|
||||
Name string
|
||||
Description string
|
||||
GroupID int
|
||||
GroupName string
|
||||
Rarity int
|
||||
GroupRate int
|
||||
GradeValue int
|
||||
WitCheck bool
|
||||
Activations [2]SkillActivation
|
||||
SPCost int
|
||||
InheritID int
|
||||
UniqueOwnerID int
|
||||
UniqueOwner string
|
||||
IconID int
|
||||
Index int
|
||||
}
|
||||
|
||||
type SkillActivation struct {
|
||||
Precondition string
|
||||
Condition string
|
||||
Duration int
|
||||
DurScale int
|
||||
Cooldown int
|
||||
Abilities [3]SkillAbility
|
||||
}
|
||||
|
||||
type SkillAbility struct {
|
||||
Type int
|
||||
ValueUsage int
|
||||
Value int
|
||||
Target int
|
||||
TargetValue int
|
||||
}
|
||||
|
||||
func Skills(ctx context.Context, db *sqlitex.Pool) ([]Skill, error) {
|
||||
conn, err := db.Take(ctx)
|
||||
defer db.Put(conn)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't get connection for skills: %w", err)
|
||||
}
|
||||
stmt, _, err := conn.PrepareTransient(skillSQL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't prepare statement for skills: %w", err)
|
||||
}
|
||||
defer stmt.Finalize()
|
||||
|
||||
var r []Skill
|
||||
for {
|
||||
ok, err := stmt.Step()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error stepping skills: %w", err)
|
||||
}
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
s := Skill{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Name: stmt.ColumnText(1),
|
||||
Description: stmt.ColumnText(2),
|
||||
GroupID: stmt.ColumnInt(3),
|
||||
GroupName: stmt.ColumnText(4),
|
||||
Rarity: stmt.ColumnInt(5),
|
||||
GroupRate: stmt.ColumnInt(6),
|
||||
GradeValue: stmt.ColumnInt(7),
|
||||
WitCheck: stmt.ColumnInt(8) != 0,
|
||||
Activations: [2]SkillActivation{
|
||||
{
|
||||
Precondition: stmt.ColumnText(9),
|
||||
Condition: stmt.ColumnText(10),
|
||||
Duration: stmt.ColumnInt(11),
|
||||
DurScale: stmt.ColumnInt(12),
|
||||
Cooldown: stmt.ColumnInt(13),
|
||||
Abilities: [3]SkillAbility{
|
||||
{
|
||||
Type: stmt.ColumnInt(14),
|
||||
ValueUsage: stmt.ColumnInt(15),
|
||||
Value: stmt.ColumnInt(16),
|
||||
Target: stmt.ColumnInt(17),
|
||||
TargetValue: stmt.ColumnInt(18),
|
||||
},
|
||||
{
|
||||
Type: stmt.ColumnInt(19),
|
||||
ValueUsage: stmt.ColumnInt(20),
|
||||
Value: stmt.ColumnInt(21),
|
||||
Target: stmt.ColumnInt(22),
|
||||
TargetValue: stmt.ColumnInt(23),
|
||||
},
|
||||
{
|
||||
Type: stmt.ColumnInt(24),
|
||||
ValueUsage: stmt.ColumnInt(25),
|
||||
Value: stmt.ColumnInt(26),
|
||||
Target: stmt.ColumnInt(27),
|
||||
TargetValue: stmt.ColumnInt(28),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Precondition: stmt.ColumnText(29),
|
||||
Condition: stmt.ColumnText(30),
|
||||
Duration: stmt.ColumnInt(31),
|
||||
DurScale: stmt.ColumnInt(32),
|
||||
Cooldown: stmt.ColumnInt(33),
|
||||
Abilities: [3]SkillAbility{
|
||||
{
|
||||
Type: stmt.ColumnInt(34),
|
||||
ValueUsage: stmt.ColumnInt(35),
|
||||
Value: stmt.ColumnInt(36),
|
||||
Target: stmt.ColumnInt(37),
|
||||
TargetValue: stmt.ColumnInt(38),
|
||||
},
|
||||
{
|
||||
Type: stmt.ColumnInt(39),
|
||||
ValueUsage: stmt.ColumnInt(40),
|
||||
Value: stmt.ColumnInt(41),
|
||||
Target: stmt.ColumnInt(42),
|
||||
TargetValue: stmt.ColumnInt(43),
|
||||
},
|
||||
{
|
||||
Type: stmt.ColumnInt(44),
|
||||
ValueUsage: stmt.ColumnInt(45),
|
||||
Value: stmt.ColumnInt(46),
|
||||
Target: stmt.ColumnInt(47),
|
||||
TargetValue: stmt.ColumnInt(48),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
SPCost: stmt.ColumnInt(49),
|
||||
InheritID: stmt.ColumnInt(50),
|
||||
UniqueOwnerID: stmt.ColumnInt(51),
|
||||
UniqueOwner: stmt.ColumnText(52),
|
||||
IconID: stmt.ColumnInt(53),
|
||||
Index: stmt.ColumnInt(54),
|
||||
}
|
||||
r = append(r, s)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
type Race struct {
|
||||
ID int
|
||||
Name string
|
||||
Grade int
|
||||
ThumbnailID int
|
||||
Primary int
|
||||
Alternate int
|
||||
}
|
||||
|
||||
func Races(ctx context.Context, db *sqlitex.Pool) ([]Race, error) {
|
||||
conn, err := db.Take(ctx)
|
||||
defer db.Put(conn)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't get connection for races: %w", err)
|
||||
}
|
||||
stmt, _, err := conn.PrepareTransient(raceSQL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't prepare statement for races: %w", err)
|
||||
}
|
||||
defer stmt.Finalize()
|
||||
|
||||
var r []Race
|
||||
for {
|
||||
ok, err := stmt.Step()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error stepping races: %w", err)
|
||||
}
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
race := Race{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Name: stmt.ColumnText(1),
|
||||
Grade: stmt.ColumnInt(2),
|
||||
ThumbnailID: stmt.ColumnInt(3),
|
||||
Primary: stmt.ColumnInt(4),
|
||||
Alternate: stmt.ColumnInt(5),
|
||||
}
|
||||
r = append(r, race)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
type Saddle struct {
|
||||
ID int
|
||||
Name string
|
||||
Races [3]int
|
||||
Type int
|
||||
Primary int
|
||||
Alternate int
|
||||
}
|
||||
|
||||
func Saddles(ctx context.Context, db *sqlitex.Pool) ([]Saddle, error) {
|
||||
conn, err := db.Take(ctx)
|
||||
defer db.Put(conn)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't get connection for saddles: %w", err)
|
||||
}
|
||||
stmt, _, err := conn.PrepareTransient(saddleSQL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't prepare statement for saddles: %w", err)
|
||||
}
|
||||
defer stmt.Finalize()
|
||||
|
||||
var r []Saddle
|
||||
for {
|
||||
ok, err := stmt.Step()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error stepping saddles: %w", err)
|
||||
}
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
s := Saddle{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Name: stmt.ColumnText(1),
|
||||
Races: [3]int{stmt.ColumnInt(2), stmt.ColumnInt(3), stmt.ColumnInt(4)},
|
||||
Type: stmt.ColumnInt(5),
|
||||
Primary: stmt.ColumnInt(6),
|
||||
Alternate: stmt.ColumnInt(7),
|
||||
}
|
||||
r = append(r, s)
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
type Spark struct {
|
||||
ID int
|
||||
Name string
|
||||
Description string
|
||||
Group int
|
||||
Rarity int
|
||||
Type int
|
||||
}
|
||||
|
||||
type SparkEffect struct {
|
||||
Target int
|
||||
Value1 int
|
||||
Value2 int
|
||||
}
|
||||
|
||||
func Sparks(ctx context.Context, db *sqlitex.Pool) ([]Spark, error) {
|
||||
conn, err := db.Take(ctx)
|
||||
defer db.Put(conn)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't get connection for sparks: %w", err)
|
||||
}
|
||||
stmt, _, err := conn.PrepareTransient(sparkSQL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't prepare statement for sparks: %w", err)
|
||||
}
|
||||
defer stmt.Finalize()
|
||||
|
||||
var r []Spark
|
||||
for {
|
||||
ok, err := stmt.Step()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error stepping sparks: %w", err)
|
||||
}
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
s := Spark{
|
||||
ID: stmt.ColumnInt(0),
|
||||
Name: stmt.ColumnText(1),
|
||||
Description: stmt.ColumnText(2),
|
||||
Group: stmt.ColumnInt(3),
|
||||
Rarity: stmt.ColumnInt(4),
|
||||
Type: stmt.ColumnInt(5),
|
||||
}
|
||||
r = append(r, s)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func SparkEffects(ctx context.Context, db *sqlitex.Pool) (map[int]map[int][]SparkEffect, error) {
|
||||
conn, err := db.Take(ctx)
|
||||
defer db.Put(conn)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't get connection for spark effects: %w", err)
|
||||
}
|
||||
stmt, _, err := conn.PrepareTransient(sparkEffectSQL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't prepare statement for spark effects: %w", err)
|
||||
}
|
||||
defer stmt.Finalize()
|
||||
|
||||
r := make(map[int]map[int][]SparkEffect)
|
||||
for {
|
||||
ok, err := stmt.Step()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error stepping spark effects: %w", err)
|
||||
}
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
group := stmt.ColumnInt(0)
|
||||
eff := stmt.ColumnInt(1)
|
||||
s := SparkEffect{
|
||||
Target: stmt.ColumnInt(2),
|
||||
Value1: stmt.ColumnInt(3),
|
||||
Value2: stmt.ColumnInt(4),
|
||||
}
|
||||
if r[group] == nil {
|
||||
r[group] = make(map[int][]SparkEffect)
|
||||
}
|
||||
r[group][eff] = append(r[group][eff], s)
|
||||
}
|
||||
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
|
||||
}
|
||||
@@ -1,227 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
"zombiezen.com/go/sqlite"
|
||||
"zombiezen.com/go/sqlite/sqlitex"
|
||||
)
|
||||
|
||||
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(®ion, "region", "global", "region the database is for (global, jp)")
|
||||
flag.Parse()
|
||||
|
||||
pctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
|
||||
go func() {
|
||||
<-pctx.Done()
|
||||
stop()
|
||||
}()
|
||||
|
||||
t, err := LoadTemplates()
|
||||
if err != nil {
|
||||
slog.Error("loading templates", slog.Any("err", err))
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
eg, ctx := errgroup.WithContext(pctx)
|
||||
var (
|
||||
charas []NamedID[Character]
|
||||
pairs []AffinityRelation
|
||||
trios []AffinityRelation
|
||||
sg []NamedID[SkillGroup]
|
||||
skills []Skill
|
||||
races []Race
|
||||
saddles []Saddle
|
||||
scens []Scenario
|
||||
sparks []Spark
|
||||
sparkeff map[int]map[int][]SparkEffect
|
||||
umas []Uma
|
||||
)
|
||||
eg.Go(func() error {
|
||||
slog.Info("get characters")
|
||||
r, err := Characters(ctx, db)
|
||||
charas = r
|
||||
return err
|
||||
})
|
||||
eg.Go(func() error {
|
||||
slog.Info("get pairs")
|
||||
r, err := CharacterPairs(ctx, db)
|
||||
pairs = r
|
||||
return err
|
||||
})
|
||||
eg.Go(func() error {
|
||||
slog.Info("get trios")
|
||||
r, err := CharacterTrios(ctx, db)
|
||||
trios = r
|
||||
return err
|
||||
})
|
||||
eg.Go(func() error {
|
||||
slog.Info("get skill groups")
|
||||
r, err := SkillGroups(ctx, db)
|
||||
sg = r
|
||||
return err
|
||||
})
|
||||
eg.Go(func() error {
|
||||
slog.Info("get skills")
|
||||
r, err := Skills(ctx, db)
|
||||
skills = r
|
||||
return err
|
||||
})
|
||||
eg.Go(func() error {
|
||||
slog.Info("get races")
|
||||
r, err := Races(ctx, db)
|
||||
races = r
|
||||
return err
|
||||
})
|
||||
eg.Go(func() error {
|
||||
slog.Info("get saddles")
|
||||
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
|
||||
})
|
||||
eg.Go(func() error {
|
||||
slog.Info("get sparks")
|
||||
r, err := Sparks(ctx, db)
|
||||
sparks = r
|
||||
return err
|
||||
})
|
||||
eg.Go(func() error {
|
||||
slog.Info("get spark effects")
|
||||
r, err := SparkEffects(ctx, db)
|
||||
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)
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(filepath.Join(out, region), 0775); err != nil {
|
||||
slog.Error("create output dir", slog.Any("err", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
eg, ctx = errgroup.WithContext(pctx)
|
||||
eg.Go(func() error {
|
||||
cf, err := os.Create(filepath.Join(out, region, "character.kk"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
gf, err := os.Create(filepath.Join(out, region, "character.go"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
slog.Info("write characters")
|
||||
return ExecCharacter(t, region, cf, gf, charas, pairs, trios)
|
||||
})
|
||||
eg.Go(func() error {
|
||||
sf, err := os.Create(filepath.Join(out, region, "skill.kk"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
gf, err := os.Create(filepath.Join(out, region, "skill.go"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
slog.Info("write skills")
|
||||
return ExecSkill(t, region, sf, gf, sg, skills)
|
||||
})
|
||||
eg.Go(func() error {
|
||||
kf, err := os.Create(filepath.Join(out, region, "race.kk"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
gf, err := os.Create(filepath.Join(out, region, "race.go"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
slog.Info("write races")
|
||||
return ExecRace(t, region, kf, gf, races)
|
||||
})
|
||||
eg.Go(func() error {
|
||||
kf, err := os.Create(filepath.Join(out, region, "saddle.kk"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
gf, err := os.Create(filepath.Join(out, region, "saddle.go"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
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)
|
||||
})
|
||||
eg.Go(func() error {
|
||||
kf, err := os.Create(filepath.Join(out, region, "spark.kk"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
gf, err := os.Create(filepath.Join(out, region, "spark.go"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
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)
|
||||
} else {
|
||||
slog.Info("done")
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
{{- define "go-race" -}}
|
||||
package {{ $.Region }}
|
||||
|
||||
// Automatically generated with horsegen; DO NOT EDIT
|
||||
|
||||
import . "git.sunturtle.xyz/zephyr/horse/horse"
|
||||
|
||||
const (
|
||||
{{- range $r := $.Races }}
|
||||
Race{{ goenum $r.Name }}{{ if $r.Alternate }}Alt{{ $r.ID }}{{ end }} RaceID = {{ $r.ID }} // {{ $r.Name }}
|
||||
{{- end }}
|
||||
)
|
||||
|
||||
var AllRaces = map[RaceID]Race{
|
||||
{{- range $r := $.Races }}
|
||||
Race{{ goenum $r.Name }}{{ if $r.Alternate }}Alt{{ $r.ID }}{{ end }}: {
|
||||
ID: {{ $r.ID }},
|
||||
Name: {{ printf "%q" $r.Name }}{{ if $r.Alternate }} + " (Alternate {{ $r.ID }})"{{ end }},
|
||||
Thumbnail: {{ $r.ThumbnailID }},
|
||||
{{- if ne $r.Primary $r.ID }}
|
||||
Primary: {{ $r.Primary }},
|
||||
{{- end }}
|
||||
},
|
||||
{{- end }}
|
||||
}
|
||||
|
||||
var RaceNameToID = map[string]RaceID{
|
||||
{{- range $r := $.Races }}
|
||||
{{ printf "%q" $r.Name }}{{ if $r.Alternate }} + " (Alternate {{ $r.ID }})"{{ end }}: {{ $r.ID }},
|
||||
{{- end }}
|
||||
}
|
||||
{{ end }}
|
||||
@@ -1,69 +0,0 @@
|
||||
{{- define "koka-race" -}}
|
||||
module horse/{{ $.Region }}/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[] = { {{- range $r := $.Races }}{{ $r.ID }},{{ end -}} };\nkk_vector_from_cint32array(arr, (kk_ssize_t){{ $.RaceCount }}, kk_context())"
|
||||
js inline "[{{ range $r := $.Races }}{{ $r.ID }},{{ end }}]"
|
||||
// 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
|
||||
{{- range $r := $.Races }}
|
||||
{{ $r.ID }} -> {{ printf "%q" $r.Name }}{{ if $r.Alternate }} ++ " (Alternate {{ $r.ID }})"{{ end }}
|
||||
{{- end }}
|
||||
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
|
||||
{{- range $r := $.Races }}
|
||||
{{ $r.ID }} -> {{ if eq $r.Grade 100 }}G1{{ else if eq $r.Grade 200 }}G2{{ else if eq $r.Grade 300 }}G3{{ else if eq $r.Grade 400 }}OP{{ else if eq $r.Grade 700 }}Pre-OP{{ else }}??? $r.Grade={{ $r.Grade }}{{ end }}
|
||||
{{- end }}
|
||||
_ -> 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
|
||||
{{- range $r := $.Races }}
|
||||
{{ $r.ID }} -> Race-thumbnail-id({{ $r.ThumbnailID }})
|
||||
{{- end }}
|
||||
_ -> 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
|
||||
{{- range $r := $.Races }}
|
||||
{{- if $r.Alternate }}
|
||||
{{ $r.ID }} -> Race-id({{ $r.Primary }})
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
_ -> r
|
||||
{{ end }}
|
||||
@@ -1,27 +0,0 @@
|
||||
{{- define "go-saddle" -}}
|
||||
package {{ $.Region }}
|
||||
|
||||
// Automatically generated with horsegen; DO NOT EDIT
|
||||
|
||||
import . "git.sunturtle.xyz/zephyr/horse/horse"
|
||||
|
||||
const (
|
||||
{{- range $s := $.Saddles }}
|
||||
Saddle{{ goenum $s.Name }}{{ if $s.Alternate }}Alt{{ $s.Alternate }}{{ end }} SaddleID = {{ $s.ID }} // {{ $s.Name }}
|
||||
{{- end }}
|
||||
)
|
||||
|
||||
var AllSaddles = map[SaddleID]Saddle{
|
||||
{{- range $s := $.Saddles }}
|
||||
Saddle{{ goenum $s.Name }}{{ if $s.Alternate }}Alt{{ $s.Alternate }}{{ end }}: {
|
||||
ID: {{ $s.ID }},
|
||||
Name: {{ printf "%q" $s.Name }}{{ if $s.Alternate }} + " (Alternate {{ $s.Alternate }})"{{ end }},
|
||||
Races: []RaceID{ {{- range $id := $s.Races }}{{ if $id }}{{ $id }}, {{ end }}{{ end -}} },
|
||||
Type: SaddleType{{ if eq $s.Type 0 }}Honor{{ else if eq $s.Type 1 }}G3{{ else if eq $s.Type 2 }}G2{{ else if eq $s.Type 3 }}G1{{ else }}??? $s.Type={{ $s.Type }}{{ end }},
|
||||
{{- if $s.Alternate }}
|
||||
Primary: {{ $s.Primary }},
|
||||
{{- end }}
|
||||
},
|
||||
{{- end }}
|
||||
}
|
||||
{{ end }}
|
||||
@@ -1,58 +0,0 @@
|
||||
{{- define "koka-saddle" -}}
|
||||
module horse/{{ $.Region }}/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/{{ $.Region }}/race
|
||||
|
||||
extern create-id-table(): vector<int>
|
||||
c inline "int32_t arr[] = { {{- range $s := $.Saddles }}{{ $s.ID }},{{ end -}} };\nkk_vector_from_cint32array(arr, (kk_ssize_t){{ $.SaddleCount }}, kk_context())"
|
||||
js inline "[{{ range $s := $.Saddles }}{{ $s.ID }},{{ end }}]"
|
||||
// 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
|
||||
{{- range $s := $.Saddles }}
|
||||
{{ $s.ID }} -> {{ printf "%q" $s.Name }}{{ if $s.Alternate }} ++ " (Alternate {{ $s.ID }})"{{ end }}
|
||||
{{- end }}
|
||||
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
|
||||
{{- range $s := $.Saddles }}
|
||||
{{ $s.ID }} -> [{{ range $id := $s.Races }}{{ if $id }}Race-id({{ $id }}), {{ end }}{{ end }}]
|
||||
{{- end }}
|
||||
_ -> []
|
||||
|
||||
// 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
|
||||
{{- range $s := $.Saddles }}
|
||||
{{ $s.ID }} -> {{ if eq $s.Type 0 }}Honor{{ else if eq $s.Type 1 }}G3-Win{{ else if eq $s.Type 2 }}G2-Win{{ else if eq $s.Type 3 }}G1-Win{{ else }}??? $s.Type={{ $s.Type }}{{ end }}
|
||||
{{- end }}
|
||||
_ -> 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
|
||||
{{- range $s := $.Saddles }}
|
||||
{{- if $s.Alternate }}
|
||||
{{ $s.ID }} -> Saddle-id({{ $s.Primary }})
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
_ -> s
|
||||
{{ end }}
|
||||
@@ -1,23 +0,0 @@
|
||||
{{- 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 }}
|
||||
@@ -1,34 +0,0 @@
|
||||
{{- define "koka-scenario" -}}
|
||||
module horse/{{ $.Region }}/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[] = { {{- range $s := $.Scenarios }}{{ $s.ID }},{{ end -}} };\nkk_vector_from_cint32array(arr, (kk_ssize_t){{ $.ScenarioCount }}, kk_context())"
|
||||
js inline "[{{ range $s := $.Scenarios }}{{ $s.ID }},{{ end }}]"
|
||||
// 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
|
||||
{{- 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 }}
|
||||
@@ -1,14 +0,0 @@
|
||||
WITH skill_names AS (
|
||||
SELECT
|
||||
"index" AS "id",
|
||||
"text" AS "name"
|
||||
FROM text_data
|
||||
WHERE category = 47
|
||||
)
|
||||
SELECT
|
||||
group_id,
|
||||
name
|
||||
FROM skill_data d
|
||||
JOIN skill_names n ON d.id = n.id
|
||||
WHERE d.group_rate = 1
|
||||
ORDER BY group_id
|
||||
@@ -1,79 +0,0 @@
|
||||
{{- define "go-skill-data" -}}
|
||||
package {{ $.Region }}
|
||||
|
||||
// Automatically generated with horsegen; DO NOT EDIT
|
||||
|
||||
import . "git.sunturtle.xyz/zephyr/horse/horse"
|
||||
|
||||
const (
|
||||
{{- range $s := $.Skills }}
|
||||
Skill{{ goenum $s.Name }}{{ if ne $s.InheritID 0 }}Inherit{{ end }} SkillID = {{ $s.ID }} // {{ $s.Name }}
|
||||
{{- end }}
|
||||
)
|
||||
|
||||
var OrderedSkills = [...]SkillID{
|
||||
{{- range $s := $.Skills }}
|
||||
Skill{{ goenum $s.Name }}{{ if ne $s.InheritID 0 }}Inherit{{ end }},
|
||||
{{- end }}
|
||||
}
|
||||
|
||||
var AllSkills = map[SkillID]Skill{
|
||||
{{- range $s := $.Skills }}
|
||||
Skill{{ goenum $s.Name }}{{ if ne $s.InheritID 0 }}Inherit{{ end }}: {
|
||||
ID: {{ $s.ID }},
|
||||
Name: {{ printf "%q" $s.Name }}{{ if ne $s.InheritID 0 }} + " (Inherited)"{{ end }},
|
||||
Description: {{ printf "%q" $s.Description }},
|
||||
Group: {{ $s.GroupID }},
|
||||
Rarity: {{ $s.Rarity }},
|
||||
GroupRate: {{ $s.GroupRate }},
|
||||
GradeValue: {{ $s.GradeValue }},
|
||||
{{- if $s.WitCheck }}
|
||||
WitCheck: {{ $s.WitCheck }},
|
||||
{{- end }}
|
||||
Activations: []Activation{
|
||||
{{- range $a := $s.Activations }}
|
||||
{{- if ne $a.Condition "" }}
|
||||
{
|
||||
{{- if $a.Precondition }}
|
||||
Precondition: {{ printf "%q" $a.Precondition }},
|
||||
{{- end }}
|
||||
Condition: {{ printf "%q" $a.Condition }},
|
||||
Duration: {{ $a.Duration }},
|
||||
DurScale: {{ $a.DurScale }},
|
||||
{{- if $a.Cooldown }}
|
||||
Cooldown: {{ $a.Cooldown }},
|
||||
{{- end }}
|
||||
Abilities: []Ability{
|
||||
{{- range $abil := $a.Abilities }}
|
||||
{{- if ne $abil.Type 0 }}
|
||||
{Type: {{ $abil.Type }}, ValueUsage: {{ $abil.ValueUsage }}, Value: {{ $abil.Value }}, Target: {{ $abil.Target }}, TargetValue: {{ $abil.TargetValue -}} },
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
},
|
||||
},
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
},
|
||||
{{- if $s.UniqueOwner }}
|
||||
UniqueOwner: {{ printf "%q" $s.UniqueOwner }},
|
||||
{{- end }}
|
||||
{{- if $s.SPCost }}
|
||||
SPCost: {{ $s.SPCost }},
|
||||
{{- end }}
|
||||
IconID: {{ $s.IconID }},
|
||||
},
|
||||
{{- end }}
|
||||
}
|
||||
|
||||
var SkillNameToID = map[string]SkillID{
|
||||
{{- range $s := $.Skills }}
|
||||
{{ printf "%q" $s.Name }}{{ if ne $s.InheritID 0 }} + " (Inherited)"{{ end }}: {{ $s.ID }},
|
||||
{{- end }}
|
||||
}
|
||||
|
||||
var SkillGroups = map[int32][4]SkillID{
|
||||
{{- range $g := $.Groups }}
|
||||
{{ $g.ID }}: { {{- range $s := index $.Related $g.ID }}Skill{{ goenum $s.Name }}{{ if ne $s.InheritID 0 }}Inherit{{ end }}, {{ end -}} },
|
||||
{{- end }}
|
||||
}
|
||||
{{ end }}
|
||||
@@ -1,230 +0,0 @@
|
||||
{{- define "koka-skill" -}}
|
||||
module horse/{{ $.Region }}/skill
|
||||
|
||||
// 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 std/num/decimal
|
||||
import horse/game-id
|
||||
import horse/movement
|
||||
pub import horse/skill
|
||||
|
||||
extern create-id-table(): vector<int>
|
||||
c inline "int32_t arr[] = { {{- range $s := $.Skills }}{{ $s.ID }},{{ end -}} };\nkk_vector_from_cint32array(arr, (kk_ssize_t){{ $.SkillCount }}, kk_context())"
|
||||
js inline "[{{ range $s := $.Skills }}{{ $s.ID }},{{ end }}]"
|
||||
// Vector of all skill ID values 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(Skill-id(id).show, id)
|
||||
m
|
||||
|
||||
// Get the skill ID that has the given exact name.
|
||||
// Inherited skills have `" (Inherited)"` appended to their names.
|
||||
// If no skill matches the name, the result is an invalid ID.
|
||||
pub fun from-name(name: string): skill-id
|
||||
Skill-id(name2id().rb-map/lookup(name).default(0))
|
||||
|
||||
// Get the name for a skill.
|
||||
// Inherited skills have `" (Inherited)"` appended to their names.
|
||||
// If no skill matches the ID, the result is the numeric ID.
|
||||
pub fun show(s: skill-id): string
|
||||
match s.game-id
|
||||
{{- range $s := $.Skills }}
|
||||
{{ $s.ID }} -> {{ printf "%q" $s.Name }}{{ if $s.InheritID }} ++ " (Inherited)"{{ end }}
|
||||
{{- end }}
|
||||
x -> "skill " ++ x.show
|
||||
|
||||
// Get the description for a skill.
|
||||
// If no skill matches the ID, the result is the empty string.
|
||||
pub fun description(s: skill-id): string
|
||||
match s.game-id
|
||||
{{- range $s := $.Skills }}
|
||||
{{ $s.ID }} -> {{ printf "%q" $s.Description }}
|
||||
{{- end }}
|
||||
_ -> ""
|
||||
|
||||
// Get the skill group ID for a skill.
|
||||
// If no skill matches the ID, the result is an invalid ID.
|
||||
pub fun group(s: skill-id): skill-group-id
|
||||
match s.game-id
|
||||
{{- range $s := $.Skills }}
|
||||
{{ $s.ID }} -> Skill-group-id( {{- $s.GroupID -}} )
|
||||
{{- end }}
|
||||
_ -> Skill-group-id(0)
|
||||
|
||||
// Get the rarity of a skill.
|
||||
// If no skill matches the ID, the result is Common.
|
||||
pub fun rarity(s: skill-id): rarity
|
||||
match s.game-id
|
||||
{{- range $s := $.Skills }}
|
||||
{{ $s.ID }} -> {{ if eq $s.Rarity 1 }}Common{{ else if eq $s.Rarity 2 }}Rare{{ else if eq $s.Rarity 3 }}Unique-Low{{ else if eq $s.Rarity 4 }}Unique-Upgraded{{ else if eq $s.Rarity 5 }}Unique{{ else }}??? $s.Rarity={{ $s.Rarity }}{{ end }}
|
||||
{{- end }}
|
||||
_ -> Common
|
||||
|
||||
// Get the group rate of a skill.
|
||||
// If no skill matches the ID, the result is 0.
|
||||
pub fun group-rate(s: skill-id): int
|
||||
match s.game-id
|
||||
{{- range $s := $.Skills }}
|
||||
{{ $s.ID }} -> {{ $s.GroupRate }}
|
||||
{{- end }}
|
||||
_ -> 0
|
||||
|
||||
// Get the grade value of a skill.
|
||||
// If no skill matches the ID, the result is 0.
|
||||
pub fun grade-value(s: skill-id): int
|
||||
match s.game-id
|
||||
{{- range $s := $.Skills }}
|
||||
{{ $s.ID }} -> {{ $s.GradeValue }}
|
||||
{{- end }}
|
||||
_ -> 0
|
||||
|
||||
// Get whether a skill is a wit check.
|
||||
// If no skill matches the ID, the result is False.
|
||||
pub fun wit-check(s: skill-id): bool
|
||||
match s.game-id
|
||||
{{- range $s := $.Skills }}
|
||||
{{ $s.ID }} -> {{ if $s.WitCheck }}True{{ else }}False{{ end }}
|
||||
{{- end }}
|
||||
_ -> False
|
||||
|
||||
// Get the activations of a skill.
|
||||
// If no skill matches the ID, the result is an empty list.
|
||||
pub fun activations(s: skill-id): list<activation>
|
||||
match s.game-id
|
||||
{{- range $s := $.Skills }}
|
||||
{{ $s.ID }} -> [
|
||||
{{- range $a := $s.Activations }}
|
||||
{{- if $a.Condition }}
|
||||
Activation(
|
||||
precondition = {{ printf "%q" $a.Precondition }},
|
||||
condition = {{ printf "%q" $a.Condition }},
|
||||
duration = {{ $a.Duration }}.decimal{{ if gt $a.Duration 0 }}(-4){{ end }},
|
||||
dur-scale = {{ if eq $a.DurScale 1 }}Direct-Dur
|
||||
{{- else if eq $a.DurScale 2 }}Front-Distance-Dur
|
||||
{{- else if eq $a.DurScale 3 }}Multiply-Remaining-HP
|
||||
{{- else if eq $a.DurScale 4 }}Increment-Pass
|
||||
{{- else if eq $a.DurScale 5 }}Midrace-Side-Block-Time-Dur
|
||||
{{- else if eq $a.DurScale 7 }}Multiply-Remaining-HP2
|
||||
{{- else }}??? $a.DurScale={{ $a.DurScale }}
|
||||
{{- end }},
|
||||
cooldown = {{ $a.Cooldown }}.decimal{{ if gt $a.Cooldown 0 }}(-4){{ end }},
|
||||
abilities = [
|
||||
{{- range $abil := $a.Abilities }}
|
||||
{{- if $abil.Type }}
|
||||
Ability(
|
||||
ability-type = {{ if eq $abil.Type 1 }}Passive-Speed({{ $abil.Value }}.decimal(-4))
|
||||
{{- else if eq $abil.Type 2 }}Passive-Stamina({{ $abil.Value }}.decimal(-4))
|
||||
{{- else if eq $abil.Type 3 }}Passive-Power({{ $abil.Value }}.decimal(-4))
|
||||
{{- else if eq $abil.Type 4 }}Passive-Guts({{ $abil.Value }}.decimal(-4))
|
||||
{{- else if eq $abil.Type 5 }}Passive-Wit({{ $abil.Value }}.decimal(-4))
|
||||
{{- else if eq $abil.Type 6 }}Great-Escape
|
||||
{{- else if eq $abil.Type 8 }}Vision({{ $abil.Value }}.decimal(-4))
|
||||
{{- else if eq $abil.Type 9 }}HP({{ $abil.Value }}.decimal(-4))
|
||||
{{- else if eq $abil.Type 10 }}Gate-Delay({{ $abil.Value }}.decimal(-4))
|
||||
{{- else if eq $abil.Type 13 }}Frenzy({{ $abil.Value }}.decimal(-4))
|
||||
{{- else if eq $abil.Type 21 }}Current-Speed({{ $abil.Value }}.decimal(-4))
|
||||
{{- else if eq $abil.Type 27 }}Target-Speed({{ $abil.Value }}.decimal(-4))
|
||||
{{- else if eq $abil.Type 28 }}Lane-Speed({{ $abil.Value }}.decimal(-4))
|
||||
{{- else if eq $abil.Type 31 }}Accel({{ $abil.Value }}.decimal(-4))
|
||||
{{- else if eq $abil.Type 35 }}Lane-Change({{ $abil.Value }}.decimal(-4))
|
||||
{{- else }}??? $abil.Type={{$abil.Type}}
|
||||
{{- end }},
|
||||
value-usage = {{ if eq $abil.ValueUsage 1 }}Direct
|
||||
{{- else if eq $abil.ValueUsage 3 }}Team-Speed
|
||||
{{- else if eq $abil.ValueUsage 4 }}Team-Stamina
|
||||
{{- else if eq $abil.ValueUsage 5 }}Team-Power
|
||||
{{- else if eq $abil.ValueUsage 6 }}Team-Guts
|
||||
{{- else if eq $abil.ValueUsage 7 }}Team-Wit
|
||||
{{- else if eq $abil.ValueUsage 8 }}Multiply-Random
|
||||
{{- else if eq $abil.ValueUsage 9 }}Multiply-Random2
|
||||
{{- else if eq $abil.ValueUsage 10 }}Climax
|
||||
{{- else if eq $abil.ValueUsage 13 }}Max-Stat
|
||||
{{- else if eq $abil.ValueUsage 14 }}Passive-Count
|
||||
{{- else if eq $abil.ValueUsage 19 }}Front-Distance-Add
|
||||
{{- else if eq $abil.ValueUsage 20 }}Midrace-Side-Block-Time
|
||||
{{- else if eq $abil.ValueUsage 22 }}Speed-Scaling
|
||||
{{- else if eq $abil.ValueUsage 23 }}Speed-Scaling2
|
||||
{{- else if eq $abil.ValueUsage 24 }}Arc-Global-Potential
|
||||
{{- else if eq $abil.ValueUsage 25 }}Max-Lead-Distance
|
||||
{{- else }}??? $abil.ValueUsage={{ $abil.ValueUsage }}
|
||||
{{- end }},
|
||||
target = {{ if eq $abil.Target 1}}Self
|
||||
{{- else if eq $abil.Target 4 }}Sympathizers
|
||||
{{- else if eq $abil.Target 4 }}In-View
|
||||
{{- else if eq $abil.Target 4 }}Frontmost
|
||||
{{- else if eq $abil.Target 9 }}Ahead({{ $abil.TargetValue }})
|
||||
{{- else if eq $abil.Target 10 }}Behind({{ $abil.TargetValue }})
|
||||
{{- else if eq $abil.Target 4 }}All-Teammates
|
||||
{{- else if eq $abil.Target 18 }}Style({{ if eq $abil.TargetValue 1 }}Front-Runner{{ else if eq $abil.TargetValue 2 }}Pace-Chaser{{ else if eq $abil.TargetValue 3 }}Late-Surger{{ else if eq $abil.TargetValue 4 }}End-Closer{{ else }}??? $abil.TargetValue={{ $abil.TargetValue }}{{ end }})
|
||||
{{- else if eq $abil.Target 19 }}Rushing-Ahead({{ $abil.TargetValue }})
|
||||
{{- else if eq $abil.Target 20 }}Rushing-Behind({{ $abil.TargetValue }})
|
||||
{{- else if eq $abil.Target 21 }}Rushing-Style({{ if eq $abil.TargetValue 1 }}Front-Runner{{ else if eq $abil.TargetValue 2 }}Pace-Chaser{{ else if eq $abil.TargetValue 3 }}Late-Surger{{ else if eq $abil.TargetValue 4 }}End-Closer{{ else }}??? $abil.TargetValue={{ $abil.TargetValue }}{{ end }})
|
||||
{{- else if eq $abil.Target 22 }}Specific-Character(Character-id({{ $abil.TargetValue }}))
|
||||
{{- else if eq $abil.Target 23 }}Triggering
|
||||
{{- end }}
|
||||
),
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
]
|
||||
),
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
]
|
||||
{{- end }}
|
||||
_ -> Nil
|
||||
|
||||
// Get the owner of a unique skill.
|
||||
// If the skill is not unique, or if there is no skill with the given ID,
|
||||
// the result is Nothing.
|
||||
pub fun unique-owner(s: skill-id): maybe<uma-id>
|
||||
match s.game-id
|
||||
{{- range $s := $.Skills }}
|
||||
{{- if $s.UniqueOwnerID }}
|
||||
{{ $s.ID }} -> Just(Uma-id({{ $s.UniqueOwnerID }}))
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
_ -> Nothing
|
||||
|
||||
// Get the SP cost of a skill.
|
||||
// If there is no skill with the given ID, the result is 0.
|
||||
pub fun sp-cost(s: skill-id): int
|
||||
match s.game-id
|
||||
{{- range $s := $.Skills }}
|
||||
{{ $s.ID }} -> {{ $s.SPCost }}
|
||||
{{- end }}
|
||||
_ -> 0
|
||||
|
||||
// Get the icon ID of a skill.
|
||||
// If there is no skill with the given ID, the result is an invalid ID.
|
||||
pub fun icon-id(s: skill-id): skill-icon-id
|
||||
match s.game-id
|
||||
{{- range $s := $.Skills }}
|
||||
{{ $s.ID }} -> Skill-icon-id({{ $s.IconID }})
|
||||
{{- end }}
|
||||
_ -> Skill-icon-id(0)
|
||||
|
||||
// Get the name for a skill group.
|
||||
// Skill group names are the name of the base skill in the group.
|
||||
// If there is no skill group with the given ID, the result is the numeric ID.
|
||||
pub fun skill-group/show(sg: skill-group-id): string
|
||||
match sg.game-id
|
||||
{{- range $g := $.Groups }}
|
||||
{{ $g.ID }} -> {{- printf "%q" $g.Name -}}
|
||||
{{- end }}
|
||||
x -> "skill group " ++ x.show
|
||||
|
||||
// Get the list of skills in a skill group.
|
||||
pub fun skill-group/skills(sg: skill-group-id): list<skill-id>
|
||||
match sg.game-id
|
||||
{{- range $g := $.Groups }}
|
||||
{{ $g.ID }} -> [ {{- range $s := index $.Related $g.ID }}Skill-id({{ $s.ID }}), {{ end -}} ]
|
||||
{{- end }}
|
||||
_ -> Nil
|
||||
|
||||
{{- end }}
|
||||
@@ -1,35 +0,0 @@
|
||||
{{- define "go-spark" -}}
|
||||
package {{ $.Region }}
|
||||
|
||||
// Automatically generated with horsegen; DO NOT EDIT
|
||||
|
||||
import . "git.sunturtle.xyz/zephyr/horse/horse"
|
||||
|
||||
const (
|
||||
{{- range $s := $.Sparks }}
|
||||
Spark{{ goenum $s.Name }}Lv{{ $s.Rarity }} SparkID = {{ $s.ID }} // {{ $s.Name }}
|
||||
{{- end }}
|
||||
)
|
||||
|
||||
var AllSparks = map[SparkID]Spark{
|
||||
{{- range $s := $.Sparks }}
|
||||
Spark{{ goenum $s.Name }}Lv{{ $s.Rarity }}: {
|
||||
ID: {{ $s.ID }},
|
||||
Name: {{ printf "%q" $s.Name }},
|
||||
Description: {{ printf "%q" $s.Description }},
|
||||
Group: {{ $s.Group }},
|
||||
Rarity: {{ $s.Rarity }},
|
||||
Type: {{ $s.Type }},
|
||||
Effects: [][]SparkEffect{
|
||||
{{- range $r := index $.SparkEffects $s.Group }}
|
||||
{
|
||||
{{- range $e := $r -}}
|
||||
{ {{- $e.Target }}, {{ $e.Value1 }}, {{ $e.Value2 -}} },
|
||||
{{- end -}}
|
||||
},
|
||||
{{- end }}
|
||||
},
|
||||
},
|
||||
{{- end }}
|
||||
}
|
||||
{{ end }}
|
||||
@@ -1,121 +0,0 @@
|
||||
{{- define "koka-spark" -}}
|
||||
module horse/{{ $.Region }}/spark
|
||||
|
||||
// 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/spark
|
||||
|
||||
extern create-id-table(): vector<int>
|
||||
c inline "int32_t arr[] = { {{- range $s := $.Sparks }}{{ $s.ID }},{{ end -}} };\nkk_vector_from_cint32array(arr, (kk_ssize_t){{ $.SparkCount }}, kk_context())"
|
||||
js inline "[{{ range $s := $.Sparks }}{{ $s.ID }},{{ end }}]"
|
||||
// Vector of all spark IDs in order for easy iterating.
|
||||
pub val all = once(create-id-table)
|
||||
|
||||
// Get the name for a spark.
|
||||
// The name does not indicate the spark level.
|
||||
// If no spark matches the ID, the result contains the numeric ID.
|
||||
pub fun show(s: spark-id): string
|
||||
match s.game-id
|
||||
{{- range $s := $.Sparks }}
|
||||
{{ $s.ID }} -> {{ printf "%q" $s.Name }}
|
||||
{{- end }}
|
||||
x -> "spark " ++ x.show
|
||||
|
||||
// Get the description for a spark.
|
||||
// The description does not indicate the spark level.
|
||||
// If no spark matches the ID, the result contains the numeric ID.
|
||||
pub fun description(s: spark-id): string
|
||||
match s.game-id
|
||||
{{- range $s := $.Sparks }}
|
||||
{{ $s.ID }} -> {{ printf "%q" $s.Description }}
|
||||
{{- end }}
|
||||
x -> "spark " ++ x.show
|
||||
|
||||
// Get the spark group ID of a spark.
|
||||
// If no spark matches the ID, the result is an invalid ID.
|
||||
pub fun spark-group(s: spark-id): spark-group-id
|
||||
match s.game-id
|
||||
{{- range $s := $.Sparks }}
|
||||
{{ $s.ID }} -> Spark-group-id({{ $s.Group }})
|
||||
{{- end }}
|
||||
_ -> Spark-group-id(0)
|
||||
|
||||
// Get the rarity (level or star count) of a spark.
|
||||
// If no spark matches the ID, the result is One.
|
||||
pub fun rarity(s: spark-id): rarity
|
||||
match s.game-id
|
||||
{{- range $s := $.Sparks }}
|
||||
{{ $s.ID }} -> {{ if eq $s.Rarity 1 }}One{{ else if eq $s.Rarity 2 }}Two{{ else if eq $s.Rarity 3 }}Three{{ else }}??? $s.Rarity={{ $s.Rarity }}{{ end }}
|
||||
{{- end }}
|
||||
_ -> One
|
||||
|
||||
// Get the type of a spark.
|
||||
// If no spark matches the ID, the result is Stat.
|
||||
pub fun spark-type(s: spark-id): spark-type
|
||||
match s.game-id
|
||||
{{- range $s := $.Sparks }}
|
||||
{{ $s.ID }} -> {{ if eq $s.Type 1 }}Stat
|
||||
{{- else if eq $s.Type 2 }}Aptitude
|
||||
{{- else if eq $s.Type 5 }}Race
|
||||
{{- else if eq $s.Type 4 }}Skill
|
||||
{{- else if eq $s.Type 6 }}Scenario
|
||||
{{- else if eq $s.Type 7 }}Carnival-Bonus
|
||||
{{- else if eq $s.Type 10 }}Surface
|
||||
{{- else if eq $s.Type 8 }}Distance
|
||||
{{- else if eq $s.Type 11 }}Style
|
||||
{{- else if eq $s.Type 9 }}Hidden
|
||||
{{- else if eq $s.Type 3 }}Unique
|
||||
{{- else }}??? $s.Type={{ $s.Type }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
_ -> Stat
|
||||
|
||||
// Get the list of all effects a spark can apply during inheritance.
|
||||
// When a spark procs, a random element is chosen from the list yielded by this
|
||||
// function according to a hidden distribution, then all effects in that are applied.
|
||||
// If no spark matches the ID, the result is the empty list.
|
||||
pub fun effects(s: spark-id): list<list<spark-effect>>
|
||||
match s.game-id
|
||||
{{- range $s := $.Sparks }}
|
||||
{{ $s.ID }} -> [
|
||||
{{- range $r := index $.SparkEffects $s.Group }}
|
||||
[
|
||||
{{- range $e := $r -}}
|
||||
{{- if eq $e.Target 1 -}}Stat-Up(Speed, {{ $e.Value1 }}),
|
||||
{{- else if eq $e.Target 2 -}}Stat-Up(Stamina, {{ $e.Value1 }}),
|
||||
{{- else if eq $e.Target 3 -}}Stat-Up(Power, {{ $e.Value1 }}),
|
||||
{{- else if eq $e.Target 4 -}}Stat-Up(Guts, {{ $e.Value1 }}),
|
||||
{{- else if eq $e.Target 5 -}}Stat-Up(Wit, {{ $e.Value1 }}),
|
||||
{{- else if eq $e.Target 6 -}}SP-Up({{ $e.Value1 }}),
|
||||
{{- else if eq $e.Target 7 -}}Random-Stat-Up({{ $e.Value1 }}),
|
||||
{{- else if eq $e.Target 11 -}}Aptitude-Up(Turf, {{ $e.Value1 }}),
|
||||
{{- else if eq $e.Target 12 -}}Aptitude-Up(Dirt, {{ $e.Value1 }}),
|
||||
{{- else if eq $e.Target 21 -}}Aptitude-Up(Front-Runner, {{ $e.Value1 }}),
|
||||
{{- else if eq $e.Target 22 -}}Aptitude-Up(Pace-Chaser, {{ $e.Value1 }}),
|
||||
{{- else if eq $e.Target 23 -}}Aptitude-Up(Late-Surger, {{ $e.Value1 }}),
|
||||
{{- else if eq $e.Target 24 -}}Aptitude-Up(End-Closer, {{ $e.Value1 }}),
|
||||
{{- else if eq $e.Target 31 -}}Aptitude-Up(Sprint, {{ $e.Value1 }}),
|
||||
{{- else if eq $e.Target 32 -}}Aptitude-Up(Mile, {{ $e.Value1 }}),
|
||||
{{- else if eq $e.Target 33 -}}Aptitude-Up(Medium, {{ $e.Value1 }}),
|
||||
{{- else if eq $e.Target 34 -}}Aptitude-Up(Long, {{ $e.Value1 }}),
|
||||
{{- else if eq $e.Target 41 -}}Skill-Hint(Skill-id({{ $e.Value1 }}), {{ $e.Value2 }}),
|
||||
{{- else if eq $e.Target 51 -}}Carnival-Bonus {{/*- skipped, but doesn't hurt to put it here -*/}}
|
||||
{{- else if eq $e.Target 61 -}}Stat-Cap-Up(Speed, {{ $e.Value1 }}),
|
||||
{{- else if eq $e.Target 62 -}}Stat-Cap-Up(Stamina, {{ $e.Value1 }}),
|
||||
{{- else if eq $e.Target 63 -}}Stat-Cap-Up(Power, {{ $e.Value1 }}),
|
||||
{{- else if eq $e.Target 64 -}}Stat-Cap-Up(Guts, {{ $e.Value1 }}),
|
||||
{{- else if eq $e.Target 65 -}}Stat-Cap-Up(Wit, {{ $e.Value1 }}),
|
||||
{{- else -}}
|
||||
??? $e.Target={{- $e.Target -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
],
|
||||
{{- end }}
|
||||
]
|
||||
{{- end }}
|
||||
_ -> []
|
||||
{{ end }}
|
||||
@@ -1,42 +0,0 @@
|
||||
{{- 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 }}
|
||||
@@ -1,221 +0,0 @@
|
||||
{{- 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.
|
||||
pub val all = 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 -}}
|
||||
Reference in New Issue
Block a user