Compare commits
10 Commits
main
...
92896ba554
| Author | SHA1 | Date | |
|---|---|---|---|
| 92896ba554 | |||
| 487fd1e5c0 | |||
| e27b08c775 | |||
| 8ed173244a | |||
| 9e55535cbd | |||
| b4b7a36c13 | |||
| f7d4712578 | |||
| feba6ddc3d | |||
| 53fc208371 | |||
| 7b44885c2d |
@@ -27,8 +27,6 @@ type Conversation struct {
|
||||
Number int `json:"number"`
|
||||
// Location is the ID of the location the conversation occurs in the lobby.
|
||||
Location LobbyConversationLocationID `json:"location"`
|
||||
// LocationName is the name of the lobby location, for convenience.
|
||||
LocationName string `json:"location_name"`
|
||||
// Chara1 is the first conversation participant ID.
|
||||
// It does not necessarily match CharacterID.
|
||||
Chara1 CharacterID `json:"chara_1"`
|
||||
|
||||
+61
-36
@@ -13,7 +13,7 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/disgoorg/disgo"
|
||||
@@ -24,15 +24,17 @@ import (
|
||||
"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"
|
||||
"git.sunturtle.xyz/zephyr/horse/mdb"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var (
|
||||
// public site
|
||||
addr string
|
||||
dataDir string
|
||||
mdbf string
|
||||
public string
|
||||
// discord
|
||||
tokenFile string
|
||||
@@ -42,8 +44,8 @@ func main() {
|
||||
level slog.Level
|
||||
textfmt string
|
||||
)
|
||||
flag.StringVar(&addr, "http", ":80", "`address` to bind HTTP server")
|
||||
flag.StringVar(&dataDir, "data", "", "`dir`ectory containing exported json data")
|
||||
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(&tokenFile, "token", "", "`file` containing the Discord bot token")
|
||||
flag.StringVar(&apiRoute, "route", "/interactions/callback", "`path` to serve Discord HTTP API calls")
|
||||
@@ -64,6 +66,7 @@ func main() {
|
||||
}
|
||||
slog.SetDefault(slog.New(lh))
|
||||
|
||||
if public != "" {
|
||||
stat, err := os.Stat(public)
|
||||
if err != nil {
|
||||
slog.Error("public", slog.Any("err", err))
|
||||
@@ -73,10 +76,21 @@ func main() {
|
||||
slog.Error("public", slog.String("err", "not a directory"))
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
skills, err := loadSkills(filepath.Join(dataDir, "skill.json"))
|
||||
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)
|
||||
}
|
||||
|
||||
var client *bot.Client
|
||||
if tokenFile != "" {
|
||||
skills, err := mdb.Skills(ctx, db)
|
||||
slog.Info("loaded skills", slog.Int("count", len(skills)))
|
||||
groups, err2 := loadSkillGroups(filepath.Join(dataDir, "skill-group.json"))
|
||||
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))
|
||||
@@ -85,15 +99,6 @@ func main() {
|
||||
skillSrv := newSkillServer(skills, groups)
|
||||
slog.Info("skill server ready")
|
||||
|
||||
token, err := os.ReadFile(tokenFile)
|
||||
if err != nil {
|
||||
slog.Error("reading token", slog.Any("err", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
token = bytes.TrimSuffix(token, []byte{'\n'})
|
||||
|
||||
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
|
||||
|
||||
r := handler.New()
|
||||
r.DefaultContext(func() context.Context { return ctx })
|
||||
r.Use(middleware.Go)
|
||||
@@ -104,16 +109,35 @@ func main() {
|
||||
r.SelectMenuComponent("/swap", skillSrv.menu)
|
||||
r.ButtonComponent("/swap/{id}", skillSrv.button)
|
||||
})
|
||||
|
||||
slog.Info("connect", slog.String("disgo", disgo.Version))
|
||||
client, err := disgo.New(string(token), bot.WithDefaultGateway(), bot.WithEventListeners(r))
|
||||
token, err := os.ReadFile(tokenFile)
|
||||
if err != nil {
|
||||
slog.Error("reading token", slog.Any("err", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
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))))
|
||||
mux.Handle("GET /api/data/", httpmiddle.Compress(5)(http.StripPrefix("/api/data", http.FileServerFS(os.DirFS(dataDir)))))
|
||||
}
|
||||
mux.Handle("GET /api/global/affinity", httpmiddle.Compress(5)(dataroute(ctx, db, mdb.AffinitySummary)))
|
||||
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 {
|
||||
@@ -130,7 +154,7 @@ func main() {
|
||||
}
|
||||
srv := http.Server{
|
||||
Addr: addr,
|
||||
Handler: mux,
|
||||
Handler: httpmiddle.Logger(mux),
|
||||
ReadTimeout: 15 * time.Second,
|
||||
WriteTimeout: 15 * time.Second,
|
||||
BaseContext: func(l net.Listener) context.Context { return ctx },
|
||||
@@ -144,6 +168,7 @@ func main() {
|
||||
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)
|
||||
@@ -154,13 +179,17 @@ func main() {
|
||||
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)
|
||||
@@ -186,26 +215,22 @@ var commands = []discord.ApplicationCommandCreate{
|
||||
},
|
||||
}
|
||||
|
||||
func loadSkills(file string) ([]horse.Skill, error) {
|
||||
b, err := os.ReadFile(file)
|
||||
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 {
|
||||
return nil, err
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
var skills []horse.Skill
|
||||
if err := json.Unmarshal(b, &skills); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return skills, nil
|
||||
}
|
||||
|
||||
func loadSkillGroups(file string) ([]horse.SkillGroup, error) {
|
||||
b, err := os.ReadFile(file)
|
||||
b, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
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
|
||||
}
|
||||
var groups []horse.SkillGroup
|
||||
if err := json.Unmarshal(b, &groups); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return groups, nil
|
||||
}
|
||||
|
||||
@@ -1,435 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"cmp"
|
||||
"context"
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"maps"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
"zombiezen.com/go/sqlite"
|
||||
"zombiezen.com/go/sqlite/sqlitex"
|
||||
|
||||
"git.sunturtle.xyz/zephyr/horse"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var (
|
||||
mdb string
|
||||
out string
|
||||
region string
|
||||
)
|
||||
flag.StringVar(&mdb, "mdb", os.ExpandEnv(`$USERPROFILE\AppData\LocalLow\Cygames\Umamusume\master\master.mdb`), "`path` to Umamusume master.mdb")
|
||||
flag.StringVar(&out, "o", `.`, "`dir`ectory for output files")
|
||||
flag.StringVar(®ion, "region", "global", "region the database is for (global, jp)")
|
||||
flag.Parse()
|
||||
|
||||
slog.Info("open", slog.String("mdb", mdb))
|
||||
db, err := sqlitex.NewPool(mdb, sqlitex.PoolOptions{Flags: sqlite.OpenReadOnly})
|
||||
if err != nil {
|
||||
slog.Error("opening mdb", slog.String("mdb", mdb), slog.Any("err", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
stop()
|
||||
}()
|
||||
|
||||
loadgroup, ctx1 := errgroup.WithContext(ctx)
|
||||
charas := load(ctx1, loadgroup, db, "characters", characterSQL, func(s *sqlite.Stmt) horse.Character {
|
||||
return horse.Character{
|
||||
ID: horse.CharacterID(s.ColumnInt(0)),
|
||||
Name: s.ColumnText(1),
|
||||
}
|
||||
})
|
||||
aff := load(ctx1, loadgroup, db, "pair affinity", affinitySQL, func(s *sqlite.Stmt) horse.AffinityRelation {
|
||||
return horse.AffinityRelation{
|
||||
IDA: s.ColumnInt(0),
|
||||
IDB: s.ColumnInt(1),
|
||||
IDC: s.ColumnInt(2),
|
||||
Affinity: s.ColumnInt(3),
|
||||
}
|
||||
})
|
||||
umas := load(ctx1, loadgroup, db, "umas", umaSQL, func(s *sqlite.Stmt) horse.Uma {
|
||||
return horse.Uma{
|
||||
ID: horse.UmaID(s.ColumnInt(0)),
|
||||
CharacterID: horse.CharacterID(s.ColumnInt(1)),
|
||||
Name: s.ColumnText(2),
|
||||
Variant: s.ColumnText(3),
|
||||
Sprint: horse.AptitudeLevel(s.ColumnInt(4)),
|
||||
Mile: horse.AptitudeLevel(s.ColumnInt(6)),
|
||||
Medium: horse.AptitudeLevel(s.ColumnInt(7)),
|
||||
Long: horse.AptitudeLevel(s.ColumnInt(8)),
|
||||
Front: horse.AptitudeLevel(s.ColumnInt(9)),
|
||||
Pace: horse.AptitudeLevel(s.ColumnInt(10)),
|
||||
Late: horse.AptitudeLevel(s.ColumnInt(11)),
|
||||
End: horse.AptitudeLevel(s.ColumnInt(12)),
|
||||
Turf: horse.AptitudeLevel(s.ColumnInt(13)),
|
||||
Dirt: horse.AptitudeLevel(s.ColumnInt(14)),
|
||||
Unique: horse.SkillID(s.ColumnInt(15)),
|
||||
Skill1: horse.SkillID(s.ColumnInt(16)),
|
||||
Skill2: horse.SkillID(s.ColumnInt(17)),
|
||||
Skill3: horse.SkillID(s.ColumnInt(18)),
|
||||
SkillPL2: horse.SkillID(s.ColumnInt(19)),
|
||||
SkillPL3: horse.SkillID(s.ColumnInt(20)),
|
||||
SkillPL4: horse.SkillID(s.ColumnInt(21)),
|
||||
SkillPL5: horse.SkillID(s.ColumnInt(22)),
|
||||
}
|
||||
})
|
||||
sg := load(ctx1, loadgroup, db, "skill groups", skillGroupSQL, func(s *sqlite.Stmt) horse.SkillGroup {
|
||||
return horse.SkillGroup{
|
||||
ID: horse.SkillGroupID(s.ColumnInt(0)),
|
||||
Skill1: horse.SkillID(s.ColumnInt(1)),
|
||||
Skill2: horse.SkillID(s.ColumnInt(2)),
|
||||
Skill3: horse.SkillID(s.ColumnInt(3)),
|
||||
SkillBad: horse.SkillID(s.ColumnInt(4)),
|
||||
}
|
||||
})
|
||||
skills := load(ctx1, loadgroup, db, "skills", skillSQL, func(s *sqlite.Stmt) horse.Skill {
|
||||
return horse.Skill{
|
||||
ID: horse.SkillID(s.ColumnInt(0)),
|
||||
Name: s.ColumnText(1),
|
||||
Description: s.ColumnText(2),
|
||||
Group: horse.SkillGroupID(s.ColumnInt32(3)),
|
||||
Rarity: int8(s.ColumnInt(5)),
|
||||
GroupRate: int8(s.ColumnInt(6)),
|
||||
GradeValue: s.ColumnInt32(7),
|
||||
WitCheck: s.ColumnBool(8),
|
||||
Activations: trimActivations([]horse.Activation{
|
||||
{
|
||||
Precondition: s.ColumnText(9),
|
||||
Condition: s.ColumnText(10),
|
||||
Duration: horse.TenThousandths(s.ColumnInt(11)),
|
||||
DurScale: horse.DurScale(s.ColumnInt(12)),
|
||||
Cooldown: horse.TenThousandths(s.ColumnInt(13)),
|
||||
Abilities: trimAbilities([]horse.Ability{
|
||||
{
|
||||
Type: horse.AbilityType(s.ColumnInt(14)),
|
||||
ValueUsage: horse.AbilityValueUsage(s.ColumnInt(15)),
|
||||
Value: horse.TenThousandths(s.ColumnInt(16)),
|
||||
Target: horse.AbilityTarget(s.ColumnInt(17)),
|
||||
TargetValue: s.ColumnInt32(18),
|
||||
},
|
||||
{
|
||||
Type: horse.AbilityType(s.ColumnInt(19)),
|
||||
ValueUsage: horse.AbilityValueUsage(s.ColumnInt(20)),
|
||||
Value: horse.TenThousandths(s.ColumnInt(21)),
|
||||
Target: horse.AbilityTarget(s.ColumnInt(22)),
|
||||
TargetValue: s.ColumnInt32(23),
|
||||
},
|
||||
{
|
||||
Type: horse.AbilityType(s.ColumnInt(24)),
|
||||
ValueUsage: horse.AbilityValueUsage(s.ColumnInt(25)),
|
||||
Value: horse.TenThousandths(s.ColumnInt(26)),
|
||||
Target: horse.AbilityTarget(s.ColumnInt(27)),
|
||||
TargetValue: s.ColumnInt32(28),
|
||||
},
|
||||
}),
|
||||
},
|
||||
{
|
||||
Precondition: s.ColumnText(29),
|
||||
Condition: s.ColumnText(30),
|
||||
Duration: horse.TenThousandths(s.ColumnInt(31)),
|
||||
DurScale: horse.DurScale(s.ColumnInt(32)),
|
||||
Cooldown: horse.TenThousandths(s.ColumnInt(33)),
|
||||
Abilities: trimAbilities([]horse.Ability{
|
||||
{
|
||||
Type: horse.AbilityType(s.ColumnInt(34)),
|
||||
ValueUsage: horse.AbilityValueUsage(s.ColumnInt(35)),
|
||||
Value: horse.TenThousandths(s.ColumnInt(36)),
|
||||
Target: horse.AbilityTarget(s.ColumnInt(37)),
|
||||
TargetValue: s.ColumnInt32(38),
|
||||
},
|
||||
{
|
||||
Type: horse.AbilityType(s.ColumnInt(39)),
|
||||
ValueUsage: horse.AbilityValueUsage(s.ColumnInt(40)),
|
||||
Value: horse.TenThousandths(s.ColumnInt(41)),
|
||||
Target: horse.AbilityTarget(s.ColumnInt(42)),
|
||||
TargetValue: s.ColumnInt32(43),
|
||||
},
|
||||
{
|
||||
Type: horse.AbilityType(s.ColumnInt(44)),
|
||||
ValueUsage: horse.AbilityValueUsage(s.ColumnInt(45)),
|
||||
Value: horse.TenThousandths(s.ColumnInt(46)),
|
||||
Target: horse.AbilityTarget(s.ColumnInt(47)),
|
||||
TargetValue: s.ColumnInt32(48),
|
||||
},
|
||||
}),
|
||||
},
|
||||
}),
|
||||
UniqueOwner: s.ColumnText(52), // TODO(zeph): should be id, not name
|
||||
Tags: parseTags(s.ColumnText(54)),
|
||||
SPCost: s.ColumnInt(49),
|
||||
IconID: s.ColumnInt(53),
|
||||
}
|
||||
})
|
||||
races := load(ctx1, loadgroup, db, "races", raceSQL, func(s *sqlite.Stmt) horse.Race {
|
||||
return horse.Race{
|
||||
ID: horse.RaceID(s.ColumnInt(0)),
|
||||
Name: s.ColumnText(1),
|
||||
// TODO(zeph): grade
|
||||
Thumbnail: s.ColumnInt(3),
|
||||
Primary: horse.RaceID(s.ColumnInt(4)),
|
||||
}
|
||||
})
|
||||
saddles := load(ctx1, loadgroup, db, "saddles", saddleSQL, func(s *sqlite.Stmt) horse.Saddle {
|
||||
return horse.Saddle{
|
||||
ID: horse.SaddleID(s.ColumnInt(0)),
|
||||
Name: s.ColumnText(1),
|
||||
Races: trimZeros(
|
||||
horse.RaceID(s.ColumnInt(2)),
|
||||
horse.RaceID(s.ColumnInt(3)),
|
||||
horse.RaceID(s.ColumnInt(4)),
|
||||
),
|
||||
Type: horse.SaddleType(s.ColumnInt(5)),
|
||||
Primary: horse.SaddleID(s.ColumnInt(6)),
|
||||
}
|
||||
})
|
||||
scenarios := load(ctx1, loadgroup, db, "scenarios", scenarioSQL, func(s *sqlite.Stmt) horse.Scenario {
|
||||
return horse.Scenario{
|
||||
ID: horse.ScenarioID(s.ColumnInt(0)),
|
||||
Name: s.ColumnText(1),
|
||||
Title: s.ColumnText(2),
|
||||
}
|
||||
})
|
||||
sparks := load(ctx1, loadgroup, db, "sparks", sparkSQL, func(s *sqlite.Stmt) horse.Spark {
|
||||
return horse.Spark{
|
||||
ID: horse.SparkID(s.ColumnInt(0)),
|
||||
Name: s.ColumnText(1),
|
||||
Description: s.ColumnText(2),
|
||||
Group: horse.SparkGroupID(s.ColumnInt(3)),
|
||||
Rarity: horse.SparkRarity(s.ColumnInt(4)),
|
||||
Type: horse.SparkType(s.ColumnInt(5)),
|
||||
// Effects filled in later.
|
||||
}
|
||||
})
|
||||
sparkeffs := load(ctx1, loadgroup, db, "spark effects", sparkEffectSQL, func(s *sqlite.Stmt) SparkEffImm {
|
||||
return SparkEffImm{
|
||||
Group: horse.SparkGroupID(s.ColumnInt(0)),
|
||||
Effect: s.ColumnInt(1),
|
||||
Target: horse.SparkTarget(s.ColumnInt(2)),
|
||||
Value1: s.ColumnInt32(3),
|
||||
Value2: s.ColumnInt32(4),
|
||||
}
|
||||
})
|
||||
convos := load(ctx1, loadgroup, db, "lobby conversations", 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)),
|
||||
LocationName: horse.LobbyConversationLocationID(s.ColumnInt(2)).String(),
|
||||
Chara1: horse.CharacterID(s.ColumnInt(3)),
|
||||
Chara2: horse.CharacterID(s.ColumnInt(4)),
|
||||
Chara3: horse.CharacterID(s.ColumnInt(5)),
|
||||
ConditionType: s.ColumnInt(6),
|
||||
}
|
||||
})
|
||||
|
||||
if err := os.MkdirAll(filepath.Join(out, region), 0775); err != nil {
|
||||
slog.Error("create output dir", slog.Any("err", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
writegroup, ctx2 := errgroup.WithContext(ctx)
|
||||
writegroup.Go(func() error { return write(ctx2, out, region, "character.json", charas) })
|
||||
writegroup.Go(func() error { return write(ctx2, out, region, "affinity.json", aff) })
|
||||
writegroup.Go(func() error { return write(ctx2, out, region, "uma.json", umas) })
|
||||
writegroup.Go(func() error { return write(ctx2, out, region, "skill-group.json", sg) })
|
||||
writegroup.Go(func() error { return write(ctx2, out, region, "skill.json", skills) })
|
||||
writegroup.Go(func() error { return write(ctx2, out, region, "race.json", races) })
|
||||
writegroup.Go(func() error { return write(ctx2, out, region, "saddle.json", saddles) })
|
||||
writegroup.Go(func() error { return write(ctx2, out, region, "scenario.json", scenarios) })
|
||||
writegroup.Go(func() error { return write(ctx2, out, region, "spark.json", mergesparks(sparks, sparkeffs)) })
|
||||
writegroup.Go(func() error { return write(ctx2, out, region, "conversation.json", convos) })
|
||||
if err := writegroup.Wait(); err != nil {
|
||||
slog.ErrorContext(ctx, "write", slog.Any("err", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
slog.InfoContext(ctx, "done")
|
||||
}
|
||||
|
||||
var (
|
||||
//go:embed sql/character.sql
|
||||
characterSQL string
|
||||
//go:embed sql/affinity.sql
|
||||
affinitySQL string
|
||||
//go:embed sql/uma.sql
|
||||
umaSQL string
|
||||
//go:embed sql/skill-group.sql
|
||||
skillGroupSQL string
|
||||
//go:embed sql/skill.sql
|
||||
skillSQL string
|
||||
//go:embed sql/race.sql
|
||||
raceSQL string
|
||||
//go:embed sql/saddle.sql
|
||||
saddleSQL string
|
||||
//go:embed sql/scenario.sql
|
||||
scenarioSQL string
|
||||
//go:embed sql/spark.sql
|
||||
sparkSQL string
|
||||
//go:embed sql/spark-effect.sql
|
||||
sparkEffectSQL string
|
||||
//go:embed sql/conversation.sql
|
||||
conversationSQL string
|
||||
)
|
||||
|
||||
func load[T any](ctx context.Context, group *errgroup.Group, db *sqlitex.Pool, kind, sql string, row func(*sqlite.Stmt) T) func() ([]T, error) {
|
||||
slog.InfoContext(ctx, "load", slog.String("kind", kind))
|
||||
var r []T
|
||||
group.Go(func() error {
|
||||
conn, err := db.Take(ctx)
|
||||
defer db.Put(conn)
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't get connection for %s: %w", kind, err)
|
||||
}
|
||||
stmt, _, err := conn.PrepareTransient(sql)
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't prepare statement for %s: %w", kind, err)
|
||||
}
|
||||
|
||||
for {
|
||||
ok, err := stmt.Step()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error stepping %s: %w", kind, err)
|
||||
}
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
r = append(r, row(stmt))
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return func() ([]T, error) {
|
||||
err := group.Wait()
|
||||
if err == context.Canceled {
|
||||
// After the first wait, all future ones return context.Canceled.
|
||||
// We want to be able to wait any number of times, so hide it.
|
||||
err = nil
|
||||
}
|
||||
return r, err
|
||||
}
|
||||
}
|
||||
|
||||
func write[T any](ctx context.Context, out, region, name string, v func() (T, error)) error {
|
||||
p := filepath.Join(out, region, name)
|
||||
r, err := v()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
slog.InfoContext(ctx, "write", slog.String("path", p))
|
||||
f, err := os.Create(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
w := bufio.NewWriter(f)
|
||||
enc := json.NewEncoder(w)
|
||||
enc.SetEscapeHTML(false)
|
||||
enc.SetIndent("", "\t")
|
||||
err = enc.Encode(r)
|
||||
err = errors.Join(err, w.Flush())
|
||||
slog.InfoContext(ctx, "marshaled", slog.String("path", p))
|
||||
return err
|
||||
}
|
||||
|
||||
func mergesparks(sparks func() ([]horse.Spark, error), effs func() ([]SparkEffImm, error)) func() ([]horse.Spark, error) {
|
||||
return func() ([]horse.Spark, error) {
|
||||
sp, err := sparks()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ef, err := effs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Spark effects are sorted by group ID, but groups apply to multiple
|
||||
// sparks, and we don't rely on sparks and groups being in the same order.
|
||||
// It is possible to merge in linear time, but not worth the effort:
|
||||
// n log n is fine since this is an AOT step.
|
||||
for i := range sp {
|
||||
k, ok := slices.BinarySearchFunc(ef, sp[i].Group, func(e SparkEffImm, v horse.SparkGroupID) int { return cmp.Compare(e.Group, v) })
|
||||
if !ok {
|
||||
panic(fmt.Errorf("mergesparks: no spark group for %+v", &sp[i]))
|
||||
}
|
||||
// Back up to the first effect in the group.
|
||||
for k > 0 && ef[k-1].Group == sp[i].Group {
|
||||
k--
|
||||
}
|
||||
// Map effect IDs to the lists of their effects.
|
||||
m := make(map[int][]horse.SparkEffect)
|
||||
for _, e := range ef[k:] {
|
||||
if e.Group != sp[i].Group {
|
||||
// Done with this group.
|
||||
break
|
||||
}
|
||||
m[e.Effect] = append(m[e.Effect], horse.SparkEffect{Target: e.Target, Value1: e.Value1, Value2: e.Value2})
|
||||
}
|
||||
// Now get effects in order.
|
||||
keys := slices.Sorted(maps.Keys(m))
|
||||
sp[i].Effects = make([][]horse.SparkEffect, 0, len(keys))
|
||||
for _, key := range keys {
|
||||
sp[i].Effects = append(sp[i].Effects, m[key])
|
||||
}
|
||||
}
|
||||
return sp, nil
|
||||
}
|
||||
}
|
||||
|
||||
type SparkEffImm struct {
|
||||
Group horse.SparkGroupID
|
||||
Effect int
|
||||
Target horse.SparkTarget
|
||||
Value1 int32
|
||||
Value2 int32
|
||||
}
|
||||
|
||||
func 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
|
||||
}
|
||||
@@ -228,6 +228,63 @@ tag_id is a slash-separated list of numeric IDs that roughly describe all effect
|
||||
- 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
|
||||
|
||||
-189583
File diff suppressed because it is too large
Load Diff
@@ -1,346 +0,0 @@
|
||||
[
|
||||
{
|
||||
"chara_id": 1001,
|
||||
"name": "Special Week"
|
||||
},
|
||||
{
|
||||
"chara_id": 1002,
|
||||
"name": "Silence Suzuka"
|
||||
},
|
||||
{
|
||||
"chara_id": 1003,
|
||||
"name": "Tokai Teio"
|
||||
},
|
||||
{
|
||||
"chara_id": 1004,
|
||||
"name": "Maruzensky"
|
||||
},
|
||||
{
|
||||
"chara_id": 1005,
|
||||
"name": "Fuji Kiseki"
|
||||
},
|
||||
{
|
||||
"chara_id": 1006,
|
||||
"name": "Oguri Cap"
|
||||
},
|
||||
{
|
||||
"chara_id": 1007,
|
||||
"name": "Gold Ship"
|
||||
},
|
||||
{
|
||||
"chara_id": 1008,
|
||||
"name": "Vodka"
|
||||
},
|
||||
{
|
||||
"chara_id": 1009,
|
||||
"name": "Daiwa Scarlet"
|
||||
},
|
||||
{
|
||||
"chara_id": 1010,
|
||||
"name": "Taiki Shuttle"
|
||||
},
|
||||
{
|
||||
"chara_id": 1011,
|
||||
"name": "Grass Wonder"
|
||||
},
|
||||
{
|
||||
"chara_id": 1012,
|
||||
"name": "Hishi Amazon"
|
||||
},
|
||||
{
|
||||
"chara_id": 1013,
|
||||
"name": "Mejiro McQueen"
|
||||
},
|
||||
{
|
||||
"chara_id": 1014,
|
||||
"name": "El Condor Pasa"
|
||||
},
|
||||
{
|
||||
"chara_id": 1015,
|
||||
"name": "T.M. Opera O"
|
||||
},
|
||||
{
|
||||
"chara_id": 1016,
|
||||
"name": "Narita Brian"
|
||||
},
|
||||
{
|
||||
"chara_id": 1017,
|
||||
"name": "Symboli Rudolf"
|
||||
},
|
||||
{
|
||||
"chara_id": 1018,
|
||||
"name": "Air Groove"
|
||||
},
|
||||
{
|
||||
"chara_id": 1019,
|
||||
"name": "Agnes Digital"
|
||||
},
|
||||
{
|
||||
"chara_id": 1020,
|
||||
"name": "Seiun Sky"
|
||||
},
|
||||
{
|
||||
"chara_id": 1021,
|
||||
"name": "Tamamo Cross"
|
||||
},
|
||||
{
|
||||
"chara_id": 1022,
|
||||
"name": "Fine Motion"
|
||||
},
|
||||
{
|
||||
"chara_id": 1023,
|
||||
"name": "Biwa Hayahide"
|
||||
},
|
||||
{
|
||||
"chara_id": 1024,
|
||||
"name": "Mayano Top Gun"
|
||||
},
|
||||
{
|
||||
"chara_id": 1025,
|
||||
"name": "Manhattan Cafe"
|
||||
},
|
||||
{
|
||||
"chara_id": 1026,
|
||||
"name": "Mihono Bourbon"
|
||||
},
|
||||
{
|
||||
"chara_id": 1027,
|
||||
"name": "Mejiro Ryan"
|
||||
},
|
||||
{
|
||||
"chara_id": 1028,
|
||||
"name": "Hishi Akebono"
|
||||
},
|
||||
{
|
||||
"chara_id": 1029,
|
||||
"name": "Yukino Bijin"
|
||||
},
|
||||
{
|
||||
"chara_id": 1030,
|
||||
"name": "Rice Shower"
|
||||
},
|
||||
{
|
||||
"chara_id": 1031,
|
||||
"name": "Ines Fujin"
|
||||
},
|
||||
{
|
||||
"chara_id": 1032,
|
||||
"name": "Agnes Tachyon"
|
||||
},
|
||||
{
|
||||
"chara_id": 1033,
|
||||
"name": "Admire Vega"
|
||||
},
|
||||
{
|
||||
"chara_id": 1034,
|
||||
"name": "Inari One"
|
||||
},
|
||||
{
|
||||
"chara_id": 1035,
|
||||
"name": "Winning Ticket"
|
||||
},
|
||||
{
|
||||
"chara_id": 1036,
|
||||
"name": "Air Shakur"
|
||||
},
|
||||
{
|
||||
"chara_id": 1037,
|
||||
"name": "Eishin Flash"
|
||||
},
|
||||
{
|
||||
"chara_id": 1038,
|
||||
"name": "Curren Chan"
|
||||
},
|
||||
{
|
||||
"chara_id": 1039,
|
||||
"name": "Kawakami Princess"
|
||||
},
|
||||
{
|
||||
"chara_id": 1040,
|
||||
"name": "Gold City"
|
||||
},
|
||||
{
|
||||
"chara_id": 1041,
|
||||
"name": "Sakura Bakushin O"
|
||||
},
|
||||
{
|
||||
"chara_id": 1042,
|
||||
"name": "Seeking the Pearl"
|
||||
},
|
||||
{
|
||||
"chara_id": 1043,
|
||||
"name": "Shinko Windy"
|
||||
},
|
||||
{
|
||||
"chara_id": 1044,
|
||||
"name": "Sweep Tosho"
|
||||
},
|
||||
{
|
||||
"chara_id": 1045,
|
||||
"name": "Super Creek"
|
||||
},
|
||||
{
|
||||
"chara_id": 1046,
|
||||
"name": "Smart Falcon"
|
||||
},
|
||||
{
|
||||
"chara_id": 1047,
|
||||
"name": "Zenno Rob Roy"
|
||||
},
|
||||
{
|
||||
"chara_id": 1048,
|
||||
"name": "Tosen Jordan"
|
||||
},
|
||||
{
|
||||
"chara_id": 1049,
|
||||
"name": "Nakayama Festa"
|
||||
},
|
||||
{
|
||||
"chara_id": 1050,
|
||||
"name": "Narita Taishin"
|
||||
},
|
||||
{
|
||||
"chara_id": 1051,
|
||||
"name": "Nishino Flower"
|
||||
},
|
||||
{
|
||||
"chara_id": 1052,
|
||||
"name": "Haru Urara"
|
||||
},
|
||||
{
|
||||
"chara_id": 1053,
|
||||
"name": "Bamboo Memory"
|
||||
},
|
||||
{
|
||||
"chara_id": 1054,
|
||||
"name": "Biko Pegasus"
|
||||
},
|
||||
{
|
||||
"chara_id": 1055,
|
||||
"name": "Marvelous Sunday"
|
||||
},
|
||||
{
|
||||
"chara_id": 1056,
|
||||
"name": "Matikanefukukitaru"
|
||||
},
|
||||
{
|
||||
"chara_id": 1057,
|
||||
"name": "Mr. C.B."
|
||||
},
|
||||
{
|
||||
"chara_id": 1058,
|
||||
"name": "Meisho Doto"
|
||||
},
|
||||
{
|
||||
"chara_id": 1059,
|
||||
"name": "Mejiro Dober"
|
||||
},
|
||||
{
|
||||
"chara_id": 1060,
|
||||
"name": "Nice Nature"
|
||||
},
|
||||
{
|
||||
"chara_id": 1061,
|
||||
"name": "King Halo"
|
||||
},
|
||||
{
|
||||
"chara_id": 1062,
|
||||
"name": "Matikanetannhauser"
|
||||
},
|
||||
{
|
||||
"chara_id": 1063,
|
||||
"name": "Ikuno Dictus"
|
||||
},
|
||||
{
|
||||
"chara_id": 1064,
|
||||
"name": "Mejiro Palmer"
|
||||
},
|
||||
{
|
||||
"chara_id": 1065,
|
||||
"name": "Daitaku Helios"
|
||||
},
|
||||
{
|
||||
"chara_id": 1066,
|
||||
"name": "Twin Turbo"
|
||||
},
|
||||
{
|
||||
"chara_id": 1067,
|
||||
"name": "Satono Diamond"
|
||||
},
|
||||
{
|
||||
"chara_id": 1068,
|
||||
"name": "Kitasan Black"
|
||||
},
|
||||
{
|
||||
"chara_id": 1069,
|
||||
"name": "Sakura Chiyono O"
|
||||
},
|
||||
{
|
||||
"chara_id": 1070,
|
||||
"name": "Sirius Symboli"
|
||||
},
|
||||
{
|
||||
"chara_id": 1071,
|
||||
"name": "Mejiro Ardan"
|
||||
},
|
||||
{
|
||||
"chara_id": 1072,
|
||||
"name": "Yaeno Muteki"
|
||||
},
|
||||
{
|
||||
"chara_id": 1073,
|
||||
"name": "Tsurumaru Tsuyoshi"
|
||||
},
|
||||
{
|
||||
"chara_id": 1074,
|
||||
"name": "Mejiro Bright"
|
||||
},
|
||||
{
|
||||
"chara_id": 1077,
|
||||
"name": "Narita Top Road"
|
||||
},
|
||||
{
|
||||
"chara_id": 1078,
|
||||
"name": "Yamanin Zephyr"
|
||||
},
|
||||
{
|
||||
"chara_id": 2001,
|
||||
"name": "Happy Meek"
|
||||
},
|
||||
{
|
||||
"chara_id": 2002,
|
||||
"name": "Bitter Glasse"
|
||||
},
|
||||
{
|
||||
"chara_id": 2003,
|
||||
"name": "Little Cocon"
|
||||
},
|
||||
{
|
||||
"chara_id": 2004,
|
||||
"name": "Montjeu"
|
||||
},
|
||||
{
|
||||
"chara_id": 9001,
|
||||
"name": "Tazuna Hayakawa"
|
||||
},
|
||||
{
|
||||
"chara_id": 9002,
|
||||
"name": "Director Akikawa"
|
||||
},
|
||||
{
|
||||
"chara_id": 9003,
|
||||
"name": "Etsuko Otonashi"
|
||||
},
|
||||
{
|
||||
"chara_id": 9004,
|
||||
"name": "Trainer Kiryuin"
|
||||
},
|
||||
{
|
||||
"chara_id": 9005,
|
||||
"name": "Sasami Anshinzawa"
|
||||
},
|
||||
{
|
||||
"chara_id": 9006,
|
||||
"name": "Riko Kashimoto"
|
||||
}
|
||||
]
|
||||
File diff suppressed because it is too large
Load Diff
-1712
File diff suppressed because it is too large
Load Diff
-1420
File diff suppressed because it is too large
Load Diff
@@ -1,17 +0,0 @@
|
||||
[
|
||||
{
|
||||
"scenario_id": 1,
|
||||
"name": "URA Finale",
|
||||
"title": "The Beginning: URA Finale"
|
||||
},
|
||||
{
|
||||
"scenario_id": 2,
|
||||
"name": "Unity Cup",
|
||||
"title": "Unity Cup: Shine On, Team Spirit!"
|
||||
},
|
||||
{
|
||||
"scenario_id": 4,
|
||||
"name": "TS Climax",
|
||||
"title": "Trackblazer: Start of the Climax"
|
||||
}
|
||||
]
|
||||
File diff suppressed because it is too large
Load Diff
-19511
File diff suppressed because it is too large
Load Diff
-38294
File diff suppressed because it is too large
Load Diff
-1994
File diff suppressed because it is too large
Load Diff
@@ -5,8 +5,8 @@ go 1.25.5
|
||||
require (
|
||||
github.com/disgoorg/disgo v0.19.0-rc.15
|
||||
github.com/go-chi/chi/v5 v5.2.5
|
||||
github.com/google/go-cmp v0.6.0
|
||||
github.com/junegunn/fzf v0.67.0
|
||||
golang.org/x/sync v0.20.0
|
||||
zombiezen.com/go/sqlite v1.4.2
|
||||
)
|
||||
|
||||
@@ -25,6 +25,7 @@ require (
|
||||
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/sync v0.20.0 // indirect
|
||||
golang.org/x/sys v0.39.0 // indirect
|
||||
modernc.org/libc v1.65.7 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
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/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: s.ColumnInt(0),
|
||||
IDB: s.ColumnInt(1),
|
||||
IDC: s.ColumnInt(2),
|
||||
Affinity: s.ColumnInt(3),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 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,224 @@
|
||||
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 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)
|
||||
}
|
||||
}
|
||||
@@ -5,5 +5,10 @@ SELECT
|
||||
value_1,
|
||||
value_2
|
||||
FROM succession_factor_effect
|
||||
WHERE factor_group_id NOT IN (40001) -- exclude Carnival Bonus
|
||||
-- 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
|
||||
@@ -15,7 +15,7 @@ WITH uma_name AS (
|
||||
uma.id,
|
||||
s.skill_id,
|
||||
s.need_rank,
|
||||
ROW_NUMBER() OVER (PARTITION BY s.available_skill_set_id, s.need_rank) AS idx
|
||||
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
|
||||
)
|
||||
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);
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
interface Props {
|
||||
id: string;
|
||||
characters: Character[];
|
||||
characters: Character[] | null;
|
||||
value: number;
|
||||
class?: ClassValue | null;
|
||||
optionClass?: ClassValue | null;
|
||||
@@ -18,7 +18,7 @@
|
||||
{#if !required}
|
||||
<option value="0" class={optionClass}></option>
|
||||
{/if}
|
||||
{#each characters as c (c.chara_id)}
|
||||
{#each characters ?? [] as c (c.chara_id)}
|
||||
<option value={c.chara_id} class={optionClass}>{c.name}</option>
|
||||
{/each}
|
||||
</select>
|
||||
|
||||
+15
-17
@@ -3,39 +3,37 @@
|
||||
ABILITY_SCALE_NAME,
|
||||
ABILITY_TYPE_FORMAT,
|
||||
DURATION_SCALE_NAME,
|
||||
skills,
|
||||
Target,
|
||||
TARGET_FORMAT,
|
||||
tenThousandths,
|
||||
ZERO_SKILL,
|
||||
type Ability,
|
||||
type Skill,
|
||||
} from './data/skill';
|
||||
|
||||
interface CommonProps {
|
||||
hint?: string;
|
||||
interface Props {
|
||||
skill: Skill | null | undefined;
|
||||
mention?: boolean;
|
||||
}
|
||||
|
||||
type Props = CommonProps & ({ skill: number; name?: never } | { name: string; skill?: never });
|
||||
const ZERO_SKILL: Skill = {
|
||||
skill_id: 0,
|
||||
name: 'Skill data is loading...',
|
||||
description: 'Skill data is still loading, or else something went wrong.',
|
||||
group: 0,
|
||||
rarity: 1,
|
||||
group_rate: 1,
|
||||
wit_check: false,
|
||||
activations: [],
|
||||
icon_id: 0,
|
||||
};
|
||||
|
||||
let { hint, mention, skill, name }: Props = $props();
|
||||
let { mention, skill }: Props = $props();
|
||||
|
||||
function splitCond(c: string): string[] {
|
||||
return c.replaceAll('&', ' & ').split('@');
|
||||
}
|
||||
|
||||
const s: Readonly<Skill> = $derived.by(() => {
|
||||
const l =
|
||||
skill != null ? skills.global.filter((s) => s.skill_id === skill) : skills.global.filter((s) => s.name.includes(name!));
|
||||
if (name != null) {
|
||||
console.warn(`skills specified as ${name} (${hint}):`, l);
|
||||
}
|
||||
if (l.length === 0) {
|
||||
return ZERO_SKILL;
|
||||
}
|
||||
return l[0];
|
||||
});
|
||||
const s = $derived(skill ?? ZERO_SKILL);
|
||||
const activationClass = $derived(s.activations.length === 1 ? null : 'block my-2 border rounded-md');
|
||||
|
||||
const spanClass = $derived(mention ? 'italic' : 'font-bold');
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
<script lang="ts">
|
||||
import { sparks } from '$lib/data/spark';
|
||||
import { type Spark } from '$lib/data/spark';
|
||||
|
||||
interface Props {
|
||||
spark: number;
|
||||
region?: keyof typeof sparks;
|
||||
spark: Spark | null | undefined;
|
||||
}
|
||||
|
||||
const { spark, region = 'global' }: Props = $props();
|
||||
const { spark }: Props = $props();
|
||||
|
||||
const cur = $derived(sparks[region].find((s) => s.spark_id === spark));
|
||||
const curClass = $derived.by(() => {
|
||||
if (cur == null) {
|
||||
if (spark == null) {
|
||||
return [];
|
||||
}
|
||||
switch (cur.type) {
|
||||
switch (spark.type) {
|
||||
case 1:
|
||||
return ['stat'];
|
||||
case 2:
|
||||
@@ -32,17 +30,17 @@
|
||||
return [];
|
||||
}
|
||||
});
|
||||
const stars = $derived('★'.repeat(cur?.rarity ?? 0));
|
||||
const stars = $derived('★'.repeat(spark?.rarity ?? 0));
|
||||
</script>
|
||||
|
||||
{#if cur != null}
|
||||
{#if spark != null}
|
||||
<div
|
||||
class={[
|
||||
curClass,
|
||||
'spark mx-1 flex items-center rounded-xl px-2 py-1 transition ease-in hover:shadow-md hover:ease-out motion-safe:duration-75 motion-safe:hover:-translate-y-0.5 dark:shadow-neutral-950',
|
||||
]}
|
||||
>
|
||||
<span>{cur.name}</span>
|
||||
<span>{spark.name}</span>
|
||||
<span class="ml-2 text-xl text-amber-800 text-shadow-md dark:text-amber-300">{stars}</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import globalJSON from '../../../../global/affinity.json';
|
||||
|
||||
/**
|
||||
* Precomputed character pair and trio affinity.
|
||||
*/
|
||||
@@ -24,9 +22,10 @@ export interface Affinity {
|
||||
affinity: number;
|
||||
}
|
||||
|
||||
export const affinity = {
|
||||
global: globalJSON as Affinity[],
|
||||
} as const;
|
||||
export async function affinity(): Promise<Affinity[]> {
|
||||
const resp = await fetch('/api/global/affinity');
|
||||
return resp.json();
|
||||
}
|
||||
|
||||
export function lookup(aff: Affinity[], chara_a: number, chara_b: number, chara_c?: number): number {
|
||||
const [a, b, c] = [chara_a, chara_b, chara_c ?? Infinity].sort((a, b) => a - b);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import type { RegionalName } from '$lib/regional-name';
|
||||
import globalJSON from '../../../../global/character.json';
|
||||
|
||||
/**
|
||||
* Character definitions.
|
||||
@@ -16,11 +15,11 @@ export interface Character {
|
||||
name: string;
|
||||
}
|
||||
|
||||
export const character = {
|
||||
global: globalJSON as Character[],
|
||||
};
|
||||
export async function character(): Promise<Character[]> {
|
||||
const resp = await fetch('/api/global/character');
|
||||
return resp.json();
|
||||
}
|
||||
|
||||
export const charaNames = globalJSON.reduce(
|
||||
(m, c) => m.set(c.chara_id, { en: c.name }),
|
||||
new Map<Character['chara_id'], RegionalName>(),
|
||||
);
|
||||
export function charaNames(charas: Character[]) {
|
||||
return charas.reduce((m, c) => m.set(c.chara_id, { en: c.name }), new Map<number, RegionalName>());
|
||||
}
|
||||
|
||||
+17
-21
@@ -1,5 +1,4 @@
|
||||
import type { RegionalName } from '$lib/regional-name';
|
||||
import globalJSON from '../../../../global/conversation.json';
|
||||
|
||||
/**
|
||||
* Lobby conversation data.
|
||||
@@ -17,10 +16,6 @@ export interface Conversation {
|
||||
* 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.
|
||||
@@ -40,16 +35,17 @@ export interface Conversation {
|
||||
condition_type: 0 | 1 | 2 | 3 | 4;
|
||||
}
|
||||
|
||||
export const conversation = {
|
||||
global: globalJSON as Conversation[],
|
||||
};
|
||||
export async function conversation(): Promise<Conversation[]> {
|
||||
const resp = await fetch('/api/global/conversation');
|
||||
return resp.json();
|
||||
}
|
||||
|
||||
export const byChara = {
|
||||
global: globalJSON.reduce(
|
||||
export function byChara(convos: Conversation[]) {
|
||||
return convos.reduce(
|
||||
(m, c) => m.set(c.chara_id, (m.get(c.chara_id) ?? []).concat(c as Conversation)),
|
||||
new Map<Conversation['chara_id'], Conversation[]>(),
|
||||
),
|
||||
};
|
||||
new Map<number, Conversation[]>(),
|
||||
);
|
||||
}
|
||||
|
||||
export const locations: Record<Conversation['location'], { name: RegionalName; group: 1 | 2 | 3 | 4 | 5 }> = {
|
||||
110: { name: { en: 'right side front' }, group: 1 },
|
||||
@@ -74,12 +70,12 @@ function locCharas(convos: Conversation[], locGroup: 1 | 2 | 3 | 4 | 5) {
|
||||
return [...m].toSorted((a, b) => b[1] - a[1]); // descending
|
||||
}
|
||||
|
||||
export const groupPopulars = {
|
||||
global: {
|
||||
1: locCharas(conversation.global, 1),
|
||||
2: locCharas(conversation.global, 2),
|
||||
3: locCharas(conversation.global, 3),
|
||||
4: locCharas(conversation.global, 4),
|
||||
5: locCharas(conversation.global, 5),
|
||||
},
|
||||
export function groupPopulars(convos: Conversation[]) {
|
||||
return {
|
||||
1: locCharas(convos, 1),
|
||||
2: locCharas(convos, 2),
|
||||
3: locCharas(convos, 3),
|
||||
4: locCharas(convos, 4),
|
||||
5: locCharas(convos, 5),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
import skillGlobal from '../../../../global/skill.json';
|
||||
import groupGlobal from '../../../../global/skill-group.json';
|
||||
|
||||
/**
|
||||
* Skill data.
|
||||
*/
|
||||
@@ -323,22 +320,12 @@ export interface SkillGroup {
|
||||
skill_bad?: number;
|
||||
}
|
||||
|
||||
export const skills = {
|
||||
global: skillGlobal as Skill[],
|
||||
} as const;
|
||||
export async function skills(): Promise<Skill[]> {
|
||||
const resp = await fetch('/api/global/skill');
|
||||
return resp.json();
|
||||
}
|
||||
|
||||
export const skillGroups = {
|
||||
global: groupGlobal as SkillGroup[],
|
||||
} as const;
|
||||
|
||||
export const ZERO_SKILL: Readonly<Skill> = {
|
||||
skill_id: 0,
|
||||
name: 'invalid skill',
|
||||
description: 'an invalid skill was specified',
|
||||
group: 0,
|
||||
rarity: 1,
|
||||
group_rate: 1,
|
||||
wit_check: false,
|
||||
activations: [],
|
||||
icon_id: 0,
|
||||
} as const;
|
||||
export async function skillGroups(): Promise<SkillGroup[]> {
|
||||
const resp = await fetch('/api/global/skill-group');
|
||||
return resp.json();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import globalJSON from '../../../../global/spark.json';
|
||||
|
||||
/**
|
||||
* Sparks, or succession factors.
|
||||
*/
|
||||
@@ -48,6 +46,7 @@ export interface SparkEffect {
|
||||
value2: number;
|
||||
}
|
||||
|
||||
export const sparks = {
|
||||
global: globalJSON as Spark[],
|
||||
} as const;
|
||||
export async function sparks(): Promise<Spark[]> {
|
||||
const resp = await fetch('/api/global/spark');
|
||||
return resp.json();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import globalJSON from '../../../../global/uma.json';
|
||||
|
||||
/**
|
||||
* Uma or character card definitions.
|
||||
*/
|
||||
@@ -70,6 +68,7 @@ export interface Uma {
|
||||
|
||||
export type AptitudeLevel = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7;
|
||||
|
||||
export const uma = {
|
||||
global: globalJSON as Uma[],
|
||||
};
|
||||
export async function uma(): Promise<Uma[]> {
|
||||
const resp = await fetch('/api/global/uma');
|
||||
return resp.json();
|
||||
}
|
||||
|
||||
@@ -1,30 +1,42 @@
|
||||
<script lang="ts">
|
||||
import { character, charaNames } from '$lib/data/character';
|
||||
import { byChara, locations, groupPopulars } from '$lib/data/convo';
|
||||
import { character, charaNames, type Character } from '$lib/data/character';
|
||||
import { byChara, locations, groupPopulars, conversation, type Conversation } from '$lib/data/convo';
|
||||
import CharaPick from '$lib/CharaPick.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
const characters = character.global.filter((c) => byChara.global.has(c.chara_id));
|
||||
let conversations: Conversation[] = $state([]);
|
||||
const convoMap = $derived(byChara(conversations));
|
||||
const popular = $derived(groupPopulars(conversations));
|
||||
let characters: Character[] = $state([]);
|
||||
const names = $derived(charaNames(characters ?? []));
|
||||
const minSuggest = 8;
|
||||
|
||||
onMount(async () => {
|
||||
const [convos, charas] = await Promise.all([conversation(), character()]);
|
||||
conversations = convos;
|
||||
characters = charas.filter((c) => convoMap.has(c.chara_id));
|
||||
});
|
||||
|
||||
let charaID = $state(1001);
|
||||
let convo = $state(1);
|
||||
|
||||
const options = $derived(byChara.global.get(charaID) ?? []);
|
||||
const options = $derived(convoMap.get(charaID) ?? []);
|
||||
const cur = $derived(options.find((c) => c.number === convo));
|
||||
const cur1Name = $derived(cur?.chara_1 && charaNames.get(cur.chara_1)?.en);
|
||||
const cur2Name = $derived(cur?.chara_2 && charaNames.get(cur.chara_2)?.en);
|
||||
const cur3Name = $derived(cur?.chara_3 && charaNames.get(cur.chara_3)?.en);
|
||||
const cur1Name = $derived(cur?.chara_1 && names.get(cur.chara_1)?.en);
|
||||
const cur2Name = $derived(cur?.chara_2 && names.get(cur.chara_2)?.en);
|
||||
const cur3Name = $derived(cur?.chara_3 && names.get(cur.chara_3)?.en);
|
||||
const alone = $derived([cur?.chara_1, cur?.chara_2, cur?.chara_3].filter((x) => x != null).length == 1 ? ' alone' : '');
|
||||
const suggested = $derived.by(() => {
|
||||
const suggested = $derived.by(async () => {
|
||||
if (cur == null) {
|
||||
return [];
|
||||
}
|
||||
const u = groupPopulars.global[locations[cur.location].group].filter(
|
||||
(s) => charaNames.get(s[0]) != null && s[0] !== cur.chara_1 && s[0] !== cur.chara_2 && s[0] !== cur.chara_3,
|
||||
const u = popular[locations[cur.location].group].filter(
|
||||
(s) => names.get(s[0]) != null && s[0] !== cur.chara_1 && s[0] !== cur.chara_2 && s[0] !== cur.chara_3,
|
||||
);
|
||||
const r = u.length <= minSuggest ? u : u.filter((s) => s[1] >= u[minSuggest][1]);
|
||||
return r.map(([chara_id, count]) => ({ chara_id, count }));
|
||||
return r.map(([chara_id, count]) => ({ chara_id, chara_name: names.get(chara_id), count }));
|
||||
});
|
||||
const curLoc = $derived(cur != null ? locations[cur.location] : null);
|
||||
</script>
|
||||
|
||||
<h1 class="text-4xl">Lobby Conversations</h1>
|
||||
@@ -42,6 +54,9 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
{#await suggested}
|
||||
<div class="mt-4 w-full text-center text-3xl">Loading...</div>
|
||||
{:then suggested}
|
||||
{#if cur}
|
||||
<div class="shadow-sm transition-shadow hover:shadow-md">
|
||||
<div class="mt-8 flex text-center text-lg">
|
||||
@@ -54,7 +69,7 @@
|
||||
{/if}
|
||||
</div>
|
||||
<div class="flex w-full text-center text-lg">
|
||||
<span class="flex-1">at {locations[cur.location].name.en}</span>
|
||||
<span class="flex-1">at {curLoc?.name.en}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4 block text-center">
|
||||
@@ -62,12 +77,14 @@
|
||||
</div>
|
||||
<div class="mt-4 grid text-center shadow-sm transition-shadow ease-in hover:shadow-md hover:ease-out md:grid-cols-4">
|
||||
{#each suggested as s (s.chara_id)}
|
||||
<span>{charaNames.get(s.chara_id)?.en}: {s.count}×</span>
|
||||
<span>{s.chara_name?.en}: {s.count}×</span>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="mt-4 block text-center">
|
||||
<span>
|
||||
Set these characters to fixed positions (main, upgrades, story, races) to maximize the chance of getting this conversation.
|
||||
Set these characters to fixed positions (main, upgrades, story, races) to maximize the chance of getting this
|
||||
conversation.
|
||||
</span>
|
||||
</div>
|
||||
{/if}
|
||||
{/await}
|
||||
|
||||
@@ -20,13 +20,13 @@
|
||||
tocViewed = true;
|
||||
obs.disconnect();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$effect(() => {
|
||||
if (tocElem == null) {
|
||||
return;
|
||||
}
|
||||
const obs = new IntersectionObserver(observeTOC, {rootMargin: "20% 0px"});
|
||||
const obs = new IntersectionObserver(observeTOC, { rootMargin: '20% 0px' });
|
||||
obs.observe(tocElem);
|
||||
});
|
||||
|
||||
|
||||
@@ -20,12 +20,93 @@
|
||||
} from '$lib/race';
|
||||
import Skill from '$lib/Skill.svelte';
|
||||
import StatChart from '$lib/StatChart.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import Article from '../Article.svelte';
|
||||
import Sec from '../Sec.svelte';
|
||||
import * as skill from '$lib/data/skill';
|
||||
|
||||
let raceLen = $state(2000);
|
||||
let secSpeedStyle = $state(RunningStyle.FrontRunner);
|
||||
|
||||
let allSkillsList: skill.Skill[] = $state([]);
|
||||
onMount(async () => {
|
||||
allSkillsList = await skill.skills();
|
||||
});
|
||||
const allSkills = $derived(allSkillsList.reduce((m, s) => m.set(s.skill_id, s), new Map<number, skill.Skill>()));
|
||||
const skills = $derived({
|
||||
view: allSkills.get(100021),
|
||||
sfv: allSkills.get(100101),
|
||||
uma2: allSkills.get(100321),
|
||||
falcoUlt: allSkills.get(100461),
|
||||
palmerUlt: allSkills.get(100641),
|
||||
kfc: allSkills.get(110041),
|
||||
cacao: allSkills.get(110261),
|
||||
right: allSkills.get(200012),
|
||||
left: allSkills.get(200022),
|
||||
firm: allSkills.get(200152),
|
||||
compSpirit: allSkills.get(200282),
|
||||
professor: allSkills.get(200331),
|
||||
cornerAdept: allSkills.get(200332),
|
||||
cornerConn: allSkills.get(200341),
|
||||
rushingGale: allSkills.get(200371),
|
||||
conc: allSkills.get(200431),
|
||||
focus: allSkills.get(200432),
|
||||
centerStage: allSkills.get(200451),
|
||||
pp: allSkills.get(200452),
|
||||
ramp: allSkills.get(200462),
|
||||
nsm: allSkills.get(200491),
|
||||
nn: allSkills.get(200492),
|
||||
homestretchHaste: allSkills.get(200512),
|
||||
ttl: allSkills.get(200531),
|
||||
earlyLead: allSkills.get(200532),
|
||||
escapeArtist: allSkills.get(200541),
|
||||
fastPaced: allSkills.get(200542),
|
||||
unrestrained: allSkills.get(200551),
|
||||
encroaching: allSkills.get(200641),
|
||||
spurt: allSkills.get(200642),
|
||||
turboSprint: allSkills.get(200651),
|
||||
tunes: allSkills.get(200721),
|
||||
greed: allSkills.get(201081),
|
||||
speedEater: allSkills.get(201082),
|
||||
siphon: allSkills.get(201221),
|
||||
murmurGold: allSkills.get(201161),
|
||||
longStraights: allSkills.get(201172),
|
||||
blast: allSkills.get(201173),
|
||||
straights: allSkills.get(201242),
|
||||
corners: allSkills.get(201252),
|
||||
sixthSense: allSkills.get(201261),
|
||||
dd: allSkills.get(201262),
|
||||
topRunner: allSkills.get(201271),
|
||||
leadersPride: allSkills.get(201272),
|
||||
moxie: allSkills.get(201282),
|
||||
eyes: allSkills.get(201441),
|
||||
savvy: allSkills.get(201522),
|
||||
lucky7: allSkills.get(201562),
|
||||
gw: allSkills.get(201601),
|
||||
thh: allSkills.get(201611),
|
||||
loneWolf: allSkills.get(201641),
|
||||
slipstream: allSkills.get(201651),
|
||||
pto: allSkills.get(201661),
|
||||
risky: allSkills.get(202032),
|
||||
runaway: allSkills.get(202051),
|
||||
burningWIT: allSkills.get(210051),
|
||||
ignitedWIT: allSkills.get(210052),
|
||||
radiant: allSkills.get(210061),
|
||||
redshiftInherit: allSkills.get(900041),
|
||||
pulseInherit: allSkills.get(900061),
|
||||
anglingInherit: allSkills.get(900201),
|
||||
pumpInherit: allSkills.get(900271),
|
||||
inesInherit: allSkills.get(900311),
|
||||
uma2Inherit: allSkills.get(900321),
|
||||
beyondInherit: allSkills.get(900591),
|
||||
vcInherit: allSkills.get(900681),
|
||||
pastaInherit: allSkills.get(900141),
|
||||
kfcInherit: allSkills.get(910041),
|
||||
barcaroleInherit: allSkills.get(910151),
|
||||
cacaoInherit: allSkills.get(910261),
|
||||
mummyCreekInherit: allSkills.get(910451),
|
||||
});
|
||||
|
||||
function mean2(x: [number, number]): number {
|
||||
return (x[0] + x[1]) * 0.5;
|
||||
}
|
||||
@@ -193,7 +274,7 @@
|
||||
At the start of late race, if they have enough HP remaining for their last spurt, horses accelerate from the mid race base
|
||||
target speed to their spurt speed, which varies by speed stat, distance aptitude, running style, race distance, and guts stat,
|
||||
in decreasing order of effect. "Last spurt" and "last spurt phase" are different and unrelated things; the latter is only used
|
||||
mechanically in the condition for <Skill skill={200512} hint="homestretch haste" mention />.
|
||||
mechanically in the condition for <Skill skill={skills.homestretchHaste} mention />.
|
||||
</p>
|
||||
<p>
|
||||
Speed skills add a flat amount of target speed, generally +0.15 m/s for white skills, +0.25 m/s for double circle skills and
|
||||
@@ -204,8 +285,8 @@
|
||||
|
||||
<Sec h={3} id="runaway">Runaway</Sec>
|
||||
<p>
|
||||
The skill <Skill skill={202051} hint="runaway" /> converts front runners into the <i>Great Escape</i> running style. However,
|
||||
no player has ever uttered the words "Great Escape" when talking about Umamusume, presumably because Runaway is a much cooler
|
||||
The skill <Skill skill={skills.runaway} /> converts front runners into the <i>Great Escape</i> running style. However, no
|
||||
player has ever uttered the words "Great Escape" when talking about Umamusume, presumably because Runaway is a much cooler
|
||||
name. ("Great Escape" is a direct translation of Japanese 大逃げ <i>oonige</i>, whereas "Front Runner" is a more liberal
|
||||
localization of 逃げ <i>nige</i> that technically just means "escape.")
|
||||
</p>
|
||||
@@ -239,32 +320,31 @@
|
||||
</p>
|
||||
<ul class="mb-4 list-disc pl-4">
|
||||
<li>
|
||||
<Skill skill={900201} hint="angling" />, sometimes called Rod, is currently the second best skill in the game. Its condition
|
||||
<Skill skill={skills.anglingInherit} />, sometimes called Rod, is currently the second best skill in the game. Its condition
|
||||
is to be in first place on any late race corner, which is the case immediately at the start of late race on all medium
|
||||
tracks,
|
||||
<a href="#niigata-1600">all but one mile</a>, and some sprints.
|
||||
</li>
|
||||
<li>
|
||||
On long distance tracks, <Skill skill={900681} hint="vc" /> takes that role instead. The front two horses get it, and it has half
|
||||
On long distance tracks, <Skill skill={skills.vcInherit} /> takes that role instead. The front two horses get it, and it has half
|
||||
the acceleration value.
|
||||
</li>
|
||||
<li>
|
||||
On those sprints where Angling is dead, the front-specific option is <Skill skill={900141} hint="pasta" /> (VPP, or Pasta). Multi-front
|
||||
builds also have access to <Skill skill={910451} hint="mummy creek" /> (HCreek). It takes both of them to equal Angling, so such
|
||||
sprints may be better served gambling on <Skill skill={200651} hint="turbo sprint" mention />, <Skill
|
||||
skill={200371}
|
||||
hint="rushing gale"
|
||||
On those sprints where Angling is dead, the front-specific option is <Skill skill={skills.pastaInherit} /> (VPP, or Pasta). Multi-front
|
||||
builds also have access to <Skill skill={skills.mummyCreekInherit} /> (HCreek). It takes both of them to equal Angling, so such
|
||||
sprints may be better served gambling on <Skill skill={skills.turboSprint} mention />, <Skill
|
||||
skill={skills.rushingGale}
|
||||
mention
|
||||
/>, and possibly <Skill skill={200551} hint="unrestrained" mention /> instead. Front runners are especially strong on sprints
|
||||
for <a href="#spot-struggle">other reasons</a> anyway.
|
||||
/>, and possibly <Skill skill={skills.unrestrained} mention /> instead. Front runners are especially strong on sprints for
|
||||
<a href="#spot-struggle">other reasons</a> anyway.
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
<Skill skill={200491} hint="nsm" /> is the best skill in the game. Unfortunately, for the most part, it's bad on front runners;
|
||||
generally not a win condition. Activating NSM requires not being in first, which means whoever <i>was</i> used Angling and is
|
||||
pulling away from you before you accumulate the blocked time to activate it. That said, on VC tracks specifically, NSM or its
|
||||
white version <Skill skill={200492} hint="nn" mention /> can be an option for multi-front builds, since the two frontmost horses
|
||||
get VC and final corner lane movement hasn't happened.
|
||||
<Skill skill={skills.nsm} /> is the best skill in the game. Unfortunately, for the most part, it's bad on front runners; generally
|
||||
not a win condition. Activating NSM requires not being in first, which means whoever <i>was</i> used Angling and is pulling
|
||||
away from you before you accumulate the blocked time to activate it. That said, on VC tracks specifically, NSM or its white
|
||||
version <Skill skill={skills.nn} mention /> can be an option for multi-front builds, since the two frontmost horses get VC and final
|
||||
corner lane movement hasn't happened.
|
||||
</p>
|
||||
|
||||
<Sec h={2} id="positioning">Positioning Mechanics</Sec>
|
||||
@@ -357,14 +437,13 @@
|
||||
/>
|
||||
</div>
|
||||
<p>
|
||||
Front runners have access to the skill <Skill skill={201262} hint="dd" />, which forces a horse who uses it to move outward to
|
||||
a specific distance from the rail. DD almost always ends shortly before the horse has finished accelerating to early race
|
||||
speed, so it does not convert the move lane speed modifier into distance.
|
||||
Front runners have access to the skill <Skill skill={skills.dd} />, which forces a horse who uses it to move outward to a
|
||||
specific distance from the rail. DD almost always ends shortly before the horse has finished accelerating to early race speed,
|
||||
so it does not convert the move lane speed modifier into distance.
|
||||
</p>
|
||||
<p>
|
||||
We get advantage from move lane speed modifier by following DD with <Skill skill={200452} hint="pp" /> or <Skill
|
||||
skill={210052}
|
||||
hint="ignited wit"
|
||||
We get advantage from move lane speed modifier by following DD with <Skill skill={skills.pp} /> or <Skill
|
||||
skill={skills.ignitedWIT}
|
||||
/>. DD created an opportunity for those return skills to convert into huge forward speed. This setup is called
|
||||
<i>lane combo</i>.
|
||||
</p>
|
||||
@@ -379,13 +458,12 @@
|
||||
an efficient pickup as a short burst of high speed to gain position.
|
||||
</p>
|
||||
<p>
|
||||
The gold versions of lane combo skills – <Skill skill={201261} hint="gold dd" mention />, <Skill
|
||||
skill={200451}
|
||||
hint="gold pp"
|
||||
The gold versions of lane combo skills – <Skill skill={skills.sixthSense} mention />, <Skill
|
||||
skill={skills.centerStage}
|
||||
mention
|
||||
/>, <Skill skill={210051} hint="burning wit" mention /> – are excellent to take on parents, but they generally make lane combo
|
||||
itself less effective. They have stronger lane change movement boosts, which does not affect the forward speed boost and is likely
|
||||
to make it last a shorter time, since the horse will return to the rail more quickly.
|
||||
/>, <Skill skill={skills.burningWIT} mention /> – are excellent to take on parents, but they generally make lane combo itself
|
||||
less effective. They have stronger lane change movement boosts, which does not affect the forward speed boost and is likely to make
|
||||
it last a shorter time, since the horse will return to the rail more quickly.
|
||||
</p>
|
||||
<p>
|
||||
For the same reasons, Ignited WIT is a bit stronger than PP, because it has a <i>smaller</i> effect value and also a longer base
|
||||
@@ -509,9 +587,9 @@
|
||||
<p>
|
||||
For the most part, there's nothing you can do about the no-overtake zone. The exception to this is with Smart Falcon, who has
|
||||
a speed unique that can fire on any mid race straight. On Tokyo 1600 (both turf and dirt), the first corner is far enough into
|
||||
mid race that <Skill skill={100461} hint="falco ult" /> is likely to fire before entering the no-overtake zone, helping to propel
|
||||
her into a lead that other front runners can't challenge until the corner begins – which is especially strong because it's
|
||||
harder to pass on corners, and on those tracks, that corner lasts all the way into late race.
|
||||
mid race that <Skill skill={skills.falcoUlt} /> is likely to fire before entering the no-overtake zone, helping to propel her into
|
||||
a lead that other front runners can't challenge until the corner begins – which is especially strong because it's harder to
|
||||
pass on corners, and on those tracks, that corner lasts all the way into late race.
|
||||
</p>
|
||||
|
||||
<Sec h={2} id="skills">Skills</Sec>
|
||||
@@ -522,37 +600,34 @@
|
||||
</p>
|
||||
<ul class="mb-4 list-disc pl-4">
|
||||
<li>
|
||||
On miles, <Skill skill={201082} hint="speed eater" /> is the strongest speed skill in the game, because it is both a full strength
|
||||
speed skill (i.e. +0.15 target speed for base 3s) and a full strength speed debuff. It plays both offense and defense simultaneously.
|
||||
On miles, <Skill skill={skills.speedEater} /> is the strongest speed skill in the game, because it is both a full strength speed
|
||||
skill (i.e. +0.15 target speed for base 3s) and a full strength speed debuff. It plays both offense and defense simultaneously.
|
||||
Every front runner should have it on every mile. Speed Eater technically has a gold version, <Skill
|
||||
skill={201081}
|
||||
hint="gold speed eater"
|
||||
skill={skills.greed}
|
||||
mention
|
||||
/>, but Cygames apparently recognized that it must not ever be allowed to exist, because there's still no source of it on
|
||||
JP.
|
||||
</li>
|
||||
<li>
|
||||
<Skill skill={201611} hint="thh" /> is a full strength speed skill that is triggered by other skills, so it excels at stacking
|
||||
– triggering THH with another speed skill is very likely to secure a pass.
|
||||
<Skill skill={skills.thh} /> is a full strength speed skill that is triggered by other skills, so it excels at stacking –
|
||||
triggering THH with another speed skill is very likely to secure a pass.
|
||||
</li>
|
||||
<li>
|
||||
<Skill skill={200462} hint="ramp" /> is only a half strength speed skill (base 1.8s), but it fires upon overtake, which helps
|
||||
to turn that into a complete pass.
|
||||
<Skill skill={skills.ramp} /> is only a half strength speed skill (base 1.8s), but it fires upon overtake, which helps to turn
|
||||
that into a complete pass.
|
||||
</li>
|
||||
<li>
|
||||
<Skill skill={201661} hint="pto" /> and <Skill skill={201651} hint="slipstream" /> are mechanically similar full-strength speed
|
||||
skills with cooldowns, so they can fire multiple times per race. Slipstream requires not being in first, and it's always wasted
|
||||
if it triggers during the <a href="#no-zone">no-overtake zone</a>, so it's marginally weaker. Both want multi-front builds.
|
||||
<Skill skill={skills.pto} /> and <Skill skill={skills.slipstream} /> are mechanically similar full-strength speed skills with
|
||||
cooldowns, so they can fire multiple times per race. Slipstream requires not being in first, and it's always wasted if it triggers
|
||||
during the <a href="#no-zone">no-overtake zone</a>, so it's marginally weaker. Both want multi-front builds.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<Sec h={3} id="gate-skills">Gate Skills</Sec>
|
||||
<p>
|
||||
Gate skills are <Skill skill={201601} hint="gw" /> (GW), <Skill skill={200532} hint="early lead" />, and <Skill
|
||||
skill={200431}
|
||||
hint="conc"
|
||||
/> (Conc), as well as all green skills including <Skill skill={202051} hint="runaway" mention /> (but excluding <Skill
|
||||
skill={201562}
|
||||
hint="lucky 7"
|
||||
Gate skills are <Skill skill={skills.gw} /> (GW), <Skill skill={skills.earlyLead} />, and <Skill skill={skills.conc} /> (Conc),
|
||||
as well as all green skills including <Skill skill={skills.runaway} mention /> (but excluding <Skill
|
||||
skill={skills.lucky7}
|
||||
mention
|
||||
/>). These skills activate the moment the race starts. Other running styles can largely ignore them, but for front runners,
|
||||
they are critical.
|
||||
@@ -574,33 +649,31 @@
|
||||
/>
|
||||
</div>
|
||||
<p>
|
||||
GW must be combined with <Skill skill={200532} hint="el" /> if you want any chance of being first out of early race. The gold version
|
||||
of EL, <Skill skill={200531} hint="ttl" />, is highly accessible as the skill from the Mihono Bourbon Wit event SSR. In
|
||||
practice, I've found it adds fewer lengths over the white, and hence less positioning ability, than a mid race gold speed
|
||||
skill. It is still absolutely <i>good</i>, and Bourbon Wit is a very usable card (treat her as a speed card that gives extra
|
||||
energy on wit), but I don't consider it mandatory anymore.
|
||||
GW must be combined with <Skill skill={skills.earlyLead} /> if you want any chance of being first out of early race. The gold version
|
||||
of EL, <Skill skill={skills.ttl} />, is highly accessible as the skill from the Mihono Bourbon Wit event SSR. In practice,
|
||||
I've found it adds fewer lengths over the white, and hence less positioning ability, than a mid race gold speed skill. It is
|
||||
still absolutely <i>good</i>, and Bourbon Wit is a very usable card (treat her as a speed card that gives extra energy on
|
||||
wit), but I don't consider it mandatory anymore.
|
||||
</p>
|
||||
<p>
|
||||
Conc is less critical. It's worth taking on horses who have it, but it isn't worth using support card slots just to get it. On
|
||||
the other hand, its white version, <Skill skill={200432} hint="focus" />, is bad; its only real use is as a backup gate skill
|
||||
for GW when you don't have enough greens available.
|
||||
the other hand, its white version, <Skill skill={skills.focus} />, is bad; its only real use is as a backup gate skill for GW
|
||||
when you don't have enough greens available.
|
||||
</p>
|
||||
|
||||
<Sec h={3} id="spurt-skills">Spurt Skills</Sec>
|
||||
<p>
|
||||
Because they are post-Angling, skills that activate in the final spurt are typically less interesting to front runners.
|
||||
Notable exceptions are <Skill skill={910151} hint="barcarole" /> and, on Tokyo turf, <Skill
|
||||
skill={900311}
|
||||
hint="ines inherit"
|
||||
Notable exceptions are <Skill skill={skills.barcaroleInherit} /> and, on Tokyo turf, <Skill
|
||||
skill={skills.inesInherit}
|
||||
/><!-- skill name ends with ! -->
|
||||
These are good inherits for those who don't have easy access to <Skill skill={910261} hint="cacao" mention /> and <Skill
|
||||
skill={910041}
|
||||
hint="kfc"
|
||||
These are good inherits for those who don't have easy access to <Skill skill={skills.cacaoInherit} mention /> and <Skill
|
||||
skill={skills.kfcInherit}
|
||||
mention
|
||||
/>.
|
||||
</p>
|
||||
<p>
|
||||
<Skill skill={900061} hint="pulse" /> is another spurt skill that may come up sometimes and is interesting to think about. It's
|
||||
<Skill skill={skills.pulseInherit} /> is another spurt skill that may come up sometimes and is interesting to think about. It's
|
||||
a 0.25 speed skill that requires being in at best second place to activate. Is it worth it to take?
|
||||
</p>
|
||||
<p>
|
||||
@@ -618,9 +691,8 @@
|
||||
<Sec h={3} id="others-skills">Other Horses' Skills</Sec>
|
||||
<p>There are two categories of other horses' skills to think about.</p>
|
||||
<p>
|
||||
The first is stamina debuffs: <Skill skill={201441} hint="eyes" />, <Skill skill={201161} hint="murmur" />, <Skill
|
||||
skill={201221}
|
||||
hint="siphon"
|
||||
The first is stamina debuffs: <Skill skill={skills.eyes} />, <Skill skill={skills.murmurGold} />, <Skill
|
||||
skill={skills.siphon}
|
||||
/>. My conclusion is that Global doesn't understand how to build debuffers, so front runners can mostly ignore these –
|
||||
assume one will hit you, but not three.
|
||||
</p>
|
||||
@@ -631,9 +703,9 @@
|
||||
</p>
|
||||
<p>
|
||||
The other category of skills to think about is other horses' uniques.
|
||||
<Skill skill={100101} hint="sfv" />, <Skill skill={100321} hint="u=ma2" />, and a number of others need tight positioning,
|
||||
requiring something like 2-4 or 3-4 in CM. The number of front runners in the match can dictate whether it's ever possible for
|
||||
those uniques to activate. This is the fundamental idea behind <a href="#triple-front">triple front</a> builds.
|
||||
<Skill skill={skills.sfv} />, <Skill skill={skills.uma2} />, and a number of others need tight positioning, requiring
|
||||
something like 2-4 or 3-4 in CM. The number of front runners in the match can dictate whether it's ever possible for those
|
||||
uniques to activate. This is the fundamental idea behind <a href="#triple-front">triple front</a> builds.
|
||||
</p>
|
||||
|
||||
<Sec h={3} id="skill-timing">Skill Timing</Sec>
|
||||
@@ -692,11 +764,10 @@
|
||||
the early and mid race skills you can manage.
|
||||
<a href="#gate-skills">Gate skills</a> are especially important, because runaways have a tremendously higher early race target
|
||||
speed. If there is a real difference between a correctly built runaway blocker and a runaway ace, it's that <Skill
|
||||
skill={910261}
|
||||
hint="cacao"
|
||||
skill={skills.cacaoInherit}
|
||||
mention
|
||||
/>
|
||||
and <Skill skill={910041} hint="kfc" mention /> are arguably more appropriate inherits than Angling, but the argument isn't strong
|
||||
and <Skill skill={skills.kfcInherit} mention /> are arguably more appropriate inherits than Angling, but the argument isn't strong
|
||||
if you're still able to hit a good stat line on your runaway.
|
||||
</p>
|
||||
<p>
|
||||
@@ -729,21 +800,19 @@
|
||||
<Sec h={3} id="long-double-front">Long Double Front</Sec>
|
||||
<p>
|
||||
At long distances, double front has different implications.
|
||||
<Skill skill={900681} hint="vc" /> is the front runner win condition, and the front two horses both get it. With late race being
|
||||
before the final corner and hence extra move lane not having started, you can take advantage of <Skill
|
||||
skill={200492}
|
||||
hint="nn"
|
||||
/> to turn the <i>second place</i> front runner into the winner.
|
||||
<Skill skill={skills.vcInherit} /> is the front runner win condition, and the front two horses both get it. With late race being
|
||||
before the final corner and hence extra move lane not having started, you can take advantage of <Skill skill={skills.nn} /> to turn
|
||||
the <i>second place</i> front runner into the winner.
|
||||
</p>
|
||||
<p>
|
||||
Building for second place to bunny with NN does not mean manipulating stats and skills to force one of the front runners into
|
||||
second. Both fronts need to be strong enough to be adjacent at late race start, and you have to beat other people's front
|
||||
runners, too. (Especially since VC and <Skill skill={200641} hint="encroaching" mention /> are currently the only consistent accels
|
||||
for long distance.) So, double front for long is ultimately about the same as double front for other distances, just with different
|
||||
runners, too. (Especially since VC and <Skill skill={skills.encroaching} mention /> are currently the only consistent accels for
|
||||
long distance.) So, double front for long is ultimately about the same as double front for other distances, just with different
|
||||
goals when choosing the legacy.
|
||||
</p>
|
||||
<p>
|
||||
Given that NN is good, it's also worth considering the gold version, <Skill skill={200491} hint="nsm" /><!-- ends with ! -->
|
||||
Given that NN is good, it's also worth considering the gold version, <Skill skill={skills.nsm} /><!-- ends with ! -->
|
||||
NSM is a better skill for the long double front build, but for now, the only way to get it while running MANT is from Yukino Bijin
|
||||
Wit. That card's numbers are not great. It's still possible to get a good stat line using her, but it will take more careers to
|
||||
get there than to just get NN from Fine Motion.
|
||||
@@ -752,8 +821,7 @@
|
||||
If you're feeling adventurous, runaway is another consideration for double (and triple) front on long distances. Your ace
|
||||
(hopefully) still gets VC, but the runaway paces up the race. As mentioned in the <a href="#solo-front">solo front</a>
|
||||
section, this especially punishes end closers, who tend to be popular on long tracks because of <Skill
|
||||
skill={200642}
|
||||
hint="straight spurt"
|
||||
skill={skills.spurt}
|
||||
mention
|
||||
/>. It also keeps your ace in <a href="#front-modes">overtake mode</a>, which is better than speed-up mode, for position keep.
|
||||
</p>
|
||||
@@ -771,9 +839,8 @@
|
||||
One type of support that all front runners do automatically is helping to kill position-based pace chaser skills. Such skills
|
||||
have conditions that translate into needing to be in 3rd or 4th, or sometimes 2nd through 4th, to activate. When you're
|
||||
bringing three front runners, if anyone else brings a single other one, they're going to occupy 2-4 naturally. If there happen
|
||||
to be three others, then even late/end win cons like <Skill skill={900591} hint="beyond" mention /> and <Skill
|
||||
skill={900271}
|
||||
hint="pump"
|
||||
to be three others, then even late/end win cons like <Skill skill={skills.beyondInherit} mention /> and <Skill
|
||||
skill={skills.pumpInherit}
|
||||
mention
|
||||
/> are dead.
|
||||
</p>
|
||||
@@ -794,10 +861,9 @@
|
||||
An SS support doesn't strictly need as much in the way of mid race skills, since her main job is to give the others overtake
|
||||
mode and then be passed. It's nonetheless a good idea to take those skills for less risk if your other fronts have a poor
|
||||
showing. In addition to the normal front win cons, it's potentially strong to take unconditional gambles like <Skill
|
||||
skill={200341}
|
||||
hint="corner conn"
|
||||
skill={skills.cornerConn}
|
||||
mention
|
||||
/> and <Skill skill={210061} hint="radiant" mention />.
|
||||
/> and <Skill skill={skills.radiant} mention />.
|
||||
</p>
|
||||
<p>
|
||||
SS supports do best on medium and long tracks, because you want to be building <i>everyone</i> for spot struggle on miles and
|
||||
@@ -808,11 +874,7 @@
|
||||
<Sec h={3} id="chariot">Chariot</Sec>
|
||||
<p>
|
||||
A front runner build that I have seen but not attempted is the chariot: a runaway with a strong mid race but insufficient HP
|
||||
to spurt stays in front of one or two other front runners who have <Skill
|
||||
skill={200491}
|
||||
hint="nsm"
|
||||
mention
|
||||
/><!-- ends with ! -->
|
||||
to spurt stays in front of one or two other front runners who have <Skill skill={skills.nsm} mention /><!-- ends with ! -->
|
||||
</p>
|
||||
<p>
|
||||
I saw a team using a chariot in CM13 round 2 day 2; that team had an overall eleven wins at the time. Maybe their horses just
|
||||
@@ -828,7 +890,7 @@
|
||||
<p>Most front runners enjoy easy careers thanks to strong kits and little chance to be blocked.</p>
|
||||
<p>
|
||||
Currently, this chapter is about MANT (a.k.a. Trackblazer). Unity Cup is still useful – obviously for runaways, but also
|
||||
for spinning up an <Skill skill={210052} hint="ignited wit" mention /> legacy.
|
||||
for spinning up an <Skill skill={skills.ignitedWIT} mention /> legacy.
|
||||
</p>
|
||||
|
||||
<Sec h={3} id="support-cards">Support Cards</Sec>
|
||||
@@ -838,47 +900,41 @@
|
||||
</p>
|
||||
<ul class="mb-4 list-disc pl-4">
|
||||
<li>
|
||||
Ines Fujin gives <Skill skill={201082} hint="speed eater" mention />, <Skill skill={201661} hint="pto" mention />, and <Skill
|
||||
skill={201651}
|
||||
hint="slipstream"
|
||||
Ines Fujin gives <Skill skill={skills.speedEater} mention />, <Skill skill={skills.pto} mention />, and <Skill
|
||||
skill={skills.slipstream}
|
||||
mention
|
||||
/>. Her guts SSR is the Kitasan Black of guts cards, with 15% training effectiveness and 80 specialty priority. She also has
|
||||
a relatively new wit SR that is decently strong even at LB0, though still objectively beaten by Marv SR until MLB.
|
||||
</li>
|
||||
<li>
|
||||
Marvelous Sunday, both power SSR and wit SR versions, give <Skill skill={200462} hint="ramp" mention /> and <Skill
|
||||
skill={201611}
|
||||
hint="thh"
|
||||
Marvelous Sunday, both power SSR and wit SR versions, give <Skill skill={skills.ramp} mention /> and <Skill
|
||||
skill={skills.thh}
|
||||
mention
|
||||
/> as hints. The SSR has 15% race bonus, while the SR has 10% race bonus and gives +3 hints. The numbers on both are otherwise
|
||||
disappointing, but those elements alone are enough to justify using them.
|
||||
</li>
|
||||
<li>
|
||||
Cards that give generic or distance-specific gold speed skills, especially mid race ones, are very valuable to front
|
||||
runners. Since <Skill skill={200331} hint="professor" mention /> is strong, Kitasan Black is still around despite only 5% race
|
||||
bonus. El Condor Pasa gives <Skill skill={200721} hint="tunes" mention />.
|
||||
runners. Since <Skill skill={skills.professor} mention /> is strong, Kitasan Black is still around despite only 5% race bonus.
|
||||
El Condor Pasa gives <Skill skill={skills.tunes} mention />.
|
||||
</li>
|
||||
<li>
|
||||
For parent runs, Smart Falcon SSR is mandatory. She gives guaranteed <Skill skill={201601} hint="gw" mention /> in her chain,
|
||||
and her gold skill is <Skill skill={200451} hint="gold pp" mention />, which you want for building a
|
||||
For parent runs, Smart Falcon SSR is mandatory. She gives guaranteed <Skill skill={skills.gw} mention /> in her chain, and her
|
||||
gold skill is <Skill skill={skills.centerStage} mention />, which you want for building a
|
||||
<a href="#lane-combo">lane combo</a> legacy. On ace runs, she is acceptable if you own her at MLB, but you'd rather get her skills
|
||||
from inheritance and use the card slot for a strong speed skill.
|
||||
</li>
|
||||
<li>
|
||||
Seiun Sky SSR is another good parent card for parents. Her chain starts with <Skill skill={201262} hint="dd" mention /> and ends
|
||||
with
|
||||
<Skill skill={200541} hint="escape artist" mention /> (albeit agemasen). She also carries a <Skill
|
||||
skill={201611}
|
||||
hint="thh"
|
||||
mention
|
||||
/> hint. Unfortunately, between being a stamina card and not being Super Creek, she isn't viable for ace runs.
|
||||
Seiun Sky SSR is another good parent card for parents. Her chain starts with <Skill skill={skills.dd} mention /> and ends with
|
||||
<Skill skill={skills.escapeArtist} mention /> (albeit agemasen). She also carries a <Skill skill={skills.thh} mention /> hint.
|
||||
Unfortunately, between being a stamina card and not being Super Creek, she isn't viable for ace runs.
|
||||
</li>
|
||||
<li>Other parenting cards include Kawakami Princess speed and Hishi Akebono guts, for gold versions of lane combo skills.</li>
|
||||
</ul>
|
||||
<p>
|
||||
A future sight advisory: Maruzensky's speed SSR is coming in early July. At this point, you should probably be saving all your
|
||||
carats for her. She is an extremely strong stat stick and gives <Skill skill={201271} hint="top runner" mention />, the gold
|
||||
version of <Skill skill={201272} hint="leader's pride" mention />.
|
||||
carats for her. She is an extremely strong stat stick and gives <Skill skill={skills.topRunner} mention />, the gold version
|
||||
of <Skill skill={skills.leadersPride} mention />.
|
||||
</p>
|
||||
|
||||
<Sec h={3} id="career-skills">Taking Skills</Sec>
|
||||
@@ -890,38 +946,37 @@
|
||||
your chance of getting skills you don't have hints for.
|
||||
</p>
|
||||
<p>
|
||||
<Skill skill={200532} hint="early lead" /> is a snap take skill. The <i>only</i> time to sit on EL is when you happen to get
|
||||
the first +1 hint the turn before inspiration. (Even then, I'd probably still take it, since there's still a race to run.)
|
||||
Early Lead is one of the strongest skills in terms of lengths gained, it applies to all tracks and conditions, and
|
||||
<Skill skill={skills.earlyLead} /> is a snap take skill. The <i>only</i> time to sit on EL is when you happen to get the first
|
||||
+1 hint the turn before inspiration. (Even then, I'd probably still take it, since there's still a race to run.) Early Lead is
|
||||
one of the strongest skills in terms of lengths gained, it applies to all tracks and conditions, and
|
||||
<i>it saves late starts</i>, which are your only source of losses on most races after junior year. Moreover, it has a base
|
||||
cost of only 120 SP; even if you do get Fast Learner after taking it, your opportunity cost was 12 SP. If you prune EL and a
|
||||
hint lands on <Skill skill={200542} hint="fast-paced" mention /> or <Skill skill={201272} hint="leader's pride" mention /> instead,
|
||||
you gave up that potential 12 SP to save 18. It's incredibly good to take early.
|
||||
hint lands on <Skill skill={skills.fastPaced} mention /> or <Skill skill={skills.leadersPride} mention /> instead, you gave up that
|
||||
potential 12 SP to save 18. It's incredibly good to take early.
|
||||
</p>
|
||||
<p>
|
||||
On parent runs, or exactly one of your three CM horses, <Skill skill={201641} hint="lone wolf" /> is another snap take. Base cost
|
||||
of 60 SP for +40 speed, which can secure a lot of races, especially early in career. Be extremely careful not to take it on multiple
|
||||
horses on a team. Save and quit from the career if you need to check. It's technically better to have it on two horses than zero,
|
||||
but it's tremendously better than that to have it on one.
|
||||
On parent runs, or exactly one of your three CM horses, <Skill skill={skills.loneWolf} /> is another snap take. Base cost of 60
|
||||
SP for +40 speed, which can secure a lot of races, especially early in career. Be extremely careful not to take it on multiple horses
|
||||
on a team. Save and quit from the career if you need to check. It's technically better to have it on two horses than zero, but it's
|
||||
tremendously better than that to have it on one.
|
||||
</p>
|
||||
<p>
|
||||
<Skill skill={900201} hint="angling" /> is a strong consideration as a mid-career take. Inheritance events are more likely to activate
|
||||
<Skill skill={skills.anglingInherit} /> is a strong consideration as a mid-career take. Inheritance events are more likely to activate
|
||||
green sparks than white sparks, so the risk of missing out on SP by taking it early is higher. However, Angling is an almost automatic
|
||||
win condition for career (outside of <a href="#3k">3Ks</a> and <a href="#niigata-1600">Niigata 1600</a>). Taking Angling early
|
||||
can save a lot of clocks, and it can rescue runs that don't get what is normally the minimum speed to win races before summer.
|
||||
</p>
|
||||
<p>
|
||||
I've had debate about this one, but I feel that <Skill skill={201522} hint="savvy" /> is a skill you will pretty much always want
|
||||
at least the first level of. Wit is a strong stat for front runners, and Savvy is a guaranteed Groundwork trigger. It's also the
|
||||
second cheapest front-specific skill, after Dodging Danger. On parent runs, it could arguably be worth sitting on it until the +2
|
||||
or +3 hint, because taking the second level gives a slightly boosted chance to generate the spark, and hints save twice as much
|
||||
SP on the double circle.
|
||||
I've had debate about this one, but I feel that <Skill skill={skills.savvy} /> is a skill you will pretty much always want at least
|
||||
the first level of. Wit is a strong stat for front runners, and Savvy is a guaranteed Groundwork trigger. It's also the second cheapest
|
||||
front-specific skill, after Dodging Danger. On parent runs, it could arguably be worth sitting on it until the +2 or +3 hint, because
|
||||
taking the second level gives a slightly boosted chance to generate the spark, and hints save twice as much SP on the double circle.
|
||||
</p>
|
||||
<p>
|
||||
<Skill skill={201242} hint="front straights" /> and <Skill skill={201252} hint="front corners" /> are strong and cheap. If you've
|
||||
taken Early Lead and Angling, they probably won't change the outcomes of any races, but it's still reasonable to take the first
|
||||
level to prune. As a corollary, outside parent runs, you should have a specific distance in mind, so your distance straights/corners
|
||||
should usually be even quicker takes.
|
||||
<Skill skill={skills.straights} /> and <Skill skill={skills.corners} /> are strong and cheap. If you've taken Early Lead and Angling,
|
||||
they probably won't change the outcomes of any races, but it's still reasonable to take the first level to prune. As a corollary,
|
||||
outside parent runs, you should have a specific distance in mind, so your distance straights/corners should usually be even quicker
|
||||
takes.
|
||||
</p>
|
||||
|
||||
<Sec h={3} id="niigata-1600">Niigata Junior Stakes</Sec>
|
||||
@@ -969,9 +1024,9 @@
|
||||
tested much without them, because I don't like throwing away my runs.
|
||||
</p>
|
||||
<p>
|
||||
<Skill skill={201282} hint="moxie" /> is the only front-specific recovery skill you can get from MANT rivals. It also is a guaranteed
|
||||
option in Bourbon Wit's first chain event. That makes it pretty often available for the 3Ks. However, if you end up overstam at
|
||||
the end of the run, buying Moxie can be as much as -162 SP, which is certainly not a trivial amount.
|
||||
<Skill skill={skills.moxie} /> is the only front-specific recovery skill you can get from MANT rivals. It also is a guaranteed option
|
||||
in Bourbon Wit's first chain event. That makes it pretty often available for the 3Ks. However, if you end up overstam at the end
|
||||
of the run, buying Moxie can be as much as -162 SP, which is certainly not a trivial amount.
|
||||
</p>
|
||||
<p>
|
||||
An alternative option to buying a recovery is to switch to Late Surger for those races. I've won Kikuka Sho with circa 300
|
||||
@@ -1005,44 +1060,36 @@
|
||||
<ul class="mb-4 list-disc pl-4">
|
||||
<li>
|
||||
Valentine's Mihono Bourbon (VBourbon) is the easiest font runner to train because she has <Skill
|
||||
skill={201601}
|
||||
hint="gw"
|
||||
skill={skills.gw}
|
||||
mention
|
||||
/> built in, whereas most others have to get it from either inheritance or cards that aren't terribly strong. She is also the
|
||||
strongest front runner, because <Skill skill={110261} hint="cacao" mention /> is full strength, mid race, extremely forgiving
|
||||
in activation, and even has a heal. And she has <Skill skill={200431} hint="conc" mention /> and <Skill
|
||||
skill={200541}
|
||||
hint="escape artist"
|
||||
mention
|
||||
/> built in, both strong distance-agnostic front runner skills with awkward sources otherwise. And she's a great parent for all
|
||||
the same reasons that her unique is strong (except that the heal becomes irrelevant).
|
||||
strongest front runner, because <Skill skill={skills.cacao} mention /> is full strength, mid race, extremely forgiving in activation,
|
||||
and even has a heal. And she has <Skill skill={skills.conc} mention /> and <Skill skill={skills.escapeArtist} mention /> built
|
||||
in, both strong distance-agnostic front runner skills with awkward sources otherwise. And she's a great parent for all the same
|
||||
reasons that her unique is strong (except that the heal becomes irrelevant).
|
||||
</li>
|
||||
<li>
|
||||
Summer Maruzensky (SMaru or KFC) is just shy of VBourbon in strength with her unique, <Skill
|
||||
skill={110041}
|
||||
hint="kfc"
|
||||
mention
|
||||
/>. It uses a heal to trigger instead of having a heal built in, but that means it sometimes has carryover potential. Using
|
||||
Summer Maruzensky (SMaru or KFC) is just shy of VBourbon in strength with her unique, <Skill skill={skills.kfc} mention />.
|
||||
It uses a heal to trigger instead of having a heal built in, but that means it sometimes has carryover potential. Using
|
||||
VBourbon as a parent for SMaru works as a trigger, too, which is especially good for shorter distances that don't want to
|
||||
spend SP on pure recoveries.
|
||||
</li>
|
||||
<li>
|
||||
Seiun Sky is the source of <Skill skill={900201} hint="angling" mention /> and therefore the best horse for front runner parenting
|
||||
Seiun Sky is the source of <Skill skill={skills.anglingInherit} mention /> and therefore the best horse for front runner parenting
|
||||
in the game, forever. As a runner, she is outshone by the former two and others who will come later, but she is an excellent choice
|
||||
for a <a href="#double-front">second front runner</a> in a team comp.
|
||||
</li>
|
||||
<li>
|
||||
Kitasan Black is the definitive front runner of long distance, both as a parent and as a competitor.
|
||||
<Skill skill={201173} hint="blast" mention /> is the gold version of <Skill skill={201172} hint="long straights" mention />,
|
||||
which is extremely strong to have built in (especially noting that hints on Long Straights take 27 SP off the price of
|
||||
Blast).
|
||||
<Skill skill={skills.blast} mention /> is the gold version of <Skill skill={skills.longStraights} mention />, which is
|
||||
extremely strong to have built in (especially noting that hints on Long Straights take 27 SP off the price of Blast).
|
||||
</li>
|
||||
<li>
|
||||
Silence Suzuka and Mejiro Palmer are currently the only runaways in the game. Both of them have uniques that are
|
||||
inconsistent normally but very consistent as runaways:
|
||||
<Skill skill={100021} hint="view" mention /> and <Skill skill={100641} hint="palmer" mention />. Outside of Team Trials,
|
||||
runaways aren't very useful in the MANT era. (My Suzuka runaway remains my #1 top scorer in TT, though. Runaway and Conc are
|
||||
both busted for points.)
|
||||
<Skill skill={skills.view} mention /> and <Skill skill={skills.palmerUlt} mention />. Outside of Team Trials, runaways
|
||||
aren't very useful in the MANT era. (My Suzuka runaway remains my #1 top scorer in TT, though. Runaway and Conc are both
|
||||
busted for points.)
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
@@ -1053,8 +1100,8 @@
|
||||
<Sec h={3} id="coc">Christmas Oguri Cap</Sec>
|
||||
<p>
|
||||
As is perhaps expected, Christmas Oguri Cap (COC) is very strong as a front runner on specific tracks. The front-specific heal
|
||||
is <Skill skill={201282} hint="moxie" mention />, which activates at the very start of the first uphill. When that first
|
||||
uphill is at the start of late race, as in the case of Tokyo 1600 Dirt, COC is online as a front runner.
|
||||
is <Skill skill={skills.moxie} mention />, which activates at the very start of the first uphill. When that first uphill is at
|
||||
the start of late race, as in the case of Tokyo 1600 Dirt, COC is online as a front runner.
|
||||
</p>
|
||||
<p>
|
||||
I've been told COC is very hard to train as a front runner. Something about aptitudes. I don't have any variety of Oguri, but
|
||||
@@ -1062,8 +1109,7 @@
|
||||
</p>
|
||||
<p>
|
||||
Another rare manifestation of Front COC is as a third place horse in a <a href="#triple-front">triple front</a> build where <Skill
|
||||
skill={900321}
|
||||
hint="u=ma2"
|
||||
skill={skills.uma2Inherit}
|
||||
mention
|
||||
/> is strong. I convinced Werseter, the Umadump guy, to try this for CM12 after he accidentally made an 8★ front Tachyon parent.
|
||||
He reported a 7% win rate for her. (But a much higher win rate overall – after all, he was using triple front.)
|
||||
@@ -1111,37 +1157,36 @@
|
||||
<p>Front runners are more reliant than other styles on getting certain skills from inspiration:</p>
|
||||
<ul class="mb-4 list-disc pl-4">
|
||||
<li>
|
||||
Building a full <Skill skill={201601} hint="gw" /> legacy is the first step to front runner training. Fronts without it are non-competitive
|
||||
Building a full <Skill skill={skills.gw} /> legacy is the first step to front runner training. Fronts without it are non-competitive
|
||||
even as supports. The cards that give it aren't great for ace builds. There is no gold version of it yet, so getting it from inheritance
|
||||
is truly ideal.
|
||||
</li>
|
||||
<li>
|
||||
<Skill skill={200452} hint="pp" /> similarly doesn't come from good cards (since Sweep Tosho has fallen off). As a piece of
|
||||
<Skill skill={skills.pp} /> similarly doesn't come from good cards (since Sweep Tosho has fallen off). As a piece of
|
||||
<a href="#lane-combo">lane combo</a>, it isn't applicable to every race, but it's very strong when it is. The white skill is
|
||||
better than the gold skill, so it is another ideal inherit.
|
||||
</li>
|
||||
<li>
|
||||
<Skill skill={210052} hint="ignited wit" /> is the stronger lane combo piece. The only sources of it are inheritance and Unity
|
||||
Cup; which is to say, the source of it is inheritance. When searching databases for borrows, looking for Ignited WIT is a shortcut
|
||||
for listing good front runner legacies, since it's only valuable to fronts and somewhat hard to get even when you focus on it.
|
||||
<Skill skill={skills.ignitedWIT} /> is the stronger lane combo piece. The only sources of it are inheritance and Unity Cup; which
|
||||
is to say, the source of it is inheritance. When searching databases for borrows, looking for Ignited WIT is a shortcut for listing
|
||||
good front runner legacies, since it's only valuable to fronts and somewhat hard to get even when you focus on it.
|
||||
</li>
|
||||
<li>
|
||||
Almost all green skills are valuable to inherit at one point or another as GW triggers.
|
||||
<Skill skill={200012} hint="right" /> and <Skill skill={200022} hint="left" /> are particularly good; one of the two is always
|
||||
the best green available for a race.
|
||||
<Skill skill={200152} hint="firm" /> is a bit less strong, and slightly superseded by the existence of Narita Top Road, but it
|
||||
applies to the majority of CM races. Season greens are great, but a bit narrow; distance greens are good. Weather greens are acceptable,
|
||||
<Skill skill={skills.right} /> and <Skill skill={skills.left} /> are particularly good; one of the two is always the best green
|
||||
available for a race.
|
||||
<Skill skill={skills.firm} /> is a bit less strong, and slightly superseded by the existence of Narita Top Road, but it applies
|
||||
to the majority of CM races. Season greens are great, but a bit narrow; distance greens are good. Weather greens are acceptable,
|
||||
but while guts is better on front runners than other styles, it isn't good.
|
||||
<Skill skill={200282} hint="comp spirit" /> is good if you like to do <a href="#triple-front">triple front</a> builds,
|
||||
because it activates when there are four of the runner's style in CM.
|
||||
<Skill skill={201522} hint="savvy" /> is slightly less valuable as an inherit, since it can come from rivals.
|
||||
<Skill skill={skills.compSpirit} /> is good if you like to do <a href="#triple-front">triple front</a> builds, because it
|
||||
activates when there are four of the runner's style in CM.
|
||||
<Skill skill={skills.savvy} /> is slightly less valuable as an inherit, since it can come from rivals.
|
||||
</li>
|
||||
<li>
|
||||
All generic speed skills that aren't strictly late race are good inherits.
|
||||
<Skill skill={202032} hint="risky" /> is the best one by ratio of strength to difficulty to acquire.
|
||||
<Skill skill={201611} hint="thh" />, <Skill skill={201661} hint="pto" />, <Skill skill={200462} hint="ramp" />, and <Skill
|
||||
skill={200332}
|
||||
hint="corner adept"
|
||||
<Skill skill={skills.risky} /> is the best one by ratio of strength to difficulty to acquire.
|
||||
<Skill skill={skills.thh} />, <Skill skill={skills.pto} />, <Skill skill={skills.ramp} />, and <Skill
|
||||
skill={skills.cornerAdept}
|
||||
/> are also strong, but available as hints or chain skills from some usable-to-good cards.
|
||||
</li>
|
||||
<li>Obviously, getting front-runner-specific skills from inheritance makes them cheaper and more consistent to get.</li>
|
||||
@@ -1300,7 +1345,7 @@
|
||||
|
||||
<Sec h={3} id="cm13">CM13 – Taurus Cup (Tokyo Derby)</Sec>
|
||||
<p>
|
||||
Maruzensky's unique, <Skill skill={900041} hint="redshift" mention />, is live for approximately everyone. Filling the ranks
|
||||
Maruzensky's unique, <Skill skill={skills.redshiftInherit} mention />, is live for approximately everyone. Filling the ranks
|
||||
with front runners should be a strong means to delay it for later positions, especially COC.
|
||||
</p>
|
||||
<p>
|
||||
@@ -1425,8 +1470,8 @@
|
||||
</p>
|
||||
<p>As a sprint, this is also where spot struggle shines. Time for Unity Cup guts builds.</p>
|
||||
<p>
|
||||
I forgot that <Skill skill={200551} hint="unrestrained" mention /> requires being in first place, so I thought it would be reasonable
|
||||
to base my team around gambling on it. That turned out not to be a great decision.
|
||||
I forgot that <Skill skill={skills.unrestrained} mention /> requires being in first place, so I thought it would be reasonable to
|
||||
base my team around gambling on it. That turned out not to be a great decision.
|
||||
</p>
|
||||
<ol class="mb-4 list-decimal pl-4">
|
||||
<li>
|
||||
@@ -1447,13 +1492,12 @@
|
||||
</li>
|
||||
</ol>
|
||||
<p>
|
||||
The plan worked exactly as I hoped, but what the plan lacked was <Skill skill={900141} hint="vpp" mention />. While I was
|
||||
The plan worked exactly as I hoped, but what the plan lacked was <Skill skill={skills.pastaInherit} mention />. While I was
|
||||
suppressing it on other teams' front runners with my outstanding mid race, they were also gambling on <Skill
|
||||
skill={200651}
|
||||
hint="gale"
|
||||
skill={skills.turboSprint}
|
||||
mention
|
||||
/> and <Skill skill={200371} hint="turbo sprint" mention />, and I didn't have enough accel to beat them. I found a mention in
|
||||
my chat history that, as of round 2 day 1, I had a 78% top two rate with a 32% win rate. Lessons learned. Still managed to get
|
||||
2nd in the finals, and also my first ever group A round 2 sweep.
|
||||
/> and <Skill skill={skills.rushingGale} mention />, and I didn't have enough accel to beat them. I found a mention in my chat
|
||||
history that, as of round 2 day 1, I had a 78% top two rate with a 32% win rate. Lessons learned. Still managed to get 2nd in
|
||||
the finals, and also my first ever group A round 2 sweep.
|
||||
</p>
|
||||
</Article>
|
||||
|
||||
@@ -12,6 +12,9 @@ const config = {
|
||||
|
||||
return isExternalLibrary ? undefined : true;
|
||||
},
|
||||
experimental: {
|
||||
async: true,
|
||||
},
|
||||
},
|
||||
kit: {
|
||||
adapter: adapter(),
|
||||
|
||||
@@ -4,6 +4,7 @@ import { playwright } from '@vitest/browser-playwright';
|
||||
import { sveltekit } from '@sveltejs/kit/vite';
|
||||
|
||||
export default defineConfig({
|
||||
clearScreen: false,
|
||||
plugins: [tailwindcss(), sveltekit()],
|
||||
test: {
|
||||
expect: { requireAssertions: true },
|
||||
@@ -33,4 +34,11 @@ export default defineConfig({
|
||||
},
|
||||
],
|
||||
},
|
||||
server: {
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://localhost:13669',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user