Compare commits
194 Commits
1f2824246f
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 48118efeeb | |||
| 79d4e76090 | |||
| ea39be0510 | |||
| 7bac55ca43 | |||
| 435da61405 | |||
| f3e7c7b43b | |||
| eded415df4 | |||
| 34029fe001 | |||
| ffb700545f | |||
| 70ad09a13e | |||
| 74c22c7313 | |||
| 2c1b4b9261 | |||
| e5128b6783 | |||
| b22c8307fd | |||
| cb54bbe414 | |||
| 096cff28b6 | |||
| 197df8f022 | |||
| 009dd1d695 | |||
| bdafc93315 | |||
| ef5b06d66e | |||
| 65b81612bc | |||
| 6269665e79 | |||
| cae7d5b8f4 | |||
| fca43e64b5 | |||
| bc395a0788 | |||
| 1d879cbf9f | |||
| 240a3d9a73 | |||
| 3d73460934 | |||
| 0c518a9ce2 | |||
| 5cbb6d7b1d | |||
| b0bd16fd04 | |||
| 55175c9c40 | |||
| 06e5a06680 | |||
| dbb0dcd2dc | |||
| 02f723b83a | |||
| 1f58dec491 | |||
| a6d264c79d | |||
| d62e729052 | |||
| 9ce665865e | |||
| 7d395b2cc7 | |||
| 2b69211a6c | |||
| 67377c4690 | |||
| 1d65a0ec14 | |||
| ad58edbfe1 | |||
| f8e7bfbec6 | |||
| 2e618b613f | |||
| cc2b5fcfcb | |||
| 8ef3936be5 | |||
| b06e4b537b | |||
| 7b4cd41d3b | |||
| 2c9434729a | |||
| 7f02925ff7 | |||
| b217691c8a | |||
| 4bce196c09 | |||
| aa17d8ccf3 | |||
| 26a5ca4496 | |||
| 51f942ee18 | |||
| 2c773391f0 | |||
| c66d969c82 | |||
| bc9d722ee0 | |||
| 6482f11620 | |||
| 75024c7c11 | |||
| dc78d51def | |||
| 5f0ad1b0e0 | |||
| 6db0ca5230 | |||
| 049617c22e | |||
| d431d3382a | |||
| a848c8eb72 | |||
| 871fd5fdcc | |||
| e3dd37f515 | |||
| 3557b32298 | |||
| 20db674d25 | |||
| 2a4da0a73e | |||
| e6335c1d6e | |||
| f40fea0ec5 | |||
| 96503e40f6 | |||
| c95e9bb4cc | |||
| 825fe0f2fb | |||
| 4ea689f426 | |||
| f0bb6d1926 | |||
| 13436abd1a | |||
| bed60a8a67 | |||
| 2b8ef759df | |||
| 9318bb9091 | |||
| 847f2eb8ca | |||
| 0b7201779c | |||
| 2b37c00ed0 | |||
| 2e5a78e1d8 | |||
| 277c904bc5 | |||
| 8945a3943b | |||
| 1cfd80ac3d | |||
| b4e6a34aca | |||
| b3c8699635 | |||
| 223495a04a | |||
| 40a015363c | |||
| 2869e7c160 | |||
| 30a72d91b8 | |||
| efb36f705c | |||
| 6a30b1d6f0 | |||
| 7b45b8761b | |||
| a89ef8fc4c | |||
| bae79a5320 | |||
| 0f14ece4da | |||
| b1c6850ce1 | |||
| bd99cfaa6d | |||
| 3ab17cf9b0 | |||
| 4bd7962182 | |||
| 09f099171b | |||
| 4fff7069a8 | |||
| 3e2153b39c | |||
| d0fa6ab15c | |||
| 9f8024d488 | |||
| 1df3bc1db9 | |||
| a8c1b9c754 | |||
| 7600c48cc7 | |||
| 2e31560d6c | |||
| 2a07f193ec | |||
| b720b325b3 | |||
| 80573a84ea | |||
| bc94d66002 | |||
| aca5fccaa7 | |||
| ee6ced1390 | |||
| af8e5907b9 | |||
| 9cf9fd198f | |||
| 0c2db10082 | |||
| fae9c38098 | |||
| 0799bf658f | |||
| 2cec7c5699 | |||
| b10a2572ec | |||
| 657cf22f71 | |||
| dce58357ae | |||
| 7abe427c03 | |||
| 1a55150ddd | |||
| 3e879f3687 | |||
| 0eb932dc3c | |||
| eb26b42543 | |||
| d082ce3374 | |||
| faccc3e912 | |||
| af8edb8999 | |||
| 0abe5fc3e4 | |||
| 5a444ea08c | |||
| dfb2ad2950 | |||
| 256e11d320 | |||
| 467098a9e4 | |||
| 9532e0ec89 | |||
| c14850a048 | |||
| d0aec5c501 | |||
| ccef87f0a3 | |||
| 34140c0bba | |||
| 0ad064725f | |||
| 886dccb6b8 | |||
| 57e8a06383 | |||
| ab14f58079 | |||
| 4106215180 | |||
| cdea376f94 | |||
| d157dfc9b6 | |||
| 773625b842 | |||
| 22ca5c98f3 | |||
| 08deedea8f | |||
| 86b769d7ed | |||
| e139eae06d | |||
| 34e8c1f812 | |||
| cc3128d65a | |||
| d04544030a | |||
| e13c435afa | |||
| 4429bbecd1 | |||
| 2099eeb97e | |||
| c22ed0dc83 | |||
| 494aeeb401 | |||
| 298b1368e8 | |||
| b20a1a5964 | |||
| af8e04473a | |||
| 351f606d29 | |||
| da376647af | |||
| 2ec8d9cfdb | |||
| 2dd75edc03 | |||
| e08580925d | |||
| 63659a4934 | |||
| af4e06411d | |||
| 4426925ebb | |||
| 8632bb8c3c | |||
| 7ff271ff2d | |||
| 5540bb2c4e | |||
| 9a73f2147b | |||
| 01b88994f3 | |||
| 424f65dc8a | |||
| cf814c6c72 | |||
| 7972bab46c | |||
| 3fa30903cd | |||
| 9ef568202c | |||
| b0e422ac01 | |||
| 2184515938 | |||
| 489457c63c | |||
| 9b3c9b22aa |
@@ -1,3 +0,0 @@
|
||||
[submodule "std"]
|
||||
path = std
|
||||
url = git@github.com:koka-community/std.git
|
||||
@@ -0,0 +1,12 @@
|
||||
when:
|
||||
- event: push
|
||||
branch: main
|
||||
- event: pull_request
|
||||
- event: manual
|
||||
|
||||
steps:
|
||||
- name: test
|
||||
image: golang:1.26-alpine
|
||||
commands:
|
||||
- go vet ./...
|
||||
- go test ./...
|
||||
@@ -0,0 +1,15 @@
|
||||
when:
|
||||
- event: push
|
||||
branch: main
|
||||
- event: pull_request
|
||||
- event: manual
|
||||
|
||||
steps:
|
||||
- name: test
|
||||
image: node:24-alpine
|
||||
commands:
|
||||
- cd zenno
|
||||
- npm ci
|
||||
- npm run check
|
||||
- npm run lint
|
||||
- npm run test
|
||||
@@ -18,9 +18,12 @@ func _() {
|
||||
_ = x[AbilityHP-9]
|
||||
_ = x[AbilityGateDelay-10]
|
||||
_ = x[AbilityFrenzy-13]
|
||||
_ = x[AbilityAddGateDelay-14]
|
||||
_ = x[AbilityCurrentSpeed-21]
|
||||
_ = x[AbilityCurrentSpeedUp-22]
|
||||
_ = x[AbilityTargetSpeed-27]
|
||||
_ = x[AbilityLaneSpeed-28]
|
||||
_ = x[AbilityRushedChance-29]
|
||||
_ = x[AbilityAccel-31]
|
||||
_ = x[AbilityLaneChange-35]
|
||||
}
|
||||
@@ -28,9 +31,9 @@ func _() {
|
||||
const (
|
||||
_AbilityType_name_0 = "SpeedStaminaPowerGutsWitEnable Great Escape"
|
||||
_AbilityType_name_1 = "VisionHPGate delay multiplier"
|
||||
_AbilityType_name_2 = "Frenzy"
|
||||
_AbilityType_name_3 = "Current speed"
|
||||
_AbilityType_name_4 = "Target speedLane change speed"
|
||||
_AbilityType_name_2 = "FrenzyAdded gate delay"
|
||||
_AbilityType_name_3 = "Current speedCurrent speed"
|
||||
_AbilityType_name_4 = "Target speedLane change speedRushed chance"
|
||||
_AbilityType_name_5 = "Acceleration"
|
||||
_AbilityType_name_6 = "Forced lane change"
|
||||
)
|
||||
@@ -38,7 +41,9 @@ const (
|
||||
var (
|
||||
_AbilityType_index_0 = [...]uint8{0, 5, 12, 17, 21, 24, 43}
|
||||
_AbilityType_index_1 = [...]uint8{0, 6, 8, 29}
|
||||
_AbilityType_index_4 = [...]uint8{0, 12, 29}
|
||||
_AbilityType_index_2 = [...]uint8{0, 6, 22}
|
||||
_AbilityType_index_3 = [...]uint8{0, 13, 26}
|
||||
_AbilityType_index_4 = [...]uint8{0, 12, 29, 42}
|
||||
)
|
||||
|
||||
func (i AbilityType) String() string {
|
||||
@@ -49,11 +54,13 @@ func (i AbilityType) String() string {
|
||||
case 8 <= i && i <= 10:
|
||||
i -= 8
|
||||
return _AbilityType_name_1[_AbilityType_index_1[i]:_AbilityType_index_1[i+1]]
|
||||
case i == 13:
|
||||
return _AbilityType_name_2
|
||||
case i == 21:
|
||||
return _AbilityType_name_3
|
||||
case 27 <= i && i <= 28:
|
||||
case 13 <= i && i <= 14:
|
||||
i -= 13
|
||||
return _AbilityType_name_2[_AbilityType_index_2[i]:_AbilityType_index_2[i+1]]
|
||||
case 21 <= i && i <= 22:
|
||||
i -= 21
|
||||
return _AbilityType_name_3[_AbilityType_index_3[i]:_AbilityType_index_3[i+1]]
|
||||
case 27 <= i && i <= 29:
|
||||
i -= 27
|
||||
return _AbilityType_name_4[_AbilityType_index_4[i]:_AbilityType_index_4[i+1]]
|
||||
case i == 31:
|
||||
@@ -0,0 +1,31 @@
|
||||
// Code generated by "stringer -type AptitudeLevel -trimprefix AptitudeLv"; DO NOT EDIT.
|
||||
|
||||
package horse
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[AptitudeLvG-1]
|
||||
_ = x[AptitudeLvF-2]
|
||||
_ = x[AptitudeLvE-3]
|
||||
_ = x[AptitudeLvD-4]
|
||||
_ = x[AptitudeLvC-5]
|
||||
_ = x[AptitudeLvB-6]
|
||||
_ = x[AptitudeLvA-7]
|
||||
_ = x[AptitudeLvS-8]
|
||||
}
|
||||
|
||||
const _AptitudeLevel_name = "GFEDCBAS"
|
||||
|
||||
var _AptitudeLevel_index = [...]uint8{0, 1, 2, 3, 4, 5, 6, 7, 8}
|
||||
|
||||
func (i AptitudeLevel) String() string {
|
||||
idx := int(i) - 1
|
||||
if i < 1 || idx >= len(_AptitudeLevel_index)-1 {
|
||||
return "AptitudeLevel(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _AptitudeLevel_name[_AptitudeLevel_index[idx]:_AptitudeLevel_index[idx+1]]
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package horse
|
||||
|
||||
type CharacterID int16
|
||||
|
||||
type Character struct {
|
||||
ID CharacterID `json:"chara_id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func (c Character) String() string {
|
||||
return c.Name
|
||||
}
|
||||
|
||||
// AffinityRelation holds precomputed affinity values for a pair or trio.
|
||||
type AffinityRelation struct {
|
||||
IDA CharacterID `json:"chara_a"`
|
||||
IDB CharacterID `json:"chara_b"`
|
||||
IDC CharacterID `json:"chara_c,omitzero"`
|
||||
Affinity int `json:"affinity"`
|
||||
}
|
||||
|
||||
// AffinityDetail holds a single affinity entry.
|
||||
type AffinityDetail struct {
|
||||
CharaID CharacterID `json:"chara_id"`
|
||||
Relation uint16 `json:"relation"`
|
||||
Affinity uint16 `json:"affinity"`
|
||||
}
|
||||
|
||||
// Conversation describes a lobby conversation.
|
||||
type Conversation struct {
|
||||
// CharacterID is the ID of the character who has the conversation as
|
||||
// a gallery entry.
|
||||
CharacterID CharacterID `json:"chara_id"`
|
||||
// Number is the conversation number within the character's gallery.
|
||||
Number int `json:"number"`
|
||||
// Location is the ID of the location the conversation occurs in the lobby.
|
||||
Location LobbyConversationLocationID `json:"location"`
|
||||
// Chara1 is the first conversation participant ID.
|
||||
// It does not necessarily match CharacterID.
|
||||
Chara1 CharacterID `json:"chara_1"`
|
||||
// Chara2 is the second conversation participant ID.
|
||||
Chara2 CharacterID `json:"chara_2,omitzero"`
|
||||
// Chara3 is the third conversation participant ID.
|
||||
Chara3 CharacterID `json:"chara_3,omitzero"`
|
||||
// ConditionType is a complete mystery to me.
|
||||
ConditionType int `json:"condition_type"`
|
||||
}
|
||||
|
||||
type LobbyConversationLocationID int
|
||||
|
||||
//go:generate go run golang.org/x/tools/cmd/stringer@v0.41.0 -type LobbyConversationLocationID -trimprefix Lobby -linecomment
|
||||
const (
|
||||
LobbyRightFront1 LobbyConversationLocationID = 110 // right side front
|
||||
LobbyRightFront2 LobbyConversationLocationID = 120 // right side front
|
||||
LobbyRightFront3 LobbyConversationLocationID = 130 // right side front
|
||||
LobbyLeftTable1 LobbyConversationLocationID = 210 // left side table
|
||||
LobbyLeftTable2 LobbyConversationLocationID = 220 // left side table
|
||||
LobbyBackSeat LobbyConversationLocationID = 310 // center back seat
|
||||
LobbyPosters1 LobbyConversationLocationID = 410 // center posters
|
||||
LobbyPosters2 LobbyConversationLocationID = 420 // center posters
|
||||
LobbyPosters3 LobbyConversationLocationID = 430 // center posters
|
||||
LobbySchoolMap1 LobbyConversationLocationID = 510 // left side school map
|
||||
LobbySchoolMap2 LobbyConversationLocationID = 520 // left side school map
|
||||
LobbySchoolMap3 LobbyConversationLocationID = 530 // left side school map
|
||||
)
|
||||
+12
-2
@@ -1,10 +1,20 @@
|
||||
# horsebot
|
||||
|
||||
Discord bot serving horse game data.
|
||||
Website and Discord bot serving horse game data.
|
||||
|
||||
Production instance is named Zenno Rob Roy, because she has read all about Umamusume and is always happy to share her knowledge and give recommendations.
|
||||
|
||||
## Running
|
||||
The `-mdb` flag is mandatory for both website and Discord bot modes.
|
||||
It provides data for both the horsebot API and the discord bot.
|
||||
|
||||
## Running the Website
|
||||
|
||||
If the `-public` flag is provided, its value gives the directory to serve at `/`.
|
||||
The `-img` flag gives a separate directory into which images are synced from GameTora; obtain permission from Gertas prior to using it.
|
||||
The images are served on `/img/`.
|
||||
|
||||
## Running the Discord Bot
|
||||
|
||||
Provide the `-token` flag pointing to a file containing the token.
|
||||
The bot always uses the Gateway API.
|
||||
If the `-http` argument is provided, it will also use the HTTP API, and `-key` must also be provided.
|
||||
|
||||
+146
-76
@@ -3,9 +3,14 @@ package main
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
@@ -18,25 +23,34 @@ import (
|
||||
"github.com/disgoorg/disgo/handler/middleware"
|
||||
"github.com/disgoorg/disgo/httpserver"
|
||||
"github.com/disgoorg/disgo/rest"
|
||||
httpmiddle "github.com/go-chi/chi/v5/middleware"
|
||||
"zombiezen.com/go/sqlite"
|
||||
"zombiezen.com/go/sqlite/sqlitex"
|
||||
|
||||
"git.sunturtle.xyz/zephyr/horse/horse"
|
||||
"git.sunturtle.xyz/zephyr/horse/horse/global"
|
||||
"git.sunturtle.xyz/zephyr/horse/mdb"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var (
|
||||
tokenFile string
|
||||
// http api options
|
||||
// public site
|
||||
addr string
|
||||
route string
|
||||
mdbf string
|
||||
public string
|
||||
img string
|
||||
// discord
|
||||
tokenFile string
|
||||
apiRoute string
|
||||
pubkey string
|
||||
// logging options
|
||||
// logging
|
||||
level slog.Level
|
||||
textfmt string
|
||||
)
|
||||
flag.StringVar(&addr, "http", ":13669", "`address` to bind HTTP server")
|
||||
flag.StringVar(&mdbf, "mdb", "", "`path` to master.mdb")
|
||||
flag.StringVar(&public, "public", "", "`dir`ectory containing the website to serve")
|
||||
flag.StringVar(&img, "img", "", "`dir`ectory to save and serve images")
|
||||
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")
|
||||
flag.StringVar(&apiRoute, "route", "/interactions/callback", "`path` to serve Discord HTTP API calls")
|
||||
flag.StringVar(&pubkey, "key", "", "Discord public key")
|
||||
flag.TextVar(&level, "log", slog.LevelInfo, "slog logging `level`")
|
||||
flag.StringVar(&textfmt, "log-format", "text", "slog logging `format`, text or json")
|
||||
@@ -54,68 +68,149 @@ func main() {
|
||||
}
|
||||
slog.SetDefault(slog.New(lh))
|
||||
|
||||
token, err := os.ReadFile(tokenFile)
|
||||
if public != "" {
|
||||
stat, err := os.Stat(public)
|
||||
if err != nil {
|
||||
slog.Error("reading token", slog.Any("err", err))
|
||||
slog.Error("public", slog.Any("err", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
token = bytes.TrimSuffix(token, []byte{'\n'})
|
||||
if !stat.IsDir() {
|
||||
slog.Error("public", slog.String("err", "not a directory"))
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
|
||||
|
||||
db, err := sqlitex.NewPool(mdbf, sqlitex.PoolOptions{Flags: sqlite.OpenReadOnly})
|
||||
if err != nil {
|
||||
slog.Error("mdb", slog.Any("err", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if img != "" {
|
||||
// Ensure the img directory is in fact a directory
|
||||
// before we start trying to fill it out.
|
||||
err := os.MkdirAll(img, 0777)
|
||||
if err != nil {
|
||||
slog.Error("img", slog.Any("err", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
go saveImgs(ctx, db, img)
|
||||
}
|
||||
|
||||
var client *bot.Client
|
||||
if tokenFile != "" {
|
||||
skills, err := mdb.Skills(ctx, db)
|
||||
slog.Info("loaded skills", slog.Int("count", len(skills)))
|
||||
groups, err2 := mdb.SkillGroups(ctx, db)
|
||||
slog.Info("loaded skill groups", slog.Int("count", len(groups)))
|
||||
if err = errors.Join(err, err2); err != nil {
|
||||
slog.Error("loading data", slog.Any("err", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
skillSrv := newSkillServer(skills, groups)
|
||||
slog.Info("skill server ready")
|
||||
|
||||
r := handler.New()
|
||||
r.DefaultContext(func() context.Context { return ctx })
|
||||
r.Use(middleware.Go)
|
||||
r.Use(logMiddleware)
|
||||
r.Route("/skill", func(r handler.Router) {
|
||||
r.SlashCommand("/", skillHandler)
|
||||
r.Autocomplete("/", skillAutocomplete)
|
||||
r.ButtonComponent("/{id}", skillButton)
|
||||
r.SlashCommand("/", skillSrv.slash)
|
||||
r.Autocomplete("/", skillSrv.autocomplete)
|
||||
r.SelectMenuComponent("/swap", skillSrv.menu)
|
||||
r.ButtonComponent("/swap/{id}", skillSrv.button)
|
||||
})
|
||||
|
||||
opts := []bot.ConfigOpt{bot.WithDefaultGateway(), bot.WithEventListeners(r)}
|
||||
if addr != "" {
|
||||
if pubkey == "" {
|
||||
slog.Error("Discord public key must be provided when using HTTP API")
|
||||
slog.Info("connect", slog.String("disgo", disgo.Version))
|
||||
token, err := os.ReadFile(tokenFile)
|
||||
if err != nil {
|
||||
slog.Error("reading token", slog.Any("err", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
opts = append(opts, bot.WithHTTPServerConfigOpts(pubkey,
|
||||
httpserver.WithAddress(addr),
|
||||
httpserver.WithURL(route),
|
||||
))
|
||||
}
|
||||
|
||||
slog.Info("connect", slog.String("disgo", disgo.Version))
|
||||
client, err := disgo.New(string(token), opts...)
|
||||
token = bytes.TrimSuffix(token, []byte{'\n'})
|
||||
client, err = disgo.New(string(token), bot.WithDefaultGateway(), bot.WithEventListeners(r))
|
||||
if err != nil {
|
||||
slog.Error("building bot", slog.Any("err", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
mux := http.NewServeMux()
|
||||
if public != "" {
|
||||
mux.Handle("GET /", httpmiddle.Compress(5)(http.FileServerFS(os.DirFS(public))))
|
||||
}
|
||||
if img != "" {
|
||||
mux.Handle("GET /img/", http.StripPrefix("/img", http.FileServerFS(os.DirFS(img))))
|
||||
}
|
||||
mux.Handle("GET /api/global/affinity", httpmiddle.Compress(5)(dataroute(ctx, db, mdb.AffinitySummary)))
|
||||
mux.Handle("GET /api/global/affinity-detail", httpmiddle.Compress(5)(dataroute(ctx, db, mdb.AffinityDetail)))
|
||||
mux.Handle("GET /api/global/character", httpmiddle.Compress(5)(dataroute(ctx, db, mdb.Characters)))
|
||||
mux.Handle("GET /api/global/conversation", httpmiddle.Compress(5)(dataroute(ctx, db, mdb.Conversations)))
|
||||
mux.Handle("GET /api/global/race", httpmiddle.Compress(5)(dataroute(ctx, db, mdb.Races)))
|
||||
mux.Handle("GET /api/global/saddle", httpmiddle.Compress(5)(dataroute(ctx, db, mdb.Saddles)))
|
||||
mux.Handle("GET /api/global/scenario", httpmiddle.Compress(5)(dataroute(ctx, db, mdb.Scenarios)))
|
||||
mux.Handle("GET /api/global/skill", httpmiddle.Compress(5)(dataroute(ctx, db, mdb.Skills)))
|
||||
mux.Handle("GET /api/global/skill-group", httpmiddle.Compress(5)(dataroute(ctx, db, mdb.SkillGroups)))
|
||||
mux.Handle("GET /api/global/spark", httpmiddle.Compress(5)(dataroute(ctx, db, mdb.Sparks)))
|
||||
mux.Handle("GET /api/global/uma", httpmiddle.Compress(5)(dataroute(ctx, db, mdb.Umas)))
|
||||
if pubkey != "" {
|
||||
pk, err := hex.DecodeString(pubkey)
|
||||
if err != nil {
|
||||
slog.Error("pubkey", slog.Any("err", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
mux.Handle("POST "+apiRoute, httpserver.HandleInteraction(httpserver.DefaultVerifier{}, pk, slog.Default(), client.EventManager.HandleHTTPEvent))
|
||||
slog.Info("Discord HTTP API enabled", slog.String("pubkey", pubkey))
|
||||
}
|
||||
l, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
slog.Error("listen", slog.String("addr", addr), slog.Any("err", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
srv := http.Server{
|
||||
Addr: addr,
|
||||
Handler: httpmiddle.Logger(mux),
|
||||
ReadTimeout: 15 * time.Second,
|
||||
WriteTimeout: 15 * time.Second,
|
||||
BaseContext: func(l net.Listener) context.Context { return ctx },
|
||||
}
|
||||
go func() {
|
||||
slog.Info("HTTP", slog.Any("addr", l.Addr()))
|
||||
err := srv.Serve(l)
|
||||
if err == http.ErrServerClosed {
|
||||
return
|
||||
}
|
||||
slog.Error("HTTP server closed", slog.Any("err", err))
|
||||
}()
|
||||
|
||||
if client != nil {
|
||||
if err := handler.SyncCommands(client, commands, nil, rest.WithCtx(ctx)); err != nil {
|
||||
slog.Error("syncing commands", slog.Any("err", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if addr != "" {
|
||||
slog.Info("start HTTP server", slog.String("address", addr), slog.String("route", route))
|
||||
if err := client.OpenHTTPServer(); err != nil {
|
||||
slog.Error("starting HTTP server", slog.Any("err", err))
|
||||
stop()
|
||||
}
|
||||
}
|
||||
slog.Info("start gateway")
|
||||
if err := client.OpenGateway(ctx); err != nil {
|
||||
slog.Error("starting gateway", slog.Any("err", err))
|
||||
stop()
|
||||
}
|
||||
}
|
||||
|
||||
slog.Info("ready")
|
||||
<-ctx.Done()
|
||||
stop()
|
||||
|
||||
ctx, stop = context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer stop()
|
||||
if client != nil {
|
||||
client.Close(ctx)
|
||||
}
|
||||
if err := srv.Shutdown(ctx); err != nil {
|
||||
slog.Error("HTTP API shutdown", slog.Any("err", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
var commands = []discord.ApplicationCommandCreate{
|
||||
@@ -129,55 +224,30 @@ var commands = []discord.ApplicationCommandCreate{
|
||||
Required: true,
|
||||
Autocomplete: true,
|
||||
},
|
||||
discord.ApplicationCommandOptionBool{
|
||||
Name: "share",
|
||||
Description: "Share the skill info",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
if id == 0 {
|
||||
// Either we weren't given a number or the number doesn't match any skill ID.
|
||||
v := global.SkillNameToID[q]
|
||||
if v == 0 {
|
||||
// No such skill.
|
||||
m := discord.MessageCreate{
|
||||
Content: "No such skill.",
|
||||
Flags: discord.MessageFlagEphemeral,
|
||||
}
|
||||
return e.CreateMessage(m)
|
||||
}
|
||||
id = int64(v)
|
||||
}
|
||||
// TODO(zeph): search conditions and effects, give a list
|
||||
m := discord.MessageCreate{
|
||||
Components: []discord.LayoutComponent{RenderSkill(horse.SkillID(id), global.AllSkills, global.SkillGroups)},
|
||||
Flags: discord.MessageFlagIsComponentsV2,
|
||||
}
|
||||
return e.CreateMessage(m)
|
||||
}
|
||||
|
||||
func skillAutocomplete(e *handler.AutocompleteEvent) error {
|
||||
q := e.Data.String("query")
|
||||
opts := skillGlobalAuto().Find(nil, q)
|
||||
return e.AutocompleteResult(opts[:min(len(opts), 25)])
|
||||
}
|
||||
|
||||
func skillButton(data discord.ButtonInteractionData, e *handler.ComponentEvent) error {
|
||||
id, err := strconv.ParseInt(e.Vars["id"], 10, 32)
|
||||
func dataroute[T any](ctx context.Context, db *sqlitex.Pool, f func(context.Context, *sqlitex.Pool) ([]T, error)) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
data, err := f(ctx, db)
|
||||
if err != nil {
|
||||
m := discord.MessageCreate{
|
||||
Content: "That button produced an invalid skill ID. That's not supposed to happen.",
|
||||
Flags: discord.MessageFlagEphemeral,
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
return e.CreateMessage(m)
|
||||
b, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Header().Set("Content-Length", strconv.Itoa(len(b)))
|
||||
if _, err := w.Write(b); err != nil {
|
||||
slog.Error("writing response", slog.Any("err", err))
|
||||
return
|
||||
}
|
||||
m := discord.MessageUpdate{
|
||||
Components: &[]discord.LayoutComponent{RenderSkill(horse.SkillID(id), global.AllSkills, global.SkillGroups)},
|
||||
}
|
||||
return e.UpdateMessage(m)
|
||||
}
|
||||
|
||||
+151
-51
@@ -2,67 +2,171 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/disgoorg/disgo/discord"
|
||||
"github.com/disgoorg/disgo/handler"
|
||||
|
||||
"git.sunturtle.xyz/zephyr/horse"
|
||||
"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 {
|
||||
s, ok := all[id]
|
||||
type skillServer struct {
|
||||
skills map[horse.SkillID]horse.Skill
|
||||
byName map[string]horse.SkillID
|
||||
groups map[horse.SkillGroupID]horse.SkillGroup
|
||||
autocom autocomplete.Set[discord.AutocompleteChoice]
|
||||
}
|
||||
|
||||
func newSkillServer(skills []horse.Skill, groups []horse.SkillGroup) *skillServer {
|
||||
s := skillServer{
|
||||
skills: make(map[horse.SkillID]horse.Skill, len(skills)),
|
||||
byName: make(map[string]horse.SkillID, len(skills)),
|
||||
groups: make(map[horse.SkillGroupID]horse.SkillGroup, len(groups)),
|
||||
}
|
||||
for _, skill := range skills {
|
||||
s.skills[skill.ID] = skill
|
||||
id := strconv.Itoa(int(skill.ID))
|
||||
switch {
|
||||
case skill.UniqueOwner == "":
|
||||
s.byName[skill.Name] = skill.ID
|
||||
s.autocom.Add(skill.Name, discord.AutocompleteChoiceString{Name: skill.Name, Value: id})
|
||||
case skill.Rarity >= 3:
|
||||
s.byName[skill.Name] = skill.ID
|
||||
s.autocom.Add(skill.Name, discord.AutocompleteChoiceString{Name: skill.Name, Value: id})
|
||||
s.autocom.Add(skill.UniqueOwner, discord.AutocompleteChoiceString{Name: "Unique: " + skill.UniqueOwner, Value: id})
|
||||
default:
|
||||
name := skill.Name + " (Inherited)"
|
||||
s.byName[name] = skill.ID
|
||||
s.autocom.Add(name, discord.AutocompleteChoiceString{Name: name, Value: id})
|
||||
s.autocom.Add(skill.UniqueOwner, discord.AutocompleteChoiceString{Name: "Inherited unique: " + skill.UniqueOwner, Value: id})
|
||||
}
|
||||
}
|
||||
for _, g := range groups {
|
||||
s.groups[g.ID] = g
|
||||
}
|
||||
return &s
|
||||
}
|
||||
|
||||
func (s *skillServer) slash(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(s.skills[horse.SkillID(id)].ID)
|
||||
}
|
||||
if id == 0 {
|
||||
// Either we weren't given a number or the number doesn't match any skill ID.
|
||||
v := s.byName[q]
|
||||
if v == 0 {
|
||||
// No such skill.
|
||||
m := discord.MessageCreate{
|
||||
Content: "No such skill.",
|
||||
Flags: discord.MessageFlagEphemeral,
|
||||
}
|
||||
return e.CreateMessage(m)
|
||||
}
|
||||
id = int64(v)
|
||||
}
|
||||
m := discord.MessageCreate{
|
||||
Components: []discord.LayoutComponent{s.render(horse.SkillID(id))},
|
||||
Flags: discord.MessageFlagIsComponentsV2,
|
||||
}
|
||||
if !data.Bool("share") {
|
||||
m.Flags |= discord.MessageFlagEphemeral
|
||||
}
|
||||
return e.CreateMessage(m)
|
||||
}
|
||||
|
||||
func (s *skillServer) autocomplete(e *handler.AutocompleteEvent) error {
|
||||
q := e.Data.String("query")
|
||||
opts := s.autocom.Find(nil, q)
|
||||
return e.AutocompleteResult(opts[:min(len(opts), 25)])
|
||||
}
|
||||
|
||||
func (s *skillServer) button(data discord.ButtonInteractionData, e *handler.ComponentEvent) error {
|
||||
id, err := strconv.ParseInt(e.Vars["id"], 10, 32)
|
||||
if err != nil {
|
||||
m := discord.MessageCreate{
|
||||
Content: "That button produced an invalid skill ID. That's not supposed to happen.",
|
||||
Flags: discord.MessageFlagEphemeral,
|
||||
}
|
||||
return e.CreateMessage(m)
|
||||
}
|
||||
m := discord.MessageUpdate{
|
||||
Components: &[]discord.LayoutComponent{s.render(horse.SkillID(id))},
|
||||
}
|
||||
return e.UpdateMessage(m)
|
||||
}
|
||||
|
||||
func (s *skillServer) menu(data discord.SelectMenuInteractionData, e *handler.ComponentEvent) error {
|
||||
d, ok := data.(discord.StringSelectMenuInteractionData)
|
||||
if !ok {
|
||||
return discord.NewContainer(discord.NewTextDisplayf("invalid skill ID %v made it to RenderSkill", id))
|
||||
return fmt.Errorf("wrong select menu type %T", data)
|
||||
}
|
||||
if len(d.Values) != 1 {
|
||||
return fmt.Errorf("wrong number of values: %q", d.Values)
|
||||
}
|
||||
id, err := strconv.ParseInt(d.Values[0], 10, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m := discord.MessageUpdate{
|
||||
Components: &[]discord.LayoutComponent{s.render(horse.SkillID(id))},
|
||||
}
|
||||
return e.UpdateMessage(m)
|
||||
}
|
||||
|
||||
func (s *skillServer) render(id horse.SkillID) discord.ContainerComponent {
|
||||
skill, ok := s.skills[id]
|
||||
if !ok {
|
||||
slog.Error("invalid skill id", slog.Int("id", int(id)))
|
||||
return discord.NewContainer(discord.NewTextDisplayf("invalid skill ID %v made it to render", id))
|
||||
}
|
||||
|
||||
thumburl := fmt.Sprintf("https://gametora.com/images/umamusume/skill_icons/utx_ico_skill_%d.png", s.IconID)
|
||||
top := "## " + s.Name
|
||||
if s.UniqueOwner != "" {
|
||||
top += "\n-# " + s.UniqueOwner
|
||||
top := "### " + skill.Name
|
||||
if skill.UniqueOwner != "" {
|
||||
top += "\n-# " + skill.UniqueOwner
|
||||
}
|
||||
r := discord.NewContainer(
|
||||
discord.NewSection(
|
||||
discord.NewTextDisplay(top),
|
||||
discord.NewTextDisplay(s.Description),
|
||||
).WithAccessory(discord.NewThumbnail(thumburl)),
|
||||
discord.NewSmallSeparator(),
|
||||
)
|
||||
var skilltype string
|
||||
switch {
|
||||
case s.Rarity == 3, s.Rarity == 4, s.Rarity == 5:
|
||||
case skill.Rarity == 3, skill.Rarity == 4, skill.Rarity == 5:
|
||||
// unique of various star levels
|
||||
r.AccentColor = 0xaca4d4
|
||||
skilltype = "Unique Skill"
|
||||
case s.UniqueOwner != "":
|
||||
case skill.UniqueOwner != "":
|
||||
r.AccentColor = 0xcccccc
|
||||
skilltype = "Inherited Unique"
|
||||
case s.Rarity == 2:
|
||||
case skill.Rarity == 2:
|
||||
// rare (gold)
|
||||
r.AccentColor = 0xd7c25b
|
||||
skilltype = "Rare Skill"
|
||||
case s.GroupRate == -1:
|
||||
case skill.GroupRate == -1:
|
||||
// negative (purple) skill
|
||||
r.AccentColor = 0x9151d4
|
||||
skilltype = "Negative Skill"
|
||||
case !s.WitCheck:
|
||||
case !skill.WitCheck:
|
||||
// should be passive (green)
|
||||
r.AccentColor = 0x66ae1c
|
||||
skilltype = "Passive Skill"
|
||||
case isDebuff(s):
|
||||
case isDebuff(skill):
|
||||
// debuff (red)
|
||||
r.AccentColor = 0xe34747
|
||||
skilltype = "Debuff Skill"
|
||||
case s.Rarity == 1:
|
||||
case skill.Rarity == 1:
|
||||
// common (white)
|
||||
r.AccentColor = 0xcccccc
|
||||
skilltype = "Common Skill"
|
||||
}
|
||||
r.Components = append(r.Components, discord.NewSmallSeparator())
|
||||
text := make([]string, 0, 3)
|
||||
abils := make([]string, 0, 3)
|
||||
for _, act := range s.Activations {
|
||||
for _, act := range skill.Activations {
|
||||
text, abils = text[:0], abils[:0]
|
||||
if act.Precondition != "" {
|
||||
text = append(text, "Precondition: "+formatCondition(act.Precondition))
|
||||
@@ -70,10 +174,8 @@ func RenderSkill(id horse.SkillID, all map[horse.SkillID]horse.Skill, groups map
|
||||
text = append(text, "Condition: "+formatCondition(act.Condition))
|
||||
var t string
|
||||
switch {
|
||||
case act.Duration < 0:
|
||||
// passive; do nothing
|
||||
case act.Duration == 0:
|
||||
t = "Instantaneous "
|
||||
case act.Duration <= 0:
|
||||
// passive or instantaneous, e.g. recoveries; do nothing
|
||||
case act.Duration >= 500e4:
|
||||
t = "Permanent "
|
||||
case act.DurScale == horse.DurationDirect:
|
||||
@@ -92,24 +194,38 @@ func RenderSkill(id horse.SkillID, all map[horse.SkillID]horse.Skill, groups map
|
||||
r.Components = append(r.Components, discord.NewTextDisplay(strings.Join(text, "\n")))
|
||||
}
|
||||
|
||||
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)
|
||||
l := discord.NewTextDisplayf("%s ・ SP cost %d ・ Grade value %d ・ [Conditions on GameTora](https://gametora.com/umamusume/skill-condition-viewer?skill=%d)", skilltype, skill.SPCost, skill.GradeValue, skill.ID)
|
||||
r.Components = append(r.Components, discord.NewSmallSeparator(), l)
|
||||
rel := make([]horse.Skill, 0, 4)
|
||||
for _, id := range groups[s.Group] {
|
||||
group := s.groups[skill.Group]
|
||||
for _, id := range [...]horse.SkillID{group.Skill1, group.Skill2, group.Skill3, group.SkillBad} {
|
||||
if id != 0 {
|
||||
rel = append(rel, all[id])
|
||||
rel = append(rel, s.skills[id])
|
||||
}
|
||||
}
|
||||
if len(rel) > 1 {
|
||||
buttons := make([]discord.InteractiveComponent, 0, 4)
|
||||
opts := make([]discord.StringSelectMenuOption, 0, 4)
|
||||
for _, rs := range rel {
|
||||
b := discord.NewSecondaryButton(rs.Name, fmt.Sprintf("/skill/%d", rs.ID))
|
||||
if rs.ID == id {
|
||||
b = b.AsDisabled()
|
||||
name := rs.Name
|
||||
emoji := "⚪"
|
||||
switch {
|
||||
case rs.Rarity == 3, rs.Rarity == 4, rs.Rarity == 5:
|
||||
emoji = "🟠"
|
||||
case rs.UniqueOwner != "":
|
||||
name += " (Inherited)"
|
||||
case rs.Rarity == 2:
|
||||
emoji = "🟡"
|
||||
case rs.GroupRate == -1:
|
||||
emoji = "🟣"
|
||||
}
|
||||
buttons = append(buttons, b)
|
||||
b := discord.NewStringSelectMenuOption(name, strconv.Itoa(int(rs.ID))).WithEmoji(discord.NewComponentEmoji(emoji))
|
||||
if rs.ID == skill.ID {
|
||||
b = b.WithDefault(true)
|
||||
}
|
||||
r.Components = append(r.Components, discord.NewActionRow(buttons...))
|
||||
opts = append(opts, b)
|
||||
}
|
||||
row := discord.NewActionRow(discord.NewStringSelectMenu("/skill/swap", "Related skills", opts...))
|
||||
r.Components = append(r.Components, row)
|
||||
}
|
||||
return r
|
||||
}
|
||||
@@ -132,19 +248,3 @@ func isDebuff(s horse.Skill) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var skillGlobalAuto = sync.OnceValue(func() *autocomplete.Set[discord.AutocompleteChoice] {
|
||||
var set autocomplete.Set[discord.AutocompleteChoice]
|
||||
for _, id := range global.OrderedSkills {
|
||||
s := global.AllSkills[id]
|
||||
set.Add(s.Name, discord.AutocompleteChoiceString{Name: s.Name, Value: s.Name})
|
||||
if s.UniqueOwner != "" {
|
||||
if s.Rarity >= 3 {
|
||||
set.Add(s.UniqueOwner, discord.AutocompleteChoiceString{Name: "Unique: " + s.UniqueOwner, Value: s.Name})
|
||||
} else {
|
||||
set.Add(s.UniqueOwner, discord.AutocompleteChoiceString{Name: "Inherited unique: " + s.UniqueOwner, Value: s.Name})
|
||||
}
|
||||
}
|
||||
}
|
||||
return &set
|
||||
})
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/png"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/gen2brain/avif"
|
||||
"golang.org/x/image/draw"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"zombiezen.com/go/sqlite"
|
||||
"zombiezen.com/go/sqlite/sqlitex"
|
||||
)
|
||||
|
||||
func saveImgs(ctx context.Context, db *sqlitex.Pool, out string) {
|
||||
skill, err := skillIconIDs(ctx, db)
|
||||
if err != nil {
|
||||
slog.Error("skills", slog.Any("err", err))
|
||||
}
|
||||
chara, err := charaIDs(ctx, db)
|
||||
if err != nil {
|
||||
slog.Error("characters", slog.Any("err", err))
|
||||
}
|
||||
rank, err := rankIDs(ctx, db)
|
||||
if err != nil {
|
||||
slog.Error("ranks", slog.Any("err", err))
|
||||
}
|
||||
|
||||
g, ctx := errgroup.WithContext(ctx)
|
||||
tick := time.NewTicker(250 * time.Millisecond)
|
||||
idouts(ctx, g, tick, skill, filepath.Join(out, "skill"), "https://media.gametora.com/umamusume/skills/icon/%d.png", image.Pt(64, 64), image.Pt(32, 32), image.Pt(16, 16))
|
||||
idouts(ctx, g, tick, chara, filepath.Join(out, "chara"), "https://gametora.com/images/umamusume/characters/icons/chr_icon_%d.png", image.Pt(256, 256), image.Pt(64, 64), image.Pt(32, 32), image.Pt(16, 16))
|
||||
idouts(ctx, g, tick, rank, filepath.Join(out, "rank"), "https://media.gametora.com/umamusume/ui/rank/%02d.png", image.Pt(128, 128), image.Pt(64, 64), image.Pt(32, 32), image.Pt(16, 16))
|
||||
idouts(ctx, g, tick, rank, filepath.Join(out, "rank", "simple"), "https://media.gametora.com/umamusume/ui/rank/simple/%02d.png", image.Pt(50, 50), image.Pt(32, 32), image.Pt(16, 16))
|
||||
if err := g.Wait(); err != nil {
|
||||
slog.Error("output", slog.Any("err", err))
|
||||
}
|
||||
}
|
||||
|
||||
// load scans all results of sql and appends them to r.
|
||||
func load[T any](ctx context.Context, db *sqlitex.Pool, r []T, sql string, row func(*sqlite.Stmt) T) ([]T, error) {
|
||||
conn, err := db.Take(ctx)
|
||||
defer db.Put(conn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stmt, err := conn.Prepare(sql)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for {
|
||||
ok, err := stmt.Step()
|
||||
if err != nil {
|
||||
return r, err
|
||||
}
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
r = append(r, row(stmt))
|
||||
}
|
||||
return r, err
|
||||
}
|
||||
|
||||
func skillIconIDs(ctx context.Context, db *sqlitex.Pool) ([]int32, error) {
|
||||
return load(ctx, db, nil, "SELECT DISTINCT icon_id FROM skill_data", func(s *sqlite.Stmt) int32 {
|
||||
return s.ColumnInt32(0)
|
||||
})
|
||||
}
|
||||
|
||||
func charaIDs(ctx context.Context, db *sqlitex.Pool) ([]int32, error) {
|
||||
return load(ctx, db, nil, "SELECT id FROM chara_data", func(s *sqlite.Stmt) int32 {
|
||||
return s.ColumnInt32(0)
|
||||
})
|
||||
}
|
||||
|
||||
func rankIDs(ctx context.Context, db *sqlitex.Pool) ([]int32, error) {
|
||||
return load(ctx, db, nil, "SELECT id-1 FROM single_mode_rank", func(s *sqlite.Stmt) int32 {
|
||||
return s.ColumnInt32(0)
|
||||
})
|
||||
}
|
||||
|
||||
var pngenc = &png.Encoder{CompressionLevel: png.BestCompression}
|
||||
|
||||
func idouts(ctx context.Context, g *errgroup.Group, tick *time.Ticker, ids []int32, p, urlf string, sizes ...image.Point) {
|
||||
for _, id := range ids {
|
||||
g.Go(func() error {
|
||||
n := strconv.Itoa(int(id))
|
||||
p := filepath.Join(p, n)
|
||||
_, err := os.Stat(p)
|
||||
if !errors.Is(err, os.ErrNotExist) {
|
||||
slog.DebugContext(ctx, "exists", slog.String("path", p))
|
||||
return nil
|
||||
}
|
||||
if err := os.MkdirAll(p, 0777); err != nil {
|
||||
return err
|
||||
}
|
||||
url := fmt.Sprintf(urlf, id)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-tick.C: // continue on
|
||||
}
|
||||
img, err := dlimg(ctx, url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
slog.InfoContext(ctx, "resize", slog.String("url", url))
|
||||
rs := resize(img, sizes...)
|
||||
for _, r := range rs {
|
||||
g.Go(func() error {
|
||||
m := r.Bounds().Max
|
||||
o := filepath.Join(p, fmt.Sprintf("%dx%d.png", m.X, m.Y))
|
||||
slog.InfoContext(ctx, "write", slog.String("path", o))
|
||||
f, err := os.Create(o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
return pngenc.Encode(f, r)
|
||||
})
|
||||
g.Go(func() error {
|
||||
m := r.Bounds().Max
|
||||
o := filepath.Join(p, fmt.Sprintf("%dx%d.avif", m.X, m.Y))
|
||||
slog.InfoContext(ctx, "write", slog.String("path", o))
|
||||
f, err := os.Create(o)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
return avif.Encode(f, r)
|
||||
})
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func dlimg(ctx context.Context, url string) (image.Image, error) {
|
||||
slog.InfoContext(ctx, "download", slog.String("url", url))
|
||||
ctx, stop := context.WithTimeout(ctx, 5*time.Second)
|
||||
defer stop()
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
slog.InfoContext(ctx, "decode", slog.String("url", url))
|
||||
img, _, err := image.Decode(resp.Body)
|
||||
return img, err
|
||||
}
|
||||
|
||||
func resize(img image.Image, sizes ...image.Point) []image.Image {
|
||||
rs := make([]image.Image, 0, len(sizes))
|
||||
for _, sz := range sizes {
|
||||
d := image.NewNRGBA(image.Rectangle{Min: image.Point{}, Max: sz})
|
||||
draw.CatmullRom.Scale(d, d.Bounds(), img, img.Bounds(), draw.Src, nil)
|
||||
rs = append(rs, d)
|
||||
}
|
||||
return rs
|
||||
}
|
||||
+137122
File diff suppressed because it is too large
Load Diff
+162
-6
@@ -6,13 +6,17 @@ This file is my notes from exploring the database.
|
||||
|
||||
# text_data categories
|
||||
|
||||
- 6 is character names, 4 is [variant] character name, 5 is [variant], 14 is variant
|
||||
- 6 is character names, 4 is [variant] character name, 5 is [variant], 14 is clothing names
|
||||
- 47 is skill names, 48 is skill descriptions
|
||||
- 75 is support card names incl. variant, 76 is support card variant, 77 is support card character
|
||||
- 147 is spark names, 172 is spark descriptions
|
||||
- 33 is race names by race id, 28 is race names by race instance id, 31 is race courses, 111 is saddle names
|
||||
- 65 is player titles, 66 is title descriptions - ties with honor_data?
|
||||
- 119 is scenario full titles (e.g. The Beginning: URA Finale), 120 is scenario descriptions, 237 is scenario names (e.g. URA Finale)
|
||||
- 130 is epithet names, 131 is epithet descriptions
|
||||
|
||||
in the decomp, text data categories are named in `public enum MasterString.Category`.
|
||||
some categories seem to be missing, though.
|
||||
|
||||
# succession factor (sparks)
|
||||
|
||||
@@ -64,9 +68,6 @@ effect_id distinguishes possibilities; factors with multiple effects (race and s
|
||||
effect_group_id determines the pmf, but no tables have non-empty joins with the same column name, so the distribution values are mystery.
|
||||
even searching for 51 and 52 (effect group ids for 1\* and 2\* race and scenario sparks) on consecutive lines gives nothing.
|
||||
|
||||
sf.grade = 1 unless it is a unique (green) spark, then sf.grade = 2.
|
||||
=> sf.grade = 2 iff sf.factor_type = 3
|
||||
|
||||
getting all interesting spark data, fully expanded with all effects:
|
||||
```sql
|
||||
WITH spark AS (
|
||||
@@ -195,12 +196,98 @@ target types:
|
||||
- 22 specific character, target value is character id
|
||||
- 23 other who triggered the skill
|
||||
|
||||
TODO target types only in jp: 2, 7, 11, 22, 23
|
||||
|
||||
ability_value_usage can be 1 for plain or 2-6 for aoharu stat skill stat scaling
|
||||
|
||||
seems to be activate_lot = 1 means wit check, 0 means guaranteed
|
||||
|
||||
tag_id is a slash-separated list of numeric IDs that roughly describe all effects relevant to the skill.
|
||||
- 101..104 style front, pace, late, end
|
||||
- 201..204 distance sprint, mile, medium, long
|
||||
- 301..303 timing early, mid, late race
|
||||
- 401 affects speed stat or target speed
|
||||
- 402 affects stamina stat or hp
|
||||
- 403 affects power stat or acceleration
|
||||
- 404 affects guts stat
|
||||
- 405 affects wit stat or vision
|
||||
- 406 is a debuff of any type, or is a main story self-debuff (creeping anxiety, blatant fear), or is Behold Thine Emperor's Divine Might (both own unique and inherited versions are tagged only 406??)
|
||||
- 407 modifies gate delay
|
||||
- 501..502 turf/dirt
|
||||
- 801..812 scenario skill
|
||||
|
||||
600 series applies to skills available in global but are only used in jp.
|
||||
- 601 ground condition passive
|
||||
- 602 weather passive
|
||||
- 603 season passive
|
||||
- 604 race track passive
|
||||
- 605 time of day passive
|
||||
- 606 exchange race passive (kawasaki, funabashi, morioka, ooi)
|
||||
- 607 distance passive (non/standard)
|
||||
- 608 track direction or corner count passive
|
||||
- 609 gate position passive
|
||||
- 610 ground type passive
|
||||
- 611 popularity passive
|
||||
- 612 running style passive
|
||||
- 613 passive depending on other horses' styles or skills
|
||||
- 614 base stat threshold passive
|
||||
- 615 mood passive
|
||||
|
||||
unrelated, query to get all condition types:
|
||||
```sql
|
||||
WITH RECURSIVE condition AS (
|
||||
SELECT DISTINCT precondition_1 AS c FROM skill_data
|
||||
UNION
|
||||
SELECT DISTINCT condition_1 AS c FROM skill_data
|
||||
UNION
|
||||
SELECT DISTINCT precondition_2 AS c FROM skill_data
|
||||
UNION
|
||||
SELECT DISTINCT condition_2 AS c FROM skill_data
|
||||
), disj AS (
|
||||
SELECT
|
||||
IIF(INSTR(c, '@') != 0, SUBSTR(c, 1, INSTR(c, '@')-1), c) AS c,
|
||||
IIF(INSTR(c, '@') != 0, SUBSTR(c, 1 + INSTR(c, '@')), '') AS rest
|
||||
FROM condition
|
||||
UNION
|
||||
SELECT
|
||||
IIF(INSTR(rest, '@') != 0, SUBSTR(rest, 1, INSTR(rest, '@')-1), rest) AS c,
|
||||
IIF(INSTR(rest, '@') != 0, SUBSTR(rest, 1 + INSTR(rest, '@')), '') AS rest
|
||||
FROM disj
|
||||
WHERE rest != ''
|
||||
), term AS (
|
||||
SELECT
|
||||
IIF(INSTR(c, '&') != 0, SUBSTR(c, 1, INSTR(c, '&')-1), c) AS term,
|
||||
IIF(INSTR(c, '&') != 0, SUBSTR(c, 1 + INSTR(c, '&')), '') AS rest
|
||||
FROM disj
|
||||
UNION
|
||||
SELECT
|
||||
IIF(INSTR(rest, '&') != 0, SUBSTR(rest, 1, INSTR(rest, '&')-1), rest) AS term,
|
||||
IIF(INSTR(rest, '&') != 0, SUBSTR(rest, 1 + INSTR(rest, '&')), '') AS rest
|
||||
FROM term
|
||||
WHERE rest != ''
|
||||
), op AS (
|
||||
SELECT
|
||||
term,
|
||||
CASE
|
||||
WHEN INSTR(term, '==') != 0 THEN '=='
|
||||
WHEN INSTR(term, '!=') != 0 THEN '!='
|
||||
WHEN INSTR(term, '<=') != 0 THEN '<='
|
||||
WHEN INSTR(term, '>=') != 0 THEN '>='
|
||||
WHEN INSTR(term, '<') != 0 THEN '<'
|
||||
WHEN INSTR(term, '>') != 0 THEN '>'
|
||||
END AS op
|
||||
FROM term WHERE term != ''
|
||||
), type_op_arg AS (
|
||||
SELECT DISTINCT
|
||||
term,
|
||||
SUBSTR(term, 1, INSTR(term, op) - 1) AS "type",
|
||||
op,
|
||||
CAST(SUBSTR(term, INSTR(term, op) + LENGTH(op)) AS INTEGER) AS arg
|
||||
FROM op
|
||||
)
|
||||
SELECT DISTINCT CONCAT(type, op), arg FROM type_op_arg
|
||||
```
|
||||
|
||||
final select can be adjusted to get different info, but type+op together seems most useful
|
||||
|
||||
# races
|
||||
|
||||
- group 1, grade: g1 100, g2 200, g3 300, op 400, pre-op 700
|
||||
@@ -233,6 +320,37 @@ so, it doesn't seem like there's a particular flag that identifies maiden races,
|
||||
- card_talent_hint_upgrade has costs to raise hint levels, but it's actually universal, only six rows
|
||||
- single_mode_route_race is career goals (not only races)
|
||||
- available_skill_set has starting skills including those unlocked by potential level given under need_rank (0 for pl1, 2 for pl2)
|
||||
- single_mode_special_chara is scenario links
|
||||
|
||||
# gl
|
||||
|
||||
single_mode_live_song_list has the song list for lives ha ha.
|
||||
this is defined from the perspective of bonuses they grant when you have them, not the shop per se.
|
||||
- text_data category for song names is 210, look up by live_id; for post-concert effect text, category 208 indexed by song list id
|
||||
- command_id and live_id are always equal
|
||||
- level is 1 for all songs except the two instances of girls' legend u
|
||||
- master_bonus_content_text_id corresponds to text_data categories 207 for pickup effect text and 209 for song name
|
||||
- live_bonus_type is 1 for specialty prio, 2 for chain frequency, 3 for fb
|
||||
- girls' legend u is defined twice as ids 22 and 24
|
||||
|
||||
costs are in single_mode_live_square.
|
||||
- square_type is 1 for stat up, 2 for skill up, 3 for energy up, 4 for live
|
||||
- perf_type_n is token type: 1 for dance, 2 for passion, 3 for vocals, 4 for visuals, 5 for composure
|
||||
- perf_value_n is number of tokens
|
||||
|
||||
immediate bonuses are in single_mode_live_master_bonus.
|
||||
- master_bonus_type is 1 for stat up, 2 for skill hint, 3 for energy up, 4 for song
|
||||
- master_bonus_type_value is 1 for type 1, live id for type 4, 0 otherwise
|
||||
- master_bonus_gain_type_n is 1 for stat, 2 for skill hint, 3 for energy, 5 for permanent training bonus
|
||||
+ 1 for stat: then master_bonus_gain_value_n_1 is 1-5 for stat id or 6 for sp, n_2 is 1 for fixed or 2 for random (not actually in the game), n_3 is lower bound on gain, n_4 is 0 for fixed or upper bound for random
|
||||
+ 2 for skill hint: then gain_value_n_1 is 3(*), n_2 is skill tag, n_3 is hint level
|
||||
+ 3 for energy: then gain_value_n_1 is amount
|
||||
+ 5 for permanent training bonus: then gain_value_n_1 is stat id (6 for sp), n_2 is amount
|
||||
(*) MasterSingleModeLiveMasterBonus.SingleModeLiveMasterBonus.GainSkillHintTypeEnum defines values of Random = 1 and SkillId = 2, but they are unused in the db.
|
||||
|
||||
there is some ostensibly unused data.
|
||||
- master bonus ids 12001-12206 grant random amounts of stats
|
||||
- id 20000 corresponds to "Group Lesson" "Skill hint appropriate for aptitude"
|
||||
|
||||
# lobby conversations!!!
|
||||
|
||||
@@ -256,11 +374,49 @@ num is how many characters are involved, but also can just check chara_id_{1,2,3
|
||||
|
||||
unsure what condition_type is.
|
||||
values of 2 and 3 always have two or three characters, and values of 4 (jp only) always have three, but 0 and 1 can have any number.
|
||||
there's no requirement for stories like having a horse at all, much less an affinity level.
|
||||
|
||||
gallery_chara_id is the character whose conversation it is; chara_id_{1,2,3} are the characters involved.
|
||||
gallery_chara_id is always one of the three, but it can be any one of the three.
|
||||
disp_order then is the conversation number within their gallery.
|
||||
|
||||
getting all conversation data:
|
||||
```sql
|
||||
WITH chara_name AS (
|
||||
SELECT "index" AS id, "text" AS name
|
||||
FROM text_data
|
||||
WHERE category = 6
|
||||
), convo_loc_names AS (
|
||||
SELECT 110 AS pos_id, 'right side front' AS name UNION ALL
|
||||
SELECT 120 AS pos_id, 'right side front' AS name UNION ALL
|
||||
SELECT 130 AS pos_id, 'right side front' AS name UNION ALL
|
||||
SELECT 210 AS pos_id, 'left side table' AS name UNION ALL
|
||||
SELECT 220 AS pos_id, 'left side table' AS name UNION ALL
|
||||
SELECT 310 AS pos_id, 'center back seat' AS name UNION ALL
|
||||
SELECT 410 AS pos_id, 'center posters' AS name UNION ALL
|
||||
SELECT 420 AS pos_id, 'center posters' AS name UNION ALL
|
||||
SELECT 430 AS pos_id, 'center posters' AS name UNION ALL
|
||||
SELECT 510 AS pos_id, 'left side school map' AS name UNION ALL
|
||||
SELECT 520 AS pos_id, 'left side school map' AS name UNION ALL
|
||||
SELECT 530 AS pos_id, 'left side school map' AS name
|
||||
)
|
||||
SELECT
|
||||
n.name,
|
||||
s.disp_order,
|
||||
l.name,
|
||||
c1.name,
|
||||
c2.name,
|
||||
c3.name,
|
||||
s.condition_type
|
||||
FROM home_story_trigger s
|
||||
LEFT JOIN chara_name n ON s.gallery_chara_id = n.id
|
||||
LEFT JOIN chara_name c1 ON s.chara_id_1 = c1.id
|
||||
LEFT JOIN chara_name c2 ON s.chara_id_2 = c2.id
|
||||
LEFT JOIN chara_name c3 ON s.chara_id_3 = c3.id
|
||||
LEFT JOIN convo_loc_names l ON s.pos_id = l.pos_id
|
||||
ORDER BY s.gallery_chara_id, s.disp_order
|
||||
```
|
||||
|
||||
# update diffs
|
||||
|
||||
complete list of tables with inserts in both the 2026-01-15 update adding fine motion, manhattan cafe ssr, inari one sr and the 2026-01-22 update adding tamamo cross and main story 5:
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -ex
|
||||
|
||||
go run ./horsegen "$@"
|
||||
go generate ./horse/...
|
||||
go fmt ./...
|
||||
go test ./...
|
||||
@@ -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)
|
||||
}
|
||||
@@ -3,30 +3,38 @@ module git.sunturtle.xyz/zephyr/horse
|
||||
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
|
||||
github.com/disgoorg/disgo v0.19.6
|
||||
github.com/gen2brain/avif v0.6.0
|
||||
github.com/go-chi/chi/v5 v5.3.1
|
||||
github.com/google/go-cmp v0.7.0
|
||||
github.com/junegunn/fzf v0.74.1
|
||||
golang.org/x/image v0.44.0
|
||||
golang.org/x/sync v0.22.0
|
||||
zombiezen.com/go/sqlite v1.4.2
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/disgoorg/godave v0.3.0 // indirect
|
||||
github.com/disgoorg/json/v2 v2.0.0 // indirect
|
||||
github.com/disgoorg/omit v1.0.0 // indirect
|
||||
github.com/disgoorg/snowflake/v2 v2.0.3 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/ebitengine/purego v0.10.2 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
github.com/klauspost/compress v1.18.2 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||
github.com/junegunn/go-shellwords v0.0.0-20250127100254-2aa3b3277741 // indirect
|
||||
github.com/klauspost/compress v1.19.1 // indirect
|
||||
github.com/mattn/go-isatty v0.0.24 // indirect
|
||||
github.com/ncruces/go-strftime v1.0.0 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/sasha-s/go-csync v0.0.0-20240107134140-fcbab37b09ad // indirect
|
||||
golang.org/x/crypto v0.46.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect
|
||||
golang.org/x/sys v0.39.0 // indirect
|
||||
modernc.org/libc v1.65.7 // indirect
|
||||
github.com/tetratelabs/wazero v1.12.0 // indirect
|
||||
golang.org/x/crypto v0.54.0 // indirect
|
||||
golang.org/x/sys v0.47.0 // indirect
|
||||
golang.org/x/tools v0.48.0 // indirect
|
||||
modernc.org/libc v1.74.3 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
modernc.org/memory v1.11.0 // indirect
|
||||
modernc.org/sqlite v1.37.1 // indirect
|
||||
modernc.org/sqlite v1.54.0 // indirect
|
||||
)
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/disgoorg/disgo v0.19.0-rc.15 h1:x0NsV2gcbdjwuztsg2wYXw76p1Cpc8f6ByDrkPcfQtU=
|
||||
github.com/disgoorg/disgo v0.19.0-rc.15/go.mod h1:14mgXzenkJqifkDmsEgU0zI1di6jNXodwX6L8geW33A=
|
||||
github.com/disgoorg/disgo v0.19.6 h1:1xJQt6KZgiqvBOnjuziG1gE4Iqd0aJn8DNfE6eE+0qw=
|
||||
github.com/disgoorg/disgo v0.19.6/go.mod h1:NnV63iw4lJdF1fnV0gX27XR43ZgRGqnL122svRMTgTE=
|
||||
github.com/disgoorg/godave v0.3.0 h1:37F3ZuiMd8/EXeoCtTeE8iP2eT2nWsfEa4/ITwoKfe4=
|
||||
github.com/disgoorg/godave v0.3.0/go.mod h1:OreAC3hpabr39bMVA+jwOVDq1EUPXH5A0XUBiZaDI1Y=
|
||||
github.com/disgoorg/json/v2 v2.0.0 h1:U16yy/ARK7/aEpzjjqK1b/KaqqGHozUdeVw/DViEzQI=
|
||||
github.com/disgoorg/json/v2 v2.0.0/go.mod h1:jZTBC0nIE1WeetSEI3/Dka8g+qglb4FPVmp5I5HpEfI=
|
||||
github.com/disgoorg/omit v1.0.0 h1:y0LkVUOyUHT8ZlnhIAeOZEA22UYykeysK8bLJ0SfT78=
|
||||
@@ -10,20 +12,30 @@ github.com/disgoorg/snowflake/v2 v2.0.3 h1:3B+PpFjr7j4ad7oeJu4RlQ+nYOTadsKapJIzg
|
||||
github.com/disgoorg/snowflake/v2 v2.0.3/go.mod h1:W6r7NUA7DwfZLwr00km6G4UnZ0zcoLBRufhkFWgAc4c=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/ebitengine/purego v0.10.2 h1:W809HbnvzAxgdm+aOvlSekrM16wGCdT/e76+9tS7gzE=
|
||||
github.com/ebitengine/purego v0.10.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/gen2brain/avif v0.6.0 h1:/8WSgcU+IEF0jhKYsUZ/mzlziFuTeJFpIKBj2siTQps=
|
||||
github.com/gen2brain/avif v0.6.0/go.mod h1:QgrYqdVE9y40PCfArK9VakcMIpYeDYpZmCSLkW6C1n8=
|
||||
github.com/go-chi/chi/v5 v5.3.1 h1:3j4HZLGZQ3JpMCrPJF/Jl3mYJfWLKBfNJ6quurUGCf8=
|
||||
github.com/go-chi/chi/v5 v5.3.1/go.mod h1:R+tYY2hNuVUUjxoPtqUdgBqevM9s9njzkTLutVsOCto=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/junegunn/fzf v0.67.0 h1:naiOdIkV5/ZCfHgKQIV/f5YDWowl95G6yyOQqW8FeSo=
|
||||
github.com/junegunn/fzf v0.67.0/go.mod h1:xlXX2/rmsccKQUnr9QOXPDi5DyV9cM0UjKy/huScBeE=
|
||||
github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk=
|
||||
github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
||||
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||
github.com/junegunn/fzf v0.74.1 h1:rCGVdCSoOkfcfTxtxCO/vG2yceDjRlKSlv7IfCGkc/Y=
|
||||
github.com/junegunn/fzf v0.74.1/go.mod h1:hKDkO8orBWT5VLIZOL8oyhxn7mRLXdGyu+gz1Ss58pU=
|
||||
github.com/junegunn/go-shellwords v0.0.0-20250127100254-2aa3b3277741 h1:7dYDtfMDfKzjT+DVfIS4iqknSEKtZpEcXtu6vuaasHs=
|
||||
github.com/junegunn/go-shellwords v0.0.0-20250127100254-2aa3b3277741/go.mod h1:6EILKtGpo5t+KLb85LNZLAF6P9LKp78hJI80PXMcn3c=
|
||||
github.com/klauspost/compress v1.19.1 h1:VsB4HPswih7mmZ8WleSFQ75c/Ui1M4trX5oAsJnhSlk=
|
||||
github.com/klauspost/compress v1.19.1/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
|
||||
github.com/mattn/go-isatty v0.0.24 h1:tGZZoVgT/KiqK1c8ocVLeDS8BSWMRd47J3Lbz7vsReI=
|
||||
github.com/mattn/go-isatty v0.0.24/go.mod h1:nMCL3Zebbrt45jsMDgnfIwz6ydEQApk5oEI3HqDio6A=
|
||||
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
|
||||
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
@@ -34,43 +46,48 @@ github.com/sasha-s/go-csync v0.0.0-20240107134140-fcbab37b09ad h1:qIQkSlF5vAUHxE
|
||||
github.com/sasha-s/go-csync v0.0.0-20240107134140-fcbab37b09ad/go.mod h1:/pA7k3zsXKdjjAiUhB5CjuKib9KJGCaLvZwtxGC8U0s=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
|
||||
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
|
||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM=
|
||||
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/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=
|
||||
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
|
||||
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
|
||||
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
|
||||
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
|
||||
github.com/tetratelabs/wazero v1.12.0 h1:DuWcpNu/FzgEXgGBDp8J1Spc+CWOvvtvVyjKlaZopYU=
|
||||
github.com/tetratelabs/wazero v1.12.0/go.mod h1:LvKtzl2RqO4gyF27BiXU+nKAjcV8f38U+kP/q2vgxh0=
|
||||
golang.org/x/crypto v0.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw=
|
||||
golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk=
|
||||
golang.org/x/image v0.44.0 h1:+tDekMZED9+LrtB3G5xzRggpVh9CARjZqROla3R3R+I=
|
||||
golang.org/x/image v0.44.0/go.mod h1:V8K3KE9KKKE+pLpQDOeN18w9oacNSvy1tDOirTu4xtY=
|
||||
golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk=
|
||||
golang.org/x/mod v0.38.0/go.mod h1:V6Xz0pq8TQ3dGqVQ1FVHuelZpAL0uNhSkk9ogYP3c40=
|
||||
golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek=
|
||||
golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
|
||||
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs=
|
||||
golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY=
|
||||
golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE=
|
||||
golang.org/x/tools v0.48.0/go.mod h1:08xX0orndb/F7jJxGDicx061tyd5pcMto75YMAXr6lk=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
modernc.org/cc/v4 v4.26.1 h1:+X5NtzVBn0KgsBCBe+xkDC7twLb/jNVj9FPgiwSQO3s=
|
||||
modernc.org/cc/v4 v4.26.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
|
||||
modernc.org/ccgo/v4 v4.28.0 h1:rjznn6WWehKq7dG4JtLRKxb52Ecv8OUGah8+Z/SfpNU=
|
||||
modernc.org/ccgo/v4 v4.28.0/go.mod h1:JygV3+9AV6SmPhDasu4JgquwU81XAKLd3OKTUDNOiKE=
|
||||
modernc.org/fileutil v1.3.1 h1:8vq5fe7jdtEvoCf3Zf9Nm0Q05sH6kGx0Op2CPx1wTC8=
|
||||
modernc.org/fileutil v1.3.1/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc=
|
||||
modernc.org/cc/v4 v4.29.1 h1:MKgdCV3WykTSPqpVrnxdEDS0HEd2FHpKZDzxzU5LyeI=
|
||||
modernc.org/cc/v4 v4.29.1/go.mod h1:OnovgIhbbMXMu1aISnJ0wvVD1KnW+cAUJkIrAWh+kVI=
|
||||
modernc.org/ccgo/v4 v4.34.6 h1:sBgfIwyN0TQ9C5hwIeuqyeAKyMWnbvj2fvpF4L11uzU=
|
||||
modernc.org/ccgo/v4 v4.34.6/go.mod h1:SZ8YcN9NG7XVsQYdm6jYBvi8PQP1qi+kqB6OhjqI3Fk=
|
||||
modernc.org/fileutil v1.4.0 h1:j6ZzNTftVS054gi281TyLjHPp6CPHr2KCxEXjEbD6SM=
|
||||
modernc.org/fileutil v1.4.0/go.mod h1:EqdKFDxiByqxLk8ozOxObDSfcVOv/54xDs/DUHdvCUU=
|
||||
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
|
||||
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
|
||||
modernc.org/libc v1.65.7 h1:Ia9Z4yzZtWNtUIuiPuQ7Qf7kxYrxP1/jeHZzG8bFu00=
|
||||
modernc.org/libc v1.65.7/go.mod h1:011EQibzzio/VX3ygj1qGFt5kMjP0lHb0qCW5/D/pQU=
|
||||
modernc.org/gc/v3 v3.1.4 h1:2g65LGVSmFQrXeITAw97x7hCRvZFcyE1uDP+7Vng7JI=
|
||||
modernc.org/gc/v3 v3.1.4/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY=
|
||||
modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=
|
||||
modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=
|
||||
modernc.org/libc v1.74.3 h1:a4J+Z8aVaxPyjyxRAdJzw246PqpcFGvVPnfT/AuM5Ws=
|
||||
modernc.org/libc v1.74.3/go.mod h1:4H7h/MJ8wnjL8RAbp9v3OXgnk22X7MouHIhDbvP3gj4=
|
||||
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
|
||||
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
|
||||
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
|
||||
modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
|
||||
modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
|
||||
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
|
||||
modernc.org/opt v0.2.0 h1:tGyef5ApycA7FSEOMraay9SaTk5zmbx7Tu+cJs4QKZg=
|
||||
modernc.org/opt v0.2.0/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
|
||||
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
|
||||
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
|
||||
modernc.org/sqlite v1.37.1 h1:EgHJK/FPoqC+q2YBXg7fUmES37pCHFc97sI7zSayBEs=
|
||||
modernc.org/sqlite v1.37.1/go.mod h1:XwdRtsE1MpiBcL54+MbKcaDvcuej+IYSMfLN6gSKV8g=
|
||||
modernc.org/sqlite v1.54.0 h1:JCxR4qwkJvOaqAoYcgDoO25Nc+ROg6EJ2LfBVzdrgog=
|
||||
modernc.org/sqlite v1.54.0/go.mod h1:4ntCLuNmnH8+GNqjka1wNg7KJd5/Hi5FYp8K+XQ7GZw=
|
||||
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
|
||||
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
||||
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
# horse
|
||||
|
||||
This directory contains manually written code and types on which the generated code depends.
|
||||
|
||||
The generated code is in ./global; other regions will follow the same convention once they are supported.
|
||||
It is always safe to delete the entire directories and regenerate them.
|
||||
@@ -1,12 +0,0 @@
|
||||
package horse
|
||||
|
||||
type CharacterID int16
|
||||
|
||||
type Character struct {
|
||||
ID CharacterID
|
||||
Name string
|
||||
}
|
||||
|
||||
func (c Character) String() string {
|
||||
return c.Name
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
module horse/character
|
||||
|
||||
import horse/game-id
|
||||
|
||||
pub struct character-detail
|
||||
character-id: character-id
|
||||
name: string
|
||||
|
||||
pub fun detail(
|
||||
c: character-id,
|
||||
?character/show: (character-id) -> string
|
||||
): character-detail
|
||||
Character-detail(c, c.show)
|
||||
|
||||
pub fun character-detail/show(d: character-detail): string
|
||||
val Character-detail(Character-id(id), name) = d
|
||||
name ++ " (ID " ++ id.show ++ ")"
|
||||
@@ -1,76 +0,0 @@
|
||||
module horse/game-id
|
||||
|
||||
// Game ID for characters, cards, skills, races, &c.
|
||||
// Values for different categories may overlap.
|
||||
pub alias game-id = int
|
||||
|
||||
// Specific game ID types.
|
||||
// I've already made mistakes with ID categories and I haven't even committed this file yet.
|
||||
|
||||
pub struct scenario-id
|
||||
game-id: game-id
|
||||
|
||||
// Game ID for characters.
|
||||
// Generally numbers in the range 1000-9999.
|
||||
pub struct character-id
|
||||
game-id: game-id
|
||||
|
||||
// Game ID for trainees, i.e. costume instances of characters.
|
||||
// Generally a character ID with two digits appended.
|
||||
pub struct uma-id
|
||||
game-id: game-id
|
||||
|
||||
// Game ID for skills.
|
||||
pub struct skill-id
|
||||
game-id: game-id
|
||||
|
||||
// Game ID for skill groups.
|
||||
pub struct skill-group-id
|
||||
game-id: game-id
|
||||
|
||||
// Game ID for skill icons.
|
||||
pub struct skill-icon-id
|
||||
game-id: game-id
|
||||
|
||||
// Game ID for races,
|
||||
// i.e. "Tenno Sho (Spring)" and not "Tenno Sho (Spring) at Kyoto Racecourse."
|
||||
pub struct race-id
|
||||
game-id: game-id
|
||||
|
||||
// Game ID for race thumbnails.
|
||||
pub struct race-thumbnail-id
|
||||
game-id: game-id
|
||||
|
||||
// Game ID for saddles,
|
||||
// i.e. one or more race wins that appear as a title.
|
||||
pub struct saddle-id
|
||||
game-id: game-id
|
||||
|
||||
// Game ID for sparks,
|
||||
// i.e. succession factors.
|
||||
pub struct spark-id
|
||||
game-id: game-id
|
||||
|
||||
// Game ID for spark groups,
|
||||
// i.e. all rarities (star counts) of a single spark.
|
||||
pub struct spark-group-id
|
||||
game-id: game-id
|
||||
|
||||
// order2 comparison between any game ID types.
|
||||
pub inline fun order2(x: a, y: a, ?a/game-id: (a) -> game-id): order2<a>
|
||||
match x.game-id.cmp(y.game-id)
|
||||
Lt -> Lt2(x, y)
|
||||
Eq -> Eq2(x)
|
||||
Gt -> Gt2(x, y)
|
||||
|
||||
// Comparison between any game ID types.
|
||||
pub inline fun cmp(x: a, y: a, ?a/game-id: (a) -> game-id): order
|
||||
x.game-id.cmp(y.game-id)
|
||||
|
||||
// Equality between any game ID types.
|
||||
pub inline fun (==)(x: a, y: a, ?a/game-id: (a) -> game-id): bool
|
||||
x.game-id == y.game-id
|
||||
|
||||
// Check whether a game ID is valid, i.e. nonzero.
|
||||
pub inline fun is-valid(x: a, ?a/game-id: (a) -> game-id): bool
|
||||
x.game-id != 0
|
||||
File diff suppressed because one or more lines are too long
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
File diff suppressed because it is too large
Load Diff
@@ -1,985 +0,0 @@
|
||||
module horse/global/saddle
|
||||
|
||||
// Automatically generated with horsegen; DO NOT EDIT
|
||||
|
||||
import horse/game-id
|
||||
pub import horse/race
|
||||
pub import horse/global/race
|
||||
|
||||
// Enumeration of all saddles for type-safe programming.
|
||||
pub type saddle
|
||||
Classic-Triple-Crown
|
||||
Senior-Autumn-Triple-Crown
|
||||
Triple-Tiara
|
||||
Senior-Spring-Triple-Crown
|
||||
Tenno-Sweep
|
||||
Dual-Grand-Prix
|
||||
Dual-Miles
|
||||
Dual-Sprints
|
||||
Dual-Dirts
|
||||
Arima-Kinen
|
||||
Japan-C
|
||||
Japanese-Derby
|
||||
Tenno-Sho-Spring
|
||||
Takarazuka-Kinen
|
||||
Tenno-Sho-Autumn
|
||||
Kikuka-Sho
|
||||
Osaka-Hai
|
||||
Satsuki-Sho
|
||||
Japanese-Oaks
|
||||
Takamatsunomiya-Kinen
|
||||
Yasuda-Kinen
|
||||
Sprinters-S
|
||||
Mile-Ch
|
||||
Oka-Sho
|
||||
Victoria-Mile
|
||||
Queen-Elizabeth-II-Cup
|
||||
NHK-Mile-C
|
||||
Shuka-Sho
|
||||
Champions-C
|
||||
February-S
|
||||
JBC-Classic
|
||||
Tokyo-Daishoten
|
||||
Asahi-Hai-FS
|
||||
Hopeful-S
|
||||
Hanshin-JF
|
||||
Teio-Sho
|
||||
JBC-Sprint
|
||||
JD-Derby
|
||||
JBC-L-Classic
|
||||
Nikkei-Shinshun-Hai
|
||||
Tokai-S
|
||||
American-JCC
|
||||
Kyoto-Kinen
|
||||
Nakayama-Kinen
|
||||
Yayoi-Sho
|
||||
Kinko-Sho
|
||||
Fillies-Revue
|
||||
Hanshin-Daishoten
|
||||
Spring-S
|
||||
Nikkei-Sho
|
||||
Hanshin-Umamusume-S
|
||||
New-Zealand-T
|
||||
Yomiuri-Milers-C
|
||||
Flora-S
|
||||
Aoba-Sho
|
||||
Kyoto-Shimbun-Hai
|
||||
Keio-Hai-Spring-C
|
||||
Meguro-Kinen
|
||||
Sapporo-Kinen
|
||||
Centaur-S
|
||||
Rose-S
|
||||
St-Lite-Kinen
|
||||
Kobe-Shimbun-Hai
|
||||
All-Comers
|
||||
Mainichi-Okan
|
||||
Kyoto-Daishoten
|
||||
Fuchu-Umamusume-S
|
||||
Swan-S
|
||||
Keio-Hai-Junior-S
|
||||
Copa-Republica-Argentina
|
||||
Daily-Hai-Junior-S
|
||||
Stayers-S
|
||||
Hanshin-C
|
||||
Kyoto-Kimpai
|
||||
Nakayama-Kimpai
|
||||
Shinzan-Kinen
|
||||
Fairy-S
|
||||
Aichi-Hai
|
||||
Keisei-Hai
|
||||
Silk-Road-S
|
||||
Negishi-S
|
||||
Kisaragi-Sho
|
||||
Tokyo-Shimbun-Hai
|
||||
Queen-C
|
||||
Kyodo-News-Hai
|
||||
Kyoto-Umamusume-S
|
||||
Diamond-S
|
||||
Kokura-Daishoten
|
||||
Arlington-C
|
||||
Hankyu-Hai
|
||||
Tulip-Sho
|
||||
Ocean-S
|
||||
Nakayama-Umamusume-S
|
||||
Falcon-S
|
||||
Flower-C
|
||||
Mainichi-Hai
|
||||
March-S
|
||||
Lord-Derby-CT
|
||||
Antares-S
|
||||
Fukushima-Umamusume-S
|
||||
Niigata-Daishoten
|
||||
Heian-S
|
||||
Naruo-Kinen
|
||||
Mermaid-S
|
||||
Epsom-C
|
||||
Unicorn-S
|
||||
Hakodate-Sprint-S
|
||||
CBC-Sho
|
||||
Radio-Nikkei-Sho
|
||||
Procyon-S
|
||||
Tanabata-Sho
|
||||
Hakodate-Kinen
|
||||
Chukyo-Kinen
|
||||
Hakodate-Junior-S
|
||||
Ibis-Summer-D
|
||||
Queen-S
|
||||
Kokura-Kinen
|
||||
Leopard-S
|
||||
Sekiya-Kinen
|
||||
Elm-S
|
||||
Kitakyushu-Kinen
|
||||
Niigata-Junior-S
|
||||
Keeneland-C
|
||||
Sapporo-Junior-S
|
||||
Kokura-Junior-S
|
||||
Niigata-Kinen
|
||||
Shion-S
|
||||
Keisei-Hai-AH
|
||||
Sirius-S
|
||||
Saudi-Arabia-RC
|
||||
Fuji-S
|
||||
Artemis-S
|
||||
Fantasy-S
|
||||
Miyako-S
|
||||
Musashino-S
|
||||
Fukushima-Kinen
|
||||
Tokyo-Sports-Hai-Junior-S
|
||||
Kyoto-Junior-S
|
||||
Keihan-Hai
|
||||
Challenge-C
|
||||
Chunichi-Shimbun-Hai
|
||||
Capella-S
|
||||
Turquoise-S
|
||||
Classic-Triple-Crown-Alt144
|
||||
Senior-Spring-Triple-Crown-Alt145
|
||||
Dual-Grand-Prix-Alt146
|
||||
Takarazuka-Kinen-Alt147
|
||||
Kikuka-Sho-Alt148
|
||||
Spring-S-Alt149
|
||||
Aoi-S
|
||||
Senior-Spring-Triple-Crown-Alt151
|
||||
Tenno-Sweep-Alt152
|
||||
Tenno-Sho-Spring-Alt153
|
||||
Classic-Triple-Crown-Alt154
|
||||
Satsuki-Sho-Alt155
|
||||
|
||||
// Get the saddle ID for a saddle.
|
||||
pub fun saddle-id(s: saddle): saddle-id
|
||||
match s
|
||||
Classic-Triple-Crown -> Saddle-id(1)
|
||||
Senior-Autumn-Triple-Crown -> Saddle-id(2)
|
||||
Triple-Tiara -> Saddle-id(3)
|
||||
Senior-Spring-Triple-Crown -> Saddle-id(4)
|
||||
Tenno-Sweep -> Saddle-id(5)
|
||||
Dual-Grand-Prix -> Saddle-id(6)
|
||||
Dual-Miles -> Saddle-id(7)
|
||||
Dual-Sprints -> Saddle-id(8)
|
||||
Dual-Dirts -> Saddle-id(9)
|
||||
Arima-Kinen -> Saddle-id(10)
|
||||
Japan-C -> Saddle-id(11)
|
||||
Japanese-Derby -> Saddle-id(12)
|
||||
Tenno-Sho-Spring -> Saddle-id(13)
|
||||
Takarazuka-Kinen -> Saddle-id(14)
|
||||
Tenno-Sho-Autumn -> Saddle-id(15)
|
||||
Kikuka-Sho -> Saddle-id(16)
|
||||
Osaka-Hai -> Saddle-id(17)
|
||||
Satsuki-Sho -> Saddle-id(18)
|
||||
Japanese-Oaks -> Saddle-id(19)
|
||||
Takamatsunomiya-Kinen -> Saddle-id(20)
|
||||
Yasuda-Kinen -> Saddle-id(21)
|
||||
Sprinters-S -> Saddle-id(22)
|
||||
Mile-Ch -> Saddle-id(23)
|
||||
Oka-Sho -> Saddle-id(24)
|
||||
Victoria-Mile -> Saddle-id(25)
|
||||
Queen-Elizabeth-II-Cup -> Saddle-id(26)
|
||||
NHK-Mile-C -> Saddle-id(27)
|
||||
Shuka-Sho -> Saddle-id(28)
|
||||
Champions-C -> Saddle-id(29)
|
||||
February-S -> Saddle-id(30)
|
||||
JBC-Classic -> Saddle-id(31)
|
||||
Tokyo-Daishoten -> Saddle-id(32)
|
||||
Asahi-Hai-FS -> Saddle-id(33)
|
||||
Hopeful-S -> Saddle-id(34)
|
||||
Hanshin-JF -> Saddle-id(35)
|
||||
Teio-Sho -> Saddle-id(36)
|
||||
JBC-Sprint -> Saddle-id(37)
|
||||
JD-Derby -> Saddle-id(38)
|
||||
JBC-L-Classic -> Saddle-id(39)
|
||||
Nikkei-Shinshun-Hai -> Saddle-id(40)
|
||||
Tokai-S -> Saddle-id(41)
|
||||
American-JCC -> Saddle-id(42)
|
||||
Kyoto-Kinen -> Saddle-id(43)
|
||||
Nakayama-Kinen -> Saddle-id(44)
|
||||
Yayoi-Sho -> Saddle-id(45)
|
||||
Kinko-Sho -> Saddle-id(46)
|
||||
Fillies-Revue -> Saddle-id(47)
|
||||
Hanshin-Daishoten -> Saddle-id(48)
|
||||
Spring-S -> Saddle-id(49)
|
||||
Nikkei-Sho -> Saddle-id(50)
|
||||
Hanshin-Umamusume-S -> Saddle-id(51)
|
||||
New-Zealand-T -> Saddle-id(52)
|
||||
Yomiuri-Milers-C -> Saddle-id(53)
|
||||
Flora-S -> Saddle-id(54)
|
||||
Aoba-Sho -> Saddle-id(55)
|
||||
Kyoto-Shimbun-Hai -> Saddle-id(56)
|
||||
Keio-Hai-Spring-C -> Saddle-id(57)
|
||||
Meguro-Kinen -> Saddle-id(58)
|
||||
Sapporo-Kinen -> Saddle-id(59)
|
||||
Centaur-S -> Saddle-id(60)
|
||||
Rose-S -> Saddle-id(61)
|
||||
St-Lite-Kinen -> Saddle-id(62)
|
||||
Kobe-Shimbun-Hai -> Saddle-id(63)
|
||||
All-Comers -> Saddle-id(64)
|
||||
Mainichi-Okan -> Saddle-id(65)
|
||||
Kyoto-Daishoten -> Saddle-id(66)
|
||||
Fuchu-Umamusume-S -> Saddle-id(67)
|
||||
Swan-S -> Saddle-id(68)
|
||||
Keio-Hai-Junior-S -> Saddle-id(69)
|
||||
Copa-Republica-Argentina -> Saddle-id(70)
|
||||
Daily-Hai-Junior-S -> Saddle-id(71)
|
||||
Stayers-S -> Saddle-id(72)
|
||||
Hanshin-C -> Saddle-id(73)
|
||||
Kyoto-Kimpai -> Saddle-id(74)
|
||||
Nakayama-Kimpai -> Saddle-id(75)
|
||||
Shinzan-Kinen -> Saddle-id(76)
|
||||
Fairy-S -> Saddle-id(77)
|
||||
Aichi-Hai -> Saddle-id(78)
|
||||
Keisei-Hai -> Saddle-id(79)
|
||||
Silk-Road-S -> Saddle-id(80)
|
||||
Negishi-S -> Saddle-id(81)
|
||||
Kisaragi-Sho -> Saddle-id(82)
|
||||
Tokyo-Shimbun-Hai -> Saddle-id(83)
|
||||
Queen-C -> Saddle-id(84)
|
||||
Kyodo-News-Hai -> Saddle-id(85)
|
||||
Kyoto-Umamusume-S -> Saddle-id(86)
|
||||
Diamond-S -> Saddle-id(87)
|
||||
Kokura-Daishoten -> Saddle-id(88)
|
||||
Arlington-C -> Saddle-id(89)
|
||||
Hankyu-Hai -> Saddle-id(90)
|
||||
Tulip-Sho -> Saddle-id(91)
|
||||
Ocean-S -> Saddle-id(92)
|
||||
Nakayama-Umamusume-S -> Saddle-id(93)
|
||||
Falcon-S -> Saddle-id(94)
|
||||
Flower-C -> Saddle-id(95)
|
||||
Mainichi-Hai -> Saddle-id(96)
|
||||
March-S -> Saddle-id(97)
|
||||
Lord-Derby-CT -> Saddle-id(98)
|
||||
Antares-S -> Saddle-id(99)
|
||||
Fukushima-Umamusume-S -> Saddle-id(100)
|
||||
Niigata-Daishoten -> Saddle-id(101)
|
||||
Heian-S -> Saddle-id(102)
|
||||
Naruo-Kinen -> Saddle-id(103)
|
||||
Mermaid-S -> Saddle-id(104)
|
||||
Epsom-C -> Saddle-id(105)
|
||||
Unicorn-S -> Saddle-id(106)
|
||||
Hakodate-Sprint-S -> Saddle-id(107)
|
||||
CBC-Sho -> Saddle-id(108)
|
||||
Radio-Nikkei-Sho -> Saddle-id(109)
|
||||
Procyon-S -> Saddle-id(110)
|
||||
Tanabata-Sho -> Saddle-id(111)
|
||||
Hakodate-Kinen -> Saddle-id(112)
|
||||
Chukyo-Kinen -> Saddle-id(113)
|
||||
Hakodate-Junior-S -> Saddle-id(114)
|
||||
Ibis-Summer-D -> Saddle-id(115)
|
||||
Queen-S -> Saddle-id(116)
|
||||
Kokura-Kinen -> Saddle-id(117)
|
||||
Leopard-S -> Saddle-id(118)
|
||||
Sekiya-Kinen -> Saddle-id(119)
|
||||
Elm-S -> Saddle-id(120)
|
||||
Kitakyushu-Kinen -> Saddle-id(121)
|
||||
Niigata-Junior-S -> Saddle-id(122)
|
||||
Keeneland-C -> Saddle-id(123)
|
||||
Sapporo-Junior-S -> Saddle-id(124)
|
||||
Kokura-Junior-S -> Saddle-id(125)
|
||||
Niigata-Kinen -> Saddle-id(126)
|
||||
Shion-S -> Saddle-id(127)
|
||||
Keisei-Hai-AH -> Saddle-id(128)
|
||||
Sirius-S -> Saddle-id(129)
|
||||
Saudi-Arabia-RC -> Saddle-id(130)
|
||||
Fuji-S -> Saddle-id(131)
|
||||
Artemis-S -> Saddle-id(132)
|
||||
Fantasy-S -> Saddle-id(133)
|
||||
Miyako-S -> Saddle-id(134)
|
||||
Musashino-S -> Saddle-id(135)
|
||||
Fukushima-Kinen -> Saddle-id(136)
|
||||
Tokyo-Sports-Hai-Junior-S -> Saddle-id(137)
|
||||
Kyoto-Junior-S -> Saddle-id(138)
|
||||
Keihan-Hai -> Saddle-id(139)
|
||||
Challenge-C -> Saddle-id(140)
|
||||
Chunichi-Shimbun-Hai -> Saddle-id(141)
|
||||
Capella-S -> Saddle-id(142)
|
||||
Turquoise-S -> Saddle-id(143)
|
||||
Classic-Triple-Crown-Alt144 -> Saddle-id(144)
|
||||
Senior-Spring-Triple-Crown-Alt145 -> Saddle-id(145)
|
||||
Dual-Grand-Prix-Alt146 -> Saddle-id(146)
|
||||
Takarazuka-Kinen-Alt147 -> Saddle-id(147)
|
||||
Kikuka-Sho-Alt148 -> Saddle-id(148)
|
||||
Spring-S-Alt149 -> Saddle-id(149)
|
||||
Aoi-S -> Saddle-id(150)
|
||||
Senior-Spring-Triple-Crown-Alt151 -> Saddle-id(151)
|
||||
Tenno-Sweep-Alt152 -> Saddle-id(152)
|
||||
Tenno-Sho-Spring-Alt153 -> Saddle-id(153)
|
||||
Classic-Triple-Crown-Alt154 -> Saddle-id(154)
|
||||
Satsuki-Sho-Alt155 -> Saddle-id(155)
|
||||
|
||||
// List of all saddles in ID order for easy iterating.
|
||||
pub val all = [
|
||||
Classic-Triple-Crown,
|
||||
Senior-Autumn-Triple-Crown,
|
||||
Triple-Tiara,
|
||||
Senior-Spring-Triple-Crown,
|
||||
Tenno-Sweep,
|
||||
Dual-Grand-Prix,
|
||||
Dual-Miles,
|
||||
Dual-Sprints,
|
||||
Dual-Dirts,
|
||||
Arima-Kinen,
|
||||
Japan-C,
|
||||
Japanese-Derby,
|
||||
Tenno-Sho-Spring,
|
||||
Takarazuka-Kinen,
|
||||
Tenno-Sho-Autumn,
|
||||
Kikuka-Sho,
|
||||
Osaka-Hai,
|
||||
Satsuki-Sho,
|
||||
Japanese-Oaks,
|
||||
Takamatsunomiya-Kinen,
|
||||
Yasuda-Kinen,
|
||||
Sprinters-S,
|
||||
Mile-Ch,
|
||||
Oka-Sho,
|
||||
Victoria-Mile,
|
||||
Queen-Elizabeth-II-Cup,
|
||||
NHK-Mile-C,
|
||||
Shuka-Sho,
|
||||
Champions-C,
|
||||
February-S,
|
||||
JBC-Classic,
|
||||
Tokyo-Daishoten,
|
||||
Asahi-Hai-FS,
|
||||
Hopeful-S,
|
||||
Hanshin-JF,
|
||||
Teio-Sho,
|
||||
JBC-Sprint,
|
||||
JD-Derby,
|
||||
JBC-L-Classic,
|
||||
Nikkei-Shinshun-Hai,
|
||||
Tokai-S,
|
||||
American-JCC,
|
||||
Kyoto-Kinen,
|
||||
Nakayama-Kinen,
|
||||
Yayoi-Sho,
|
||||
Kinko-Sho,
|
||||
Fillies-Revue,
|
||||
Hanshin-Daishoten,
|
||||
Spring-S,
|
||||
Nikkei-Sho,
|
||||
Hanshin-Umamusume-S,
|
||||
New-Zealand-T,
|
||||
Yomiuri-Milers-C,
|
||||
Flora-S,
|
||||
Aoba-Sho,
|
||||
Kyoto-Shimbun-Hai,
|
||||
Keio-Hai-Spring-C,
|
||||
Meguro-Kinen,
|
||||
Sapporo-Kinen,
|
||||
Centaur-S,
|
||||
Rose-S,
|
||||
St-Lite-Kinen,
|
||||
Kobe-Shimbun-Hai,
|
||||
All-Comers,
|
||||
Mainichi-Okan,
|
||||
Kyoto-Daishoten,
|
||||
Fuchu-Umamusume-S,
|
||||
Swan-S,
|
||||
Keio-Hai-Junior-S,
|
||||
Copa-Republica-Argentina,
|
||||
Daily-Hai-Junior-S,
|
||||
Stayers-S,
|
||||
Hanshin-C,
|
||||
Kyoto-Kimpai,
|
||||
Nakayama-Kimpai,
|
||||
Shinzan-Kinen,
|
||||
Fairy-S,
|
||||
Aichi-Hai,
|
||||
Keisei-Hai,
|
||||
Silk-Road-S,
|
||||
Negishi-S,
|
||||
Kisaragi-Sho,
|
||||
Tokyo-Shimbun-Hai,
|
||||
Queen-C,
|
||||
Kyodo-News-Hai,
|
||||
Kyoto-Umamusume-S,
|
||||
Diamond-S,
|
||||
Kokura-Daishoten,
|
||||
Arlington-C,
|
||||
Hankyu-Hai,
|
||||
Tulip-Sho,
|
||||
Ocean-S,
|
||||
Nakayama-Umamusume-S,
|
||||
Falcon-S,
|
||||
Flower-C,
|
||||
Mainichi-Hai,
|
||||
March-S,
|
||||
Lord-Derby-CT,
|
||||
Antares-S,
|
||||
Fukushima-Umamusume-S,
|
||||
Niigata-Daishoten,
|
||||
Heian-S,
|
||||
Naruo-Kinen,
|
||||
Mermaid-S,
|
||||
Epsom-C,
|
||||
Unicorn-S,
|
||||
Hakodate-Sprint-S,
|
||||
CBC-Sho,
|
||||
Radio-Nikkei-Sho,
|
||||
Procyon-S,
|
||||
Tanabata-Sho,
|
||||
Hakodate-Kinen,
|
||||
Chukyo-Kinen,
|
||||
Hakodate-Junior-S,
|
||||
Ibis-Summer-D,
|
||||
Queen-S,
|
||||
Kokura-Kinen,
|
||||
Leopard-S,
|
||||
Sekiya-Kinen,
|
||||
Elm-S,
|
||||
Kitakyushu-Kinen,
|
||||
Niigata-Junior-S,
|
||||
Keeneland-C,
|
||||
Sapporo-Junior-S,
|
||||
Kokura-Junior-S,
|
||||
Niigata-Kinen,
|
||||
Shion-S,
|
||||
Keisei-Hai-AH,
|
||||
Sirius-S,
|
||||
Saudi-Arabia-RC,
|
||||
Fuji-S,
|
||||
Artemis-S,
|
||||
Fantasy-S,
|
||||
Miyako-S,
|
||||
Musashino-S,
|
||||
Fukushima-Kinen,
|
||||
Tokyo-Sports-Hai-Junior-S,
|
||||
Kyoto-Junior-S,
|
||||
Keihan-Hai,
|
||||
Challenge-C,
|
||||
Chunichi-Shimbun-Hai,
|
||||
Capella-S,
|
||||
Turquoise-S,
|
||||
Classic-Triple-Crown-Alt144,
|
||||
Senior-Spring-Triple-Crown-Alt145,
|
||||
Dual-Grand-Prix-Alt146,
|
||||
Takarazuka-Kinen-Alt147,
|
||||
Kikuka-Sho-Alt148,
|
||||
Spring-S-Alt149,
|
||||
Aoi-S,
|
||||
Senior-Spring-Triple-Crown-Alt151,
|
||||
Tenno-Sweep-Alt152,
|
||||
Tenno-Sho-Spring-Alt153,
|
||||
Classic-Triple-Crown-Alt154,
|
||||
Satsuki-Sho-Alt155,
|
||||
]
|
||||
|
||||
// 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!",
|
||||
},
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
module horse/global/scenario
|
||||
|
||||
// Automatically generated with horsegen; DO NOT EDIT
|
||||
|
||||
import horse/game-id
|
||||
|
||||
// Enumeration of all scenarios for type-safe programming.
|
||||
pub type scenario
|
||||
URA-Finale
|
||||
Unity-Cup
|
||||
|
||||
// Get the scenario ID for a scenario.
|
||||
pub fun scenario-id(s: scenario): scenario-id
|
||||
match s
|
||||
URA-Finale -> Scenario-id(1)
|
||||
Unity-Cup -> Scenario-id(2)
|
||||
|
||||
// List of all scenarios in ID order for easy iterating.
|
||||
pub val all = [
|
||||
URA-Finale,
|
||||
Unity-Cup,
|
||||
]
|
||||
|
||||
// Get the name for a scenario.
|
||||
// If no scenario matches the ID, the result contains the numeric ID.
|
||||
pub fun show(s: scenario-id): string
|
||||
match s.game-id
|
||||
1 -> "URA Finale"
|
||||
2 -> "Unity Cup"
|
||||
x -> "scenario " ++ x.show
|
||||
|
||||
// Get the full title for a scenario, e.g. "The Beginning: URA Finale".
|
||||
// If no scenario matches the ID, the result contains the numeric ID.
|
||||
pub fun title(s: scenario-id): string
|
||||
match s.game-id
|
||||
1 -> "The Beginning: URA Finale"
|
||||
2 -> "Unity Cup: Shine On, Team Spirit!"
|
||||
x -> "scenario " ++ x.show
|
||||
-13481
File diff suppressed because it is too large
Load Diff
-16123
File diff suppressed because it is too large
Load Diff
-13052
File diff suppressed because it is too large
Load Diff
-12246
File diff suppressed because it is too large
Load Diff
@@ -1,18 +0,0 @@
|
||||
module horse/legacy
|
||||
|
||||
import horse/character
|
||||
import horse/game-id
|
||||
import horse/race
|
||||
import horse/spark
|
||||
|
||||
pub struct legacy
|
||||
uma: veteran
|
||||
parents: (veteran, veteran)
|
||||
|
||||
pub struct veteran
|
||||
character: character-id
|
||||
stat: spark<stat>
|
||||
aptitude: spark<aptitude>
|
||||
unique: maybe<spark<unique>>
|
||||
generic: list<spark<generic>>
|
||||
saddles: list<saddle-id>
|
||||
@@ -1,132 +0,0 @@
|
||||
module horse/movement
|
||||
|
||||
// Surface types.
|
||||
pub type surface
|
||||
Turf
|
||||
Dirt
|
||||
|
||||
// Automatically generated.
|
||||
// Shows a string representation of the `surface` type.
|
||||
pub fun surface/show(this : surface) : e string
|
||||
match this
|
||||
Turf -> "Turf"
|
||||
Dirt -> "Dirt"
|
||||
|
||||
// Race distance types.
|
||||
pub type distance
|
||||
Sprint
|
||||
Mile
|
||||
Medium
|
||||
Long
|
||||
|
||||
// Automatically generated.
|
||||
// Shows a string representation of the `distance` type.
|
||||
pub fun distance/show(this : distance) : e string
|
||||
match this
|
||||
Sprint -> "Sprint"
|
||||
Mile -> "Mile"
|
||||
Medium -> "Medium"
|
||||
Long -> "Long"
|
||||
|
||||
// Running styles.
|
||||
pub type style
|
||||
Front-Runner
|
||||
Pace-Chaser
|
||||
Late-Surger
|
||||
End-Closer
|
||||
|
||||
// Automatically generated.
|
||||
// Equality comparison of the `style` type.
|
||||
pub fun style/(==)(this : style, other : style) : e bool
|
||||
match (this, other)
|
||||
(Front-Runner, Front-Runner) -> True
|
||||
(Pace-Chaser, Pace-Chaser) -> True
|
||||
(Late-Surger, Late-Surger) -> True
|
||||
(End-Closer, End-Closer) -> True
|
||||
(_, _) -> False
|
||||
|
||||
// Shows a string representation of the `style` type.
|
||||
pub fun style/show(this : style) : e string
|
||||
match this
|
||||
Front-Runner -> "Front Runner"
|
||||
Pace-Chaser -> "Pace Chaser"
|
||||
Late-Surger -> "Late Surger"
|
||||
End-Closer -> "End Closer"
|
||||
|
||||
// Starting aptitude levels.
|
||||
pub type level
|
||||
G
|
||||
F
|
||||
E
|
||||
D
|
||||
C
|
||||
B
|
||||
A
|
||||
S
|
||||
|
||||
// Automatically generated.
|
||||
// Comparison of the `level` type.
|
||||
pub fun level/cmp(this : level, other : level) : e order
|
||||
match (this, other)
|
||||
(G, G) -> Eq
|
||||
(G, _) -> Lt
|
||||
(_, G) -> Gt
|
||||
(F, F) -> Eq
|
||||
(F, _) -> Lt
|
||||
(_, F) -> Gt
|
||||
(E, E) -> Eq
|
||||
(E, _) -> Lt
|
||||
(_, E) -> Gt
|
||||
(D, D) -> Eq
|
||||
(D, _) -> Lt
|
||||
(_, D) -> Gt
|
||||
(C, C) -> Eq
|
||||
(C, _) -> Lt
|
||||
(_, C) -> Gt
|
||||
(B, B) -> Eq
|
||||
(B, _) -> Lt
|
||||
(_, B) -> Gt
|
||||
(A, A) -> Eq
|
||||
(A, _) -> Lt
|
||||
(_, A) -> Gt
|
||||
(S, S) -> Eq
|
||||
|
||||
// Automatically generated.
|
||||
// Fip comparison of the `level` type.
|
||||
pub fun level/order2(this : level, other : level) : order2<level>
|
||||
match (this, other)
|
||||
(G, G) -> Eq2(G)
|
||||
(G, other') -> Lt2(G, other')
|
||||
(this', G) -> Gt2(G, this')
|
||||
(F, F) -> Eq2(F)
|
||||
(F, other') -> Lt2(F, other')
|
||||
(this', F) -> Gt2(F, this')
|
||||
(E, E) -> Eq2(E)
|
||||
(E, other') -> Lt2(E, other')
|
||||
(this', E) -> Gt2(E, this')
|
||||
(D, D) -> Eq2(D)
|
||||
(D, other') -> Lt2(D, other')
|
||||
(this', D) -> Gt2(D, this')
|
||||
(C, C) -> Eq2(C)
|
||||
(C, other') -> Lt2(C, other')
|
||||
(this', C) -> Gt2(C, this')
|
||||
(B, B) -> Eq2(B)
|
||||
(B, other') -> Lt2(B, other')
|
||||
(this', B) -> Gt2(B, this')
|
||||
(A, A) -> Eq2(A)
|
||||
(A, other') -> Lt2(A, other')
|
||||
(this', A) -> Gt2(A, this')
|
||||
(S, S) -> Eq2(S)
|
||||
|
||||
// Automatically generated.
|
||||
// Shows a string representation of the `level` type.
|
||||
pub fun level/show(this : level) : string
|
||||
match this
|
||||
G -> "G"
|
||||
F -> "F"
|
||||
E -> "E"
|
||||
D -> "D"
|
||||
C -> "C"
|
||||
B -> "B"
|
||||
A -> "A"
|
||||
S -> "S"
|
||||
@@ -1,158 +0,0 @@
|
||||
module horse/prob/kfl
|
||||
|
||||
// kfl is a semiring of probabilities formed by vibes.
|
||||
pub type kfl
|
||||
// Effectively if not literally impossible events.
|
||||
Impossible
|
||||
// Not worth aiming for, but can technically still happen.
|
||||
Probably-Not
|
||||
// You expect it not to happen most of the time, but it might still be worth
|
||||
// trying for it if you're being forced to play to your outs.
|
||||
Doubtful
|
||||
// More likely that it won't happen, but a success isn't surprising.
|
||||
Unlikely
|
||||
// Either it does or it doesn't.
|
||||
Mayhapsibly
|
||||
// Decent chance it doesn't happen, but you still expect it to.
|
||||
Probably
|
||||
// You expect it to happen most of the time, but accept that there will be failures.
|
||||
Most-Likely
|
||||
// Very close to guaranteed, but technically with a small chance to fail.
|
||||
Cry-If-Not
|
||||
// Absolutely guaranteed events.
|
||||
Guaranteed
|
||||
|
||||
// Automatically generated.
|
||||
// Comparison of the `kfl` type.
|
||||
pub fun cmp(this : kfl, other : kfl) : e order
|
||||
match (this, other)
|
||||
(Impossible, Impossible) -> Eq
|
||||
(Impossible, _) -> Lt
|
||||
(_, Impossible) -> Gt
|
||||
(Probably-Not, Probably-Not) -> Eq
|
||||
(Probably-Not, _) -> Lt
|
||||
(_, Probably-Not) -> Gt
|
||||
(Doubtful, Doubtful) -> Eq
|
||||
(Doubtful, _) -> Lt
|
||||
(_, Doubtful) -> Gt
|
||||
(Unlikely, Unlikely) -> Eq
|
||||
(Unlikely, _) -> Lt
|
||||
(_, Unlikely) -> Gt
|
||||
(Mayhapsibly, Mayhapsibly) -> Eq
|
||||
(Mayhapsibly, _) -> Lt
|
||||
(_, Mayhapsibly) -> Gt
|
||||
(Probably, Probably) -> Eq
|
||||
(Probably, _) -> Lt
|
||||
(_, Probably) -> Gt
|
||||
(Most-Likely, Most-Likely) -> Eq
|
||||
(Most-Likely, _) -> Lt
|
||||
(_, Most-Likely) -> Gt
|
||||
(Cry-If-Not, Cry-If-Not) -> Eq
|
||||
(Cry-If-Not, _) -> Lt
|
||||
(_, Cry-If-Not) -> Gt
|
||||
(Guaranteed, Guaranteed) -> Eq
|
||||
|
||||
// Shows a string representation of the `kfl` type.
|
||||
pub fun show(this : kfl) : e string
|
||||
match this
|
||||
Impossible -> "impossible"
|
||||
Probably-Not -> "probably not"
|
||||
Doubtful -> "doubtful"
|
||||
Unlikely -> "unlikely"
|
||||
Mayhapsibly -> "mayhapsibly"
|
||||
Probably -> "probably"
|
||||
Most-Likely -> "most likely"
|
||||
Cry-If-Not -> "cry if not"
|
||||
Guaranteed -> "guaranteed"
|
||||
|
||||
// KFL multiplication, or the probability of cooccurrence of two independent events.
|
||||
pub fun (*)(a: kfl, b: kfl): e kfl
|
||||
val (l, h) = match a.cmp(b) // this operation is commutative
|
||||
Gt -> (b, a)
|
||||
_ -> (a, b)
|
||||
match (l, h)
|
||||
(r, Guaranteed) -> r // factor out Guaranteed cases
|
||||
(Impossible, _) -> Impossible
|
||||
(Probably-Not, _) -> Impossible
|
||||
(r, Cry-If-Not) -> r // factor out further Cry-If-Not cases
|
||||
(Doubtful, Most-Likely) -> Probably-Not
|
||||
(Doubtful, _) -> Impossible
|
||||
(Unlikely, Most-Likely) -> Doubtful
|
||||
(Unlikely, Probably) -> Doubtful
|
||||
(Unlikely, Mayhapsibly) -> Probably-Not
|
||||
(Unlikely, _) -> Probably-Not // (Unlikely, Unlikely) because commutative
|
||||
(Mayhapsibly, Most-Likely) -> Unlikely
|
||||
(Mayhapsibly, Probably) -> Unlikely
|
||||
(Mayhapsibly, _) -> Unlikely
|
||||
(Probably, Most-Likely) -> Mayhapsibly
|
||||
(Probably, _) -> Unlikely
|
||||
(Most-Likely, _) -> Probably
|
||||
// These two are only needed because the type system doesn't understand commutativity.
|
||||
(Cry-If-Not, _) -> Cry-If-Not
|
||||
(Guaranteed, _) -> Guaranteed
|
||||
|
||||
// KFL addition, or the probability of occurrence of at least one of two independent events.
|
||||
pub fun (+)(a: kfl, b: kfl): e kfl
|
||||
val (l, h) = match a.cmp(b) // this operation is commutative
|
||||
Gt -> (b, a)
|
||||
_ -> (a, b)
|
||||
match (l, h)
|
||||
// Cases with _ on the right are (a, a) due to commutativity.
|
||||
// Cases with _ on the left simplify later cases that all absorb to the right.
|
||||
(Guaranteed, _) -> Guaranteed
|
||||
(_, Guaranteed) -> Guaranteed
|
||||
(Cry-If-Not, _) -> Guaranteed
|
||||
(Most-Likely, Cry-If-Not) -> Cry-If-Not
|
||||
(Most-Likely, _) -> Cry-If-Not
|
||||
(_, Cry-If-Not) -> Cry-If-Not
|
||||
(Probably, Most-Likely) -> Cry-If-Not
|
||||
(Probably, _) -> Most-Likely
|
||||
(_, Most-Likely) -> Most-Likely
|
||||
(Mayhapsibly, Probably) -> Most-Likely
|
||||
(Mayhapsibly, _) -> Probably
|
||||
(Unlikely, Probably) -> Most-Likely
|
||||
(Unlikely, Mayhapsibly) -> Probably
|
||||
(Unlikely, _) -> Mayhapsibly
|
||||
(_, Probably) -> Probably
|
||||
(Doubtful, Mayhapsibly) -> Probably
|
||||
(Doubtful, Unlikely) -> Mayhapsibly
|
||||
(Doubtful, _) -> Unlikely
|
||||
(_, Mayhapsibly) -> Mayhapsibly
|
||||
(_, Unlikely) -> Unlikely
|
||||
(Probably-Not, Doubtful) -> Unlikely
|
||||
(Probably-Not, _) -> Probably-Not
|
||||
(_, Doubtful) -> Doubtful
|
||||
(_, Probably-Not) -> Probably-Not
|
||||
(_, Impossible) -> Impossible
|
||||
|
||||
// KFL union, or the probability of occurrence of exactly one of two independent events.
|
||||
pub fun either(a: kfl, b: kfl): e kfl
|
||||
val (l, h) = match a.cmp(b) // this operation is commutative
|
||||
Gt -> (b, a)
|
||||
_ -> (a, b)
|
||||
match (l, h)
|
||||
(Impossible, r) -> r
|
||||
(Probably-Not, Guaranteed) -> Cry-If-Not
|
||||
(Probably-Not, r) -> r
|
||||
(Doubtful, Guaranteed) -> Most-Likely
|
||||
(Doubtful, Cry-If-Not) -> Most-Likely
|
||||
(Doubtful, Most-Likely) -> Probably
|
||||
(Doubtful, Probably) -> Mayhapsibly
|
||||
(Doubtful, Mayhapsibly) -> Mayhapsibly
|
||||
(Doubtful, Unlikely) -> Mayhapsibly
|
||||
(Doubtful, _) -> Unlikely
|
||||
(Unlikely, Guaranteed) -> Probably
|
||||
(Unlikely, Cry-If-Not) -> Mayhapsibly
|
||||
(Unlikely, Most-Likely) -> Mayhapsibly
|
||||
(Unlikely, _) -> Probably
|
||||
(Mayhapsibly, Guaranteed) -> Mayhapsibly
|
||||
(Mayhapsibly, Cry-If-Not) -> Mayhapsibly
|
||||
(Mayhapsibly, Most-Likely) -> Mayhapsibly
|
||||
(Mayhapsibly, _) -> Probably
|
||||
(Probably, Guaranteed) -> Unlikely
|
||||
(Probably, Cry-If-Not) -> Unlikely
|
||||
(Probably, Most-Likely) -> Unlikely
|
||||
(Probably, _) -> Mayhapsibly
|
||||
(Most-Likely, _) -> Doubtful
|
||||
(Cry-If-Not, _) -> Probably-Not
|
||||
(Guaranteed, _) -> Impossible
|
||||
@@ -1,58 +0,0 @@
|
||||
module horse/prob/pmf
|
||||
|
||||
import std/core/list
|
||||
|
||||
// Discrete-support probability distribution implemented as a list with the invariant
|
||||
// that support is always given in increasing order.
|
||||
pub type pmf<s, v>
|
||||
Event(s: s, v: v, next: pmf<s, v>)
|
||||
End
|
||||
|
||||
// Add an independent event to the distribution.
|
||||
pub fun add(p: pmf<s, v>, s: s, v: v, ?s/cmp: (a: s, b: s) -> order, ?v/(+): (new: v, old: v) -> e v): e pmf<s, v>
|
||||
match p
|
||||
End -> Event(s, v, End)
|
||||
Event(s', v', next) -> match s.cmp(s')
|
||||
Lt -> Event(s, v, Event(s', v', next))
|
||||
Eq -> Event(s, v + v', next)
|
||||
Gt -> Event(s', v', add(next, s, v))
|
||||
|
||||
// Replace an event in the distribution.
|
||||
pub inline fun set(p: pmf<s, v>, s: s, v: v, ?s/cmp: (a: s, b: s) -> order): e pmf<s, v>
|
||||
p.add(s, v, cmp, fn(new, old) new)
|
||||
|
||||
// Construct a pmf from a list of (support, value) entries.
|
||||
pub fun list/pmf(l: list<(s, v)>, ?s/cmp: (a: s, b: s) -> order, ?v/(+): (new: v, old: v) -> e v): e pmf<s, v>
|
||||
l.foldl(End) fn(p, (s, v)) p.add(s, v)
|
||||
|
||||
// Fold over the entries of the distribution.
|
||||
pub tail fun foldl(p: pmf<s, v>, init: a, f: (a, s, v) -> e a): e a
|
||||
match p
|
||||
End -> init
|
||||
Event(s, v, next) -> foldl(next, f(init, s, v), f)
|
||||
|
||||
// Convert the distribution to a list of entries.
|
||||
pub fun pmf/list(p: pmf<s, v>): list<(s, v)>
|
||||
p.foldl(Nil) fn(l, s, v) Cons((s, v), l)
|
||||
|
||||
// Distribution of cooccurrence of two events described by their distributions.
|
||||
pub fun (*)(a: pmf<s, v>, b: pmf<s, v>, ?s/cmp: (a: s, b: s) -> order, ?v/(*): (a: v, b: v) -> e v): e pmf<s, v>
|
||||
match a
|
||||
End -> End
|
||||
Event(sa, va, nexta) -> match b
|
||||
End -> End
|
||||
Event(sb, vb, nextb) -> match sa.cmp(sb)
|
||||
Lt -> nexta * b
|
||||
Eq -> Event(sa, va * vb, nexta * nextb)
|
||||
Gt -> a * nextb
|
||||
|
||||
// Distribution of occurrence of at least one of two events described by their distributions.
|
||||
pub fun (+)(a: pmf<s, v>, b: pmf<s, v>, ?s/cmp: (a: s, b: s) -> order, ?v/(+): (a: v, b: v) -> e v): e pmf<s, v>
|
||||
match a
|
||||
End -> b
|
||||
Event(sa, va, nexta) -> match b
|
||||
End -> a
|
||||
Event(sb, vb, nextb) -> match sa.cmp(sb)
|
||||
Lt -> Event(sa, va, nexta + b)
|
||||
Eq -> Event(sa, va + vb, nexta + nextb)
|
||||
Gt -> Event(sb, vb, a + nextb)
|
||||
-301
@@ -1,301 +0,0 @@
|
||||
module horse/race
|
||||
|
||||
import std/data/linearset
|
||||
import horse/game-id
|
||||
|
||||
pub struct race-detail
|
||||
race-id: race-id
|
||||
name: string
|
||||
grade: grade
|
||||
thumbnail-id: race-thumbnail-id
|
||||
// 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: race-id
|
||||
|
||||
pub fun detail(
|
||||
r: race-id,
|
||||
?race/show: (race-id) -> string,
|
||||
?race/grade: (race-id) -> grade,
|
||||
?race/thumbnail: (race-id) -> race-thumbnail-id,
|
||||
?race/primary: (race-id) -> race-id
|
||||
): race-detail
|
||||
Race-detail(r, r.show, r.grade, r.thumbnail, r.primary)
|
||||
|
||||
pub fun race-detail/show(r: race-detail): string
|
||||
val Race-detail(Race-id(id), name) = r
|
||||
name ++ " (ID " ++ id.show ++ ")"
|
||||
|
||||
// Race grades.
|
||||
pub type grade
|
||||
Pre-OP
|
||||
OP
|
||||
G3
|
||||
G2
|
||||
G1
|
||||
EX
|
||||
|
||||
// Automatically generated.
|
||||
// Comparison of the `grade` type.
|
||||
pub fun grade/cmp(this : grade, other : grade) : e order
|
||||
match (this, other)
|
||||
(Pre-OP, Pre-OP) -> Eq
|
||||
(Pre-OP, _) -> Lt
|
||||
(_, Pre-OP) -> Gt
|
||||
(OP, OP) -> Eq
|
||||
(OP, _) -> Lt
|
||||
(_, OP) -> Gt
|
||||
(G3, G3) -> Eq
|
||||
(G3, _) -> Lt
|
||||
(_, G3) -> Gt
|
||||
(G2, G2) -> Eq
|
||||
(G2, _) -> Lt
|
||||
(_, G2) -> Gt
|
||||
(G1, G1) -> Eq
|
||||
(G1, _) -> Lt
|
||||
(_, G1) -> Gt
|
||||
(EX, EX) -> Eq
|
||||
|
||||
// Automatically generated.
|
||||
// Shows a string representation of the `grade` type.
|
||||
pub fun grade/show(this : grade) : e string
|
||||
match this
|
||||
Pre-OP -> "Pre-OP"
|
||||
OP -> "OP"
|
||||
G3 -> "G3"
|
||||
G2 -> "G2"
|
||||
G1 -> "G1"
|
||||
EX -> "EX"
|
||||
|
||||
pub struct saddle-detail
|
||||
saddle-id: saddle-id
|
||||
name: string
|
||||
races: list<race-id>
|
||||
saddle-type: saddle-type
|
||||
// For careers with unusual races, granted saddles also differ.
|
||||
// This field holds the normal saddle's ID for such cases.
|
||||
primary: saddle-id
|
||||
|
||||
pub fun saddle/detail(
|
||||
id: saddle-id,
|
||||
?saddle/show: (saddle-id) -> string,
|
||||
?saddle/races: (saddle-id) -> list<race-id>,
|
||||
?saddle/saddle-type: (saddle-id) -> saddle-type,
|
||||
?saddle/primary: (saddle-id) -> saddle-id
|
||||
): saddle-detail
|
||||
Saddle-detail(id, id.show, id.races, id.saddle-type, id.primary)
|
||||
|
||||
pub fun saddle-detail/show(s: saddle-detail): string
|
||||
val Saddle-detail(Saddle-id(id), name, _, _, Saddle-id(primary)) = s
|
||||
if id == primary then name else name ++ " (Alternate " ++ id.show ++ ")"
|
||||
|
||||
// Types of saddles.
|
||||
pub type saddle-type
|
||||
Honor // multiple race wins: classic triple crown, dual grand prix, &c.
|
||||
G3-Win
|
||||
G2-Win
|
||||
G1-Win
|
||||
|
||||
// Automatically generated.
|
||||
// Shows a string representation of the `saddle-type` type.
|
||||
pub fun saddle-type/show(this : saddle-type) : e string
|
||||
match this
|
||||
Honor -> "Honor"
|
||||
G3-Win -> "G3"
|
||||
G2-Win -> "G2"
|
||||
G1-Win -> "G1"
|
||||
|
||||
// Automatically generated.
|
||||
// Equality comparison of the `saddle-type` type.
|
||||
pub fun saddle-type/(==)(this : saddle-type, other : saddle-type) : e bool
|
||||
match (this, other)
|
||||
(Honor, Honor) -> True
|
||||
(G3-Win, G3-Win) -> True
|
||||
(G2-Win, G2-Win) -> True
|
||||
(G1-Win, G1-Win) -> True
|
||||
(_, _) -> False
|
||||
|
||||
// Turn that a race occurred.
|
||||
pub struct turn
|
||||
year: turn-year
|
||||
month: turn-month
|
||||
half: turn-half
|
||||
|
||||
// Automatically generated.
|
||||
// Equality comparison of the `turn` type.
|
||||
pub fun turn/(==)(this : turn, other : turn) : e bool
|
||||
match (this, other)
|
||||
(Turn(year, month, half), Turn(year', month', half')) -> year == year' && month == month' && half == half'
|
||||
|
||||
// Automatically generated.
|
||||
// Fip comparison of the `turn` type.
|
||||
pub fun turn/order2(this : turn, other : turn) : e order2<turn>
|
||||
match (this, other)
|
||||
(Turn(year, month, half), Turn(year', month', half')) ->
|
||||
match year.order2(year')
|
||||
Eq2(year_eq) ->
|
||||
match month.order2(month')
|
||||
Eq2(month_eq) ->
|
||||
match half.order2(half')
|
||||
Eq2(half_eq) -> Eq2(Turn(year_eq, month_eq, half_eq))
|
||||
Lt2(half_lt, half_gt) -> Lt2(Turn(year_eq, month_eq, half_lt), Turn(year_eq, month_eq, half_gt))
|
||||
Gt2(half_lt, half_gt) -> Gt2(Turn(year_eq, month_eq, half_lt), Turn(year_eq, month_eq, half_gt))
|
||||
Lt2(month_lt, month_gt) -> Lt2(Turn(year_eq, month_lt, half), Turn(year_eq, month_gt, half'))
|
||||
Gt2(month_lt, month_gt) -> Gt2(Turn(year_eq, month_lt, half'), Turn(year_eq, month_gt, half))
|
||||
Lt2(year_lt, year_gt) -> Lt2(Turn(year_lt, month, half), Turn(year_gt, month', half'))
|
||||
Gt2(year_lt, year_gt) -> Gt2(Turn(year_lt, month', half'), Turn(year_gt, month, half))
|
||||
|
||||
// Automatically generated.
|
||||
// Shows a string representation of the `turn` type.
|
||||
pub fun turn/show(this : turn) : e string
|
||||
this.year.show ++ " " ++ this.half.show ++ " " ++ this.month.show
|
||||
|
||||
pub type turn-year
|
||||
Junior
|
||||
Classic
|
||||
Senior
|
||||
Finale
|
||||
|
||||
// Automatically generated.
|
||||
// Equality comparison of the `turn-year` type.
|
||||
pub fun turn-year/(==)(this : turn-year, other : turn-year) : e bool
|
||||
match (this, other)
|
||||
(Junior, Junior) -> True
|
||||
(Classic, Classic) -> True
|
||||
(Senior, Senior) -> True
|
||||
(Finale, Finale) -> True
|
||||
(_, _) -> False
|
||||
|
||||
// Automatically generated.
|
||||
// Fip comparison of the `turn-year` type.
|
||||
pub fun turn-year/order2(this : turn-year, other : turn-year) : e order2<turn-year>
|
||||
match (this, other)
|
||||
(Junior, Junior) -> Eq2(Junior)
|
||||
(Junior, other') -> Lt2(Junior, other')
|
||||
(this', Junior) -> Gt2(Junior, this')
|
||||
(Classic, Classic) -> Eq2(Classic)
|
||||
(Classic, other') -> Lt2(Classic, other')
|
||||
(this', Classic) -> Gt2(Classic, this')
|
||||
(Senior, Senior) -> Eq2(Senior)
|
||||
(Senior, other') -> Lt2(Senior, other')
|
||||
(this', Senior) -> Gt2(Senior, this')
|
||||
(Finale, Finale) -> Eq2(Finale)
|
||||
|
||||
// Automatically generated.
|
||||
// Shows a string representation of the `turn-year` type.
|
||||
pub fun turn-year/show(this : turn-year) : e string
|
||||
match this
|
||||
Junior -> "Junior Year"
|
||||
Classic -> "Classic Year"
|
||||
Senior -> "Senior Year"
|
||||
Finale -> "Finale 1" // the 1 is in the game
|
||||
|
||||
pub type turn-month
|
||||
January
|
||||
February
|
||||
March
|
||||
April
|
||||
May
|
||||
June
|
||||
July
|
||||
August
|
||||
September
|
||||
November
|
||||
December
|
||||
|
||||
// Automatically generated.
|
||||
// Equality comparison of the `turn-month` type.
|
||||
pub fun turn-month/(==)(this : turn-month, other : turn-month) : e bool
|
||||
match (this, other)
|
||||
(January, January) -> True
|
||||
(February, February) -> True
|
||||
(March, March) -> True
|
||||
(April, April) -> True
|
||||
(May, May) -> True
|
||||
(June, June) -> True
|
||||
(July, July) -> True
|
||||
(August, August) -> True
|
||||
(September, September) -> True
|
||||
(November, November) -> True
|
||||
(December, December) -> True
|
||||
(_, _) -> False
|
||||
|
||||
// Automatically generated.
|
||||
// Fip comparison of the `turn-month` type.
|
||||
pub fun turn-month/order2(this : turn-month, other : turn-month) : e order2<turn-month>
|
||||
match (this, other)
|
||||
(January, January) -> Eq2(January)
|
||||
(January, other') -> Lt2(January, other')
|
||||
(this', January) -> Gt2(January, this')
|
||||
(February, February) -> Eq2(February)
|
||||
(February, other') -> Lt2(February, other')
|
||||
(this', February) -> Gt2(February, this')
|
||||
(March, March) -> Eq2(March)
|
||||
(March, other') -> Lt2(March, other')
|
||||
(this', March) -> Gt2(March, this')
|
||||
(April, April) -> Eq2(April)
|
||||
(April, other') -> Lt2(April, other')
|
||||
(this', April) -> Gt2(April, this')
|
||||
(May, May) -> Eq2(May)
|
||||
(May, other') -> Lt2(May, other')
|
||||
(this', May) -> Gt2(May, this')
|
||||
(June, June) -> Eq2(June)
|
||||
(June, other') -> Lt2(June, other')
|
||||
(this', June) -> Gt2(June, this')
|
||||
(July, July) -> Eq2(July)
|
||||
(July, other') -> Lt2(July, other')
|
||||
(this', July) -> Gt2(July, this')
|
||||
(August, August) -> Eq2(August)
|
||||
(August, other') -> Lt2(August, other')
|
||||
(this', August) -> Gt2(August, this')
|
||||
(September, September) -> Eq2(September)
|
||||
(September, other') -> Lt2(September, other')
|
||||
(this', September) -> Gt2(September, this')
|
||||
(November, November) -> Eq2(November)
|
||||
(November, other') -> Lt2(November, other')
|
||||
(this', November) -> Gt2(November, this')
|
||||
(December, December) -> Eq2(December)
|
||||
|
||||
// Automatically generated.
|
||||
// Shows a string representation of the `turn-month` type.
|
||||
pub fun turn-month/show(this : turn-month) : e string
|
||||
match this
|
||||
January -> "January"
|
||||
February -> "February"
|
||||
March -> "March"
|
||||
April -> "April"
|
||||
May -> "May"
|
||||
June -> "June"
|
||||
July -> "July"
|
||||
August -> "August"
|
||||
September -> "September"
|
||||
November -> "November"
|
||||
December -> "December"
|
||||
|
||||
pub type turn-half
|
||||
Early
|
||||
Late
|
||||
|
||||
// Automatically generated.
|
||||
// Equality comparison of the `turn-half` type.
|
||||
pub fun turn-half/(==)(this : turn-half, other : turn-half) : e bool
|
||||
match (this, other)
|
||||
(Early, Early) -> True
|
||||
(Late, Late) -> True
|
||||
(_, _) -> False
|
||||
|
||||
// Automatically generated.
|
||||
// Fip comparison of the `turn-half` type.
|
||||
pub fun turn-half/order2(this : turn-half, other : turn-half) : e order2<turn-half>
|
||||
match (this, other)
|
||||
(Early, Early) -> Eq2(Early)
|
||||
(Early, other') -> Lt2(Early, other')
|
||||
(this', Early) -> Gt2(Early, this')
|
||||
(Late, Late) -> Eq2(Late)
|
||||
|
||||
// Automatically generated.
|
||||
// Shows a string representation of the `turn-half` type.
|
||||
pub fun turn-half/show(this : turn-half) : e string
|
||||
match this
|
||||
Early -> "Early"
|
||||
Late -> "Late"
|
||||
-249
@@ -1,249 +0,0 @@
|
||||
module horse/skill
|
||||
|
||||
// This module contains skill-related definitions
|
||||
// common to all versions of the game.
|
||||
|
||||
import std/num/decimal
|
||||
import horse/game-id
|
||||
import horse/movement
|
||||
|
||||
// Full details about a skill.
|
||||
pub struct skill-detail
|
||||
skill-id: skill-id
|
||||
name: string
|
||||
description: string
|
||||
group-id: skill-group-id
|
||||
rarity: rarity
|
||||
group-rate: int
|
||||
grade-value: int
|
||||
wit-check: bool
|
||||
activations: list<activation>
|
||||
owner: maybe<trainee-id>
|
||||
sp-cost: int
|
||||
icon-id: skill-icon-id
|
||||
|
||||
pub fun detail(
|
||||
s: skill-id,
|
||||
?skill/show: (skill-id) -> string,
|
||||
?skill/description: (skill-id) -> string,
|
||||
?skill/group: (skill-id) -> skill-group-id,
|
||||
?skill/rarity: (skill-id) -> rarity,
|
||||
?skill/group-rate: (skill-id) -> int,
|
||||
?skill/grade-value: (skill-id) -> int,
|
||||
?skill/wit-check: (skill-id) -> bool,
|
||||
?skill/activations: (skill-id) -> list<activation>,
|
||||
?skill/unique-owner: (skill-id) -> maybe<trainee-id>,
|
||||
?skill/sp-cost: (skill-id) -> int,
|
||||
?skill/icon-id: (skill-id) -> skill-icon-id
|
||||
): skill-detail
|
||||
Skill-detail(
|
||||
s,
|
||||
s.show,
|
||||
s.description,
|
||||
s.group,
|
||||
s.rarity,
|
||||
s.group-rate,
|
||||
s.grade-value,
|
||||
s.wit-check,
|
||||
s.activations,
|
||||
s.unique-owner,
|
||||
s.sp-cost,
|
||||
s.icon-id
|
||||
)
|
||||
|
||||
pub fun skill-detail/show(d: skill-detail, ?character/show: (character-id) -> string, ?trainee/show: (trainee-id) -> string): string
|
||||
val Skill-detail(Skill-id(id), name, desc, _, rarity, _, grade-value, wit-check, activations, owner, sp-cost, _) = d
|
||||
val r = name ++ " (ID " ++ id.show ++ "): " ++ desc ++ " " ++ activations.map(activation/show).join(". ") ++ (if wit-check then ". Wit check. " else ". No wit check. ") ++ rarity.show ++ " costing " ++ sp-cost.show ++ " SP, worth " ++ grade-value.show ++ " grade value."
|
||||
match owner
|
||||
Nothing -> r
|
||||
Just(owner-id) -> match owner-id.show
|
||||
"" -> r ++ " Unique skill of trainee with ID " ++ owner-id.show ++ "."
|
||||
owner-name -> r ++ " Unique skill of " ++ owner-name ++ "."
|
||||
|
||||
// Skill rarity levels.
|
||||
pub type rarity
|
||||
Common // white
|
||||
Rare // gold
|
||||
Unique-Low // 1*/2* unique
|
||||
Unique-Upgraded // 3*+ unique on a trainee upgraded from 1*/2*
|
||||
Unique // base 3* unique
|
||||
|
||||
pub fun rarity/show(r: rarity): string
|
||||
match r
|
||||
Common -> "Common"
|
||||
Rare -> "Rare"
|
||||
Unique-Low -> "Unique (1\u2606/2\u2606)"
|
||||
Unique-Upgraded -> "Unique (3\u2606+ from 1\u2606/2\u2606 upgraded)"
|
||||
Unique -> "Unique (3\u2606+)"
|
||||
|
||||
// Condition and precondition logic.
|
||||
pub alias condition = string
|
||||
|
||||
// Activation conditions and effects.
|
||||
// A skill has one or two activations.
|
||||
pub struct activation
|
||||
precondition: condition
|
||||
condition: condition
|
||||
duration: decimal // seconds
|
||||
dur-scale: dur-scale
|
||||
cooldown: decimal // seconds
|
||||
abilities: list<ability> // one to three elements
|
||||
|
||||
pub fun activation/show(a: activation, ?character/show: (character-id) -> string): string
|
||||
match a
|
||||
Activation("", condition, duration, _, _, abilities) | !duration.is-pos -> condition ++ " -> " ++ abilities.show
|
||||
Activation("", condition, duration, Direct-Dur, cooldown, abilities) | cooldown >= 500.decimal -> condition ++ " -> for " ++ duration.show ++ "s, " ++ abilities.show
|
||||
Activation("", condition, duration, dur-scale, cooldown, abilities) | cooldown >= 500.decimal -> condition ++ " -> for " ++ duration.show ++ "s " ++ dur-scale.show ++ ", " ++ abilities.show
|
||||
Activation("", condition, duration, Direct-Dur, cooldown, abilities) -> condition ++ " -> for " ++ duration.show ++ "s on " ++ cooldown.show ++ "s cooldown, " ++ abilities.show
|
||||
Activation("", condition, duration, dur-scale, cooldown, abilities) -> condition ++ " -> for " ++ duration.show ++ "s " ++ dur-scale.show ++ " on " ++ cooldown.show ++ "s cooldown, " ++ abilities.show
|
||||
Activation(precondition, condition, duration, _, _, abilities) | !duration.is-pos -> precondition ++ " -> " ++ condition ++ " -> " ++ abilities.show
|
||||
Activation(precondition, condition, duration, Direct-Dur, cooldown, abilities) | cooldown >= 500.decimal -> precondition ++ " -> " ++ condition ++ " -> for " ++ duration.show ++ "s, " ++ abilities.show
|
||||
Activation(precondition, condition, duration, dur-scale, cooldown, abilities) | cooldown >= 500.decimal -> precondition ++ " -> " ++ condition ++ " -> for " ++ duration.show ++ "s " ++ dur-scale.show ++ ", " ++ abilities.show
|
||||
Activation(precondition, condition, duration, Direct-Dur, cooldown, abilities) -> precondition ++ " -> " ++ condition ++ " -> for " ++ duration.show ++ "s on " ++ cooldown.show ++ "s cooldown, " ++ abilities.show
|
||||
Activation(precondition, condition, duration, dur-scale, cooldown, abilities) -> precondition ++ " -> " ++ condition ++ " -> for " ++ duration.show ++ "s " ++ dur-scale.show ++ " on " ++ cooldown.show ++ "s cooldown, " ++ abilities.show
|
||||
|
||||
// Special scaling types for skill activation durations.
|
||||
pub type dur-scale
|
||||
Direct-Dur
|
||||
Front-Distance-Dur
|
||||
Multiply-Remaining-HP
|
||||
Increment-Pass
|
||||
Midrace-Side-Block-Time-Dur
|
||||
Multiply-Remaining-HP2
|
||||
|
||||
pub fun dur-scale/show(s: dur-scale): string
|
||||
match s
|
||||
Direct-Dur -> "with no scaling"
|
||||
Front-Distance-Dur -> "scaling with distance from the front"
|
||||
Multiply-Remaining-HP -> "scaling with remaining HP"
|
||||
Increment-Pass -> "increasing with each pass while active"
|
||||
Midrace-Side-Block-Time-Dur -> "scaling with mid-race phase blocked side time"
|
||||
Multiply-Remaining-HP2 -> "scaling with remaining HP"
|
||||
|
||||
// Effects of activating a skill.
|
||||
pub struct ability
|
||||
ability-type: ability-type
|
||||
value-usage: value-usage
|
||||
target: target
|
||||
|
||||
pub fun ability/show(a: ability, ?character/show: (character-id) -> string): string
|
||||
match a
|
||||
Ability(t, Direct, Self) -> t.show
|
||||
Ability(t, Direct, target) -> t.show ++ " " ++ target.show
|
||||
Ability(t, v, Self) -> t.show ++ " " ++ v.show
|
||||
Ability(t, v, target) -> t.show ++ " " ++ target.show ++ " " ++ v.show
|
||||
|
||||
// Skill ability effects.
|
||||
pub type ability-type
|
||||
Passive-Speed(bonus: decimal)
|
||||
Passive-Stamina(bonus: decimal)
|
||||
Passive-Power(bonus: decimal)
|
||||
Passive-Guts(bonus: decimal)
|
||||
Passive-Wit(bonus: decimal)
|
||||
Great-Escape
|
||||
Vision(bonus: decimal)
|
||||
HP(rate: decimal)
|
||||
Gate-Delay(rate: decimal)
|
||||
Frenzy(add: decimal)
|
||||
Current-Speed(add: decimal)
|
||||
Target-Speed(add: decimal)
|
||||
Lane-Speed(add: decimal)
|
||||
Accel(add: decimal)
|
||||
Lane-Change(add: decimal)
|
||||
|
||||
pub fun ability-type/show(a: ability-type): string
|
||||
match a
|
||||
Passive-Speed(bonus) -> bonus.show ++ " Speed"
|
||||
Passive-Stamina(bonus) -> bonus.show ++ " Stamina"
|
||||
Passive-Power(bonus) -> bonus.show ++ " Power"
|
||||
Passive-Guts(bonus) -> bonus.show ++ " Guts"
|
||||
Passive-Wit(bonus) -> bonus.show ++ " Wit"
|
||||
Great-Escape -> "enable Great Escape style"
|
||||
Vision(bonus) -> bonus.show ++ " vision"
|
||||
HP(rate) | rate.is-pos -> show(rate * 100.decimal) ++ "% HP recovery"
|
||||
HP(rate) -> show(rate * 100.decimal) ++ "% HP loss"
|
||||
Gate-Delay(rate) -> rate.show ++ "× gate delay"
|
||||
Frenzy(add) -> add.show ++ "s longer Rushed"
|
||||
Current-Speed(rate) -> rate.show ++ "m/s current speed"
|
||||
Target-Speed(rate) -> rate.show ++ "m/s target speed"
|
||||
Lane-Speed(rate) -> rate.show ++ "m/s lane change speed"
|
||||
Accel(rate) -> rate.show ++ "m/s² acceleration"
|
||||
Lane-Change(rate) -> rate.show ++ " course width movement"
|
||||
|
||||
// Special scaling types for skill abilities.
|
||||
pub type value-usage
|
||||
Direct
|
||||
Team-Speed
|
||||
Team-Stamina
|
||||
Team-Power
|
||||
Team-Guts
|
||||
Team-Wit
|
||||
Multiply-Random
|
||||
Multiply-Random2
|
||||
Climax
|
||||
Max-Stat
|
||||
Passive-Count
|
||||
Front-Distance-Add
|
||||
Midrace-Side-Block-Time
|
||||
Speed-Scaling
|
||||
Speed-Scaling2
|
||||
Arc-Global-Potential
|
||||
Max-Lead-Distance
|
||||
|
||||
pub fun value-usage/show(v: value-usage): string
|
||||
match v
|
||||
Direct -> "with no scaling"
|
||||
Team-Speed -> "scaling with team Speed"
|
||||
Team-Stamina -> "scaling with team Stamina"
|
||||
Team-Power -> "scaling with team Power"
|
||||
Team-Guts -> "scaling with team Guts"
|
||||
Team-Wit -> "scaling with team Wit"
|
||||
Multiply-Random -> "scaling with a random multiplier (0×, 0.02×, or 0.04×)"
|
||||
Multiply-Random2 -> "scaling with a random multiplier (0×, 0.02×, or 0.04×)"
|
||||
Climax -> "scaling with the number of races won during training"
|
||||
Max-Stat -> "scaling with the value of the user's highest stat"
|
||||
Passive-Count -> "scaling with the number of Passive skills activated"
|
||||
Front-Distance-Add -> "scaling with distance from the leader"
|
||||
Midrace-Side-Block-Time -> "scaling with mid-race phase blocked side time"
|
||||
Speed-Scaling -> "scaling with overall speed"
|
||||
Speed-Scaling2 -> "scaling with overall speed"
|
||||
Arc-Global-Potential -> "scaling with L'Arc global potential"
|
||||
Max-Lead-Distance -> "scaling with the distance of the longest lead obtained in the first two thirds of the race"
|
||||
|
||||
// Who a skill ability targets.
|
||||
pub type target
|
||||
Self
|
||||
Sympathizers
|
||||
In-View
|
||||
Frontmost(limit: int)
|
||||
Ahead(limit: int)
|
||||
Behind(limit: int)
|
||||
All-Teammates
|
||||
Style(style: style)
|
||||
Rushing-Ahead(limit: int)
|
||||
Rushing-Behind(limit: int)
|
||||
Rushing-Style(style: style)
|
||||
Specific-Character(who: character-id)
|
||||
Triggering
|
||||
|
||||
pub fun target/show(t: target, ?character/show: (character-id) -> string): string
|
||||
match t
|
||||
Self -> "self"
|
||||
Sympathizers -> "others with Sympathy"
|
||||
In-View -> "others in field of view"
|
||||
Frontmost(limit) -> "frontmost " ++ limit.show
|
||||
Ahead(limit) | limit >= 18 -> "others ahead"
|
||||
Ahead(limit) -> "next " ++ limit.show ++ " others ahead"
|
||||
Behind(limit) | limit >= 18 -> "others behind"
|
||||
Behind(limit) -> "next " ++ limit.show ++ " others behind"
|
||||
All-Teammates -> "all teammates"
|
||||
Style(s) -> "other " ++ s.show ++ "s"
|
||||
Rushing-Ahead(limit) | limit >= 18 -> "others rushing ahead"
|
||||
Rushing-Ahead(limit) -> "next " ++ limit.show ++ " others rushing ahead"
|
||||
Rushing-Behind(limit) | limit >= 18 -> "others rushing behind"
|
||||
Rushing-Behind(limit) -> "next " ++ limit.show ++ " others rushing behind"
|
||||
Rushing-Style(s) -> "rushing " ++ s.show ++ "s"
|
||||
Specific-Character(who) -> match who.show
|
||||
"" -> "character with ID " ++ who.show
|
||||
name -> name
|
||||
Triggering -> "whosoever triggered this skill"
|
||||
@@ -1,58 +0,0 @@
|
||||
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 {
|
||||
val horse.TenThousandths
|
||||
want string
|
||||
}{
|
||||
{0, "0"},
|
||||
{500, "0.05"},
|
||||
{-500, "-0.05"},
|
||||
{10000, "1"},
|
||||
{-10000, "-1"},
|
||||
{15000, "1.5"},
|
||||
{-15000, "-1.5"},
|
||||
{10001, "1.0001"},
|
||||
{5000000, "500"},
|
||||
}
|
||||
for _, c := range cases {
|
||||
got := c.val.String()
|
||||
if got != c.want {
|
||||
t.Errorf("%d: want %q, got %q", c.val, c.want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
-121
@@ -1,121 +0,0 @@
|
||||
module horse/spark
|
||||
|
||||
import std/num/decimal
|
||||
import horse/game-id
|
||||
import horse/movement
|
||||
|
||||
// A spark on a veteran.
|
||||
pub struct spark-detail
|
||||
spark-id: spark-id
|
||||
typ: spark-type
|
||||
rarity: rarity
|
||||
|
||||
pub fun spark-detail/show(s: spark-detail, ?spark/show: (spark-id) -> string): string
|
||||
s.spark-id.show ++ " " ++ "\u2605".repeat(s.rarity.int)
|
||||
|
||||
// The category of a spark; roughly, blue, pink, green, or white, with some
|
||||
// further subdivisions.
|
||||
pub type spark-type
|
||||
Stat // blue
|
||||
Aptitude // red/pink
|
||||
Unique // green
|
||||
Race
|
||||
Skill
|
||||
// skip Carnival Bonus
|
||||
Scenario
|
||||
Surface
|
||||
Distance
|
||||
Style
|
||||
Hidden
|
||||
|
||||
// Spark targets and effects.
|
||||
pub type spark-effect
|
||||
Stat-Up(s: stat, amount: int)
|
||||
SP-Up(amount: int)
|
||||
// skip Carnival Bonus
|
||||
Random-Stat-Up(amount: int)
|
||||
Aptitude-Up(a: aptitude, amount: int)
|
||||
Skill-Hint(s: skill-id, levels: int)
|
||||
Stat-Cap-Up(s: stat, amount: int)
|
||||
|
||||
// Get the base probability for a spark to trigger during a single inheritance.
|
||||
pub fun decimal/base-proc(s: spark-detail): decimal
|
||||
match s
|
||||
Spark-detail(_, Stat, One) -> 70.decimal(-2)
|
||||
Spark-detail(_, Stat, Two) -> 80.decimal(-2)
|
||||
Spark-detail(_, Stat, Three) -> 90.decimal(-2)
|
||||
Spark-detail(_, Aptitude, One) -> 1.decimal(-2)
|
||||
Spark-detail(_, Aptitude, Two) -> 3.decimal(-2)
|
||||
Spark-detail(_, Aptitude, Three) -> 5.decimal(-2)
|
||||
Spark-detail(_, Unique, One) -> 5.decimal(-2)
|
||||
Spark-detail(_, Unique, Two) -> 10.decimal(-2)
|
||||
Spark-detail(_, Unique, Three) -> 15.decimal(-2)
|
||||
Spark-detail(_, Race, One) -> 1.decimal(-2)
|
||||
Spark-detail(_, Race, Two) -> 2.decimal(-2)
|
||||
Spark-detail(_, Race, Three) -> 3.decimal(-2)
|
||||
Spark-detail(_, _, One) -> 3.decimal(-2)
|
||||
Spark-detail(_, _, Two) -> 6.decimal(-2)
|
||||
Spark-detail(_, _, Three) -> 9.decimal(-2)
|
||||
|
||||
// The level or star count of a spark.
|
||||
pub type rarity
|
||||
One
|
||||
Two
|
||||
Three
|
||||
|
||||
pub fun rarity/int(l: rarity): int
|
||||
match l
|
||||
One -> 1
|
||||
Two -> 2
|
||||
Three -> 3
|
||||
|
||||
pub fun rarity/show(l: rarity): string
|
||||
match l
|
||||
One -> "1"
|
||||
Two -> "2"
|
||||
Three -> "3"
|
||||
|
||||
// Stat (blue) spark.
|
||||
pub type stat
|
||||
Speed
|
||||
Stamina
|
||||
Power
|
||||
Guts
|
||||
Wit
|
||||
|
||||
// Automatically generated.
|
||||
// Shows a string representation of the `stat` type.
|
||||
pub fun stat/show(this : stat) : e string
|
||||
match this
|
||||
Speed -> "Speed"
|
||||
Stamina -> "Stamina"
|
||||
Power -> "Power"
|
||||
Guts -> "Guts"
|
||||
Wit -> "Wit"
|
||||
|
||||
// Aptitude (red/pink) spark.
|
||||
pub type aptitude
|
||||
Turf
|
||||
Dirt
|
||||
Sprint
|
||||
Mile
|
||||
Medium
|
||||
Long
|
||||
Front-Runner
|
||||
Pace-Chaser
|
||||
Late-Surger
|
||||
End-Closer
|
||||
|
||||
// Shows a string representation of the `aptitude` type.
|
||||
pub fun aptitude/show(this : aptitude): string
|
||||
match this
|
||||
Turf -> "Turf"
|
||||
Dirt -> "Dirt"
|
||||
Sprint -> "Sprint"
|
||||
Mile -> "Mile"
|
||||
Medium -> "Medium"
|
||||
Long -> "Long"
|
||||
Front-Runner -> "Front Runner"
|
||||
Pace-Chaser -> "Pace Chaser"
|
||||
Late-Surger -> "Late Surger"
|
||||
End-Closer -> "End Closer"
|
||||
@@ -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*{{ $.Count }} + 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*{{ $.Count }}*{{ $.Count }} + b*{{ $.Count }} + c])
|
||||
}
|
||||
{{ end }}
|
||||
@@ -1,108 +0,0 @@
|
||||
{{ define "koka-character" -}}
|
||||
module horse/{{ $.Region }}/character
|
||||
|
||||
// Automatically generated with horsegen; DO NOT EDIT
|
||||
|
||||
import std/core/vector
|
||||
import std/core-extras
|
||||
import std/data/rb-map
|
||||
import horse/game-id
|
||||
pub import horse/character
|
||||
|
||||
// Enumeration of all characters for type-safe programming.
|
||||
pub type character
|
||||
{{- range $uma := $.Characters }}
|
||||
{{ kkenum $uma.Name }}
|
||||
{{- end }}
|
||||
|
||||
// Get the character ID for a character.
|
||||
pub fun character-id(c: character): character-id
|
||||
match c
|
||||
{{- range $uma := $.Characters }}
|
||||
{{ kkenum $uma.Name }} -> Character-id({{ $uma.ID }})
|
||||
{{- end }}
|
||||
|
||||
// List of all characters in ID order for easy iterating.
|
||||
pub val all = [
|
||||
{{- range $uma := $.Characters }}
|
||||
{{ kkenum $uma.Name }},
|
||||
{{- end }}
|
||||
]
|
||||
|
||||
val name2id: rbmap<string, character-id> = rb-map/empty()
|
||||
{{- range $uma := $.Characters }}
|
||||
.set({{ printf "%q" $uma.Name }}, Character-id({{ $uma.ID}}))
|
||||
{{- end }}
|
||||
|
||||
// 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
|
||||
name2id.lookup(name).default(Character-id(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 $uma := $.Characters }}
|
||||
{{ $uma.ID }} -> {{ printf "%q" $uma.Name }}
|
||||
{{- end }}
|
||||
x -> "character " ++ x.show
|
||||
|
||||
fun character/index(c: character-id): int
|
||||
match c.game-id
|
||||
{{- range $uma := $.Characters }}
|
||||
{{ $uma.ID }} -> {{ $uma.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 "kk_intx_t arr[] = {
|
||||
{{- range $a := $.Characters }}
|
||||
{{- range $b := $.Characters }}
|
||||
{{- index $.PairMaps $a.ID $b.ID }},
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
};\nkk_vector_from_cintarray(arr, (kk_ssize_t){{ $.Count }} * (kk_ssize_t){{ $.Count }}, 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 * {{ $.Count }} + 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 "kk_intx_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_cintarray(arr, (kk_ssize_t){{ $.Count }} * (kk_ssize_t){{ $.Count }} * (kk_ssize_t){{ $.Count }}, 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 * {{ $.Count }} * {{ $.Count }} + b.index * {{ $.Count }} + c.index).default(0)
|
||||
|
||||
{{- end }}
|
||||
@@ -1,9 +0,0 @@
|
||||
SELECT
|
||||
"index" AS "id",
|
||||
"text" AS "name",
|
||||
ROW_NUMBER() OVER (ORDER BY "index") - 1 AS "index"
|
||||
FROM text_data
|
||||
WHERE category = 6 AND "index" BETWEEN 1000 AND 1999
|
||||
-- Exclude characters who have no succession relations defined.
|
||||
AND "index" IN (SELECT chara_id FROM succession_relation_member)
|
||||
ORDER BY "id"
|
||||
-242
@@ -1,242 +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
|
||||
Count 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
|
||||
}{region, groups, skills, m}
|
||||
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
|
||||
}{region, 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
|
||||
}{region, 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
|
||||
}{region, scen}
|
||||
var err error
|
||||
if kk != nil {
|
||||
err = errors.Join(err, t.ExecuteTemplate(kk, "koka-scenario", &data))
|
||||
}
|
||||
if g != nil {
|
||||
err = errors.Join(err, t.ExecuteTemplate(g, "go-scenario", &data))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
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
|
||||
}{region, sparks, effects}
|
||||
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
|
||||
}
|
||||
|
||||
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,543 +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 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
|
||||
}
|
||||
@@ -1,208 +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
|
||||
)
|
||||
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
|
||||
})
|
||||
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)
|
||||
})
|
||||
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,80 +0,0 @@
|
||||
{{- define "koka-race" -}}
|
||||
module horse/{{ $.Region }}/race
|
||||
|
||||
// Automatically generated with horsegen; DO NOT EDIT
|
||||
|
||||
import std/data/rb-map
|
||||
import horse/game-id
|
||||
pub import horse/race
|
||||
|
||||
// Enumeration of all races for type-safe programming.
|
||||
pub type race
|
||||
{{- range $r := $.Races }}
|
||||
{{ kkenum $r.Name }}{{ if $r.Alternate }}-Alt{{ $r.ID }}{{ end }}
|
||||
{{- end }}
|
||||
|
||||
// Get the race ID for a race.
|
||||
pub fun race-id(r: race): race-id
|
||||
match r
|
||||
{{- range $r := $.Races }}
|
||||
{{ kkenum $r.Name }}{{ if $r.Alternate }}-Alt{{ $r.ID }}{{ end }} -> Race-id({{ $r.ID }})
|
||||
{{- end }}
|
||||
|
||||
// List of all races in ID order for easy iterating.
|
||||
pub val all = [
|
||||
{{- range $r := $.Races }}
|
||||
{{ kkenum $r.Name }}{{ if $r.Alternate }}-Alt{{ $r.ID }}{{ end }},
|
||||
{{- end }}
|
||||
]
|
||||
|
||||
val name2id: rbmap<string, race-id> = rb-map/empty()
|
||||
{{- range $r := $.Races }}
|
||||
.set({{ printf "%q" $r.Name }}{{ if $r.Alternate }} ++ " (Alternate {{ $r.ID }})"{{ end }}, Race-id({{ $r.ID }}))
|
||||
{{- end }}
|
||||
|
||||
// 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
|
||||
name2id.lookup(name).default(Race-id(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,69 +0,0 @@
|
||||
{{- define "koka-saddle" -}}
|
||||
module horse/{{ $.Region }}/saddle
|
||||
|
||||
// Automatically generated with horsegen; DO NOT EDIT
|
||||
|
||||
import horse/game-id
|
||||
pub import horse/race
|
||||
pub import horse/{{ $.Region }}/race
|
||||
|
||||
// Enumeration of all saddles for type-safe programming.
|
||||
pub type saddle
|
||||
{{- range $s := $.Saddles }}
|
||||
{{ kkenum $s.Name }}{{ if $s.Alternate }}-Alt{{ $s.ID }}{{ end }}
|
||||
{{- end }}
|
||||
|
||||
// Get the saddle ID for a saddle.
|
||||
pub fun saddle-id(s: saddle): saddle-id
|
||||
match s
|
||||
{{- range $s := $.Saddles }}
|
||||
{{ kkenum $s.Name }}{{ if $s.Alternate }}-Alt{{ $s.ID }}{{ end }} -> Saddle-id({{ $s.ID }})
|
||||
{{- end }}
|
||||
|
||||
// List of all saddles in ID order for easy iterating.
|
||||
pub val all = [
|
||||
{{- range $s := $.Saddles }}
|
||||
{{ kkenum $s.Name }}{{ if $s.Alternate }}-Alt{{ $s.ID }}{{ end }},
|
||||
{{- end }}
|
||||
]
|
||||
|
||||
// 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,45 +0,0 @@
|
||||
{{- define "koka-scenario" -}}
|
||||
module horse/{{ $.Region }}/scenario
|
||||
|
||||
// Automatically generated with horsegen; DO NOT EDIT
|
||||
|
||||
import horse/game-id
|
||||
|
||||
// Enumeration of all scenarios for type-safe programming.
|
||||
pub type scenario
|
||||
{{- range $s := $.Scenarios }}
|
||||
{{ kkenum $s.Name }}
|
||||
{{- end }}
|
||||
|
||||
// Get the scenario ID for a scenario.
|
||||
pub fun scenario-id(s: scenario): scenario-id
|
||||
match s
|
||||
{{- range $s := $.Scenarios }}
|
||||
{{ kkenum $s.Name }} -> Scenario-id({{ $s.ID }})
|
||||
{{- end }}
|
||||
|
||||
// List of all scenarios in ID order for easy iterating.
|
||||
pub val all = [
|
||||
{{- range $s := $.Scenarios }}
|
||||
{{ kkenum $s.Name }},
|
||||
{{- end }}
|
||||
]
|
||||
|
||||
// Get the name for a scenario.
|
||||
// If no scenario matches the ID, the result contains the numeric ID.
|
||||
pub fun show(s: scenario-id): string
|
||||
match s.game-id
|
||||
{{- range $s := $.Scenarios }}
|
||||
{{ $s.ID }} -> {{ printf "%q" $s.Name }}
|
||||
{{- end }}
|
||||
x -> "scenario " ++ x.show
|
||||
|
||||
// Get the full title for a scenario, e.g. "The Beginning: URA Finale".
|
||||
// If no scenario matches the ID, the result contains the numeric ID.
|
||||
pub fun title(s: scenario-id): string
|
||||
match s.game-id
|
||||
{{- range $s := $.Scenarios }}
|
||||
{{ $s.ID }} -> {{ printf "%q" $s.Title }}
|
||||
{{- end }}
|
||||
x -> "scenario " ++ x.show
|
||||
{{ end }}
|
||||
@@ -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,241 +0,0 @@
|
||||
{{- define "koka-skill" -}}
|
||||
module horse/{{ $.Region }}/skill
|
||||
|
||||
// Automatically generated with horsegen; DO NOT EDIT
|
||||
|
||||
import std/data/rb-map
|
||||
import std/num/decimal
|
||||
import horse/game-id
|
||||
import horse/movement
|
||||
pub import horse/skill
|
||||
|
||||
// Enumeration of all skills for type-safe programming.
|
||||
pub type skill
|
||||
{{- range $s := $.Skills }}
|
||||
{{ kkenum $s.Name }}{{ if $s.InheritID }}-Inherit{{ end }}
|
||||
{{- end }}
|
||||
|
||||
// Get the skill ID for a skill.
|
||||
pub fun skill-id(s: skill): skill-id
|
||||
match s
|
||||
{{- range $s := $.Skills }}
|
||||
{{ kkenum $s.Name }}{{ if $s.InheritID }}-Inherit{{ end }} -> Skill-id({{ $s.ID }})
|
||||
{{- end }}
|
||||
|
||||
// List of all skills in ID order for easy iterating.
|
||||
pub val all = [
|
||||
{{- range $s := $.Skills }}
|
||||
{{ kkenum $s.Name }}{{ if $s.InheritID }}-Inherit{{ end }},
|
||||
{{- end }}
|
||||
]
|
||||
|
||||
val name2id: rbmap<string, skill-id> = rb-map/empty()
|
||||
{{- range $s := $.Skills }}
|
||||
.set({{ printf "%q" $s.Name }}{{ if $s.InheritID }} ++ " (Inherited)"{{ end }}, Skill-id({{ $s.ID }}))
|
||||
{{- end }}
|
||||
|
||||
// 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
|
||||
name2id.lookup(name).default(Skill-id(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<trainee-id>
|
||||
match s.game-id
|
||||
{{- range $s := $.Skills }}
|
||||
{{- if $s.UniqueOwnerID }}
|
||||
{{ $s.ID }} -> Just(Trainee-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,9 +0,0 @@
|
||||
SELECT
|
||||
factor_group_id,
|
||||
effect_id,
|
||||
target_type,
|
||||
value_1,
|
||||
value_2
|
||||
FROM succession_factor_effect
|
||||
WHERE factor_group_id NOT IN (40001) -- exclude Carnival Bonus
|
||||
ORDER BY factor_group_id, effect_id, target_type
|
||||
@@ -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,132 +0,0 @@
|
||||
{{- define "koka-spark" -}}
|
||||
module horse/{{ $.Region }}/spark
|
||||
|
||||
// Automatically generated with horsegen; DO NOT EDIT
|
||||
|
||||
import horse/game-id
|
||||
pub import horse/spark
|
||||
|
||||
// Enumeration of all sparks for type-safe programming.
|
||||
pub type spark
|
||||
{{- range $s := $.Sparks }}
|
||||
{{ kkenum $s.Name }}-Lv{{ $s.Rarity }}
|
||||
{{- end }}
|
||||
|
||||
// Get the ID for a spark.
|
||||
pub fun spark-id(s: spark): spark-id
|
||||
match s
|
||||
{{- range $s := $.Sparks }}
|
||||
{{ kkenum $s.Name }}-Lv{{ $s.Rarity }} -> Spark-id({{ $s.ID }})
|
||||
{{- end }}
|
||||
|
||||
// List of all sparks in ID order for easy iterating.
|
||||
pub val all = [
|
||||
{{- range $s := $.Sparks }}
|
||||
{{ kkenum $s.Name }}-Lv{{ $s.Rarity }},
|
||||
{{- end }}
|
||||
]
|
||||
|
||||
// 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 }}
|
||||
@@ -0,0 +1,47 @@
|
||||
// Code generated by "stringer -type LobbyConversationLocationID -trimprefix Lobby -linecomment"; DO NOT EDIT.
|
||||
|
||||
package horse
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[LobbyRightFront1-110]
|
||||
_ = x[LobbyRightFront2-120]
|
||||
_ = x[LobbyRightFront3-130]
|
||||
_ = x[LobbyLeftTable1-210]
|
||||
_ = x[LobbyLeftTable2-220]
|
||||
_ = x[LobbyBackSeat-310]
|
||||
_ = x[LobbyPosters1-410]
|
||||
_ = x[LobbyPosters2-420]
|
||||
_ = x[LobbyPosters3-430]
|
||||
_ = x[LobbySchoolMap1-510]
|
||||
_ = x[LobbySchoolMap2-520]
|
||||
_ = x[LobbySchoolMap3-530]
|
||||
}
|
||||
|
||||
const _LobbyConversationLocationID_name = "right side frontright side frontright side frontleft side tableleft side tablecenter back seatcenter posterscenter posterscenter postersleft side school mapleft side school mapleft side school map"
|
||||
|
||||
var _LobbyConversationLocationID_map = map[LobbyConversationLocationID]string{
|
||||
110: _LobbyConversationLocationID_name[0:16],
|
||||
120: _LobbyConversationLocationID_name[16:32],
|
||||
130: _LobbyConversationLocationID_name[32:48],
|
||||
210: _LobbyConversationLocationID_name[48:63],
|
||||
220: _LobbyConversationLocationID_name[63:78],
|
||||
310: _LobbyConversationLocationID_name[78:94],
|
||||
410: _LobbyConversationLocationID_name[94:108],
|
||||
420: _LobbyConversationLocationID_name[108:122],
|
||||
430: _LobbyConversationLocationID_name[122:136],
|
||||
510: _LobbyConversationLocationID_name[136:156],
|
||||
520: _LobbyConversationLocationID_name[156:176],
|
||||
530: _LobbyConversationLocationID_name[176:196],
|
||||
}
|
||||
|
||||
func (i LobbyConversationLocationID) String() string {
|
||||
if str, ok := _LobbyConversationLocationID_map[i]; ok {
|
||||
return str
|
||||
}
|
||||
return "LobbyConversationLocationID(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package mdb
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
|
||||
"zombiezen.com/go/sqlite"
|
||||
"zombiezen.com/go/sqlite/sqlitex"
|
||||
|
||||
"git.sunturtle.xyz/zephyr/horse"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed sql/character.sql
|
||||
characterSQL string
|
||||
//go:embed sql/affinity.sql
|
||||
affinitySQL string
|
||||
//go:embed sql/affinity-detail.sql
|
||||
affinityDetailSQL string
|
||||
//go:embed sql/uma.sql
|
||||
umaSQL string
|
||||
//go:embed sql/conversation.sql
|
||||
conversationSQL string
|
||||
)
|
||||
|
||||
// Characters retrieves all named characters.
|
||||
func Characters(ctx context.Context, db *sqlitex.Pool) ([]horse.Character, error) {
|
||||
return load(ctx, db, make([]horse.Character, 0, 128), characterSQL, func(s *sqlite.Stmt) horse.Character {
|
||||
return horse.Character{
|
||||
ID: horse.CharacterID(s.ColumnInt(0)),
|
||||
Name: s.ColumnText(1),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// AffinitySummary gets precomputed base affinity for all pairs and trios of characters.
|
||||
func AffinitySummary(ctx context.Context, db *sqlitex.Pool) ([]horse.AffinityRelation, error) {
|
||||
return load(ctx, db, nil, affinitySQL, func(s *sqlite.Stmt) horse.AffinityRelation {
|
||||
return horse.AffinityRelation{
|
||||
IDA: horse.CharacterID(s.ColumnInt(0)),
|
||||
IDB: horse.CharacterID(s.ColumnInt(1)),
|
||||
IDC: horse.CharacterID(s.ColumnInt(2)),
|
||||
Affinity: s.ColumnInt(3),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// AffinityDetail gets all individual affinity group entries.
|
||||
func AffinityDetail(ctx context.Context, db *sqlitex.Pool) ([]horse.AffinityDetail, error) {
|
||||
return load(ctx, db, nil, affinityDetailSQL, func(s *sqlite.Stmt) horse.AffinityDetail {
|
||||
return horse.AffinityDetail{
|
||||
CharaID: horse.CharacterID(s.ColumnInt(0)),
|
||||
Relation: uint16(s.ColumnInt(1)),
|
||||
Affinity: uint16(s.ColumnInt(2)),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Umas retrieves all trainable Uma variants.
|
||||
func Umas(ctx context.Context, db *sqlitex.Pool) ([]horse.Uma, error) {
|
||||
return load(ctx, db, make([]horse.Uma, 0, 128), 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(5)),
|
||||
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)),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func Conversations(ctx context.Context, db *sqlitex.Pool) ([]horse.Conversation, error) {
|
||||
return load(ctx, db, make([]horse.Conversation, 0, 1024), conversationSQL, func(s *sqlite.Stmt) horse.Conversation {
|
||||
return horse.Conversation{
|
||||
CharacterID: horse.CharacterID(s.ColumnInt(0)),
|
||||
Number: s.ColumnInt(1),
|
||||
Location: horse.LobbyConversationLocationID(s.ColumnInt(2)),
|
||||
Chara1: horse.CharacterID(s.ColumnInt(3)),
|
||||
Chara2: horse.CharacterID(s.ColumnInt(4)),
|
||||
Chara3: horse.CharacterID(s.ColumnInt(5)),
|
||||
ConditionType: s.ColumnInt(6),
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,325 @@
|
||||
package mdb_test
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"testing"
|
||||
|
||||
"git.sunturtle.xyz/zephyr/horse"
|
||||
"git.sunturtle.xyz/zephyr/horse/mdb"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
)
|
||||
|
||||
//go:embed testdata/character.sql
|
||||
var characterSQL string
|
||||
|
||||
func TestCharacters(t *testing.T) {
|
||||
db := testdb(t.Context(), "file:TestCharacters?mode=memory&cache=shared", characterSQL)
|
||||
got, err := mdb.Characters(t.Context(), db)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
want := []horse.Character{
|
||||
{ID: 1001, Name: "Special Week"},
|
||||
{ID: 1002, Name: "Silence Suzuka"},
|
||||
{ID: 1078, Name: "Yamanin Zephyr"},
|
||||
{ID: 2001, Name: "Happy Meek"},
|
||||
{ID: 9001, Name: "Tazuna Hayakawa"},
|
||||
}
|
||||
if diff := cmp.Diff(want, got); diff != "" {
|
||||
t.Errorf("wrong characters (+got/-want):\n%s", diff)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAffinitySummary(t *testing.T) {
|
||||
db := testdb(t.Context(), "file:TestAffinitySummary?mode=memory&cache=shared", characterSQL)
|
||||
got, err := mdb.AffinitySummary(t.Context(), db)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
want := []horse.AffinityRelation{
|
||||
{IDA: 1001, IDB: 1002, Affinity: 23},
|
||||
}
|
||||
if diff := cmp.Diff(want, got); diff != "" {
|
||||
t.Errorf("wrong affinity (+got/-want):\n%s", diff)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAffinityDetail(t *testing.T) {
|
||||
db := testdb(t.Context(), "file:TestAffinityDetail?mode=memory&cache=shared", characterSQL)
|
||||
got, err := mdb.AffinityDetail(t.Context(), db)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
want := []horse.AffinityDetail{
|
||||
{CharaID: 1001, Relation: 103, Affinity: 2},
|
||||
{CharaID: 1001, Relation: 202, Affinity: 2},
|
||||
{CharaID: 1001, Relation: 301, Affinity: 2},
|
||||
{CharaID: 1001, Relation: 401, Affinity: 2},
|
||||
{CharaID: 1001, Relation: 502, Affinity: 2},
|
||||
{CharaID: 1001, Relation: 510, Affinity: 2},
|
||||
{CharaID: 1001, Relation: 2001, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 2102, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 2301, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 2406, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 2506, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 2510, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 2516, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 2519, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 2601, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 2603, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 2811, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 2903, Affinity: 7},
|
||||
{CharaID: 1001, Relation: 3003, Affinity: 7},
|
||||
{CharaID: 1001, Relation: 3004, Affinity: 7},
|
||||
{CharaID: 1001, Relation: 3101, Affinity: 7},
|
||||
{CharaID: 1001, Relation: 3205, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 7003, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 7004, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 7005, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 7006, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 7007, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 8001, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 8002, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 8003, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 8004, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 8005, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 8006, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 8007, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 8008, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 8009, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 8010, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 8011, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 8012, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 8013, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 8014, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 8015, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 8016, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 8443, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 8479, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 8511, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 8536, Affinity: 1},
|
||||
{CharaID: 1001, Relation: 8640, Affinity: 1},
|
||||
{CharaID: 1002, Relation: 104, Affinity: 2},
|
||||
{CharaID: 1002, Relation: 202, Affinity: 2},
|
||||
{CharaID: 1002, Relation: 301, Affinity: 2},
|
||||
{CharaID: 1002, Relation: 402, Affinity: 2},
|
||||
{CharaID: 1002, Relation: 2001, Affinity: 1},
|
||||
{CharaID: 1002, Relation: 2406, Affinity: 1},
|
||||
{CharaID: 1002, Relation: 2512, Affinity: 1},
|
||||
{CharaID: 1002, Relation: 2601, Affinity: 1},
|
||||
{CharaID: 1002, Relation: 2603, Affinity: 1},
|
||||
{CharaID: 1002, Relation: 2810, Affinity: 1},
|
||||
{CharaID: 1002, Relation: 2901, Affinity: 7},
|
||||
{CharaID: 1002, Relation: 3003, Affinity: 7},
|
||||
{CharaID: 1002, Relation: 3101, Affinity: 7},
|
||||
{CharaID: 1002, Relation: 3205, Affinity: 1},
|
||||
{CharaID: 1002, Relation: 7000, Affinity: 1},
|
||||
{CharaID: 1002, Relation: 7001, Affinity: 1},
|
||||
{CharaID: 1002, Relation: 7002, Affinity: 1},
|
||||
{CharaID: 1002, Relation: 7013, Affinity: 1},
|
||||
{CharaID: 1002, Relation: 7015, Affinity: 1},
|
||||
{CharaID: 1002, Relation: 8017, Affinity: 1},
|
||||
{CharaID: 1002, Relation: 8018, Affinity: 1},
|
||||
{CharaID: 1002, Relation: 8019, Affinity: 1},
|
||||
{CharaID: 1002, Relation: 8020, Affinity: 1},
|
||||
{CharaID: 1002, Relation: 8021, Affinity: 1},
|
||||
{CharaID: 1002, Relation: 8022, Affinity: 1},
|
||||
{CharaID: 1002, Relation: 8023, Affinity: 1},
|
||||
{CharaID: 1002, Relation: 8024, Affinity: 1},
|
||||
{CharaID: 1002, Relation: 8025, Affinity: 1},
|
||||
{CharaID: 1002, Relation: 8026, Affinity: 1},
|
||||
{CharaID: 1002, Relation: 8027, Affinity: 1},
|
||||
{CharaID: 1002, Relation: 8028, Affinity: 1},
|
||||
{CharaID: 1002, Relation: 8029, Affinity: 1},
|
||||
{CharaID: 1002, Relation: 8030, Affinity: 1},
|
||||
{CharaID: 1002, Relation: 8031, Affinity: 1},
|
||||
{CharaID: 1002, Relation: 8032, Affinity: 1},
|
||||
{CharaID: 1002, Relation: 8444, Affinity: 1},
|
||||
{CharaID: 1002, Relation: 8480, Affinity: 1},
|
||||
{CharaID: 1002, Relation: 8512, Affinity: 1},
|
||||
{CharaID: 1002, Relation: 8537, Affinity: 1},
|
||||
{CharaID: 1002, Relation: 8641, Affinity: 1},
|
||||
}
|
||||
if diff := cmp.Diff(want, got); diff != "" {
|
||||
t.Errorf("wrong affinity details (+got/-want):\n%s", diff)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUmas(t *testing.T) {
|
||||
db := testdb(t.Context(), "file:TestUmas?mode=memory&cache=shared", characterSQL)
|
||||
got, err := mdb.Umas(t.Context(), db)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
want := []horse.Uma{
|
||||
{
|
||||
ID: 100101,
|
||||
CharacterID: 1001,
|
||||
Name: `[Special Dreamer] Special Week`,
|
||||
Variant: `[Special Dreamer]`,
|
||||
Sprint: 2,
|
||||
Mile: 5,
|
||||
Medium: 7,
|
||||
Long: 7,
|
||||
Front: 1,
|
||||
Pace: 7,
|
||||
Late: 7,
|
||||
End: 5,
|
||||
Turf: 7,
|
||||
Dirt: 1,
|
||||
Unique: 100011,
|
||||
Skill1: 200512,
|
||||
Skill2: 201352,
|
||||
Skill3: 200732,
|
||||
SkillPL2: 200162,
|
||||
SkillPL3: 201351,
|
||||
SkillPL4: 200612,
|
||||
SkillPL5: 200511,
|
||||
},
|
||||
{
|
||||
ID: 100102,
|
||||
CharacterID: 1001,
|
||||
Name: `[Hopp'n♪Happy Heart] Special Week`,
|
||||
Variant: `[Hopp'n♪Happy Heart]`,
|
||||
Sprint: 2,
|
||||
Mile: 5,
|
||||
Medium: 7,
|
||||
Long: 7,
|
||||
Front: 1,
|
||||
Pace: 7,
|
||||
Late: 7,
|
||||
End: 5,
|
||||
Turf: 7,
|
||||
Dirt: 1,
|
||||
Unique: 110011,
|
||||
Skill1: 200462,
|
||||
Skill2: 200592,
|
||||
Skill3: 201132,
|
||||
SkillPL2: 200212,
|
||||
SkillPL3: 200591,
|
||||
SkillPL4: 201611,
|
||||
SkillPL5: 200461,
|
||||
},
|
||||
{
|
||||
ID: 100201,
|
||||
CharacterID: 1002,
|
||||
Name: `[Innocent Silence] Silence Suzuka`,
|
||||
Variant: `[Innocent Silence]`,
|
||||
Sprint: 4,
|
||||
Mile: 7,
|
||||
Medium: 7,
|
||||
Long: 3,
|
||||
Front: 7,
|
||||
Pace: 5,
|
||||
Late: 3,
|
||||
End: 1,
|
||||
Turf: 7,
|
||||
Dirt: 1,
|
||||
Unique: 100021,
|
||||
Skill1: 200432,
|
||||
Skill2: 200552,
|
||||
Skill3: 200712,
|
||||
SkillPL2: 200022,
|
||||
SkillPL3: 200431,
|
||||
SkillPL4: 200542,
|
||||
SkillPL5: 200551,
|
||||
},
|
||||
}
|
||||
if diff := cmp.Diff(want, got); diff != "" {
|
||||
t.Errorf("wrong umas (+got/-want):\n%s", diff)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConversations(t *testing.T) {
|
||||
db := testdb(t.Context(), "file:TestConversations?mode=memory&cache=shared", characterSQL)
|
||||
got, err := mdb.Conversations(t.Context(), db)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
want := []horse.Conversation{
|
||||
{
|
||||
CharacterID: 1001,
|
||||
Number: 1,
|
||||
Location: 410,
|
||||
Chara1: 1001,
|
||||
},
|
||||
{
|
||||
CharacterID: 1001,
|
||||
Number: 2,
|
||||
Location: 510,
|
||||
Chara1: 1001,
|
||||
ConditionType: 1,
|
||||
},
|
||||
{
|
||||
CharacterID: 1001,
|
||||
Number: 3,
|
||||
Location: 310,
|
||||
Chara1: 1001,
|
||||
ConditionType: 1,
|
||||
},
|
||||
{
|
||||
CharacterID: 1001,
|
||||
Number: 4,
|
||||
Location: 120,
|
||||
Chara1: 1001,
|
||||
Chara2: 1002,
|
||||
ConditionType: 2,
|
||||
},
|
||||
{
|
||||
CharacterID: 1001,
|
||||
Number: 5,
|
||||
Location: 520,
|
||||
Chara1: 1003,
|
||||
Chara2: 1001,
|
||||
ConditionType: 3,
|
||||
},
|
||||
{
|
||||
CharacterID: 1001,
|
||||
Number: 6,
|
||||
Location: 430,
|
||||
Chara1: 1001,
|
||||
Chara2: 1014,
|
||||
Chara3: 1011,
|
||||
ConditionType: 1,
|
||||
},
|
||||
{
|
||||
CharacterID: 1002,
|
||||
Number: 1,
|
||||
Location: 310,
|
||||
Chara1: 1002,
|
||||
},
|
||||
{
|
||||
CharacterID: 1002,
|
||||
Number: 2,
|
||||
Location: 210,
|
||||
Chara1: 1002,
|
||||
ConditionType: 1,
|
||||
},
|
||||
{
|
||||
CharacterID: 1002,
|
||||
Number: 3,
|
||||
Location: 110,
|
||||
Chara1: 1002,
|
||||
ConditionType: 1,
|
||||
},
|
||||
{
|
||||
CharacterID: 1002,
|
||||
Number: 4,
|
||||
Location: 520,
|
||||
Chara1: 1010,
|
||||
Chara2: 1002,
|
||||
ConditionType: 3,
|
||||
},
|
||||
{
|
||||
CharacterID: 1002,
|
||||
Number: 5,
|
||||
Location: 220,
|
||||
Chara1: 1002,
|
||||
Chara2: 1018,
|
||||
ConditionType: 2,
|
||||
},
|
||||
}
|
||||
if diff := cmp.Diff(want, got); diff != "" {
|
||||
t.Errorf("wrong conversations (+got/-want):\n%s", diff)
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package mdb
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"zombiezen.com/go/sqlite"
|
||||
"zombiezen.com/go/sqlite/sqlitex"
|
||||
)
|
||||
|
||||
// load scans all results of sql and appends them to r.
|
||||
func load[T any](ctx context.Context, db *sqlitex.Pool, r []T, sql string, row func(*sqlite.Stmt) T) ([]T, error) {
|
||||
conn, err := db.Take(ctx)
|
||||
defer db.Put(conn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stmt, err := conn.Prepare(sql)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for {
|
||||
ok, err := stmt.Step()
|
||||
if err != nil {
|
||||
return r, err
|
||||
}
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
r = append(r, row(stmt))
|
||||
}
|
||||
return r, err
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package mdb_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"zombiezen.com/go/sqlite"
|
||||
"zombiezen.com/go/sqlite/sqlitex"
|
||||
)
|
||||
|
||||
func testdb(ctx context.Context, uri, schema string) *sqlitex.Pool {
|
||||
db, err := sqlitex.NewPool(uri, sqlitex.PoolOptions{Flags: sqlite.OpenCreate | sqlite.OpenReadWrite | sqlite.OpenMemory | sqlite.OpenSharedCache | sqlite.OpenURI})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
conn, err := db.Take(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := sqlitex.ExecScript(conn, schema); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return db
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package mdb
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
|
||||
"zombiezen.com/go/sqlite"
|
||||
"zombiezen.com/go/sqlite/sqlitex"
|
||||
|
||||
"git.sunturtle.xyz/zephyr/horse"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed sql/race.sql
|
||||
raceSQL string
|
||||
//go:embed sql/saddle.sql
|
||||
saddleSQL string
|
||||
//go:embed sql/scenario.sql
|
||||
scenarioSQL string
|
||||
)
|
||||
|
||||
// Races retrieves all races.
|
||||
func Races(ctx context.Context, db *sqlitex.Pool) ([]horse.Race, error) {
|
||||
return load(ctx, db, nil, 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 retrieves all saddles.
|
||||
func Saddles(ctx context.Context, db *sqlitex.Pool) ([]horse.Saddle, error) {
|
||||
return load(ctx, db, nil, 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 retrieves all scenarios.
|
||||
func Scenarios(ctx context.Context, db *sqlitex.Pool) ([]horse.Scenario, error) {
|
||||
return load(ctx, db, nil, scenarioSQL, func(s *sqlite.Stmt) horse.Scenario {
|
||||
return horse.Scenario{
|
||||
ID: horse.ScenarioID(s.ColumnInt(0)),
|
||||
Name: s.ColumnText(1),
|
||||
Title: s.ColumnText(2),
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
package mdb_test
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"testing"
|
||||
|
||||
"git.sunturtle.xyz/zephyr/horse"
|
||||
"git.sunturtle.xyz/zephyr/horse/mdb"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
)
|
||||
|
||||
//go:embed testdata/race.sql
|
||||
var raceSQL string
|
||||
|
||||
func TestRaces(t *testing.T) {
|
||||
db := testdb(t.Context(), "file:TestRaces?mode=memory&cache=shared", raceSQL)
|
||||
got, err := mdb.Races(t.Context(), db)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
want := []horse.Race{
|
||||
{
|
||||
ID: 1005,
|
||||
Name: "Satsuki Sho",
|
||||
Thumbnail: 1005,
|
||||
Primary: 1005,
|
||||
},
|
||||
{
|
||||
ID: 1010,
|
||||
Name: "Tokyo Yushun (Japanese Derby)",
|
||||
Thumbnail: 1010,
|
||||
Primary: 1010,
|
||||
},
|
||||
{
|
||||
ID: 1015,
|
||||
Name: "Kikuka Sho",
|
||||
Thumbnail: 1015,
|
||||
Primary: 1015,
|
||||
},
|
||||
{
|
||||
ID: 1026,
|
||||
Name: "Kikuka Sho",
|
||||
Thumbnail: 1015,
|
||||
Primary: 1015,
|
||||
},
|
||||
{
|
||||
ID: 1028,
|
||||
Name: "Satsuki Sho",
|
||||
Thumbnail: 1028,
|
||||
Primary: 1005,
|
||||
},
|
||||
{
|
||||
ID: 1101,
|
||||
Name: "Teio Sho",
|
||||
Thumbnail: 1101,
|
||||
Primary: 1101,
|
||||
},
|
||||
{
|
||||
ID: 2001,
|
||||
Name: "Nikkei Shinshun Hai",
|
||||
Thumbnail: 2001,
|
||||
Primary: 2001,
|
||||
},
|
||||
{
|
||||
ID: 2010,
|
||||
Name: "Spring Stakes",
|
||||
Thumbnail: 2010,
|
||||
Primary: 2010,
|
||||
},
|
||||
{
|
||||
ID: 2035,
|
||||
Name: "Spring Stakes",
|
||||
Thumbnail: 2010,
|
||||
Primary: 2010,
|
||||
},
|
||||
{
|
||||
ID: 3001,
|
||||
Name: "Kyoto Kimpai",
|
||||
Thumbnail: 3001,
|
||||
Primary: 3001,
|
||||
},
|
||||
{
|
||||
ID: 4001,
|
||||
Name: "Manyo Stakes",
|
||||
Thumbnail: 4001,
|
||||
Primary: 4001,
|
||||
},
|
||||
{
|
||||
ID: 4501,
|
||||
Name: "Aster Sho",
|
||||
Thumbnail: 4501,
|
||||
Primary: 4501,
|
||||
},
|
||||
}
|
||||
if diff := cmp.Diff(want, got); diff != "" {
|
||||
t.Errorf("wrong races (+got/-want):\n%s", diff)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSaddles(t *testing.T) {
|
||||
db := testdb(t.Context(), "file:TestSaddles?mode=memory&cache=shared", raceSQL)
|
||||
got, err := mdb.Saddles(t.Context(), db)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
want := []horse.Saddle{
|
||||
{
|
||||
ID: 1,
|
||||
Name: "Classic Triple Crown",
|
||||
Races: []horse.RaceID{100501, 101001, 101501},
|
||||
Type: 0,
|
||||
Primary: 1,
|
||||
},
|
||||
{
|
||||
ID: 12,
|
||||
Name: "Japanese Derby",
|
||||
Races: []horse.RaceID{101001},
|
||||
Type: 3,
|
||||
Primary: 12,
|
||||
},
|
||||
{
|
||||
ID: 16,
|
||||
Name: "Kikuka Sho",
|
||||
Races: []horse.RaceID{101501},
|
||||
Type: 3,
|
||||
Primary: 16,
|
||||
},
|
||||
{
|
||||
ID: 18,
|
||||
Name: "Satsuki Sho",
|
||||
Races: []horse.RaceID{100501},
|
||||
Type: 3,
|
||||
Primary: 18,
|
||||
},
|
||||
{
|
||||
ID: 36,
|
||||
Name: "Teio Sho",
|
||||
Races: []horse.RaceID{110101},
|
||||
Type: 3,
|
||||
Primary: 36,
|
||||
},
|
||||
{
|
||||
ID: 40,
|
||||
Name: "Nikkei Shinshun Hai",
|
||||
Races: []horse.RaceID{200101},
|
||||
Type: 2,
|
||||
Primary: 40,
|
||||
},
|
||||
{
|
||||
ID: 49,
|
||||
Name: "Spring S.",
|
||||
Races: []horse.RaceID{201001},
|
||||
Type: 2,
|
||||
Primary: 49,
|
||||
},
|
||||
{
|
||||
ID: 74,
|
||||
Name: "Kyoto Kimpai",
|
||||
Races: []horse.RaceID{300101},
|
||||
Type: 1,
|
||||
Primary: 74,
|
||||
},
|
||||
{
|
||||
ID: 144,
|
||||
Name: "Classic Triple Crown",
|
||||
Races: []horse.RaceID{100501, 101001, 102601},
|
||||
Type: 0,
|
||||
Primary: 1,
|
||||
},
|
||||
{
|
||||
ID: 148,
|
||||
Name: "Kikuka Sho",
|
||||
Races: []horse.RaceID{102601},
|
||||
Type: 3,
|
||||
Primary: 16,
|
||||
},
|
||||
{
|
||||
ID: 149,
|
||||
Name: "Spring S.",
|
||||
Races: []horse.RaceID{203501},
|
||||
Type: 2,
|
||||
Primary: 49,
|
||||
},
|
||||
{
|
||||
ID: 154,
|
||||
Name: "Classic Triple Crown",
|
||||
Races: []horse.RaceID{102801, 101001, 101501},
|
||||
Type: 0,
|
||||
Primary: 1,
|
||||
},
|
||||
{
|
||||
ID: 155,
|
||||
Name: "Satsuki Sho",
|
||||
Races: []horse.RaceID{102801},
|
||||
Type: 3,
|
||||
Primary: 18,
|
||||
},
|
||||
}
|
||||
if diff := cmp.Diff(want, got); diff != "" {
|
||||
t.Errorf("wrong saddles (+got/-want):\n%s", diff)
|
||||
}
|
||||
}
|
||||
|
||||
func TestScenarios(t *testing.T) {
|
||||
db := testdb(t.Context(), "file:TestScenarios?mode=memory&cache=shared", raceSQL)
|
||||
got, err := mdb.Scenarios(t.Context(), db)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
want := []horse.Scenario{
|
||||
{
|
||||
ID: 1,
|
||||
Name: "URA Finale",
|
||||
Title: "The Beginning: URA Finale",
|
||||
},
|
||||
{
|
||||
ID: 2,
|
||||
Name: "Unity Cup",
|
||||
Title: "Unity Cup: Shine On, Team Spirit!",
|
||||
},
|
||||
{
|
||||
ID: 4,
|
||||
Name: "TS Climax",
|
||||
Title: "Trackblazer: Start of the Climax",
|
||||
},
|
||||
}
|
||||
if diff := cmp.Diff(want, got); diff != "" {
|
||||
t.Errorf("wrong scenarios (+got/-want):\n%s", diff)
|
||||
}
|
||||
}
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
package mdb
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"zombiezen.com/go/sqlite"
|
||||
"zombiezen.com/go/sqlite/sqlitex"
|
||||
|
||||
"git.sunturtle.xyz/zephyr/horse"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed sql/skill-group.sql
|
||||
skillGroupSQL string
|
||||
//go:embed sql/skill.sql
|
||||
skillSQL string
|
||||
)
|
||||
|
||||
// SkillGroups retrieves all skill groups.
|
||||
func SkillGroups(ctx context.Context, db *sqlitex.Pool) ([]horse.SkillGroup, error) {
|
||||
return load(ctx, db, nil, 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 retrieves all skills.
|
||||
func Skills(ctx context.Context, db *sqlitex.Pool) ([]horse.Skill, error) {
|
||||
return load(ctx, db, nil, 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
|
||||
Tags: parseTags(s.ColumnText(54)),
|
||||
SPCost: s.ColumnInt(49),
|
||||
IconID: s.ColumnInt(53),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func parseTags(s string) []uint16 {
|
||||
r := make([]uint16, 0, 8)
|
||||
for s != "" {
|
||||
t, u, _ := strings.Cut(s, "/")
|
||||
s = u
|
||||
v, err := strconv.ParseUint(t, 10, 16)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("parsing skill tags: %w", err))
|
||||
}
|
||||
r = append(r, uint16(v))
|
||||
}
|
||||
return trimZeros(r...)
|
||||
}
|
||||
|
||||
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,701 @@
|
||||
package mdb_test
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"testing"
|
||||
|
||||
"git.sunturtle.xyz/zephyr/horse"
|
||||
"git.sunturtle.xyz/zephyr/horse/mdb"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
)
|
||||
|
||||
//go:embed testdata/skill.sql
|
||||
var skillSQL string
|
||||
|
||||
func TestSkillGroups(t *testing.T) {
|
||||
db := testdb(t.Context(), "file:TestSkillGroups?mode=memory&cache=shared", skillSQL)
|
||||
got, err := mdb.SkillGroups(t.Context(), db)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
want := []horse.SkillGroup{
|
||||
{ID: 1035, Skill1: 10351},
|
||||
{ID: 10001, Skill1: 100011, Skill2: 900011},
|
||||
{ID: 10035, Skill1: 100351, Skill2: 900351},
|
||||
{ID: 11024, Skill1: 110241, Skill2: 910241},
|
||||
{ID: 20001, Skill1: 200012, Skill2: 200011, Skill3: 200014, SkillBad: 200013},
|
||||
{ID: 20002, Skill1: 200022, Skill2: 200021, SkillBad: 200023},
|
||||
{ID: 20036, Skill1: 200362, Skill2: 200361},
|
||||
{ID: 20083, Skill1: 200831},
|
||||
{ID: 20180, SkillBad: 201801},
|
||||
{ID: 30001, Skill1: 300011},
|
||||
{ID: 90001, Skill1: 100011, Skill2: 900011},
|
||||
{ID: 90035, Skill1: 100351, Skill2: 900351},
|
||||
{ID: 91024, Skill1: 110241, Skill2: 910241},
|
||||
}
|
||||
if diff := cmp.Diff(want, got); diff != "" {
|
||||
t.Errorf("wrong skill groups (+got/-want):\n%s", diff)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSkills(t *testing.T) {
|
||||
db := testdb(t.Context(), "file:TestSkills?mode=memory&cache=shared", skillSQL)
|
||||
got, err := mdb.Skills(t.Context(), db)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
want := []horse.Skill{
|
||||
{
|
||||
ID: 10351,
|
||||
Name: "V Is for Victory!",
|
||||
Description: "Moderately increase velocity with winning ambition when positioned toward the front on the final straight after engaging in a challenge on the final corner or later.",
|
||||
Group: 1035,
|
||||
Rarity: 3,
|
||||
GroupRate: 1,
|
||||
GradeValue: 240,
|
||||
WitCheck: false,
|
||||
Activations: []horse.Activation{
|
||||
{
|
||||
Precondition: "is_finalcorner==1&blocked_side_continuetime>=2",
|
||||
Condition: "is_finalcorner==1&corner==0&order<=5",
|
||||
Duration: 50000,
|
||||
DurScale: 1,
|
||||
Cooldown: 5000000,
|
||||
Abilities: []horse.Ability{
|
||||
{
|
||||
Type: 27,
|
||||
ValueUsage: 1,
|
||||
Value: 2500,
|
||||
Target: 1,
|
||||
TargetValue: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
UniqueOwner: "[Get to Winning!] Winning Ticket",
|
||||
Tags: []uint16{401},
|
||||
SPCost: 0,
|
||||
IconID: 20013,
|
||||
},
|
||||
{
|
||||
ID: 100011,
|
||||
Name: "Shooting Star",
|
||||
Description: "Ride the momentum to increase velocity and very slightly increase acceleration after passing another runner toward the front late-race.",
|
||||
Group: 10001,
|
||||
Rarity: 5,
|
||||
GroupRate: 1,
|
||||
GradeValue: 340,
|
||||
WitCheck: false,
|
||||
Activations: []horse.Activation{
|
||||
{
|
||||
Precondition: "",
|
||||
Condition: "phase>=2&order>=1&order_rate<=50&change_order_onetime<0",
|
||||
Duration: 50000,
|
||||
DurScale: 1,
|
||||
Cooldown: 5000000,
|
||||
Abilities: []horse.Ability{
|
||||
{
|
||||
Type: 27,
|
||||
ValueUsage: 1,
|
||||
Value: 3500,
|
||||
Target: 1,
|
||||
TargetValue: 0,
|
||||
},
|
||||
{
|
||||
Type: 31,
|
||||
ValueUsage: 1,
|
||||
Value: 1000,
|
||||
Target: 1,
|
||||
TargetValue: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
UniqueOwner: "[Special Dreamer] Special Week",
|
||||
Tags: []uint16{401, 403},
|
||||
SPCost: 0,
|
||||
IconID: 20013,
|
||||
},
|
||||
{
|
||||
ID: 100351,
|
||||
Name: "Our Ticket to Win!",
|
||||
Description: "Increase velocity with winning ambition when positioned toward the front on the final straight after engaging in a challenge on the final corner or later.",
|
||||
Group: 10035,
|
||||
Rarity: 4,
|
||||
GroupRate: 1,
|
||||
GradeValue: 340,
|
||||
WitCheck: false,
|
||||
Activations: []horse.Activation{
|
||||
{
|
||||
Precondition: "is_finalcorner==1&blocked_side_continuetime>=2",
|
||||
Condition: "is_finalcorner==1&corner==0&order<=5",
|
||||
Duration: 50000,
|
||||
DurScale: 1,
|
||||
Cooldown: 5000000,
|
||||
Abilities: []horse.Ability{
|
||||
{
|
||||
Type: 27,
|
||||
ValueUsage: 1,
|
||||
Value: 3500,
|
||||
Target: 1,
|
||||
TargetValue: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
UniqueOwner: "[Get to Winning!] Winning Ticket",
|
||||
Tags: []uint16{401},
|
||||
SPCost: 0,
|
||||
IconID: 20013,
|
||||
},
|
||||
{
|
||||
ID: 110241,
|
||||
Name: "Flowery☆Maneuver",
|
||||
Description: "Increase velocity when passing another runner toward the front on the final corner. If passing toward the back, increase acceleration instead.",
|
||||
Group: 11024,
|
||||
Rarity: 5,
|
||||
GroupRate: 1,
|
||||
GradeValue: 340,
|
||||
WitCheck: false,
|
||||
Activations: []horse.Activation{
|
||||
{
|
||||
Precondition: "",
|
||||
Condition: "is_finalcorner==1&corner!=0&order_rate<=40&change_order_onetime<0",
|
||||
Duration: 50000,
|
||||
DurScale: 1,
|
||||
Cooldown: 5000000,
|
||||
Abilities: []horse.Ability{
|
||||
{
|
||||
Type: 27,
|
||||
ValueUsage: 1,
|
||||
Value: 3500,
|
||||
Target: 1,
|
||||
TargetValue: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Precondition: "",
|
||||
Condition: "is_finalcorner==1&corner!=0&order_rate>=50&order_rate<=80&change_order_onetime<0",
|
||||
Duration: 40000,
|
||||
DurScale: 1,
|
||||
Cooldown: 5000000,
|
||||
Abilities: []horse.Ability{
|
||||
{
|
||||
Type: 31,
|
||||
ValueUsage: 1,
|
||||
Value: 4000,
|
||||
Target: 1,
|
||||
TargetValue: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
UniqueOwner: "[Sunlight Bouquet] Mayano Top Gun",
|
||||
Tags: []uint16{401, 403},
|
||||
SPCost: 0,
|
||||
IconID: 20013,
|
||||
},
|
||||
{
|
||||
ID: 200011,
|
||||
Name: "Right-Handed ◎",
|
||||
Description: "Increase performance on right-handed tracks.",
|
||||
Group: 20001,
|
||||
Rarity: 1,
|
||||
GroupRate: 2,
|
||||
GradeValue: 174,
|
||||
WitCheck: false,
|
||||
Activations: []horse.Activation{
|
||||
{
|
||||
Precondition: "",
|
||||
Condition: "rotation==1",
|
||||
Duration: -1,
|
||||
DurScale: 1,
|
||||
Cooldown: 0,
|
||||
Abilities: []horse.Ability{
|
||||
{
|
||||
Type: 1,
|
||||
ValueUsage: 1,
|
||||
Value: 600000,
|
||||
Target: 1,
|
||||
TargetValue: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Tags: []uint16{401},
|
||||
SPCost: 110,
|
||||
IconID: 10011,
|
||||
},
|
||||
{
|
||||
ID: 200012,
|
||||
Name: "Right-Handed ○",
|
||||
Description: "Moderately increase performance on right-handed tracks.",
|
||||
Group: 20001,
|
||||
Rarity: 1,
|
||||
GroupRate: 1,
|
||||
GradeValue: 129,
|
||||
WitCheck: false,
|
||||
Activations: []horse.Activation{
|
||||
{
|
||||
Precondition: "",
|
||||
Condition: "rotation==1",
|
||||
Duration: -1,
|
||||
DurScale: 1,
|
||||
Cooldown: 0,
|
||||
Abilities: []horse.Ability{
|
||||
{
|
||||
Type: 1,
|
||||
ValueUsage: 1,
|
||||
Value: 400000,
|
||||
Target: 1,
|
||||
TargetValue: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Tags: []uint16{401},
|
||||
SPCost: 90,
|
||||
IconID: 10011,
|
||||
},
|
||||
{
|
||||
ID: 200013,
|
||||
Name: "Right-Handed ×",
|
||||
Description: "Moderately decrease performance on right-handed tracks.",
|
||||
Group: 20001,
|
||||
Rarity: 1,
|
||||
GroupRate: -1,
|
||||
GradeValue: -129,
|
||||
WitCheck: false,
|
||||
Activations: []horse.Activation{
|
||||
{
|
||||
Precondition: "",
|
||||
Condition: "rotation==1",
|
||||
Duration: -1,
|
||||
DurScale: 1,
|
||||
Cooldown: 0,
|
||||
Abilities: []horse.Ability{
|
||||
{
|
||||
Type: 1,
|
||||
ValueUsage: 1,
|
||||
Value: -400000,
|
||||
Target: 1,
|
||||
TargetValue: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Tags: []uint16{401},
|
||||
SPCost: 50,
|
||||
IconID: 10014,
|
||||
},
|
||||
{
|
||||
ID: 200014,
|
||||
Name: "Right-Handed Demon",
|
||||
Description: "Increase proficiency in right-handed tracks, increasing Speed and Power.",
|
||||
Group: 20001,
|
||||
Rarity: 2,
|
||||
GroupRate: 3,
|
||||
GradeValue: 461,
|
||||
WitCheck: false,
|
||||
Activations: []horse.Activation{
|
||||
{
|
||||
Precondition: "",
|
||||
Condition: "rotation==1",
|
||||
Duration: -1,
|
||||
DurScale: 1,
|
||||
Cooldown: 0,
|
||||
Abilities: []horse.Ability{
|
||||
{
|
||||
Type: 1,
|
||||
ValueUsage: 1,
|
||||
Value: 600000,
|
||||
Target: 1,
|
||||
TargetValue: 0,
|
||||
},
|
||||
{
|
||||
Type: 3,
|
||||
ValueUsage: 1,
|
||||
Value: 600000,
|
||||
Target: 1,
|
||||
TargetValue: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Tags: []uint16{401, 403},
|
||||
SPCost: 130,
|
||||
IconID: 10012,
|
||||
},
|
||||
{
|
||||
ID: 200021,
|
||||
Name: "Left-Handed ◎",
|
||||
Description: "Increase performance on left-handed tracks.",
|
||||
Group: 20002,
|
||||
Rarity: 1,
|
||||
GroupRate: 2,
|
||||
GradeValue: 174,
|
||||
WitCheck: false,
|
||||
Activations: []horse.Activation{
|
||||
{
|
||||
Precondition: "",
|
||||
Condition: "rotation==2",
|
||||
Duration: -1,
|
||||
DurScale: 1,
|
||||
Cooldown: 0,
|
||||
Abilities: []horse.Ability{
|
||||
{
|
||||
Type: 1,
|
||||
ValueUsage: 1,
|
||||
Value: 600000,
|
||||
Target: 1,
|
||||
TargetValue: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Tags: []uint16{401},
|
||||
SPCost: 110,
|
||||
IconID: 10011,
|
||||
},
|
||||
{
|
||||
ID: 200022,
|
||||
Name: "Left-Handed ○",
|
||||
Description: "Moderately increase performance on left-handed tracks.",
|
||||
Group: 20002,
|
||||
Rarity: 1,
|
||||
GroupRate: 1,
|
||||
GradeValue: 129,
|
||||
WitCheck: false,
|
||||
Activations: []horse.Activation{
|
||||
{
|
||||
Precondition: "",
|
||||
Condition: "rotation==2",
|
||||
Duration: -1,
|
||||
DurScale: 1,
|
||||
Cooldown: 0,
|
||||
Abilities: []horse.Ability{
|
||||
{
|
||||
Type: 1,
|
||||
ValueUsage: 1,
|
||||
Value: 400000,
|
||||
Target: 1,
|
||||
TargetValue: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Tags: []uint16{401},
|
||||
SPCost: 90,
|
||||
IconID: 10011,
|
||||
},
|
||||
{
|
||||
ID: 200023,
|
||||
Name: "Left-Handed ×",
|
||||
Description: "Moderately decrease performance on left-handed tracks.",
|
||||
Group: 20002,
|
||||
Rarity: 1,
|
||||
GroupRate: -1,
|
||||
GradeValue: -129,
|
||||
WitCheck: false,
|
||||
Activations: []horse.Activation{
|
||||
{
|
||||
Precondition: "",
|
||||
Condition: "rotation==2",
|
||||
Duration: -1,
|
||||
DurScale: 1,
|
||||
Cooldown: 0,
|
||||
Abilities: []horse.Ability{
|
||||
{
|
||||
Type: 1,
|
||||
ValueUsage: 1,
|
||||
Value: -400000,
|
||||
Target: 1,
|
||||
TargetValue: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Tags: []uint16{401},
|
||||
SPCost: 50,
|
||||
IconID: 10014,
|
||||
},
|
||||
{
|
||||
ID: 200361,
|
||||
Name: "Beeline Burst",
|
||||
Description: "Increase velocity on a straight.",
|
||||
Group: 20036,
|
||||
Rarity: 2,
|
||||
GroupRate: 2,
|
||||
GradeValue: 508,
|
||||
WitCheck: true,
|
||||
Activations: []horse.Activation{
|
||||
{
|
||||
Precondition: "",
|
||||
Condition: "straight_random==1",
|
||||
Duration: 24000,
|
||||
DurScale: 1,
|
||||
Cooldown: 300000,
|
||||
Abilities: []horse.Ability{
|
||||
{
|
||||
Type: 27,
|
||||
ValueUsage: 1,
|
||||
Value: 3500,
|
||||
Target: 1,
|
||||
TargetValue: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Tags: []uint16{401},
|
||||
SPCost: 170,
|
||||
IconID: 20012,
|
||||
},
|
||||
{
|
||||
ID: 200362,
|
||||
Name: "Straightaway Adept",
|
||||
Description: "Slightly increase velocity on a straight.",
|
||||
Group: 20036,
|
||||
Rarity: 1,
|
||||
GroupRate: 1,
|
||||
GradeValue: 217,
|
||||
WitCheck: true,
|
||||
Activations: []horse.Activation{
|
||||
{
|
||||
Precondition: "",
|
||||
Condition: "straight_random==1",
|
||||
Duration: 24000,
|
||||
DurScale: 1,
|
||||
Cooldown: 300000,
|
||||
Abilities: []horse.Ability{
|
||||
{
|
||||
Type: 27,
|
||||
ValueUsage: 1,
|
||||
Value: 1500,
|
||||
Target: 1,
|
||||
TargetValue: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Tags: []uint16{401},
|
||||
SPCost: 170,
|
||||
IconID: 20011,
|
||||
},
|
||||
{
|
||||
ID: 200831,
|
||||
Name: "Subdued Front Runners",
|
||||
Description: "Slightly increase fatigue for front runners early-race.",
|
||||
Group: 20083,
|
||||
Rarity: 1,
|
||||
GroupRate: 1,
|
||||
GradeValue: 217,
|
||||
WitCheck: true,
|
||||
Activations: []horse.Activation{
|
||||
{
|
||||
Precondition: "",
|
||||
Condition: "running_style_count_nige_otherself>=1&phase_random==0&accumulatetime>=5",
|
||||
Duration: 0,
|
||||
DurScale: 1,
|
||||
Cooldown: 5000000,
|
||||
Abilities: []horse.Ability{
|
||||
{
|
||||
Type: 9,
|
||||
ValueUsage: 1,
|
||||
Value: -100,
|
||||
Target: 18,
|
||||
TargetValue: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Tags: []uint16{301, 406},
|
||||
SPCost: 130,
|
||||
IconID: 30051,
|
||||
},
|
||||
{
|
||||
ID: 201801,
|
||||
Name: "♡ 3D Nail Art",
|
||||
Description: "Moderately decrease performance on firm ground.",
|
||||
Group: 20180,
|
||||
Rarity: 1,
|
||||
GroupRate: -1,
|
||||
GradeValue: -129,
|
||||
WitCheck: false,
|
||||
Activations: []horse.Activation{
|
||||
{
|
||||
Precondition: "",
|
||||
Condition: "ground_condition==1",
|
||||
Duration: -1,
|
||||
DurScale: 1,
|
||||
Cooldown: 0,
|
||||
Abilities: []horse.Ability{
|
||||
{
|
||||
Type: 1,
|
||||
ValueUsage: 1,
|
||||
Value: -400000,
|
||||
Target: 1,
|
||||
TargetValue: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Tags: []uint16{401},
|
||||
SPCost: 50,
|
||||
IconID: 10014,
|
||||
},
|
||||
{
|
||||
ID: 300011,
|
||||
Name: "Unquenched Thirst",
|
||||
Description: "Moderately increase performance with the desire to race.",
|
||||
Group: 30001,
|
||||
Rarity: 1,
|
||||
GroupRate: 1,
|
||||
GradeValue: 0,
|
||||
WitCheck: false,
|
||||
Activations: []horse.Activation{
|
||||
{
|
||||
Precondition: "",
|
||||
Condition: "track_id==10008",
|
||||
Duration: -1,
|
||||
DurScale: 1,
|
||||
Cooldown: 0,
|
||||
Abilities: []horse.Ability{
|
||||
{
|
||||
Type: 2,
|
||||
ValueUsage: 1,
|
||||
Value: 400000,
|
||||
Target: 1,
|
||||
TargetValue: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Tags: []uint16{402},
|
||||
SPCost: 0,
|
||||
IconID: 10021,
|
||||
},
|
||||
{
|
||||
ID: 900011,
|
||||
Name: "Shooting Star",
|
||||
Description: "Slightly increase velocity and very minimally increase acceleration after passing another runner toward the front late-race.",
|
||||
Group: 10001,
|
||||
Rarity: 1,
|
||||
GroupRate: 2,
|
||||
GradeValue: 180,
|
||||
WitCheck: true,
|
||||
Activations: []horse.Activation{
|
||||
{
|
||||
Precondition: "",
|
||||
Condition: "phase>=2&order>=1&order_rate<=50&change_order_onetime<0",
|
||||
Duration: 30000,
|
||||
DurScale: 1,
|
||||
Cooldown: 5000000,
|
||||
Abilities: []horse.Ability{
|
||||
{
|
||||
Type: 27,
|
||||
ValueUsage: 1,
|
||||
Value: 1500,
|
||||
Target: 1,
|
||||
TargetValue: 0,
|
||||
},
|
||||
{
|
||||
Type: 31,
|
||||
ValueUsage: 1,
|
||||
Value: 500,
|
||||
Target: 1,
|
||||
TargetValue: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
UniqueOwner: "[Special Dreamer] Special Week",
|
||||
Tags: []uint16{401, 403},
|
||||
SPCost: 200,
|
||||
IconID: 20011,
|
||||
},
|
||||
{
|
||||
ID: 900351,
|
||||
Name: "Our Ticket to Win!",
|
||||
Description: "Slightly increase velocity when positioned toward the front on the final straight after engaging in a challenge on the final corner or later.",
|
||||
Group: 10035,
|
||||
Rarity: 1,
|
||||
GroupRate: 2,
|
||||
GradeValue: 180,
|
||||
WitCheck: true,
|
||||
Activations: []horse.Activation{
|
||||
{
|
||||
Precondition: "is_finalcorner==1&blocked_side_continuetime>=2",
|
||||
Condition: "is_finalcorner==1&corner==0&order<=5",
|
||||
Duration: 30000,
|
||||
DurScale: 1,
|
||||
Cooldown: 5000000,
|
||||
Abilities: []horse.Ability{
|
||||
{
|
||||
Type: 27,
|
||||
ValueUsage: 1,
|
||||
Value: 1500,
|
||||
Target: 1,
|
||||
TargetValue: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
UniqueOwner: "[Get to Winning!] Winning Ticket",
|
||||
Tags: []uint16{401},
|
||||
SPCost: 200,
|
||||
IconID: 20011,
|
||||
},
|
||||
{
|
||||
ID: 910241,
|
||||
Name: "Flowery☆Maneuver",
|
||||
Description: "Slightly increase velocity when passing another runner toward the front on the final corner. If passing toward the back, slightly increase acceleration instead.",
|
||||
Group: 11024,
|
||||
Rarity: 1,
|
||||
GroupRate: 2,
|
||||
GradeValue: 180,
|
||||
WitCheck: true,
|
||||
Activations: []horse.Activation{
|
||||
{
|
||||
Precondition: "",
|
||||
Condition: "is_finalcorner==1&corner!=0&order_rate<=40&change_order_onetime<0",
|
||||
Duration: 30000,
|
||||
DurScale: 1,
|
||||
Cooldown: 5000000,
|
||||
Abilities: []horse.Ability{
|
||||
{
|
||||
Type: 27,
|
||||
ValueUsage: 1,
|
||||
Value: 1500,
|
||||
Target: 1,
|
||||
TargetValue: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Precondition: "",
|
||||
Condition: "is_finalcorner==1&corner!=0&order_rate>=50&order_rate<=80&change_order_onetime<0",
|
||||
Duration: 24000,
|
||||
DurScale: 1,
|
||||
Cooldown: 5000000,
|
||||
Abilities: []horse.Ability{
|
||||
{
|
||||
Type: 31,
|
||||
ValueUsage: 1,
|
||||
Value: 2000,
|
||||
Target: 1,
|
||||
TargetValue: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
UniqueOwner: "[Sunlight Bouquet] Mayano Top Gun",
|
||||
Tags: []uint16{401, 403},
|
||||
SPCost: 200,
|
||||
IconID: 20011,
|
||||
},
|
||||
}
|
||||
if diff := cmp.Diff(want, got); diff != "" {
|
||||
t.Errorf("wrong skills (+got/-want):\n%s", diff)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package mdb
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
|
||||
"zombiezen.com/go/sqlite/sqlitex"
|
||||
|
||||
"git.sunturtle.xyz/zephyr/horse"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed sql/spark.sql
|
||||
sparkSQL string
|
||||
//go:embed sql/spark-effect.sql
|
||||
sparkEffectSQL string
|
||||
)
|
||||
|
||||
func Sparks(ctx context.Context, db *sqlitex.Pool) ([]horse.Spark, error) {
|
||||
// We don't use func load here because we have multiple queries to run.
|
||||
conn, err := db.Take(ctx)
|
||||
defer db.Put(conn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var sp []horse.Spark
|
||||
{
|
||||
stmt := conn.Prep(sparkSQL)
|
||||
defer stmt.Reset()
|
||||
for {
|
||||
ok, err := stmt.Step()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
sp = append(sp, horse.Spark{
|
||||
ID: horse.SparkID(stmt.ColumnInt(0)),
|
||||
Name: stmt.ColumnText(1),
|
||||
Description: stmt.ColumnText(2),
|
||||
Group: horse.SparkGroupID(stmt.ColumnInt(3)),
|
||||
Rarity: horse.SparkRarity(stmt.ColumnInt(4)),
|
||||
Type: horse.SparkType(stmt.ColumnInt(5)),
|
||||
// Effects filled in later, but we can start with space.
|
||||
// The vast majority of sparks are skill sparks,
|
||||
// which have five rolls.
|
||||
Effects: make([][]horse.SparkEffect, 0, 5),
|
||||
})
|
||||
}
|
||||
}
|
||||
stmt := conn.Prep(sparkEffectSQL)
|
||||
defer stmt.Reset()
|
||||
cur := sp
|
||||
last := 0
|
||||
for {
|
||||
ok, err := stmt.Step()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
// We sort sparks by group ID first, so we can add effects in a single pass.
|
||||
group := stmt.ColumnInt(0)
|
||||
for len(cur) > 0 && cur[0].Group != horse.SparkGroupID(group) {
|
||||
cur = cur[1:]
|
||||
last = 0 // reset whenever we change group IDs
|
||||
}
|
||||
effect := stmt.ColumnInt(1)
|
||||
if effect != last {
|
||||
// This effect is a separate roll from the previous one.
|
||||
// Create a new slot for the effects to go into.
|
||||
for i := range cur {
|
||||
if cur[i].Group != horse.SparkGroupID(group) {
|
||||
break
|
||||
}
|
||||
cur[i].Effects = append(cur[i].Effects, make([]horse.SparkEffect, 0, 1))
|
||||
}
|
||||
last = effect
|
||||
}
|
||||
for i := range cur {
|
||||
if cur[i].Group != horse.SparkGroupID(group) {
|
||||
break
|
||||
}
|
||||
e := horse.SparkEffect{
|
||||
Target: horse.SparkTarget(stmt.ColumnInt(2)),
|
||||
Value1: stmt.ColumnInt32(3),
|
||||
Value2: stmt.ColumnInt32(4),
|
||||
}
|
||||
cur[i].Effects[len(cur[i].Effects)-1] = append(cur[i].Effects[len(cur[i].Effects)-1], e)
|
||||
}
|
||||
}
|
||||
return sp, nil
|
||||
}
|
||||
@@ -0,0 +1,345 @@
|
||||
package mdb_test
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
"git.sunturtle.xyz/zephyr/horse"
|
||||
"git.sunturtle.xyz/zephyr/horse/mdb"
|
||||
)
|
||||
|
||||
//go:embed testdata/spark.sql
|
||||
var sparkSQL string
|
||||
|
||||
func TestSparks(t *testing.T) {
|
||||
db := testdb(t.Context(), "file:TestSparks?mode=memory&cache=shared", sparkSQL)
|
||||
got, err := mdb.Sparks(t.Context(), db)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
want := []horse.Spark{
|
||||
{
|
||||
ID: 101,
|
||||
Name: "Speed",
|
||||
Description: "A Spark that increases Speed.",
|
||||
Group: 1,
|
||||
Rarity: 1,
|
||||
Type: 1,
|
||||
Effects: [][]horse.SparkEffect{
|
||||
{{Target: 1, Value1: 1}},
|
||||
{{Target: 1, Value1: 4}},
|
||||
{{Target: 1, Value1: 7}},
|
||||
{{Target: 1, Value1: 10}},
|
||||
{{Target: 1, Value1: 13}},
|
||||
{{Target: 1, Value1: 16}},
|
||||
{{Target: 1, Value1: 19}},
|
||||
{{Target: 1, Value1: 22}},
|
||||
{{Target: 1, Value1: 25}},
|
||||
{{Target: 1, Value1: 28}},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: 102,
|
||||
Name: "Speed",
|
||||
Description: "A Spark that increases Speed.",
|
||||
Group: 1,
|
||||
Rarity: 2,
|
||||
Type: 1,
|
||||
Effects: [][]horse.SparkEffect{
|
||||
{{Target: 1, Value1: 1}},
|
||||
{{Target: 1, Value1: 4}},
|
||||
{{Target: 1, Value1: 7}},
|
||||
{{Target: 1, Value1: 10}},
|
||||
{{Target: 1, Value1: 13}},
|
||||
{{Target: 1, Value1: 16}},
|
||||
{{Target: 1, Value1: 19}},
|
||||
{{Target: 1, Value1: 22}},
|
||||
{{Target: 1, Value1: 25}},
|
||||
{{Target: 1, Value1: 28}},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: 103,
|
||||
Name: "Speed",
|
||||
Description: "A Spark that increases Speed.",
|
||||
Group: 1,
|
||||
Rarity: 3,
|
||||
Type: 1,
|
||||
Effects: [][]horse.SparkEffect{
|
||||
{{Target: 1, Value1: 1}},
|
||||
{{Target: 1, Value1: 4}},
|
||||
{{Target: 1, Value1: 7}},
|
||||
{{Target: 1, Value1: 10}},
|
||||
{{Target: 1, Value1: 13}},
|
||||
{{Target: 1, Value1: 16}},
|
||||
{{Target: 1, Value1: 19}},
|
||||
{{Target: 1, Value1: 22}},
|
||||
{{Target: 1, Value1: 25}},
|
||||
{{Target: 1, Value1: 28}},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: 201,
|
||||
Name: "Stamina",
|
||||
Description: "A Spark that increases Stamina.",
|
||||
Group: 2,
|
||||
Rarity: 1,
|
||||
Type: 1,
|
||||
Effects: [][]horse.SparkEffect{
|
||||
{{Target: 2, Value1: 1}},
|
||||
{{Target: 2, Value1: 4}},
|
||||
{{Target: 2, Value1: 7}},
|
||||
{{Target: 2, Value1: 10}},
|
||||
{{Target: 2, Value1: 13}},
|
||||
{{Target: 2, Value1: 16}},
|
||||
{{Target: 2, Value1: 19}},
|
||||
{{Target: 2, Value1: 22}},
|
||||
{{Target: 2, Value1: 25}},
|
||||
{{Target: 2, Value1: 28}},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: 202,
|
||||
Name: "Stamina",
|
||||
Description: "A Spark that increases Stamina.",
|
||||
Group: 2,
|
||||
Rarity: 2,
|
||||
Type: 1,
|
||||
Effects: [][]horse.SparkEffect{
|
||||
{{Target: 2, Value1: 1}},
|
||||
{{Target: 2, Value1: 4}},
|
||||
{{Target: 2, Value1: 7}},
|
||||
{{Target: 2, Value1: 10}},
|
||||
{{Target: 2, Value1: 13}},
|
||||
{{Target: 2, Value1: 16}},
|
||||
{{Target: 2, Value1: 19}},
|
||||
{{Target: 2, Value1: 22}},
|
||||
{{Target: 2, Value1: 25}},
|
||||
{{Target: 2, Value1: 28}},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: 203,
|
||||
Name: "Stamina",
|
||||
Description: "A Spark that increases Stamina.",
|
||||
Group: 2,
|
||||
Rarity: 3,
|
||||
Type: 1,
|
||||
Effects: [][]horse.SparkEffect{
|
||||
{{Target: 2, Value1: 1}},
|
||||
{{Target: 2, Value1: 4}},
|
||||
{{Target: 2, Value1: 7}},
|
||||
{{Target: 2, Value1: 10}},
|
||||
{{Target: 2, Value1: 13}},
|
||||
{{Target: 2, Value1: 16}},
|
||||
{{Target: 2, Value1: 19}},
|
||||
{{Target: 2, Value1: 22}},
|
||||
{{Target: 2, Value1: 25}},
|
||||
{{Target: 2, Value1: 28}},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: 1101,
|
||||
Name: "Turf",
|
||||
Description: "A Spark that increases Turf Aptitude.",
|
||||
Group: 11,
|
||||
Rarity: 1,
|
||||
Type: 2,
|
||||
Effects: [][]horse.SparkEffect{
|
||||
{{Target: 11, Value1: 1}},
|
||||
{{Target: 11, Value1: 2}},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: 1102,
|
||||
Name: "Turf",
|
||||
Description: "A Spark that increases Turf Aptitude.",
|
||||
Group: 11,
|
||||
Rarity: 2,
|
||||
Type: 2,
|
||||
Effects: [][]horse.SparkEffect{
|
||||
{{Target: 11, Value1: 1}},
|
||||
{{Target: 11, Value1: 2}},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: 1103,
|
||||
Name: "Turf",
|
||||
Description: "A Spark that increases Turf Aptitude.",
|
||||
Group: 11,
|
||||
Rarity: 3,
|
||||
Type: 2,
|
||||
Effects: [][]horse.SparkEffect{
|
||||
{{Target: 11, Value1: 1}},
|
||||
{{Target: 11, Value1: 2}},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: 1000101,
|
||||
Name: "February S.",
|
||||
Description: `A Spark that increases Power and gives a skill hint for "Winter Runner ○".`,
|
||||
Group: 10001,
|
||||
Rarity: 1,
|
||||
Type: 5,
|
||||
Effects: [][]horse.SparkEffect{
|
||||
{{Target: 3, Value1: 3}, {Target: 41, Value1: 200202, Value2: 1}},
|
||||
{{Target: 3, Value1: 6}, {Target: 41, Value1: 200202, Value2: 1}},
|
||||
{{Target: 3, Value1: 9}, {Target: 41, Value1: 200202, Value2: 1}},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: 1000102,
|
||||
Name: "February S.",
|
||||
Description: `A Spark that increases Power and gives a skill hint for "Winter Runner ○".`,
|
||||
Group: 10001,
|
||||
Rarity: 2,
|
||||
Type: 5,
|
||||
Effects: [][]horse.SparkEffect{
|
||||
{{Target: 3, Value1: 3}, {Target: 41, Value1: 200202, Value2: 1}},
|
||||
{{Target: 3, Value1: 6}, {Target: 41, Value1: 200202, Value2: 1}},
|
||||
{{Target: 3, Value1: 9}, {Target: 41, Value1: 200202, Value2: 1}},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: 1000103,
|
||||
Name: "February S.",
|
||||
Description: `A Spark that increases Power and gives a skill hint for "Winter Runner ○".`,
|
||||
Group: 10001,
|
||||
Rarity: 3,
|
||||
Type: 5,
|
||||
Effects: [][]horse.SparkEffect{
|
||||
{{Target: 3, Value1: 3}, {Target: 41, Value1: 200202, Value2: 1}},
|
||||
{{Target: 3, Value1: 6}, {Target: 41, Value1: 200202, Value2: 1}},
|
||||
{{Target: 3, Value1: 9}, {Target: 41, Value1: 200202, Value2: 1}},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: 2000101,
|
||||
Name: "Right-Handed ○",
|
||||
Description: `A Spark that gives a skill hint for "Right-Handed ○".`,
|
||||
Group: 20001,
|
||||
Rarity: 1,
|
||||
Type: 4,
|
||||
Effects: [][]horse.SparkEffect{
|
||||
{{Target: 41, Value1: 200012, Value2: 1}},
|
||||
{{Target: 41, Value1: 200012, Value2: 2}},
|
||||
{{Target: 41, Value1: 200012, Value2: 3}},
|
||||
{{Target: 41, Value1: 200012, Value2: 4}},
|
||||
{{Target: 41, Value1: 200012, Value2: 5}},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: 2000102,
|
||||
Name: "Right-Handed ○",
|
||||
Description: `A Spark that gives a skill hint for "Right-Handed ○".`,
|
||||
Group: 20001,
|
||||
Rarity: 2,
|
||||
Type: 4,
|
||||
Effects: [][]horse.SparkEffect{
|
||||
{{Target: 41, Value1: 200012, Value2: 1}},
|
||||
{{Target: 41, Value1: 200012, Value2: 2}},
|
||||
{{Target: 41, Value1: 200012, Value2: 3}},
|
||||
{{Target: 41, Value1: 200012, Value2: 4}},
|
||||
{{Target: 41, Value1: 200012, Value2: 5}},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: 2000103,
|
||||
Name: "Right-Handed ○",
|
||||
Description: `A Spark that gives a skill hint for "Right-Handed ○".`,
|
||||
Group: 20001,
|
||||
Rarity: 3,
|
||||
Type: 4,
|
||||
Effects: [][]horse.SparkEffect{
|
||||
{{Target: 41, Value1: 200012, Value2: 1}},
|
||||
{{Target: 41, Value1: 200012, Value2: 2}},
|
||||
{{Target: 41, Value1: 200012, Value2: 3}},
|
||||
{{Target: 41, Value1: 200012, Value2: 4}},
|
||||
{{Target: 41, Value1: 200012, Value2: 5}},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: 3000101,
|
||||
Name: "URA Finale",
|
||||
Description: `A Spark that increases Speed and Stamina.`,
|
||||
Group: 30001,
|
||||
Rarity: 1,
|
||||
Type: 6,
|
||||
Effects: [][]horse.SparkEffect{
|
||||
{{Target: 1, Value1: 10}, {Target: 2, Value1: 10}},
|
||||
{{Target: 1, Value1: 20}, {Target: 2, Value1: 20}},
|
||||
{{Target: 1, Value1: 30}, {Target: 2, Value1: 30}},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: 3000102,
|
||||
Name: "URA Finale",
|
||||
Description: `A Spark that increases Speed and Stamina.`,
|
||||
Group: 30001,
|
||||
Rarity: 2,
|
||||
Type: 6,
|
||||
Effects: [][]horse.SparkEffect{
|
||||
{{Target: 1, Value1: 10}, {Target: 2, Value1: 10}},
|
||||
{{Target: 1, Value1: 20}, {Target: 2, Value1: 20}},
|
||||
{{Target: 1, Value1: 30}, {Target: 2, Value1: 30}},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: 3000103,
|
||||
Name: "URA Finale",
|
||||
Description: `A Spark that increases Speed and Stamina.`,
|
||||
Group: 30001,
|
||||
Rarity: 3,
|
||||
Type: 6,
|
||||
Effects: [][]horse.SparkEffect{
|
||||
{{Target: 1, Value1: 10}, {Target: 2, Value1: 10}},
|
||||
{{Target: 1, Value1: 20}, {Target: 2, Value1: 20}},
|
||||
{{Target: 1, Value1: 30}, {Target: 2, Value1: 30}},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: 10010101,
|
||||
Name: "Shooting Star",
|
||||
Description: `A Spark that gives a skill hint for "Shooting Star".`,
|
||||
Group: 100101,
|
||||
Rarity: 1,
|
||||
Type: 3,
|
||||
Effects: [][]horse.SparkEffect{
|
||||
{{Target: 41, Value1: 900011, Value2: 1}},
|
||||
{{Target: 41, Value1: 900011, Value2: 2}},
|
||||
{{Target: 41, Value1: 900011, Value2: 3}},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: 10010102,
|
||||
Name: "Shooting Star",
|
||||
Description: `A Spark that gives a skill hint for "Shooting Star".`,
|
||||
Group: 100101,
|
||||
Rarity: 2,
|
||||
Type: 3,
|
||||
Effects: [][]horse.SparkEffect{
|
||||
{{Target: 41, Value1: 900011, Value2: 1}},
|
||||
{{Target: 41, Value1: 900011, Value2: 2}},
|
||||
{{Target: 41, Value1: 900011, Value2: 3}},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: 10010103,
|
||||
Name: "Shooting Star",
|
||||
Description: `A Spark that gives a skill hint for "Shooting Star".`,
|
||||
Group: 100101,
|
||||
Rarity: 3,
|
||||
Type: 3,
|
||||
Effects: [][]horse.SparkEffect{
|
||||
{{Target: 41, Value1: 900011, Value2: 1}},
|
||||
{{Target: 41, Value1: 900011, Value2: 2}},
|
||||
{{Target: 41, Value1: 900011, Value2: 3}},
|
||||
},
|
||||
},
|
||||
}
|
||||
if diff := cmp.Diff(want, got); diff != "" {
|
||||
t.Errorf("wrong sparks (+got/-want):\n%s", diff)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
SELECT
|
||||
m.chara_id,
|
||||
m.relation_type,
|
||||
r.relation_point
|
||||
FROM succession_relation_member m
|
||||
JOIN succession_relation r ON m.relation_type = r.relation_type
|
||||
ORDER BY m.chara_id, m.relation_type
|
||||
@@ -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,6 @@
|
||||
SELECT
|
||||
"index" AS "id",
|
||||
"text" AS "name"
|
||||
FROM text_data
|
||||
WHERE category = 6
|
||||
ORDER BY "id"
|
||||
@@ -0,0 +1,10 @@
|
||||
SELECT
|
||||
gallery_chara_id,
|
||||
disp_order,
|
||||
pos_id,
|
||||
chara_id_1,
|
||||
chara_id_2,
|
||||
chara_id_3,
|
||||
condition_type
|
||||
FROM home_story_trigger
|
||||
ORDER BY gallery_chara_id, disp_order
|
||||
@@ -14,4 +14,4 @@ SELECT
|
||||
FROM single_mode_scenario sc
|
||||
JOIN scenario_name n ON sc.id = n.id
|
||||
JOIN scenario_title t ON sc.id = t.id
|
||||
ORDER BY sc.id
|
||||
ORDER BY sc.sort_id
|
||||
@@ -0,0 +1,17 @@
|
||||
WITH skill_groups AS (
|
||||
SELECT DISTINCT group_id FROM skill_data
|
||||
)
|
||||
SELECT
|
||||
g.group_id,
|
||||
COALESCE(inh_from.id, s1.id, 0) AS skill1,
|
||||
COALESCE(inh_to.id, 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
|
||||
LEFT JOIN skill_data inh_to ON s1.id = inh_to.unique_skill_id_1
|
||||
LEFT JOIN skill_data inh_from ON s2.unique_skill_id_1 = inh_from.id
|
||||
ORDER BY g.group_id
|
||||
@@ -87,7 +87,7 @@ SELECT
|
||||
COALESCE(u.owner_id, iu.owner_id, 0) AS unique_owner_id,
|
||||
COALESCE(u.name, iu.name, '') AS unique_owner,
|
||||
d.icon_id,
|
||||
ROW_NUMBER() OVER (ORDER BY d.id) - 1 AS "index"
|
||||
d.tag_id
|
||||
FROM skill_data d
|
||||
JOIN skill_names n ON d.id = n.id
|
||||
LEFT JOIN skill_data ud ON d.unique_skill_id_1 = ud.id
|
||||
@@ -0,0 +1,14 @@
|
||||
SELECT
|
||||
factor_group_id,
|
||||
effect_id,
|
||||
target_type,
|
||||
value_1,
|
||||
value_2
|
||||
FROM succession_factor_effect
|
||||
-- exclude Carnival Bonus
|
||||
WHERE factor_group_id NOT IN (
|
||||
SELECT factor_group_id
|
||||
FROM succession_factor
|
||||
WHERE factor_type = 7
|
||||
)
|
||||
ORDER BY factor_group_id, effect_id, id
|
||||
@@ -17,4 +17,4 @@ SELECT
|
||||
FROM spark
|
||||
JOIN succession_factor sf ON spark.id = sf.factor_id
|
||||
WHERE sf.factor_type != 7 -- exclude Carnival Bonus
|
||||
ORDER BY sf.factor_id
|
||||
ORDER BY sf.factor_group_id, sf.factor_id
|
||||
@@ -0,0 +1,59 @@
|
||||
WITH uma_name AS (
|
||||
SELECT "index" AS id, "text" AS name
|
||||
FROM text_data
|
||||
WHERE category = 4
|
||||
), uma_variant AS (
|
||||
SELECT "index" AS id, "text" AS variant
|
||||
FROM text_data
|
||||
WHERE category = 5
|
||||
), chara_name AS (
|
||||
SELECT "index" AS id, "text" AS name
|
||||
FROM text_data
|
||||
WHERE category = 6
|
||||
), skills AS (
|
||||
SELECT
|
||||
uma.id,
|
||||
s.skill_id,
|
||||
s.need_rank,
|
||||
ROW_NUMBER() OVER (PARTITION BY s.available_skill_set_id, s.need_rank ORDER BY s.id) AS idx
|
||||
FROM card_data uma
|
||||
LEFT JOIN available_skill_set s ON uma.available_skill_set_id = s.available_skill_set_id
|
||||
)
|
||||
SELECT
|
||||
uma.card_id,
|
||||
card_data.chara_id,
|
||||
n.name,
|
||||
v.variant,
|
||||
c.name AS chara_name,
|
||||
uma.proper_distance_short,
|
||||
uma.proper_distance_mile,
|
||||
uma.proper_distance_middle,
|
||||
uma.proper_distance_long,
|
||||
uma.proper_running_style_nige,
|
||||
uma.proper_running_style_senko,
|
||||
uma.proper_running_style_sashi,
|
||||
uma.proper_running_style_oikomi,
|
||||
uma.proper_ground_turf,
|
||||
uma.proper_ground_dirt,
|
||||
su.skill_id1 AS unique_skill,
|
||||
s1.skill_id AS skill1,
|
||||
s2.skill_id AS skill2,
|
||||
s3.skill_id AS skill3,
|
||||
sp2.skill_id AS skill_pl2,
|
||||
sp3.skill_id AS skill_pl3,
|
||||
sp4.skill_id AS skill_pl4,
|
||||
sp5.skill_id AS skill_pl5
|
||||
FROM card_data
|
||||
JOIN card_rarity_data uma ON card_data.id = uma.card_id
|
||||
JOIN chara_name c ON card_data.chara_id = c.id
|
||||
JOIN skill_set su ON uma.skill_set = su.id
|
||||
JOIN skills s1 ON uma.card_id = s1.id AND s1.need_rank = 0 AND s1.idx = 1
|
||||
JOIN skills s2 ON uma.card_id = s2.id AND s2.need_rank = 0 AND s2.idx = 2
|
||||
JOIN skills s3 ON uma.card_id = s3.id AND s3.need_rank = 0 AND s3.idx = 3
|
||||
JOIN skills sp2 ON uma.card_id = sp2.id AND sp2.need_rank = 2
|
||||
JOIN skills sp3 ON uma.card_id = sp3.id AND sp3.need_rank = 3
|
||||
JOIN skills sp4 ON uma.card_id = sp4.id AND sp4.need_rank = 4
|
||||
JOIN skills sp5 ON uma.card_id = sp5.id AND sp5.need_rank = 5
|
||||
LEFT JOIN uma_name n ON uma.card_id = n.id
|
||||
LEFT JOIN uma_variant v ON uma.card_id = v.id
|
||||
WHERE uma.rarity = 5
|
||||
Vendored
+262
@@ -0,0 +1,262 @@
|
||||
CREATE TABLE IF NOT EXISTS 'text_data' ('id' INTEGER NOT NULL, 'category' INTEGER NOT NULL, 'index' INTEGER NOT NULL, 'text' TEXT NOT NULL, PRIMARY KEY('category','index'));
|
||||
-- SELECT * FROM text_data WHERE category = 6 AND "index" IN (1001, 1002, 1078, 2001, 9001) OR category IN (4, 5) AND "index" IN (SELECT id FROM card_data WHERE chara_id IN (1001, 1002, 1078, 2001, 9001));
|
||||
INSERT INTO text_data VALUES(6,6,1001,'Special Week');
|
||||
INSERT INTO text_data VALUES(6,6,1002,'Silence Suzuka');
|
||||
INSERT INTO text_data VALUES(6,6,1078,'Yamanin Zephyr');
|
||||
INSERT INTO text_data VALUES(6,6,2001,'Happy Meek');
|
||||
INSERT INTO text_data VALUES(6,6,9001,'Tazuna Hayakawa');
|
||||
INSERT INTO text_data VALUES(4,4,100101,'[Special Dreamer] Special Week');
|
||||
INSERT INTO text_data VALUES(4,4,100102,'[Hopp''n♪Happy Heart] Special Week');
|
||||
INSERT INTO text_data VALUES(4,4,100201,'[Innocent Silence] Silence Suzuka');
|
||||
INSERT INTO text_data VALUES(5,5,100101,'[Special Dreamer]');
|
||||
INSERT INTO text_data VALUES(5,5,100102,'[Hopp''n♪Happy Heart]');
|
||||
INSERT INTO text_data VALUES(5,5,100201,'[Innocent Silence]');
|
||||
|
||||
CREATE TABLE IF NOT EXISTS 'chara_data' ('id' INTEGER NOT NULL, 'birth_year' INTEGER NOT NULL, 'birth_month' INTEGER NOT NULL, 'birth_day' INTEGER NOT NULL, 'sex' INTEGER NOT NULL, 'image_color_main' TEXT NOT NULL, 'image_color_sub' TEXT NOT NULL, 'ui_color_main' TEXT NOT NULL, 'ui_color_sub' TEXT NOT NULL, 'ui_training_color_1' TEXT NOT NULL, 'ui_training_color_2' TEXT NOT NULL, 'ui_border_color' TEXT NOT NULL, 'ui_num_color_1' TEXT NOT NULL, 'ui_num_color_2' TEXT NOT NULL, 'ui_turn_color' TEXT NOT NULL, 'ui_wipe_color_1' TEXT NOT NULL, 'ui_wipe_color_2' TEXT NOT NULL, 'ui_wipe_color_3' TEXT NOT NULL, 'ui_speech_color_1' TEXT NOT NULL, 'ui_speech_color_2' TEXT NOT NULL, 'ui_nameplate_color_1' TEXT NOT NULL, 'ui_nameplate_color_2' TEXT NOT NULL, 'height' INTEGER NOT NULL, 'bust' INTEGER NOT NULL, 'scale' INTEGER NOT NULL, 'skin' INTEGER NOT NULL, 'shape' INTEGER NOT NULL, 'socks' INTEGER NOT NULL, 'personal_dress' INTEGER NOT NULL, 'tail_model_id' INTEGER NOT NULL, 'race_running_type' INTEGER NOT NULL, 'ear_random_time_min' INTEGER NOT NULL, 'ear_random_time_max' INTEGER NOT NULL, 'tail_random_time_min' INTEGER NOT NULL, 'tail_random_time_max' INTEGER NOT NULL, 'story_ear_random_time_min' INTEGER NOT NULL, 'story_ear_random_time_max' INTEGER NOT NULL, 'story_tail_random_time_min' INTEGER NOT NULL, 'story_tail_random_time_max' INTEGER NOT NULL, 'attachment_model_id' INTEGER NOT NULL, 'mini_mayu_shader_type' INTEGER NOT NULL, 'start_date' INTEGER NOT NULL, 'chara_category' INTEGER NOT NULL, PRIMARY KEY('id'));
|
||||
-- SELECT * FROM chara_data WHERE id IN (1001, 1002, 1078, 2001, 9001);
|
||||
INSERT INTO chara_data VALUES(1001,1995,5,2,1,'FCA7FF','FF58D9','EE6DCB','FFDEF9','FF7FDD','F759CD','F759CD','FF7FDD','FA50CD','FA50CD','FCCAEE','FCE3F5','FDEDFE','FF7FDD','FF7FDD','FF7CDC','FEB4EA',1,2,158,1,0,3,0,1,1,110,220,30,90,275,425,130,250,-1,0,1483228800,0);
|
||||
INSERT INTO chara_data VALUES(1002,1994,5,1,1,'8FE78D','FBFF3B','29BD70','FFCE48','4BD18C','27B36B','27B36B','4BD18C','27B36B','27B36B','BDF2D6','D4F2E2','FFF5CC','4BD18C','4BD18C','43C883','82ECB5',1,0,161,1,1,6,0,1,1,170,270,180,310,275,425,180,310,-1,0,1483228800,0);
|
||||
INSERT INTO chara_data VALUES(1078,1988,5,27,1,'A8C6FD','5277D6','da483a','ffda93','4C91F1','2B75DD','2B75DD','71ADFF','1667D9','1667D9','BCD5F5','D6E4F6','FFEBF6','4C91F1','4C91F1','4C91F1','8DBCFD',1,3,154,1,0,1,0,1,1,170,270,180,310,275,425,180,310,-1,0,2524608000,0);
|
||||
INSERT INTO chara_data VALUES(2001,1971,3,15,1,'FFFFFF','FFFFFF','FFFFFF','FFFFFF','FFFFFF','FFFFFF','FFFFFF','FFFFFF','FFFFFF','FFFFFF','FFFFFF','FFFFFF','FFFFFF','68D25D','68D25D','66D713','25C4A4',2,2,163,0,0,3,0,2,1,170,270,180,310,275,425,180,310,-1,0,2524608000,0);
|
||||
INSERT INTO chara_data VALUES(9001,1948,5,2,2,'44A705','FFFFFF','44A705','F3CD00','FFFFFF','FFFFFF','FFFFFF','FFFFFF','FFFFFF','FFFFFF','FFFFFF','FFFFFF','FFFFFF','68D25D','68D25D','66D713','25C4A4',2,2,166,1,2,7,0,-1,1,170,270,180,310,275,425,180,310,-1,0,2524608000,1);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS 'card_data' ('id' INTEGER NOT NULL, 'chara_id' INTEGER NOT NULL, 'default_rarity' INTEGER NOT NULL, 'limited_chara' INTEGER NOT NULL, 'available_skill_set_id' INTEGER NOT NULL, 'talent_speed' INTEGER NOT NULL, 'talent_stamina' INTEGER NOT NULL, 'talent_pow' INTEGER NOT NULL, 'talent_guts' INTEGER NOT NULL, 'talent_wiz' INTEGER NOT NULL, 'talent_group_id' INTEGER NOT NULL, 'bg_id' INTEGER NOT NULL, 'get_piece_id' INTEGER NOT NULL, 'running_style' INTEGER NOT NULL, PRIMARY KEY('id'));
|
||||
-- SELECT * FROM card_data WHERE chara_id IN (1001, 1002, 1078, 2001, 9001);
|
||||
INSERT INTO card_data VALUES(100101,1001,3,0,100101,0,20,0,0,10,100101,8,100101,3);
|
||||
INSERT INTO card_data VALUES(100102,1001,3,0,100102,0,10,10,10,0,100102,317,100102,3);
|
||||
INSERT INTO card_data VALUES(100201,1002,3,0,100201,20,0,0,10,0,100201,30,100201,1);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS 'card_rarity_data' ('id' INTEGER NOT NULL, 'card_id' INTEGER NOT NULL, 'rarity' INTEGER NOT NULL, 'race_dress_id' INTEGER NOT NULL, 'skill_set' INTEGER NOT NULL, 'speed' INTEGER NOT NULL, 'stamina' INTEGER NOT NULL, 'pow' INTEGER NOT NULL, 'guts' INTEGER NOT NULL, 'wiz' INTEGER NOT NULL, 'max_speed' INTEGER NOT NULL, 'max_stamina' INTEGER NOT NULL, 'max_pow' INTEGER NOT NULL, 'max_guts' INTEGER NOT NULL, 'max_wiz' INTEGER NOT NULL, 'proper_distance_short' INTEGER NOT NULL, 'proper_distance_mile' INTEGER NOT NULL, 'proper_distance_middle' INTEGER NOT NULL, 'proper_distance_long' INTEGER NOT NULL, 'proper_running_style_nige' INTEGER NOT NULL, 'proper_running_style_senko' INTEGER NOT NULL, 'proper_running_style_sashi' INTEGER NOT NULL, 'proper_running_style_oikomi' INTEGER NOT NULL, 'proper_ground_turf' INTEGER NOT NULL, 'proper_ground_dirt' INTEGER NOT NULL, 'get_dress_id_1' INTEGER NOT NULL, 'get_dress_id_2' INTEGER NOT NULL, PRIMARY KEY('id'));
|
||||
-- SELECT * FROM card_rarity_data WHERE card_id IN (SELECT id FROM card_data WHERE chara_id IN (1001, 1002, 1078, 2001, 9001));
|
||||
INSERT INTO card_rarity_data VALUES(10010103,100101,3,100101,10010103,83,88,98,90,91,1200,1200,1200,1200,1200,2,5,7,7,1,7,7,5,7,1,101,100101);
|
||||
INSERT INTO card_rarity_data VALUES(10010104,100101,4,100101,10010104,92,98,109,100,101,1200,1200,1200,1200,1200,2,5,7,7,1,7,7,5,7,1,101,100101);
|
||||
INSERT INTO card_rarity_data VALUES(10010105,100101,5,100101,10010105,102,108,120,110,110,1200,1200,1200,1200,1200,2,5,7,7,1,7,7,5,7,1,101,100101);
|
||||
INSERT INTO card_rarity_data VALUES(10010203,100102,3,100130,11010103,77,90,103,98,82,1200,1200,1200,1200,1200,2,5,7,7,1,7,7,5,7,1,101,100130);
|
||||
INSERT INTO card_rarity_data VALUES(10010204,100102,4,100130,11010104,86,100,114,109,91,1200,1200,1200,1200,1200,2,5,7,7,1,7,7,5,7,1,101,100130);
|
||||
INSERT INTO card_rarity_data VALUES(10010205,100102,5,100130,11010105,94,110,125,119,102,1200,1200,1200,1200,1200,2,5,7,7,1,7,7,5,7,1,101,100130);
|
||||
INSERT INTO card_rarity_data VALUES(10020103,100201,3,100201,10020103,101,84,77,100,88,1200,1200,1200,1200,1200,4,7,7,3,7,5,3,1,7,1,101,100201);
|
||||
INSERT INTO card_rarity_data VALUES(10020104,100201,4,100201,10020104,112,93,85,111,99,1200,1200,1200,1200,1200,4,7,7,3,7,5,3,1,7,1,101,100201);
|
||||
INSERT INTO card_rarity_data VALUES(10020105,100201,5,100201,10020105,124,102,94,122,108,1200,1200,1200,1200,1200,4,7,7,3,7,5,3,1,7,1,101,100201);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS 'available_skill_set' ('id' INTEGER NOT NULL, 'available_skill_set_id' INTEGER NOT NULL, 'skill_id' INTEGER NOT NULL, 'need_rank' INTEGER NOT NULL, PRIMARY KEY('id'));
|
||||
-- SELECT * FROM available_skill_set WHERE available_skill_set_id IN (SELECT available_skill_set_id FROM card_data WHERE chara_id IN (1001, 1002, 1078, 2001, 9001));
|
||||
INSERT INTO available_skill_set VALUES(1,100101,200512,0);
|
||||
INSERT INTO available_skill_set VALUES(2,100101,201352,0);
|
||||
INSERT INTO available_skill_set VALUES(3,100101,200732,0);
|
||||
INSERT INTO available_skill_set VALUES(11,100101,200162,2);
|
||||
INSERT INTO available_skill_set VALUES(12,100101,201351,3);
|
||||
INSERT INTO available_skill_set VALUES(13,100101,200612,4);
|
||||
INSERT INTO available_skill_set VALUES(14,100101,200511,5);
|
||||
INSERT INTO available_skill_set VALUES(715,100102,200462,0);
|
||||
INSERT INTO available_skill_set VALUES(716,100102,200592,0);
|
||||
INSERT INTO available_skill_set VALUES(717,100102,201132,0);
|
||||
INSERT INTO available_skill_set VALUES(718,100102,200212,2);
|
||||
INSERT INTO available_skill_set VALUES(719,100102,200591,3);
|
||||
INSERT INTO available_skill_set VALUES(720,100102,201611,4);
|
||||
INSERT INTO available_skill_set VALUES(721,100102,200461,5);
|
||||
INSERT INTO available_skill_set VALUES(15,100201,200432,0);
|
||||
INSERT INTO available_skill_set VALUES(16,100201,200552,0);
|
||||
INSERT INTO available_skill_set VALUES(17,100201,200712,0);
|
||||
INSERT INTO available_skill_set VALUES(25,100201,200022,2);
|
||||
INSERT INTO available_skill_set VALUES(26,100201,200431,3);
|
||||
INSERT INTO available_skill_set VALUES(27,100201,200542,4);
|
||||
INSERT INTO available_skill_set VALUES(28,100201,200551,5);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS 'skill_set' ('id' INTEGER NOT NULL, 'skill_id1' INTEGER NOT NULL, 'skill_level1' INTEGER NOT NULL, 'skill_id2' INTEGER NOT NULL, 'skill_level2' INTEGER NOT NULL, 'skill_id3' INTEGER NOT NULL, 'skill_level3' INTEGER NOT NULL, 'skill_id4' INTEGER NOT NULL, 'skill_level4' INTEGER NOT NULL, 'skill_id5' INTEGER NOT NULL, 'skill_level5' INTEGER NOT NULL, 'skill_id6' INTEGER NOT NULL, 'skill_level6' INTEGER NOT NULL, 'skill_id7' INTEGER NOT NULL, 'skill_level7' INTEGER NOT NULL, 'skill_id8' INTEGER NOT NULL, 'skill_level8' INTEGER NOT NULL, 'skill_id9' INTEGER NOT NULL, 'skill_level9' INTEGER NOT NULL, 'skill_id10' INTEGER NOT NULL, 'skill_level10' INTEGER NOT NULL, PRIMARY KEY('id'));
|
||||
-- SELECT * FROM skill_set WHERE id IN (SELECT skill_set FROM card_rarity_data WHERE card_id IN (SELECT id FROM card_data WHERE chara_id IN (1001, 1002, 1078, 2001, 9001)));
|
||||
INSERT INTO skill_set VALUES(10010103,100011,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(10010104,100011,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(10010105,100011,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(10020103,100021,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(10020104,100021,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(10020105,100021,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(11010103,110011,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(11010104,110011,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(11010105,110011,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS 'succession_relation_member' ('id' INTEGER NOT NULL, 'relation_type' INTEGER NOT NULL, 'chara_id' INTEGER NOT NULL, PRIMARY KEY('id'));
|
||||
-- SELECT * FROM succession_relation_member WHERE chara_id IN (1001, 1002, 1078, 2001, 9001);
|
||||
INSERT INTO succession_relation_member VALUES(18,103,1001);
|
||||
INSERT INTO succession_relation_member VALUES(80,202,1001);
|
||||
INSERT INTO succession_relation_member VALUES(123,301,1001);
|
||||
INSERT INTO succession_relation_member VALUES(169,401,1001);
|
||||
INSERT INTO succession_relation_member VALUES(188,502,1001);
|
||||
INSERT INTO succession_relation_member VALUES(208,2001,1001);
|
||||
INSERT INTO succession_relation_member VALUES(220,2102,1001);
|
||||
INSERT INTO succession_relation_member VALUES(235,2301,1001);
|
||||
INSERT INTO succession_relation_member VALUES(241,2601,1001);
|
||||
INSERT INTO succession_relation_member VALUES(308,7003,1001);
|
||||
INSERT INTO succession_relation_member VALUES(310,7004,1001);
|
||||
INSERT INTO succession_relation_member VALUES(312,7005,1001);
|
||||
INSERT INTO succession_relation_member VALUES(314,7006,1001);
|
||||
INSERT INTO succession_relation_member VALUES(316,7007,1001);
|
||||
INSERT INTO succession_relation_member VALUES(397,2811,1001);
|
||||
INSERT INTO succession_relation_member VALUES(448,2903,1001);
|
||||
INSERT INTO succession_relation_member VALUES(509,3003,1001);
|
||||
INSERT INTO succession_relation_member VALUES(555,3004,1001);
|
||||
INSERT INTO succession_relation_member VALUES(570,3101,1001);
|
||||
INSERT INTO succession_relation_member VALUES(662,2510,1001);
|
||||
INSERT INTO succession_relation_member VALUES(674,2506,1001);
|
||||
INSERT INTO succession_relation_member VALUES(686,2516,1001);
|
||||
INSERT INTO succession_relation_member VALUES(758,2519,1001);
|
||||
INSERT INTO succession_relation_member VALUES(825,3205,1001);
|
||||
INSERT INTO succession_relation_member VALUES(835,8001,1001);
|
||||
INSERT INTO succession_relation_member VALUES(837,8002,1001);
|
||||
INSERT INTO succession_relation_member VALUES(839,8003,1001);
|
||||
INSERT INTO succession_relation_member VALUES(841,8004,1001);
|
||||
INSERT INTO succession_relation_member VALUES(843,8005,1001);
|
||||
INSERT INTO succession_relation_member VALUES(845,8006,1001);
|
||||
INSERT INTO succession_relation_member VALUES(847,8007,1001);
|
||||
INSERT INTO succession_relation_member VALUES(849,8008,1001);
|
||||
INSERT INTO succession_relation_member VALUES(851,8009,1001);
|
||||
INSERT INTO succession_relation_member VALUES(853,8010,1001);
|
||||
INSERT INTO succession_relation_member VALUES(855,8011,1001);
|
||||
INSERT INTO succession_relation_member VALUES(857,8012,1001);
|
||||
INSERT INTO succession_relation_member VALUES(859,8013,1001);
|
||||
INSERT INTO succession_relation_member VALUES(861,8014,1001);
|
||||
INSERT INTO succession_relation_member VALUES(863,8015,1001);
|
||||
INSERT INTO succession_relation_member VALUES(865,8016,1001);
|
||||
INSERT INTO succession_relation_member VALUES(1703,2406,1001);
|
||||
INSERT INTO succession_relation_member VALUES(1715,2603,1001);
|
||||
INSERT INTO succession_relation_member VALUES(1740,510,1001);
|
||||
INSERT INTO succession_relation_member VALUES(1802,8443,1001);
|
||||
INSERT INTO succession_relation_member VALUES(1876,8479,1001);
|
||||
INSERT INTO succession_relation_member VALUES(1940,8511,1001);
|
||||
INSERT INTO succession_relation_member VALUES(1990,8536,1001);
|
||||
INSERT INTO succession_relation_member VALUES(2198,8640,1001);
|
||||
INSERT INTO succession_relation_member VALUES(31,104,1002);
|
||||
INSERT INTO succession_relation_member VALUES(81,202,1002);
|
||||
INSERT INTO succession_relation_member VALUES(124,301,1002);
|
||||
INSERT INTO succession_relation_member VALUES(174,402,1002);
|
||||
INSERT INTO succession_relation_member VALUES(207,2001,1002);
|
||||
INSERT INTO succession_relation_member VALUES(242,2601,1002);
|
||||
INSERT INTO succession_relation_member VALUES(302,7000,1002);
|
||||
INSERT INTO succession_relation_member VALUES(304,7001,1002);
|
||||
INSERT INTO succession_relation_member VALUES(306,7002,1002);
|
||||
INSERT INTO succession_relation_member VALUES(329,7013,1002);
|
||||
INSERT INTO succession_relation_member VALUES(333,7015,1002);
|
||||
INSERT INTO succession_relation_member VALUES(392,2810,1002);
|
||||
INSERT INTO succession_relation_member VALUES(416,2901,1002);
|
||||
INSERT INTO succession_relation_member VALUES(510,3003,1002);
|
||||
INSERT INTO succession_relation_member VALUES(571,3101,1002);
|
||||
INSERT INTO succession_relation_member VALUES(648,2512,1002);
|
||||
INSERT INTO succession_relation_member VALUES(826,3205,1002);
|
||||
INSERT INTO succession_relation_member VALUES(867,8017,1002);
|
||||
INSERT INTO succession_relation_member VALUES(869,8018,1002);
|
||||
INSERT INTO succession_relation_member VALUES(871,8019,1002);
|
||||
INSERT INTO succession_relation_member VALUES(873,8020,1002);
|
||||
INSERT INTO succession_relation_member VALUES(875,8021,1002);
|
||||
INSERT INTO succession_relation_member VALUES(877,8022,1002);
|
||||
INSERT INTO succession_relation_member VALUES(879,8023,1002);
|
||||
INSERT INTO succession_relation_member VALUES(881,8024,1002);
|
||||
INSERT INTO succession_relation_member VALUES(883,8025,1002);
|
||||
INSERT INTO succession_relation_member VALUES(885,8026,1002);
|
||||
INSERT INTO succession_relation_member VALUES(887,8027,1002);
|
||||
INSERT INTO succession_relation_member VALUES(889,8028,1002);
|
||||
INSERT INTO succession_relation_member VALUES(891,8029,1002);
|
||||
INSERT INTO succession_relation_member VALUES(893,8030,1002);
|
||||
INSERT INTO succession_relation_member VALUES(895,8031,1002);
|
||||
INSERT INTO succession_relation_member VALUES(897,8032,1002);
|
||||
INSERT INTO succession_relation_member VALUES(1704,2406,1002);
|
||||
INSERT INTO succession_relation_member VALUES(1716,2603,1002);
|
||||
INSERT INTO succession_relation_member VALUES(1804,8444,1002);
|
||||
INSERT INTO succession_relation_member VALUES(1878,8480,1002);
|
||||
INSERT INTO succession_relation_member VALUES(1942,8512,1002);
|
||||
INSERT INTO succession_relation_member VALUES(1992,8537,1002);
|
||||
INSERT INTO succession_relation_member VALUES(2200,8641,1002);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS 'succession_relation' ('relation_type' INTEGER NOT NULL, 'relation_point' INTEGER NOT NULL, PRIMARY KEY('relation_type'));
|
||||
-- SELECT * FROM succession_relation WHERE relation_type IN (SELECT relation_type FROM succession_relation_member WHERE chara_id IN (1001, 1002, 1078, 2001, 9001));
|
||||
INSERT INTO succession_relation VALUES(103,2);
|
||||
INSERT INTO succession_relation VALUES(104,2);
|
||||
INSERT INTO succession_relation VALUES(202,2);
|
||||
INSERT INTO succession_relation VALUES(301,2);
|
||||
INSERT INTO succession_relation VALUES(401,2);
|
||||
INSERT INTO succession_relation VALUES(402,2);
|
||||
INSERT INTO succession_relation VALUES(502,2);
|
||||
INSERT INTO succession_relation VALUES(510,2);
|
||||
INSERT INTO succession_relation VALUES(2001,1);
|
||||
INSERT INTO succession_relation VALUES(2102,1);
|
||||
INSERT INTO succession_relation VALUES(2301,1);
|
||||
INSERT INTO succession_relation VALUES(2406,1);
|
||||
INSERT INTO succession_relation VALUES(2506,1);
|
||||
INSERT INTO succession_relation VALUES(2510,1);
|
||||
INSERT INTO succession_relation VALUES(2512,1);
|
||||
INSERT INTO succession_relation VALUES(2516,1);
|
||||
INSERT INTO succession_relation VALUES(2519,1);
|
||||
INSERT INTO succession_relation VALUES(2601,1);
|
||||
INSERT INTO succession_relation VALUES(2603,1);
|
||||
INSERT INTO succession_relation VALUES(2810,1);
|
||||
INSERT INTO succession_relation VALUES(2811,1);
|
||||
INSERT INTO succession_relation VALUES(2901,7);
|
||||
INSERT INTO succession_relation VALUES(2903,7);
|
||||
INSERT INTO succession_relation VALUES(3003,7);
|
||||
INSERT INTO succession_relation VALUES(3004,7);
|
||||
INSERT INTO succession_relation VALUES(3101,7);
|
||||
INSERT INTO succession_relation VALUES(3205,1);
|
||||
INSERT INTO succession_relation VALUES(7000,1);
|
||||
INSERT INTO succession_relation VALUES(7001,1);
|
||||
INSERT INTO succession_relation VALUES(7002,1);
|
||||
INSERT INTO succession_relation VALUES(7003,1);
|
||||
INSERT INTO succession_relation VALUES(7004,1);
|
||||
INSERT INTO succession_relation VALUES(7005,1);
|
||||
INSERT INTO succession_relation VALUES(7006,1);
|
||||
INSERT INTO succession_relation VALUES(7007,1);
|
||||
INSERT INTO succession_relation VALUES(7013,1);
|
||||
INSERT INTO succession_relation VALUES(7015,1);
|
||||
INSERT INTO succession_relation VALUES(8001,1);
|
||||
INSERT INTO succession_relation VALUES(8002,1);
|
||||
INSERT INTO succession_relation VALUES(8003,1);
|
||||
INSERT INTO succession_relation VALUES(8004,1);
|
||||
INSERT INTO succession_relation VALUES(8005,1);
|
||||
INSERT INTO succession_relation VALUES(8006,1);
|
||||
INSERT INTO succession_relation VALUES(8007,1);
|
||||
INSERT INTO succession_relation VALUES(8008,1);
|
||||
INSERT INTO succession_relation VALUES(8009,1);
|
||||
INSERT INTO succession_relation VALUES(8010,1);
|
||||
INSERT INTO succession_relation VALUES(8011,1);
|
||||
INSERT INTO succession_relation VALUES(8012,1);
|
||||
INSERT INTO succession_relation VALUES(8013,1);
|
||||
INSERT INTO succession_relation VALUES(8014,1);
|
||||
INSERT INTO succession_relation VALUES(8015,1);
|
||||
INSERT INTO succession_relation VALUES(8016,1);
|
||||
INSERT INTO succession_relation VALUES(8017,1);
|
||||
INSERT INTO succession_relation VALUES(8018,1);
|
||||
INSERT INTO succession_relation VALUES(8019,1);
|
||||
INSERT INTO succession_relation VALUES(8020,1);
|
||||
INSERT INTO succession_relation VALUES(8021,1);
|
||||
INSERT INTO succession_relation VALUES(8022,1);
|
||||
INSERT INTO succession_relation VALUES(8023,1);
|
||||
INSERT INTO succession_relation VALUES(8024,1);
|
||||
INSERT INTO succession_relation VALUES(8025,1);
|
||||
INSERT INTO succession_relation VALUES(8026,1);
|
||||
INSERT INTO succession_relation VALUES(8027,1);
|
||||
INSERT INTO succession_relation VALUES(8028,1);
|
||||
INSERT INTO succession_relation VALUES(8029,1);
|
||||
INSERT INTO succession_relation VALUES(8030,1);
|
||||
INSERT INTO succession_relation VALUES(8031,1);
|
||||
INSERT INTO succession_relation VALUES(8032,1);
|
||||
INSERT INTO succession_relation VALUES(8443,1);
|
||||
INSERT INTO succession_relation VALUES(8444,1);
|
||||
INSERT INTO succession_relation VALUES(8479,1);
|
||||
INSERT INTO succession_relation VALUES(8480,1);
|
||||
INSERT INTO succession_relation VALUES(8511,1);
|
||||
INSERT INTO succession_relation VALUES(8512,1);
|
||||
INSERT INTO succession_relation VALUES(8536,1);
|
||||
INSERT INTO succession_relation VALUES(8537,1);
|
||||
INSERT INTO succession_relation VALUES(8640,1);
|
||||
INSERT INTO succession_relation VALUES(8641,1);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS 'home_story_trigger' ('id' INTEGER NOT NULL, 'pos_id' INTEGER NOT NULL, 'home_event_type' INTEGER NOT NULL, 'num' INTEGER NOT NULL, 'story_id' INTEGER NOT NULL, 'chara_id_1' INTEGER NOT NULL, 'chara_id_2' INTEGER NOT NULL, 'chara_id_3' INTEGER NOT NULL, 'condition_type' INTEGER NOT NULL, 'gallery_chara_id' INTEGER NOT NULL, 'disp_order' INTEGER NOT NULL, PRIMARY KEY('id'), UNIQUE('gallery_chara_id','disp_order'));
|
||||
-- SELECT * FROM home_story_trigger WHERE gallery_chara_id IN (1001, 1002, 1078, 2001, 9001);
|
||||
INSERT INTO home_story_trigger VALUES(1,410,0,1,1001001,1001,0,0,0,1001,1);
|
||||
INSERT INTO home_story_trigger VALUES(2,510,0,1,1001002,1001,0,0,1,1001,2);
|
||||
INSERT INTO home_story_trigger VALUES(3,310,0,1,1001003,1001,0,0,1,1001,3);
|
||||
INSERT INTO home_story_trigger VALUES(76,120,0,2,1001001,1001,1002,0,2,1001,4);
|
||||
INSERT INTO home_story_trigger VALUES(77,520,0,2,1001002,1003,1001,0,3,1001,5);
|
||||
INSERT INTO home_story_trigger VALUES(126,430,0,3,1,1001,1014,1011,1,1001,6);
|
||||
INSERT INTO home_story_trigger VALUES(4,310,0,1,1002001,1002,0,0,0,1002,1);
|
||||
INSERT INTO home_story_trigger VALUES(5,210,0,1,1002002,1002,0,0,1,1002,2);
|
||||
INSERT INTO home_story_trigger VALUES(6,110,0,1,1002003,1002,0,0,1,1002,3);
|
||||
INSERT INTO home_story_trigger VALUES(78,520,0,2,1002001,1010,1002,0,3,1002,4);
|
||||
INSERT INTO home_story_trigger VALUES(79,220,0,2,1002002,1002,1018,0,2,1002,5);
|
||||
Vendored
+86
@@ -0,0 +1,86 @@
|
||||
CREATE TABLE IF NOT EXISTS 'text_data' ('id' INTEGER NOT NULL, 'category' INTEGER NOT NULL, 'index' INTEGER NOT NULL, 'text' TEXT NOT NULL, PRIMARY KEY('category','index'));
|
||||
-- SELECT * FROM text_data WHERE category = 33 AND "index" IN (1005, 1010, 1015, 1026, 1028, 1101, 2001, 2010, 2035, 3001, 4001, 4501) OR category = 111 AND "index" IN (SELECT id FROM single_mode_wins_saddle WHERE race_instance_id_1 IN (SELECT id FROM race_instance WHERE race_id IN (1005, 1010, 1015, 1026, 1028, 1101, 2001, 2010, 2035, 3001, 4001, 4501)) UNION SELECT id FROM single_mode_wins_saddle WHERE race_instance_id_2 IN (SELECT id FROM race_instance WHERE race_id IN (1005, 1010, 1015, 1026, 1028, 1101, 2001, 2010, 2035, 3001, 4001, 4501)) UNION SELECT id FROM single_mode_wins_saddle WHERE race_instance_id_3 IN (SELECT id FROM race_instance WHERE race_id IN (1005, 1010, 1015, 1026, 1028, 1101, 2001, 2010, 2035, 3001, 4001, 4501))) OR category IN (237, 119) AND "index" IN (1, 2, 4);
|
||||
INSERT INTO text_data VALUES(33,33,1005,'Satsuki Sho');
|
||||
INSERT INTO text_data VALUES(33,33,1010,'Tokyo Yushun (Japanese Derby)');
|
||||
INSERT INTO text_data VALUES(33,33,1015,'Kikuka Sho');
|
||||
INSERT INTO text_data VALUES(33,33,1026,'Kikuka Sho');
|
||||
INSERT INTO text_data VALUES(33,33,1028,'Satsuki Sho');
|
||||
INSERT INTO text_data VALUES(33,33,1101,'Teio Sho');
|
||||
INSERT INTO text_data VALUES(33,33,2001,'Nikkei Shinshun Hai');
|
||||
INSERT INTO text_data VALUES(33,33,2010,'Spring Stakes');
|
||||
INSERT INTO text_data VALUES(33,33,2035,'Spring Stakes');
|
||||
INSERT INTO text_data VALUES(33,33,3001,'Kyoto Kimpai');
|
||||
INSERT INTO text_data VALUES(33,33,4001,'Manyo Stakes');
|
||||
INSERT INTO text_data VALUES(33,33,4501,'Aster Sho');
|
||||
INSERT INTO text_data VALUES(111,111,1,'Classic Triple Crown');
|
||||
INSERT INTO text_data VALUES(111,111,12,'Japanese Derby');
|
||||
INSERT INTO text_data VALUES(111,111,16,'Kikuka Sho');
|
||||
INSERT INTO text_data VALUES(111,111,18,'Satsuki Sho');
|
||||
INSERT INTO text_data VALUES(111,111,36,'Teio Sho');
|
||||
INSERT INTO text_data VALUES(111,111,40,'Nikkei Shinshun Hai');
|
||||
INSERT INTO text_data VALUES(111,111,49,'Spring S.');
|
||||
INSERT INTO text_data VALUES(111,111,74,'Kyoto Kimpai');
|
||||
INSERT INTO text_data VALUES(111,111,144,'Classic Triple Crown');
|
||||
INSERT INTO text_data VALUES(111,111,148,'Kikuka Sho');
|
||||
INSERT INTO text_data VALUES(111,111,149,'Spring S.');
|
||||
INSERT INTO text_data VALUES(111,111,154,'Classic Triple Crown');
|
||||
INSERT INTO text_data VALUES(111,111,155,'Satsuki Sho');
|
||||
INSERT INTO text_data VALUES(119,119,1,'The Beginning: URA Finale');
|
||||
INSERT INTO text_data VALUES(119,119,2,'Unity Cup: Shine On, Team Spirit!');
|
||||
INSERT INTO text_data VALUES(119,119,4,'Trackblazer: Start of the Climax');
|
||||
INSERT INTO text_data VALUES(237,237,1,'URA Finale');
|
||||
INSERT INTO text_data VALUES(237,237,2,'Unity Cup');
|
||||
INSERT INTO text_data VALUES(237,237,4,'TS Climax');
|
||||
|
||||
CREATE TABLE IF NOT EXISTS 'race' ('id' INTEGER NOT NULL, 'group' INTEGER NOT NULL, 'grade' INTEGER NOT NULL, 'course_set' INTEGER NOT NULL, 'thumbnail_id' INTEGER NOT NULL, 'ff_cue_name' TEXT NOT NULL, 'ff_cuesheet_name' TEXT NOT NULL, 'ff_anim' INTEGER NOT NULL, 'ff_camera' INTEGER NOT NULL, 'ff_camera_sub' INTEGER NOT NULL, 'ff_sub' INTEGER NOT NULL, 'goal_gate' INTEGER NOT NULL, 'goal_flower' INTEGER NOT NULL, 'audience' INTEGER NOT NULL, 'entry_num' INTEGER NOT NULL, PRIMARY KEY('id'));
|
||||
-- SELECT * FROM race WHERE id IN (1005, 1010, 1015, 1026, 1028, 1101, 2001, 2010, 2035, 3001, 4001, 4501);
|
||||
INSERT INTO race VALUES(1005,1,100,10504,1005,'snd_mfx_1001_CL','snd_mfx_1001_CL',1005,101,0,0,1,1,0,18);
|
||||
INSERT INTO race VALUES(1010,1,100,10606,1010,'snd_mfx_1001_CL','snd_mfx_1001_CL',1010,101,0,0,5,5,0,18);
|
||||
INSERT INTO race VALUES(1015,1,100,10810,1015,'snd_mfx_1002_CL','snd_mfx_1002_CL',1015,102,0,0,3,3,0,18);
|
||||
INSERT INTO race VALUES(1026,1,100,10810,1015,'snd_mfx_1002_CL','snd_mfx_1002_CL',1015,102,0,0,3,3,0,17);
|
||||
INSERT INTO race VALUES(1028,1,100,10604,1028,'snd_mfx_1001_CL','snd_mfx_1001_CL',1028,101,0,0,9,0,0,18);
|
||||
INSERT INTO race VALUES(1101,1,100,11103,1101,'snd_mfx_1015_CL','snd_mfx_1015_CL',1101,313,0,0,1,0,0,16);
|
||||
INSERT INTO race VALUES(2001,1,200,10809,2001,'snd_mfx_1008_CL','snd_mfx_1008_CL',2001,208,0,0,0,0,0,18);
|
||||
INSERT INTO race VALUES(2010,1,200,10503,2010,'snd_mfx_1005_CL','snd_mfx_1005_CL',2010,205,0,0,0,0,0,16);
|
||||
INSERT INTO race VALUES(2035,1,200,10503,2010,'snd_mfx_1005_CL','snd_mfx_1005_CL',2010,205,0,0,0,0,0,5);
|
||||
INSERT INTO race VALUES(3001,1,300,10805,3001,'snd_mfx_1008_CL','snd_mfx_1008_CL',3001,208,0,0,0,0,0,18);
|
||||
INSERT INTO race VALUES(4001,1,400,10810,4001,'snd_mfx_1013_CL','snd_mfx_1013_CL',4001,313,0,0,0,0,0,18);
|
||||
INSERT INTO race VALUES(4501,1,700,10502,4501,'snd_mfx_1010_CL','snd_mfx_1010_CL',4501,310,0,0,0,0,0,16);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS 'race_instance' ('id' INTEGER NOT NULL, 'race_id' INTEGER NOT NULL, 'npc_group_id' INTEGER NOT NULL, 'date' INTEGER NOT NULL, 'time' INTEGER NOT NULL, 'clock_time' INTEGER NOT NULL, 'race_number' INTEGER NOT NULL, PRIMARY KEY('id'));
|
||||
-- SELECT * FROM race_instance WHERE race_id IN (1005, 1010, 1015, 1026, 1028, 1101, 2001, 2010, 2035, 3001, 4001, 4501);
|
||||
INSERT INTO race_instance VALUES(100501,1005,199,414,2,0,11);
|
||||
INSERT INTO race_instance VALUES(101001,1010,199,526,2,0,11);
|
||||
INSERT INTO race_instance VALUES(701301,1010,0,0,2,0,11);
|
||||
INSERT INTO race_instance VALUES(101501,1015,199,1020,2,0,11);
|
||||
INSERT INTO race_instance VALUES(102601,1026,199,1020,2,0,11);
|
||||
INSERT INTO race_instance VALUES(102801,1028,199,414,2,0,11);
|
||||
INSERT INTO race_instance VALUES(110101,1101,303,626,4,0,11);
|
||||
INSERT INTO race_instance VALUES(200101,2001,103,117,2,0,11);
|
||||
INSERT INTO race_instance VALUES(201001,2010,102,317,2,0,11);
|
||||
INSERT INTO race_instance VALUES(203501,2035,102,317,2,0,11);
|
||||
INSERT INTO race_instance VALUES(300101,3001,102,105,2,0,11);
|
||||
INSERT INTO race_instance VALUES(400101,4001,104,105,2,0,10);
|
||||
INSERT INTO race_instance VALUES(450101,4501,102,907,2,0,9);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS 'single_mode_wins_saddle' ('id' INTEGER NOT NULL, 'priority' INTEGER NOT NULL, 'group_id' INTEGER NOT NULL, 'condition' INTEGER NOT NULL, 'win_saddle_type' INTEGER NOT NULL, 'race_instance_id_1' INTEGER NOT NULL, 'race_instance_id_2' INTEGER NOT NULL, 'race_instance_id_3' INTEGER NOT NULL, 'race_instance_id_4' INTEGER NOT NULL, 'race_instance_id_5' INTEGER NOT NULL, 'race_instance_id_6' INTEGER NOT NULL, 'race_instance_id_7' INTEGER NOT NULL, 'race_instance_id_8' INTEGER NOT NULL, PRIMARY KEY('id'));
|
||||
-- SELECT * FROM single_mode_wins_saddle WHERE id IN (SELECT id FROM single_mode_wins_saddle WHERE race_instance_id_1 IN (SELECT id FROM race_instance WHERE race_id IN (1005, 1010, 1015, 1026, 1028, 1101, 2001, 2010, 2035, 3001, 4001, 4501)) UNION SELECT id FROM single_mode_wins_saddle WHERE race_instance_id_2 IN (SELECT id FROM race_instance WHERE race_id IN (1005, 1010, 1015, 1026, 1028, 1101, 2001, 2010, 2035, 3001, 4001, 4501)) UNION SELECT id FROM single_mode_wins_saddle WHERE race_instance_id_3 IN (SELECT id FROM race_instance WHERE race_id IN (1005, 1010, 1015, 1026, 1028, 1101, 2001, 2010, 2035, 3001, 4001, 4501)));
|
||||
INSERT INTO single_mode_wins_saddle VALUES(1,1,1,0,0,100501,101001,101501,0,0,0,0,0);
|
||||
INSERT INTO single_mode_wins_saddle VALUES(12,15,22,0,3,101001,0,0,0,0,0,0,0);
|
||||
INSERT INTO single_mode_wins_saddle VALUES(16,20,28,0,3,101501,0,0,0,0,0,0,0);
|
||||
INSERT INTO single_mode_wins_saddle VALUES(18,23,17,0,3,100501,0,0,0,0,0,0,0);
|
||||
INSERT INTO single_mode_wins_saddle VALUES(36,41,39,0,3,110101,0,0,0,0,0,0,0);
|
||||
INSERT INTO single_mode_wins_saddle VALUES(40,45,45,0,2,200101,0,0,0,0,0,0,0);
|
||||
INSERT INTO single_mode_wins_saddle VALUES(49,54,54,0,2,201001,0,0,0,0,0,0,0);
|
||||
INSERT INTO single_mode_wins_saddle VALUES(74,80,80,0,1,300101,0,0,0,0,0,0,0);
|
||||
INSERT INTO single_mode_wins_saddle VALUES(144,2,1,0,0,100501,101001,102601,0,0,0,0,0);
|
||||
INSERT INTO single_mode_wins_saddle VALUES(148,21,28,0,3,102601,0,0,0,0,0,0,0);
|
||||
INSERT INTO single_mode_wins_saddle VALUES(149,55,54,0,2,203501,0,0,0,0,0,0,0);
|
||||
INSERT INTO single_mode_wins_saddle VALUES(154,2,1,0,0,102801,101001,101501,0,0,0,0,0);
|
||||
INSERT INTO single_mode_wins_saddle VALUES(155,23,17,0,3,102801,0,0,0,0,0,0,0);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS 'single_mode_scenario' ('id' INTEGER NOT NULL, 'sort_id' INTEGER NOT NULL, 'scenario_image_id' INTEGER NOT NULL, 'prologue_id' INTEGER NOT NULL, 'turn_set_id' INTEGER NOT NULL, 'hint_rate' INTEGER NOT NULL, 'start_date' INTEGER NOT NULL, 'end_date' INTEGER NOT NULL, 'bg_id' INTEGER NOT NULL, 'bg_sub_id' INTEGER NOT NULL, 'bg_offset_x' INTEGER NOT NULL, 'sec_bg_id' INTEGER NOT NULL, 'sec_bg_sub_id' INTEGER NOT NULL, 'label_font_color' TEXT NOT NULL, 'label_bg_color' TEXT NOT NULL, 'chara_program_change_flag' INTEGER NOT NULL, PRIMARY KEY('id'));
|
||||
-- SELECT * FROM single_mode_scenario WHERE id IN (1, 2, 4);
|
||||
INSERT INTO single_mode_scenario VALUES(1,1,1,80000001,1,0,1577836800,2524608000,5,5110,375,37,110,'FFFFFF','9CD127',0);
|
||||
INSERT INTO single_mode_scenario VALUES(2,2,2,80000002,2,0,1762466400,2524608000,124,2111,0,79,110,'FFFFFF','18B1FF',0);
|
||||
INSERT INTO single_mode_scenario VALUES(4,3,4,80000004,4,0,1773352800,2524608000,24,110,0,56,111,'FFFFFF','EABA00',1);
|
||||
Vendored
+164
@@ -0,0 +1,164 @@
|
||||
CREATE TABLE IF NOT EXISTS 'text_data' ('id' INTEGER NOT NULL, 'category' INTEGER NOT NULL, 'index' INTEGER NOT NULL, 'text' TEXT NOT NULL, PRIMARY KEY('category','index'));
|
||||
-- SELECT * FROM text_data WHERE category IN (47, 48) AND "index" IN (10351, 100011, 100351, 110241, 200011, 200012, 200013, 200014, 200021, 200022, 200023, 200361, 200362, 200831, 201801, 300011, 900011, 900351, 910241) OR category = 4 AND "index" IN (SELECT card_id FROM card_rarity_data WHERE skill_set IN (SELECT id FROM skill_set WHERE skill_id1 IN (10351, 100011, 100351, 110241, 200011, 200012, 200013, 200014, 200021, 200022, 200023, 200361, 200362, 200831, 201801, 300011, 900011, 900351, 910241)));
|
||||
INSERT INTO text_data VALUES(47,47,10351,'V Is for Victory!');
|
||||
INSERT INTO text_data VALUES(47,47,100011,'Shooting Star');
|
||||
INSERT INTO text_data VALUES(47,47,100351,'Our Ticket to Win!');
|
||||
INSERT INTO text_data VALUES(47,47,110241,'Flowery☆Maneuver');
|
||||
INSERT INTO text_data VALUES(47,47,200011,'Right-Handed ◎');
|
||||
INSERT INTO text_data VALUES(47,47,200012,'Right-Handed ○');
|
||||
INSERT INTO text_data VALUES(47,47,200013,'Right-Handed ×');
|
||||
INSERT INTO text_data VALUES(47,47,200014,'Right-Handed Demon');
|
||||
INSERT INTO text_data VALUES(47,47,200021,'Left-Handed ◎');
|
||||
INSERT INTO text_data VALUES(47,47,200022,'Left-Handed ○');
|
||||
INSERT INTO text_data VALUES(47,47,200023,'Left-Handed ×');
|
||||
INSERT INTO text_data VALUES(47,47,200361,'Beeline Burst');
|
||||
INSERT INTO text_data VALUES(47,47,200362,'Straightaway Adept');
|
||||
INSERT INTO text_data VALUES(47,47,200831,'Subdued Front Runners');
|
||||
INSERT INTO text_data VALUES(47,47,201801,'♡ 3D Nail Art');
|
||||
INSERT INTO text_data VALUES(47,47,300011,'Unquenched Thirst');
|
||||
INSERT INTO text_data VALUES(47,47,900011,'Shooting Star');
|
||||
INSERT INTO text_data VALUES(47,47,900351,'Our Ticket to Win!');
|
||||
INSERT INTO text_data VALUES(47,47,910241,'Flowery☆Maneuver');
|
||||
INSERT INTO text_data VALUES(48,48,10351,'Moderately increase velocity with winning ambition when positioned toward the front on the final straight after engaging in a challenge on the final corner or later.');
|
||||
INSERT INTO text_data VALUES(48,48,100011,'Ride the momentum to increase velocity and very slightly increase acceleration after passing another runner toward the front late-race.');
|
||||
INSERT INTO text_data VALUES(48,48,100351,'Increase velocity with winning ambition when positioned toward the front on the final straight after engaging in a challenge on the final corner or later.');
|
||||
INSERT INTO text_data VALUES(48,48,110241,'Increase velocity when passing another runner toward the front on the final corner. If passing toward the back, increase acceleration instead.');
|
||||
INSERT INTO text_data VALUES(48,48,200011,'Increase performance on right-handed tracks.');
|
||||
INSERT INTO text_data VALUES(48,48,200012,'Moderately increase performance on right-handed tracks.');
|
||||
INSERT INTO text_data VALUES(48,48,200013,'Moderately decrease performance on right-handed tracks.');
|
||||
INSERT INTO text_data VALUES(48,48,200014,'Increase proficiency in right-handed tracks, increasing Speed and Power.');
|
||||
INSERT INTO text_data VALUES(48,48,200021,'Increase performance on left-handed tracks.');
|
||||
INSERT INTO text_data VALUES(48,48,200022,'Moderately increase performance on left-handed tracks.');
|
||||
INSERT INTO text_data VALUES(48,48,200023,'Moderately decrease performance on left-handed tracks.');
|
||||
INSERT INTO text_data VALUES(48,48,200361,'Increase velocity on a straight.');
|
||||
INSERT INTO text_data VALUES(48,48,200362,'Slightly increase velocity on a straight.');
|
||||
INSERT INTO text_data VALUES(48,48,200831,'Slightly increase fatigue for front runners early-race.');
|
||||
INSERT INTO text_data VALUES(48,48,201801,'Moderately decrease performance on firm ground.');
|
||||
INSERT INTO text_data VALUES(48,48,300011,'Moderately increase performance with the desire to race.');
|
||||
INSERT INTO text_data VALUES(48,48,900011,'Slightly increase velocity and very minimally increase acceleration after passing another runner toward the front late-race.');
|
||||
INSERT INTO text_data VALUES(48,48,900351,'Slightly increase velocity when positioned toward the front on the final straight after engaging in a challenge on the final corner or later.');
|
||||
INSERT INTO text_data VALUES(48,48,910241,'Slightly increase velocity when passing another runner toward the front on the final corner. If passing toward the back, slightly increase acceleration instead.');
|
||||
INSERT INTO text_data VALUES(4,4,100101,'[Special Dreamer] Special Week');
|
||||
INSERT INTO text_data VALUES(4,4,102402,'[Sunlight Bouquet] Mayano Top Gun');
|
||||
INSERT INTO text_data VALUES(4,4,103501,'[Get to Winning!] Winning Ticket');
|
||||
|
||||
CREATE TABLE IF NOT EXISTS 'skill_data' ('id' INTEGER NOT NULL, 'rarity' INTEGER NOT NULL, 'group_id' INTEGER NOT NULL, 'group_rate' INTEGER NOT NULL, 'filter_switch' INTEGER NOT NULL, 'grade_value' INTEGER NOT NULL, 'skill_category' INTEGER NOT NULL, 'tag_id' TEXT NOT NULL, 'unique_skill_id_1' INTEGER NOT NULL, 'unique_skill_id_2' INTEGER NOT NULL, 'exp_type' INTEGER NOT NULL, 'potential_per_default' INTEGER NOT NULL, 'activate_lot' INTEGER NOT NULL, 'precondition_1' TEXT NOT NULL, 'condition_1' TEXT NOT NULL, 'float_ability_time_1' INTEGER NOT NULL, 'ability_time_usage_1' INTEGER NOT NULL, 'float_cooldown_time_1' INTEGER NOT NULL, 'ability_type_1_1' INTEGER NOT NULL, 'ability_value_usage_1_1' INTEGER NOT NULL, 'ability_value_level_usage_1_1' INTEGER NOT NULL, 'float_ability_value_1_1' INTEGER NOT NULL, 'target_type_1_1' INTEGER NOT NULL, 'target_value_1_1' INTEGER NOT NULL, 'ability_type_1_2' INTEGER NOT NULL, 'ability_value_usage_1_2' INTEGER NOT NULL, 'ability_value_level_usage_1_2' INTEGER NOT NULL, 'float_ability_value_1_2' INTEGER NOT NULL, 'target_type_1_2' INTEGER NOT NULL, 'target_value_1_2' INTEGER NOT NULL, 'ability_type_1_3' INTEGER NOT NULL, 'ability_value_usage_1_3' INTEGER NOT NULL, 'ability_value_level_usage_1_3' INTEGER NOT NULL, 'float_ability_value_1_3' INTEGER NOT NULL, 'target_type_1_3' INTEGER NOT NULL, 'target_value_1_3' INTEGER NOT NULL, 'precondition_2' TEXT NOT NULL, 'condition_2' TEXT NOT NULL, 'float_ability_time_2' INTEGER NOT NULL, 'ability_time_usage_2' INTEGER NOT NULL, 'float_cooldown_time_2' INTEGER NOT NULL, 'ability_type_2_1' INTEGER NOT NULL, 'ability_value_usage_2_1' INTEGER NOT NULL, 'ability_value_level_usage_2_1' INTEGER NOT NULL, 'float_ability_value_2_1' INTEGER NOT NULL, 'target_type_2_1' INTEGER NOT NULL, 'target_value_2_1' INTEGER NOT NULL, 'ability_type_2_2' INTEGER NOT NULL, 'ability_value_usage_2_2' INTEGER NOT NULL, 'ability_value_level_usage_2_2' INTEGER NOT NULL, 'float_ability_value_2_2' INTEGER NOT NULL, 'target_type_2_2' INTEGER NOT NULL, 'target_value_2_2' INTEGER NOT NULL, 'ability_type_2_3' INTEGER NOT NULL, 'ability_value_usage_2_3' INTEGER NOT NULL, 'ability_value_level_usage_2_3' INTEGER NOT NULL, 'float_ability_value_2_3' INTEGER NOT NULL, 'target_type_2_3' INTEGER NOT NULL, 'target_value_2_3' INTEGER NOT NULL, 'popularity_add_param_1' INTEGER NOT NULL, 'popularity_add_value_1' INTEGER NOT NULL, 'popularity_add_param_2' INTEGER NOT NULL, 'popularity_add_value_2' INTEGER NOT NULL, 'disp_order' INTEGER NOT NULL, 'icon_id' INTEGER NOT NULL, 'plate_type' INTEGER NOT NULL, 'disable_singlemode' INTEGER NOT NULL, 'disable_count_condition' INTEGER NOT NULL, 'is_general_skill' INTEGER NOT NULL, 'start_date' INTEGER NOT NULL, 'end_date' INTEGER NOT NULL, PRIMARY KEY('id'));
|
||||
-- SELECT * FROM skill_data WHERE id IN (10351, 100011, 100351, 110241, 200011, 200012, 200013, 200014, 200021, 200022, 200023, 200361, 200362, 200831, 201801, 300011, 900011, 900351, 910241);
|
||||
INSERT INTO skill_data VALUES(10351,3,1035,1,0,240,5,'401',0,0,1,0,0,'is_finalcorner==1&blocked_side_continuetime>=2','is_finalcorner==1&corner==0&order<=5',50000,1,5000000,27,1,1,2500,1,0,0,1,1,0,0,0,0,1,1,0,0,0,'','',0,1,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,1,30,0,0,10,20013,0,1,0,0,1483228800,2524608000);
|
||||
INSERT INTO skill_data VALUES(100011,5,10001,1,0,340,5,'401/403',0,0,1,0,0,'','phase>=2&order>=1&order_rate<=50&change_order_onetime<0',50000,1,5000000,27,1,1,3500,1,0,31,1,1,1000,1,0,0,1,1,0,0,0,'','',0,1,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,1,60,0,0,10,20013,0,1,0,0,1483228800,2524608000);
|
||||
INSERT INTO skill_data VALUES(100351,4,10035,1,0,340,5,'401',0,0,1,0,0,'is_finalcorner==1&blocked_side_continuetime>=2','is_finalcorner==1&corner==0&order<=5',50000,1,5000000,27,1,1,3500,1,0,0,1,1,0,0,0,0,1,1,0,0,0,'','',0,1,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,1,60,0,0,10,20013,0,1,0,0,1483228800,2524608000);
|
||||
INSERT INTO skill_data VALUES(110241,5,11024,1,0,340,5,'401/403',0,0,1,0,0,'','is_finalcorner==1&corner!=0&order_rate<=40&change_order_onetime<0',50000,1,5000000,27,1,1,3500,1,0,0,1,1,0,0,0,0,1,1,0,0,0,'','is_finalcorner==1&corner!=0&order_rate>=50&order_rate<=80&change_order_onetime<0',40000,1,5000000,31,1,1,4000,1,0,0,1,1,0,0,0,0,1,1,0,0,0,1,30,3,30,10,20013,0,1,0,0,1483228800,2524608000);
|
||||
INSERT INTO skill_data VALUES(200011,1,20001,2,0,174,0,'401',0,0,0,10,0,'','rotation==1',-1,1,0,1,1,1,600000,1,0,0,1,1,0,0,0,0,1,1,0,0,0,'','',0,1,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,1,45,0,0,1005,10011,0,1,0,1,1483228800,2524608000);
|
||||
INSERT INTO skill_data VALUES(200012,1,20001,1,0,129,0,'401',0,0,0,10,0,'','rotation==1',-1,1,0,1,1,1,400000,1,0,0,1,1,0,0,0,0,1,1,0,0,0,'','',0,1,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,1,30,0,0,1010,10011,0,0,0,1,1483228800,2524608000);
|
||||
INSERT INTO skill_data VALUES(200013,1,20001,-1,0,-129,0,'401',0,0,0,10,0,'','rotation==1',-1,1,0,1,1,1,-400000,1,0,0,1,1,0,0,0,0,1,1,0,0,0,'','',0,1,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,1,-30,0,0,1020,10014,0,1,0,1,1483228800,2524608000);
|
||||
INSERT INTO skill_data VALUES(200014,2,20001,3,0,461,0,'401/403',0,0,0,10,0,'','rotation==1',-1,1,0,1,1,1,600000,1,0,3,1,1,600000,1,0,0,1,1,0,0,0,'','',0,1,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,1,30,3,30,1000,10012,0,1,0,1,1483228800,2524608000);
|
||||
INSERT INTO skill_data VALUES(200021,1,20002,2,0,174,0,'401',0,0,0,10,0,'','rotation==2',-1,1,0,1,1,1,600000,1,0,0,1,1,0,0,0,0,1,1,0,0,0,'','',0,1,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,1,45,0,0,1030,10011,0,1,0,1,1483228800,2524608000);
|
||||
INSERT INTO skill_data VALUES(200022,1,20002,1,0,129,0,'401',0,0,0,10,0,'','rotation==2',-1,1,0,1,1,1,400000,1,0,0,1,1,0,0,0,0,1,1,0,0,0,'','',0,1,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,1,30,0,0,1040,10011,0,0,0,1,1483228800,2524608000);
|
||||
INSERT INTO skill_data VALUES(200023,1,20002,-1,0,-129,0,'401',0,0,0,10,0,'','rotation==2',-1,1,0,1,1,1,-400000,1,0,0,1,1,0,0,0,0,1,1,0,0,0,'','',0,1,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,1,-30,0,0,1050,10014,0,1,0,1,1483228800,2524608000);
|
||||
INSERT INTO skill_data VALUES(200361,2,20036,2,0,508,4,'401',0,0,0,10,1,'','straight_random==1',24000,1,300000,27,1,1,3500,1,0,0,1,1,0,0,0,0,1,1,0,0,0,'','',0,1,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,1,60,0,0,1980,20012,0,1,0,1,1483228800,2524608000);
|
||||
INSERT INTO skill_data VALUES(200362,1,20036,1,0,217,4,'401',0,0,0,10,1,'','straight_random==1',24000,1,300000,27,1,1,1500,1,0,0,1,1,0,0,0,0,1,1,0,0,0,'','',0,1,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,1,20,0,0,1990,20011,0,0,0,1,1483228800,2524608000);
|
||||
INSERT INTO skill_data VALUES(200831,1,20083,1,0,217,1,'301/406',0,0,0,10,1,'','running_style_count_nige_otherself>=1&phase_random==0&accumulatetime>=5',0,1,5000000,9,1,1,-100,18,1,0,1,1,0,0,0,0,1,1,0,0,0,'','',0,1,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,2,10,5,10,2820,30051,0,0,0,1,1483228800,2524608000);
|
||||
INSERT INTO skill_data VALUES(201801,1,20180,-1,0,-129,0,'401',0,0,0,10,0,'','ground_condition==1',-1,1,0,1,1,1,-400000,1,0,0,1,1,0,0,0,0,1,1,0,0,0,'','',0,1,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,1,-30,0,0,20,10014,0,1,0,1,1483228800,2524608000);
|
||||
INSERT INTO skill_data VALUES(300011,1,30001,1,0,0,0,'402',0,0,0,0,0,'','track_id==10008',-1,1,0,2,1,1,400000,1,0,0,1,1,0,0,0,0,1,1,0,0,0,'','',0,1,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,2,30,0,0,70000,10021,1,1,0,0,1483228800,2524608000);
|
||||
INSERT INTO skill_data VALUES(900011,1,90001,2,0,180,5,'401/403',100011,0,0,0,1,'','phase>=2&order>=1&order_rate<=50&change_order_onetime<0',30000,1,5000000,27,1,1,1500,1,0,31,1,1,500,1,0,0,1,1,0,0,0,'','',0,1,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,1,15,0,0,30,20011,0,1,0,1,1483228800,2524608000);
|
||||
INSERT INTO skill_data VALUES(900351,1,90035,2,0,180,5,'401',100351,10351,0,0,1,'is_finalcorner==1&blocked_side_continuetime>=2','is_finalcorner==1&corner==0&order<=5',30000,1,5000000,27,1,1,1500,1,0,0,1,1,0,0,0,0,1,1,0,0,0,'','',0,1,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,1,15,0,0,30,20011,0,1,0,1,1483228800,2524608000);
|
||||
INSERT INTO skill_data VALUES(910241,1,91024,2,0,180,5,'401/403',110241,0,0,0,1,'','is_finalcorner==1&corner!=0&order_rate<=40&change_order_onetime<0',30000,1,5000000,27,1,1,1500,1,0,0,1,1,0,0,0,0,1,1,0,0,0,'','is_finalcorner==1&corner!=0&order_rate>=50&order_rate<=80&change_order_onetime<0',24000,1,5000000,31,1,1,2000,1,0,0,1,1,0,0,0,0,1,1,0,0,0,1,7,3,7,30,20011,0,1,0,1,1483228800,2524608000);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS 'single_mode_skill_need_point' ('id' INTEGER NOT NULL, 'need_skill_point' INTEGER NOT NULL, 'status_type' INTEGER NOT NULL, 'status_value' INTEGER NOT NULL, 'solvable_type' INTEGER NOT NULL, PRIMARY KEY('id'));
|
||||
-- SELECT * FROM single_mode_skill_need_point WHERE id IN (10351, 100011, 100351, 110241, 200011, 200012, 200013, 200014, 200021, 200022, 200023, 200361, 200362, 200831, 201801, 300011, 900011, 900351, 910241);
|
||||
INSERT INTO single_mode_skill_need_point VALUES(200011,110,0,0,0);
|
||||
INSERT INTO single_mode_skill_need_point VALUES(200012,90,0,0,0);
|
||||
INSERT INTO single_mode_skill_need_point VALUES(200013,50,0,0,0);
|
||||
INSERT INTO single_mode_skill_need_point VALUES(200014,130,0,0,0);
|
||||
INSERT INTO single_mode_skill_need_point VALUES(200021,110,0,0,0);
|
||||
INSERT INTO single_mode_skill_need_point VALUES(200022,90,0,0,0);
|
||||
INSERT INTO single_mode_skill_need_point VALUES(200023,50,0,0,0);
|
||||
INSERT INTO single_mode_skill_need_point VALUES(200361,170,0,0,0);
|
||||
INSERT INTO single_mode_skill_need_point VALUES(200362,170,0,0,0);
|
||||
INSERT INTO single_mode_skill_need_point VALUES(200831,130,0,0,0);
|
||||
INSERT INTO single_mode_skill_need_point VALUES(201801,50,0,0,0);
|
||||
INSERT INTO single_mode_skill_need_point VALUES(900011,200,0,0,0);
|
||||
INSERT INTO single_mode_skill_need_point VALUES(900351,200,0,0,0);
|
||||
INSERT INTO single_mode_skill_need_point VALUES(910241,200,0,0,0);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS 'card_data' ('id' INTEGER NOT NULL, 'chara_id' INTEGER NOT NULL, 'default_rarity' INTEGER NOT NULL, 'limited_chara' INTEGER NOT NULL, 'available_skill_set_id' INTEGER NOT NULL, 'talent_speed' INTEGER NOT NULL, 'talent_stamina' INTEGER NOT NULL, 'talent_pow' INTEGER NOT NULL, 'talent_guts' INTEGER NOT NULL, 'talent_wiz' INTEGER NOT NULL, 'talent_group_id' INTEGER NOT NULL, 'bg_id' INTEGER NOT NULL, 'get_piece_id' INTEGER NOT NULL, 'running_style' INTEGER NOT NULL, PRIMARY KEY('id'));
|
||||
-- SELECT * FROM card_data WHERE id IN (SELECT card_id FROM card_rarity_data WHERE skill_set IN (SELECT id FROM skill_set WHERE skill_id1 IN (10351, 100011, 100351, 110241, 200011, 200012, 200013, 200014, 200021, 200022, 200023, 200361, 200362, 200831, 201801, 300011, 900011, 900351, 910241)));
|
||||
INSERT INTO card_data VALUES(100101,1001,3,0,100101,0,20,0,0,10,100101,8,100101,3);
|
||||
INSERT INTO card_data VALUES(102402,1024,3,0,102402,10,10,0,0,10,102402,291,102402,2);
|
||||
INSERT INTO card_data VALUES(103501,1035,1,0,103501,0,10,20,0,0,103501,8,103501,3);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS 'card_rarity_data' ('id' INTEGER NOT NULL, 'card_id' INTEGER NOT NULL, 'rarity' INTEGER NOT NULL, 'race_dress_id' INTEGER NOT NULL, 'skill_set' INTEGER NOT NULL, 'speed' INTEGER NOT NULL, 'stamina' INTEGER NOT NULL, 'pow' INTEGER NOT NULL, 'guts' INTEGER NOT NULL, 'wiz' INTEGER NOT NULL, 'max_speed' INTEGER NOT NULL, 'max_stamina' INTEGER NOT NULL, 'max_pow' INTEGER NOT NULL, 'max_guts' INTEGER NOT NULL, 'max_wiz' INTEGER NOT NULL, 'proper_distance_short' INTEGER NOT NULL, 'proper_distance_mile' INTEGER NOT NULL, 'proper_distance_middle' INTEGER NOT NULL, 'proper_distance_long' INTEGER NOT NULL, 'proper_running_style_nige' INTEGER NOT NULL, 'proper_running_style_senko' INTEGER NOT NULL, 'proper_running_style_sashi' INTEGER NOT NULL, 'proper_running_style_oikomi' INTEGER NOT NULL, 'proper_ground_turf' INTEGER NOT NULL, 'proper_ground_dirt' INTEGER NOT NULL, 'get_dress_id_1' INTEGER NOT NULL, 'get_dress_id_2' INTEGER NOT NULL, PRIMARY KEY('id'));
|
||||
-- SELECT * FROM card_rarity_data WHERE skill_set IN (SELECT id FROM skill_set WHERE skill_id1 IN (10351, 100011, 100351, 110241, 200011, 200012, 200013, 200014, 200021, 200022, 200023, 200361, 200362, 200831, 201801, 300011, 900011, 900351, 910241));
|
||||
INSERT INTO card_rarity_data VALUES(10010103,100101,3,100101,10010103,83,88,98,90,91,1200,1200,1200,1200,1200,2,5,7,7,1,7,7,5,7,1,101,100101);
|
||||
INSERT INTO card_rarity_data VALUES(10010104,100101,4,100101,10010104,92,98,109,100,101,1200,1200,1200,1200,1200,2,5,7,7,1,7,7,5,7,1,101,100101);
|
||||
INSERT INTO card_rarity_data VALUES(10010105,100101,5,100101,10010105,102,108,120,110,110,1200,1200,1200,1200,1200,2,5,7,7,1,7,7,5,7,1,101,100101);
|
||||
INSERT INTO card_rarity_data VALUES(10240203,102402,3,102426,11240103,83,100,82,90,95,1200,1200,1200,1200,1200,4,4,7,7,7,7,6,6,7,3,101,102426);
|
||||
INSERT INTO card_rarity_data VALUES(10240204,102402,4,102426,11240104,92,112,91,100,105,1200,1200,1200,1200,1200,4,4,7,7,7,7,6,6,7,3,101,102426);
|
||||
INSERT INTO card_rarity_data VALUES(10240205,102402,5,102426,11240105,102,123,100,110,115,1200,1200,1200,1200,1200,4,4,7,7,7,7,6,6,7,3,101,102426);
|
||||
INSERT INTO card_rarity_data VALUES(10350101,103501,1,101,10350101,87,68,91,74,80,1200,1200,1200,1200,1200,1,2,7,6,1,6,7,1,7,1,101,0);
|
||||
INSERT INTO card_rarity_data VALUES(10350102,103501,2,101,10350102,93,72,97,78,85,1200,1200,1200,1200,1200,1,2,7,6,1,6,7,1,7,1,101,0);
|
||||
INSERT INTO card_rarity_data VALUES(10350103,103501,3,103501,10350103,98,76,102,83,91,1200,1200,1200,1200,1200,1,2,7,6,1,6,7,1,7,1,101,103501);
|
||||
INSERT INTO card_rarity_data VALUES(10350104,103501,4,103501,10350104,109,85,114,92,100,1200,1200,1200,1200,1200,1,2,7,6,1,6,7,1,7,1,101,103501);
|
||||
INSERT INTO card_rarity_data VALUES(10350105,103501,5,103501,10350105,120,93,125,101,111,1200,1200,1200,1200,1200,1,2,7,6,1,6,7,1,7,1,101,103501);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS 'skill_set' ('id' INTEGER NOT NULL, 'skill_id1' INTEGER NOT NULL, 'skill_level1' INTEGER NOT NULL, 'skill_id2' INTEGER NOT NULL, 'skill_level2' INTEGER NOT NULL, 'skill_id3' INTEGER NOT NULL, 'skill_level3' INTEGER NOT NULL, 'skill_id4' INTEGER NOT NULL, 'skill_level4' INTEGER NOT NULL, 'skill_id5' INTEGER NOT NULL, 'skill_level5' INTEGER NOT NULL, 'skill_id6' INTEGER NOT NULL, 'skill_level6' INTEGER NOT NULL, 'skill_id7' INTEGER NOT NULL, 'skill_level7' INTEGER NOT NULL, 'skill_id8' INTEGER NOT NULL, 'skill_level8' INTEGER NOT NULL, 'skill_id9' INTEGER NOT NULL, 'skill_level9' INTEGER NOT NULL, 'skill_id10' INTEGER NOT NULL, 'skill_level10' INTEGER NOT NULL, PRIMARY KEY('id'));
|
||||
-- SELECT * FROM skill_set WHERE skill_id1 IN (10351, 100011, 100351, 110241, 200011, 200012, 200013, 200014, 200021, 200022, 200023, 200361, 200362, 200831, 201801, 300011, 900011, 900351, 910241);
|
||||
INSERT INTO skill_set VALUES(8001,200012,1,200433,1,200532,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(8007,200022,1,200572,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(8008,200362,1,200562,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(8011,200012,1,200592,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(8016,200022,1,200472,1,200502,1,200632,1,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(8028,200012,1,200492,1,200572,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(8034,200022,1,200612,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(8037,200362,1,200632,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(8043,200012,1,200401,1,200532,1,200712,1,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(8053,200362,1,200502,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(8054,200022,1,200352,1,200612,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(8057,200012,1,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(8068,200022,1,200572,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(8072,200022,1,200612,1,200752,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(8078,200012,1,200401,1,200202,1,200622,1,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(8083,200022,1,200332,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(8101,200362,1,200352,1,200552,1,200682,1,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(8103,200012,1,200052,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(8107,200012,1,200372,1,200582,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(8114,200012,1,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(8117,200022,1,200332,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(8123,200362,1,200532,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(8124,200012,1,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(8133,200022,1,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(100013,100351,1,200591,1,201401,1,201392,1,201422,1,200492,1,200432,1,200612,1,200032,1,200732,1);
|
||||
INSERT INTO skill_set VALUES(100037,100351,1,201401,1,200612,1,200462,1,200732,1,200032,1,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(100046,100351,1,201401,1,200612,1,200462,1,200732,1,200032,1,201691,1,200441,1,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(400007,200012,1,200492,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(400012,200022,1,200612,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(400019,200012,1,200401,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(400028,200022,1,200352,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(400030,200012,1,200871,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(1100101,100011,1,200511,1,200612,1,200602,1,200032,1,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(1100102,100011,1,200511,1,200491,1,200602,1,200032,1,200132,1,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(1103401,200361,1,200461,1,202002,1,200172,1,200292,1,200752,1,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(1103501,100351,1,200282,1,200612,1,200462,1,200732,1,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(1106701,200361,1,201242,1,201262,1,201522,1,200352,1,200382,1,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(10010103,100011,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(10010104,100011,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(10010105,100011,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(10350101,10351,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(10350102,10351,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(10350103,100351,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(10350104,100351,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(10350105,100351,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(11240103,110241,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(11240104,110241,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(11240105,110241,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(32100101,100011,1,200511,1,200612,1,201402,1,200592,1,200342,1,200562,1,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(32100102,100011,1,200511,1,200611,1,201401,1,200592,1,200342,1,200332,1,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(32100106,100011,1,200511,1,201401,1,200592,1,200342,1,200332,1,200732,1,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(32101301,200361,1,200562,1,200462,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(32101304,200361,1,200462,1,200742,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(32103502,100351,1,200591,1,201401,1,201392,1,200732,1,201422,1,200492,1,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(32801301,200012,1,201352,1,200432,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(32802801,200362,1,200992,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(32804001,200362,1,200622,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(51100132,100011,1,200511,1,200612,1,200732,1,200592,1,0,0,0,0,0,0,0,0,0,0);
|
||||
INSERT INTO skill_set VALUES(51103531,100351,1,202081,1,201402,1,200612,1,200602,1,0,0,0,0,0,0,0,0,0,0);
|
||||
Vendored
+113
@@ -0,0 +1,113 @@
|
||||
CREATE TABLE IF NOT EXISTS 'text_data' ('id' INTEGER NOT NULL, 'category' INTEGER NOT NULL, 'index' INTEGER NOT NULL, 'text' TEXT NOT NULL, PRIMARY KEY('category','index'));
|
||||
-- SELECT * FROM text_data WHERE category IN (147, 172) AND "index" in (101, 102, 103, 201, 202, 203, 1101, 1102, 1103, 1000101, 1000102, 1000103, 2000101, 2000102, 2000103, 3000101, 3000102, 3000103, 10010101, 10010102, 10010103);
|
||||
INSERT INTO text_data VALUES(147,147,101,'Speed');
|
||||
INSERT INTO text_data VALUES(147,147,102,'Speed');
|
||||
INSERT INTO text_data VALUES(147,147,103,'Speed');
|
||||
INSERT INTO text_data VALUES(147,147,201,'Stamina');
|
||||
INSERT INTO text_data VALUES(147,147,202,'Stamina');
|
||||
INSERT INTO text_data VALUES(147,147,203,'Stamina');
|
||||
INSERT INTO text_data VALUES(147,147,1101,'Turf');
|
||||
INSERT INTO text_data VALUES(147,147,1102,'Turf');
|
||||
INSERT INTO text_data VALUES(147,147,1103,'Turf');
|
||||
INSERT INTO text_data VALUES(147,147,1000101,'February S.');
|
||||
INSERT INTO text_data VALUES(147,147,1000102,'February S.');
|
||||
INSERT INTO text_data VALUES(147,147,1000103,'February S.');
|
||||
INSERT INTO text_data VALUES(147,147,2000101,'Right-Handed ○');
|
||||
INSERT INTO text_data VALUES(147,147,2000102,'Right-Handed ○');
|
||||
INSERT INTO text_data VALUES(147,147,2000103,'Right-Handed ○');
|
||||
INSERT INTO text_data VALUES(147,147,3000101,'URA Finale');
|
||||
INSERT INTO text_data VALUES(147,147,3000102,'URA Finale');
|
||||
INSERT INTO text_data VALUES(147,147,3000103,'URA Finale');
|
||||
INSERT INTO text_data VALUES(147,147,10010101,'Shooting Star');
|
||||
INSERT INTO text_data VALUES(147,147,10010102,'Shooting Star');
|
||||
INSERT INTO text_data VALUES(147,147,10010103,'Shooting Star');
|
||||
INSERT INTO text_data VALUES(172,172,101,'A Spark that increases Speed.');
|
||||
INSERT INTO text_data VALUES(172,172,102,'A Spark that increases Speed.');
|
||||
INSERT INTO text_data VALUES(172,172,103,'A Spark that increases Speed.');
|
||||
INSERT INTO text_data VALUES(172,172,201,'A Spark that increases Stamina.');
|
||||
INSERT INTO text_data VALUES(172,172,202,'A Spark that increases Stamina.');
|
||||
INSERT INTO text_data VALUES(172,172,203,'A Spark that increases Stamina.');
|
||||
INSERT INTO text_data VALUES(172,172,1101,'A Spark that increases Turf Aptitude.');
|
||||
INSERT INTO text_data VALUES(172,172,1102,'A Spark that increases Turf Aptitude.');
|
||||
INSERT INTO text_data VALUES(172,172,1103,'A Spark that increases Turf Aptitude.');
|
||||
INSERT INTO text_data VALUES(172,172,1000101,'A Spark that increases Power and gives a skill hint for "Winter Runner ○".');
|
||||
INSERT INTO text_data VALUES(172,172,1000102,'A Spark that increases Power and gives a skill hint for "Winter Runner ○".');
|
||||
INSERT INTO text_data VALUES(172,172,1000103,'A Spark that increases Power and gives a skill hint for "Winter Runner ○".');
|
||||
INSERT INTO text_data VALUES(172,172,2000101,'A Spark that gives a skill hint for "Right-Handed ○".');
|
||||
INSERT INTO text_data VALUES(172,172,2000102,'A Spark that gives a skill hint for "Right-Handed ○".');
|
||||
INSERT INTO text_data VALUES(172,172,2000103,'A Spark that gives a skill hint for "Right-Handed ○".');
|
||||
INSERT INTO text_data VALUES(172,172,3000101,'A Spark that increases Speed and Stamina.');
|
||||
INSERT INTO text_data VALUES(172,172,3000102,'A Spark that increases Speed and Stamina.');
|
||||
INSERT INTO text_data VALUES(172,172,3000103,'A Spark that increases Speed and Stamina.');
|
||||
INSERT INTO text_data VALUES(172,172,10010101,'A Spark that gives a skill hint for "Shooting Star".');
|
||||
INSERT INTO text_data VALUES(172,172,10010102,'A Spark that gives a skill hint for "Shooting Star".');
|
||||
INSERT INTO text_data VALUES(172,172,10010103,'A Spark that gives a skill hint for "Shooting Star".');
|
||||
|
||||
CREATE TABLE IF NOT EXISTS 'succession_factor' ('factor_id' INTEGER NOT NULL, 'factor_group_id' INTEGER NOT NULL, 'rarity' INTEGER NOT NULL, 'grade' INTEGER NOT NULL, 'factor_type' INTEGER NOT NULL, 'effect_group_id' INTEGER NOT NULL, 'start_date' INTEGER NOT NULL, 'end_date' INTEGER NOT NULL, PRIMARY KEY('factor_id'));
|
||||
-- SELECT * FROM succession_factor WHERE factor_id IN (101, 102, 103, 201, 202, 203, 1101, 1102, 1103, 1000101, 1000102, 1000103, 2000101, 2000102, 2000103, 3000101, 3000102, 3000103, 10010101, 10010102, 10010103);
|
||||
INSERT INTO succession_factor VALUES(101,1,1,1,1,11,1483228800,2524608000);
|
||||
INSERT INTO succession_factor VALUES(102,1,2,1,1,12,1483228800,2524608000);
|
||||
INSERT INTO succession_factor VALUES(103,1,3,1,1,13,1483228800,2524608000);
|
||||
INSERT INTO succession_factor VALUES(201,2,1,1,1,11,1483228800,2524608000);
|
||||
INSERT INTO succession_factor VALUES(202,2,2,1,1,12,1483228800,2524608000);
|
||||
INSERT INTO succession_factor VALUES(203,2,3,1,1,13,1483228800,2524608000);
|
||||
INSERT INTO succession_factor VALUES(1101,11,1,1,2,21,1483228800,2524608000);
|
||||
INSERT INTO succession_factor VALUES(1102,11,2,1,2,22,1483228800,2524608000);
|
||||
INSERT INTO succession_factor VALUES(1103,11,3,1,2,23,1483228800,2524608000);
|
||||
INSERT INTO succession_factor VALUES(1000101,10001,1,1,5,51,1483228800,2524608000);
|
||||
INSERT INTO succession_factor VALUES(1000102,10001,2,1,5,52,1483228800,2524608000);
|
||||
INSERT INTO succession_factor VALUES(1000103,10001,3,1,5,53,1483228800,2524608000);
|
||||
INSERT INTO succession_factor VALUES(2000101,20001,1,1,4,41,1483228800,2524608000);
|
||||
INSERT INTO succession_factor VALUES(2000102,20001,2,1,4,42,1483228800,2524608000);
|
||||
INSERT INTO succession_factor VALUES(2000103,20001,3,1,4,43,1483228800,2524608000);
|
||||
INSERT INTO succession_factor VALUES(3000101,30001,1,1,6,51,1483228800,2524608000);
|
||||
INSERT INTO succession_factor VALUES(3000102,30001,2,1,6,52,1483228800,2524608000);
|
||||
INSERT INTO succession_factor VALUES(3000103,30001,3,1,6,53,1483228800,2524608000);
|
||||
INSERT INTO succession_factor VALUES(10010101,100101,1,2,3,31,1483228800,2524608000);
|
||||
INSERT INTO succession_factor VALUES(10010102,100101,2,2,3,32,1483228800,2524608000);
|
||||
INSERT INTO succession_factor VALUES(10010103,100101,3,2,3,33,1483228800,2524608000);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS 'succession_factor_effect' ('id' INTEGER NOT NULL, 'factor_group_id' INTEGER NOT NULL, 'effect_id' INTEGER NOT NULL, 'target_type' INTEGER NOT NULL, 'value_1' INTEGER NOT NULL, 'value_2' INTEGER NOT NULL, PRIMARY KEY('id'));
|
||||
-- SELECT * FROM succession_factor_effect WHERE factor_group_id IN (SELECT factor_group_id FROM succession_factor WHERE factor_id IN (101, 102, 103, 201, 202, 203, 1101, 1102, 1103, 1000101, 1000102, 1000103, 2000101, 2000102, 2000103, 3000101, 3000102, 3000103, 10010101, 10010102, 10010103));
|
||||
INSERT INTO succession_factor_effect VALUES(1,1,1,1,1,0);
|
||||
INSERT INTO succession_factor_effect VALUES(2,1,2,1,4,0);
|
||||
INSERT INTO succession_factor_effect VALUES(3,1,3,1,7,0);
|
||||
INSERT INTO succession_factor_effect VALUES(4,1,4,1,10,0);
|
||||
INSERT INTO succession_factor_effect VALUES(5,1,5,1,13,0);
|
||||
INSERT INTO succession_factor_effect VALUES(6,1,6,1,16,0);
|
||||
INSERT INTO succession_factor_effect VALUES(7,1,7,1,19,0);
|
||||
INSERT INTO succession_factor_effect VALUES(8,1,8,1,22,0);
|
||||
INSERT INTO succession_factor_effect VALUES(9,1,9,1,25,0);
|
||||
INSERT INTO succession_factor_effect VALUES(10,1,10,1,28,0);
|
||||
INSERT INTO succession_factor_effect VALUES(11,2,1,2,1,0);
|
||||
INSERT INTO succession_factor_effect VALUES(12,2,2,2,4,0);
|
||||
INSERT INTO succession_factor_effect VALUES(13,2,3,2,7,0);
|
||||
INSERT INTO succession_factor_effect VALUES(14,2,4,2,10,0);
|
||||
INSERT INTO succession_factor_effect VALUES(15,2,5,2,13,0);
|
||||
INSERT INTO succession_factor_effect VALUES(16,2,6,2,16,0);
|
||||
INSERT INTO succession_factor_effect VALUES(17,2,7,2,19,0);
|
||||
INSERT INTO succession_factor_effect VALUES(18,2,8,2,22,0);
|
||||
INSERT INTO succession_factor_effect VALUES(19,2,9,2,25,0);
|
||||
INSERT INTO succession_factor_effect VALUES(20,2,10,2,28,0);
|
||||
INSERT INTO succession_factor_effect VALUES(51,11,1,11,1,0);
|
||||
INSERT INTO succession_factor_effect VALUES(52,11,2,11,2,0);
|
||||
INSERT INTO succession_factor_effect VALUES(1144,10001,1,3,3,0);
|
||||
INSERT INTO succession_factor_effect VALUES(1145,10001,1,41,200202,1);
|
||||
INSERT INTO succession_factor_effect VALUES(1146,10001,2,3,6,0);
|
||||
INSERT INTO succession_factor_effect VALUES(1147,10001,2,41,200202,1);
|
||||
INSERT INTO succession_factor_effect VALUES(1148,10001,3,3,9,0);
|
||||
INSERT INTO succession_factor_effect VALUES(1149,10001,3,41,200202,1);
|
||||
INSERT INTO succession_factor_effect VALUES(344,20001,1,41,200012,1);
|
||||
INSERT INTO succession_factor_effect VALUES(345,20001,2,41,200012,2);
|
||||
INSERT INTO succession_factor_effect VALUES(346,20001,3,41,200012,3);
|
||||
INSERT INTO succession_factor_effect VALUES(347,20001,4,41,200012,4);
|
||||
INSERT INTO succession_factor_effect VALUES(348,20001,5,41,200012,5);
|
||||
INSERT INTO succession_factor_effect VALUES(1324,30001,1,1,10,0);
|
||||
INSERT INTO succession_factor_effect VALUES(1325,30001,1,2,10,0);
|
||||
INSERT INTO succession_factor_effect VALUES(1326,30001,2,1,20,0);
|
||||
INSERT INTO succession_factor_effect VALUES(1327,30001,2,2,20,0);
|
||||
INSERT INTO succession_factor_effect VALUES(1328,30001,3,1,30,0);
|
||||
INSERT INTO succession_factor_effect VALUES(1329,30001,3,2,30,0);
|
||||
INSERT INTO succession_factor_effect VALUES(71,100101,1,41,900011,1);
|
||||
INSERT INTO succession_factor_effect VALUES(73,100101,2,41,900011,2);
|
||||
INSERT INTO succession_factor_effect VALUES(75,100101,3,41,900011,3);
|
||||
+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"`
|
||||
}
|
||||
@@ -0,0 +1,424 @@
|
||||
/**
|
||||
* TypeScript schema for JSON files generated by horsegen.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Character definitions.
|
||||
*/
|
||||
export interface Character {
|
||||
/**
|
||||
* Character ID.
|
||||
*/
|
||||
chara_id: number;
|
||||
/**
|
||||
* Regional name of the character.
|
||||
* E.g., Special Week for Global, or スペシャルウィーク for JP.
|
||||
*/
|
||||
name: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Precomputed character pair and trio affinity.
|
||||
*/
|
||||
export interface Affinity {
|
||||
/**
|
||||
* First character in the relation.
|
||||
*/
|
||||
chara_a: number;
|
||||
/**
|
||||
* Second character in the relation.
|
||||
* chara_a < chara_b is an invariant.
|
||||
*/
|
||||
chara_b: number;
|
||||
/**
|
||||
* Third character in the relation, if it is a trio relation.
|
||||
* If defined, chara_b < chara_c is an invariant.
|
||||
*/
|
||||
chara_c?: number;
|
||||
/**
|
||||
* Total base compatibility between characters in the relation.
|
||||
*/
|
||||
affinity: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uma or character card definitions.
|
||||
*/
|
||||
export interface Uma {
|
||||
/**
|
||||
* Uma ID.
|
||||
*/
|
||||
chara_card_id: number;
|
||||
/**
|
||||
* Character ID that the Uma is a variant of.
|
||||
*/
|
||||
chara_id: number;
|
||||
/**
|
||||
* Regional name of the Uma, comprised of the variant name and the character name.
|
||||
* E.g. "[Special Dreamer] Special Week".
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* Regional variant name.
|
||||
* E.g. "[Special Dreamer]".
|
||||
*/
|
||||
variant: string;
|
||||
|
||||
sprint: AptitudeLevel;
|
||||
mile: AptitudeLevel;
|
||||
medium: AptitudeLevel;
|
||||
long: AptitudeLevel;
|
||||
front: AptitudeLevel;
|
||||
pace: AptitudeLevel;
|
||||
late: AptitudeLevel;
|
||||
end: AptitudeLevel;
|
||||
turf: AptitudeLevel;
|
||||
dirt: AptitudeLevel;
|
||||
|
||||
/**
|
||||
* ID of the Uma's unique skill.
|
||||
*/
|
||||
unique: number;
|
||||
/**
|
||||
* ID of the Uma's first built-in skill.
|
||||
*/
|
||||
skill1: number;
|
||||
/**
|
||||
* ID of the Uma's second built-in skill.
|
||||
*/
|
||||
skill2: number;
|
||||
/**
|
||||
* ID of the Uma's third built-in skill.
|
||||
*/
|
||||
skill3: number;
|
||||
/**
|
||||
* ID of the skill unlocked at potential level 2.
|
||||
*/
|
||||
skill_pl2: number;
|
||||
/**
|
||||
* ID of the skill unlocked at potential level 3.
|
||||
*/
|
||||
skill_pl3: number;
|
||||
/**
|
||||
* ID of the skill unlocked at potential level 4.
|
||||
*/
|
||||
skill_pl4: number;
|
||||
/**
|
||||
* ID of the skill unlocked at potential level 5.
|
||||
*/
|
||||
skill_pl5: number;
|
||||
}
|
||||
|
||||
export type AptitudeLevel = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7;
|
||||
|
||||
/**
|
||||
* Race data.
|
||||
*/
|
||||
export interface Race {
|
||||
/**
|
||||
* Race ID.
|
||||
*/
|
||||
race_id: number;
|
||||
/**
|
||||
* Regional name of the race.
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* Thumbnail asset ID number.
|
||||
*/
|
||||
thumbnail: number;
|
||||
/**
|
||||
* Primary race ID.
|
||||
* For most races, this is the same as race_id. Some races are alternate
|
||||
* versions for certain careers; this holds the ID of the normal version of
|
||||
* the race.
|
||||
*/
|
||||
primary: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Race saddle data.
|
||||
*/
|
||||
export interface Saddle {
|
||||
/**
|
||||
* Saddle ID.
|
||||
*/
|
||||
saddle_id: number;
|
||||
/**
|
||||
* Regional name of the saddle.
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* IDs of race wins required to earn the saddle.
|
||||
*/
|
||||
races: number[];
|
||||
/**
|
||||
* Saddle type: 0 for multi-race honors, 3 for G1, 2 for G2, 1 for G3.
|
||||
*/
|
||||
type: 0 | 1 | 2 | 3;
|
||||
/**
|
||||
* Primary saddle ID.
|
||||
* Respective for races.
|
||||
*/
|
||||
primary: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scenario data.
|
||||
*/
|
||||
export interface Scenario {
|
||||
/**
|
||||
* Scenario ID.
|
||||
*/
|
||||
scenario_id: number;
|
||||
/**
|
||||
* Regional scenario name, e.g. "TS Climax".
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* Regional full title, e.g. "Trackblazer: Start of the Climax".
|
||||
*/
|
||||
title: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skill data.
|
||||
*/
|
||||
export interface Skill {
|
||||
/**
|
||||
* Skill ID.
|
||||
*/
|
||||
skill_id: number;
|
||||
/**
|
||||
* Regional skill name.
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* Regional skil description.
|
||||
*/
|
||||
description: string;
|
||||
/**
|
||||
* Skill group ID.
|
||||
*/
|
||||
group: number;
|
||||
/**
|
||||
* Skill rarity. 3-5 are uniques for various star levels.
|
||||
*/
|
||||
rarity: 1 | 2 | 3 | 4 | 5;
|
||||
/**
|
||||
* Upgrade position within the skill's group.
|
||||
* -1 is for negative (purple) skills.
|
||||
*/
|
||||
group_rate: 1 | 2 | 3 | -1;
|
||||
/**
|
||||
* Grade value, or the amount of rating gained for having the skill with
|
||||
* appropriate aptitude.
|
||||
*/
|
||||
grade_value?: number;
|
||||
/**
|
||||
* Whether the skill requires a wit check.
|
||||
*/
|
||||
wit_check: boolean;
|
||||
/**
|
||||
* Conditions and results of skill activation.
|
||||
*/
|
||||
activations: [Activation] | [Activation, Activation];
|
||||
/**
|
||||
* Name of the Uma which owns this skill as a unique, if applicable.
|
||||
*/
|
||||
unique_owner?: string;
|
||||
/**
|
||||
* Skill tags, numeric IDs for matching against other effects.
|
||||
*/
|
||||
tags: number[];
|
||||
/**
|
||||
* SP cost to purchase the skill, if applicable.
|
||||
*/
|
||||
sp_cost?: number;
|
||||
/**
|
||||
* Skill icon ID.
|
||||
*/
|
||||
icon_id: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Conditions and results of skill activation.
|
||||
*/
|
||||
export interface Activation {
|
||||
/**
|
||||
* Precondition which must be satisfied before the condition is checked.
|
||||
*/
|
||||
precondition?: string;
|
||||
/**
|
||||
* Activation conditions.
|
||||
*/
|
||||
condition: string;
|
||||
/**
|
||||
* Skill duration in ten thousandths of a second.
|
||||
* Generally undefined for activations which only affect HP.
|
||||
*/
|
||||
duration?: number;
|
||||
/**
|
||||
* Special skill duration scaling mode.
|
||||
*/
|
||||
dur_scale: 1 | 2 | 3 | 4 | 5 | 7;
|
||||
/**
|
||||
* Skill cooldown in ten thousandths of a second.
|
||||
* A value of 5000000 indicates that the cooldown is forever.
|
||||
* Generally undefined for passive skills.
|
||||
*/
|
||||
cooldown?: number;
|
||||
/**
|
||||
* Results applied when the skill's conditions are met.
|
||||
*/
|
||||
abilities: [Ability] | [Ability, Ability] | [Ability, Ability, Ability];
|
||||
}
|
||||
|
||||
/**
|
||||
* Effects applied when a skill activates.
|
||||
*/
|
||||
export interface Ability {
|
||||
/**
|
||||
* Race mechanic affected by the ability.
|
||||
*/
|
||||
type: 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 13 | 21 | 27 | 28 | 31 | 35;
|
||||
/**
|
||||
* Special scaling type of the skill value.
|
||||
*/
|
||||
value_usage: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 19 | 20 | 22 | 23 | 24 | 25;
|
||||
/**
|
||||
* Amount that the skill modifies the race mechanic in ten thousandths of
|
||||
* whatever is the appropriate unit.
|
||||
*/
|
||||
value: number;
|
||||
/**
|
||||
* Selector for horses targeted by the ability.
|
||||
*/
|
||||
target: 1 | 2 | 4 | 7 | 9 | 10 | 11 | 18 | 19 | 20 | 21 | 22 | 23;
|
||||
/**
|
||||
* Argument value for the ability target, when appropriate.
|
||||
*/
|
||||
target_value?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skill groups.
|
||||
* Skills in a skill group replace each other when purchased.
|
||||
*
|
||||
* As a special case, horsegen lists both unique skills and their inherited
|
||||
* versions in the skill groups for both.
|
||||
*/
|
||||
export interface SkillGroup {
|
||||
/**
|
||||
* Skill group ID.
|
||||
*/
|
||||
skill_group: number;
|
||||
/**
|
||||
* Base skill in the skill group, if any.
|
||||
* Either a common (white) skill or an Uma's own unique.
|
||||
*
|
||||
* Some skill groups, e.g. for G1 Averseness, have no base skill.
|
||||
*/
|
||||
skill1?: number;
|
||||
/**
|
||||
* First upgraded version of a skill, if any.
|
||||
* A rare (gold) skill, double circle skill, or an inherited unique skill.
|
||||
*/
|
||||
skill2?: number;
|
||||
/**
|
||||
* Highest upgraded version of a skill, if any.
|
||||
* Gold version of a skill with a double circle version.
|
||||
*/
|
||||
skill3?: number;
|
||||
/**
|
||||
* Negative (purple) version of a skill, if any.
|
||||
*/
|
||||
skill_bad?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sparks, or succession factors.
|
||||
*/
|
||||
export interface Spark {
|
||||
/**
|
||||
* Spark ID.
|
||||
*/
|
||||
spark_id: number;
|
||||
/**
|
||||
* Regional spark name.
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* Regional spark description.
|
||||
*/
|
||||
description: string;
|
||||
/**
|
||||
* Spark group.
|
||||
* Different star levels of a given spark are different spark IDs but
|
||||
* share a spark group.
|
||||
*/
|
||||
spark_group: number;
|
||||
/**
|
||||
* Spark rarity, or star level.
|
||||
*/
|
||||
rarity: 1 | 2 | 3;
|
||||
/**
|
||||
* Spark type.
|
||||
* Roughly the spark color, with extra subdivisions for white sparks.
|
||||
*/
|
||||
type: 1 | 2 | 5 | 4 | 6 | 7 | 10 | 8 | 11 | 9 | 3;
|
||||
/**
|
||||
* Possible effects applied by the spark during inspiration.
|
||||
* A random element is selected from this list according to unknown
|
||||
* distributions, then all effects in that selection are applied.
|
||||
*/
|
||||
effects: SparkEffect[][];
|
||||
}
|
||||
|
||||
/**
|
||||
* Effects that a spark can apply.
|
||||
*/
|
||||
export interface SparkEffect {
|
||||
target: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 21 | 22 | 23 | 24 | 31 | 32 | 33 | 34 | 41 | 51 | 61 | 62 | 63 | 64 | 65;
|
||||
value1?: number;
|
||||
value2: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lobby conversation data.
|
||||
*/
|
||||
export interface Conversation {
|
||||
/**
|
||||
* Character who owns the conversation as a gallery entry.
|
||||
*/
|
||||
chara_id: number;
|
||||
/**
|
||||
* Number of the conversation within the character's conversation gallery.
|
||||
*/
|
||||
number: number;
|
||||
/**
|
||||
* Location ID of the conversation.
|
||||
*/
|
||||
location: 110 | 120 | 130 | 210 | 220 | 310 | 410 | 420 | 430 | 510 | 520 | 530;
|
||||
/**
|
||||
* English name of the location, for convenience.
|
||||
*/
|
||||
location_name: string;
|
||||
/**
|
||||
* First character in the conversation.
|
||||
* Not necessarily equal to chara_id.
|
||||
*/
|
||||
chara_1: number;
|
||||
/**
|
||||
* Second character, if present.
|
||||
*/
|
||||
chara_2?: number;
|
||||
/**
|
||||
* Third character, if present.
|
||||
*/
|
||||
chara_3?: number;
|
||||
/**
|
||||
* Some unknown number in the game's local database.
|
||||
*/
|
||||
condition_type: 0 | 1 | 2 | 3 | 4;
|
||||
}
|
||||
+64
-27
@@ -27,37 +27,38 @@ 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"`
|
||||
Tags []uint16 `json:"tags"`
|
||||
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"`
|
||||
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,omitzero"`
|
||||
}
|
||||
|
||||
func (a Ability) String() string {
|
||||
@@ -77,19 +78,26 @@ func (a Ability) String() string {
|
||||
case AbilityHP:
|
||||
r = append(r, (a.Value * 100).String()...)
|
||||
r = append(r, '%')
|
||||
case AbilityGateDelay:
|
||||
case AbilityRushedChance:
|
||||
r = append(r, a.Value.String()...)
|
||||
r = append(r, "×"...)
|
||||
case AbilityFrenzy:
|
||||
r = append(r, '%')
|
||||
case AbilityGateDelay:
|
||||
// This skill type in particular should be × instead of +.
|
||||
r = append(r[:len(r)-1], "×"...)
|
||||
r = append(r, a.Value.String()...)
|
||||
case AbilityFrenzy, AbilityAddGateDelay:
|
||||
r = append(r, a.Value.String()...)
|
||||
r = append(r, 's')
|
||||
case AbilityCurrentSpeed, AbilityTargetSpeed, AbilityLaneSpeed:
|
||||
case AbilityCurrentSpeed, AbilityCurrentSpeedUp, AbilityTargetSpeed, AbilityLaneSpeed:
|
||||
r = append(r, a.Value.String()...)
|
||||
r = append(r, " m/s"...)
|
||||
case AbilityAccel:
|
||||
r = append(r, a.Value.String()...)
|
||||
r = append(r, " m/s²"...)
|
||||
case AbilityLaneChange:
|
||||
// This skill type should be "to 0.5 track widths."
|
||||
// (The only skill that has it is Dodging Danger/Sixth Sense.)
|
||||
r = append(r[:len(r)-1], "to "...)
|
||||
r = append(r, a.Value.String()...)
|
||||
r = append(r, " track widths"...)
|
||||
}
|
||||
@@ -153,9 +161,12 @@ const (
|
||||
AbilityHP AbilityType = 9 // HP
|
||||
AbilityGateDelay AbilityType = 10 // Gate delay multiplier
|
||||
AbilityFrenzy AbilityType = 13 // Frenzy
|
||||
AbilityAddGateDelay AbilityType = 14 // Added gate delay
|
||||
AbilityCurrentSpeed AbilityType = 21 // Current speed
|
||||
AbilityCurrentSpeedUp AbilityType = 22 // Current speed
|
||||
AbilityTargetSpeed AbilityType = 27 // Target speed
|
||||
AbilityLaneSpeed AbilityType = 28 // Lane change speed
|
||||
AbilityRushedChance AbilityType = 29 // Rushed chance
|
||||
AbilityAccel AbilityType = 31 // Acceleration
|
||||
AbilityLaneChange AbilityType = 35 // Forced lane change
|
||||
)
|
||||
@@ -202,3 +213,29 @@ 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.
|
||||
//
|
||||
// As a special case, horsegen lists both unique skills and their inherited
|
||||
// versions in the skill groups for both.
|
||||
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"`
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package horse_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.sunturtle.xyz/zephyr/horse"
|
||||
)
|
||||
|
||||
func TestTenThousandthsString(t *testing.T) {
|
||||
t.Parallel()
|
||||
cases := []struct {
|
||||
val horse.TenThousandths
|
||||
want string
|
||||
}{
|
||||
{0, "0"},
|
||||
{500, "0.05"},
|
||||
{-500, "-0.05"},
|
||||
{10000, "1"},
|
||||
{-10000, "-1"},
|
||||
{15000, "1.5"},
|
||||
{-15000, "-1.5"},
|
||||
{10001, "1.0001"},
|
||||
{5000000, "500"},
|
||||
}
|
||||
for _, c := range cases {
|
||||
got := c.val.String()
|
||||
if got != c.want {
|
||||
t.Errorf("%d: want %q, got %q", c.val, c.want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
+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
|
||||
-1
Submodule std deleted from 41b8aed39e
@@ -1,11 +0,0 @@
|
||||
module test/global
|
||||
|
||||
import horse/global/character
|
||||
import horse/global/race
|
||||
import horse/global/saddle
|
||||
import horse/global/scenario
|
||||
import horse/global/skill
|
||||
import horse/global/spark
|
||||
|
||||
pub fun main()
|
||||
()
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user