1 Commits

Author SHA1 Message Date
02c543922d horsebot: make skill responses ephemeral with share button 2026-03-09 11:09:53 -04:00
30 changed files with 1245 additions and 170322 deletions

3
.gitignore vendored
View File

@@ -1,5 +1,2 @@
.astro
.koka
.vscode
dist
node_modules

View File

@@ -1,6 +0,0 @@
import { defineConfig } from "astro/config";
export default defineConfig({
site: "https://zenno.sunturtle.xyz",
srcDir: "./site",
});

View File

@@ -84,8 +84,8 @@ func main() {
r.Route("/skill", func(r handler.Router) {
r.SlashCommand("/", skillSrv.slash)
r.Autocomplete("/", skillSrv.autocomplete)
r.SelectMenuComponent("/swap", skillSrv.menu)
r.ButtonComponent("/swap/{id}", skillSrv.button)
r.ButtonComponent("/share/{id}", skillSrv.share)
})
opts := []bot.ConfigOpt{bot.WithDefaultGateway(), bot.WithEventListeners(r)}
@@ -144,10 +144,6 @@ var commands = []discord.ApplicationCommandCreate{
Required: true,
Autocomplete: true,
},
discord.ApplicationCommandOptionBool{
Name: "share",
Description: "Share the skill info",
},
},
},
}

View File

@@ -29,15 +29,13 @@ func newSkillServer(skills []horse.Skill, groups []horse.SkillGroup) *skillServe
for _, skill := range skills {
s.skills[skill.ID] = skill
s.byName[skill.Name] = skill.ID
switch {
case skill.UniqueOwner == "":
s.autocom.Add(skill.Name, discord.AutocompleteChoiceString{Name: skill.Name, Value: strconv.Itoa(int(skill.ID))})
case skill.Rarity >= 3:
s.autocom.Add(skill.Name, discord.AutocompleteChoiceString{Name: skill.Name, Value: skill.Name})
s.autocom.Add(skill.UniqueOwner, discord.AutocompleteChoiceString{Name: "Unique: " + skill.UniqueOwner, Value: strconv.Itoa(int(skill.ID))})
default:
s.autocom.Add(skill.Name, discord.AutocompleteChoiceString{Name: skill.Name + " (Inherited)", Value: strconv.Itoa(int(skill.ID))})
s.autocom.Add(skill.UniqueOwner, discord.AutocompleteChoiceString{Name: "Inherited unique: " + skill.UniqueOwner, Value: skill.Name})
s.autocom.Add(skill.Name, discord.AutocompleteChoiceString{Name: skill.Name, Value: skill.Name})
if skill.UniqueOwner != "" {
if skill.Rarity >= 3 {
s.autocom.Add(skill.UniqueOwner, discord.AutocompleteChoiceString{Name: "Unique: " + skill.UniqueOwner, Value: skill.Name})
} else {
s.autocom.Add(skill.UniqueOwner, discord.AutocompleteChoiceString{Name: "Inherited unique: " + skill.UniqueOwner, Value: skill.Name})
}
}
}
for _, g := range groups {
@@ -67,11 +65,8 @@ func (s *skillServer) slash(data discord.SlashCommandInteractionData, e *handler
id = int64(v)
}
m := discord.MessageCreate{
Components: []discord.LayoutComponent{s.render(horse.SkillID(id))},
Flags: discord.MessageFlagIsComponentsV2,
}
if !data.Bool("share") {
m.Flags |= discord.MessageFlagEphemeral
Components: []discord.LayoutComponent{s.render(horse.SkillID(id), false)},
Flags: discord.MessageFlagIsComponentsV2 | discord.MessageFlagEphemeral,
}
return e.CreateMessage(m)
}
@@ -92,43 +87,43 @@ func (s *skillServer) button(data discord.ButtonInteractionData, e *handler.Comp
return e.CreateMessage(m)
}
m := discord.MessageUpdate{
Components: &[]discord.LayoutComponent{s.render(horse.SkillID(id))},
Components: &[]discord.LayoutComponent{s.render(horse.SkillID(id), false)},
}
return e.UpdateMessage(m)
}
func (s *skillServer) menu(data discord.SelectMenuInteractionData, e *handler.ComponentEvent) error {
d, ok := data.(discord.StringSelectMenuInteractionData)
if !ok {
return fmt.Errorf("wrong select menu type %T", data)
}
if len(d.Values) != 1 {
return fmt.Errorf("wrong number of values: %q", d.Values)
}
id, err := strconv.ParseInt(d.Values[0], 10, 32)
func (s *skillServer) share(data discord.ButtonInteractionData, e *handler.ComponentEvent) error {
id, err := strconv.ParseInt(e.Vars["id"], 10, 32)
if err != nil {
return err
m := discord.MessageCreate{
Content: "That button produced an invalid skill ID. That's not supposed to happen.",
Flags: discord.MessageFlagEphemeral,
}
return e.CreateMessage(m)
}
m := discord.MessageUpdate{
Components: &[]discord.LayoutComponent{s.render(horse.SkillID(id))},
m := discord.MessageCreate{
Components: []discord.LayoutComponent{s.render(horse.SkillID(id), true)},
}
return e.UpdateMessage(m)
return e.CreateMessage(m)
}
func (s *skillServer) render(id horse.SkillID) discord.ContainerComponent {
func (s *skillServer) render(id horse.SkillID, share bool) discord.ContainerComponent {
skill, ok := s.skills[id]
if !ok {
slog.Error("invalid skill id", slog.Int("id", int(id)))
slog.Error("invalid skill id", slog.Int("id", int(id)), slog.Bool("share", share))
return discord.NewContainer(discord.NewTextDisplayf("invalid skill ID %v made it to render", id))
}
top := "### " + skill.Name
thumburl := fmt.Sprintf("https://gametora.com/images/umamusume/skill_icons/utx_ico_skill_%d.png", skill.IconID)
top := "## " + skill.Name
if skill.UniqueOwner != "" {
top += "\n-# " + skill.UniqueOwner
}
r := discord.NewContainer(
discord.NewTextDisplay(top),
discord.NewSmallSeparator(),
discord.NewSection(
discord.NewTextDisplay(top),
discord.NewTextDisplay(skill.Description),
).WithAccessory(discord.NewThumbnail(thumburl)),
)
var skilltype string
switch {
@@ -160,6 +155,7 @@ func (s *skillServer) render(id horse.SkillID) discord.ContainerComponent {
r.AccentColor = 0xcccccc
skilltype = "Common Skill"
}
r.Components = append(r.Components, discord.NewSmallSeparator())
text := make([]string, 0, 3)
abils := make([]string, 0, 3)
for _, act := range skill.Activations {
@@ -201,31 +197,19 @@ func (s *skillServer) render(id horse.SkillID) discord.ContainerComponent {
rel = append(rel, s.skills[id])
}
}
if len(rel) > 1 {
opts := make([]discord.StringSelectMenuOption, 0, 4)
if len(rel) > 1 || !share {
buttons := make([]discord.InteractiveComponent, 0, 4)
for _, rs := range rel {
name := rs.Name
emoji := "⚪"
switch rs.Rarity {
case 1:
if rs.UniqueOwner != "" {
name += " (Inherited)"
}
case 2:
emoji = "🟡"
case 3, 4, 5:
emoji = "🟣"
default:
emoji = "⁉️"
b := discord.NewSecondaryButton(rs.Name, fmt.Sprintf("/skill/swap/%d", rs.ID))
if rs.ID == id {
b = b.AsDisabled()
}
b := discord.NewStringSelectMenuOption(name, strconv.Itoa(int(rs.ID))).WithEmoji(discord.NewComponentEmoji(emoji))
if rs.ID == skill.ID {
b = b.WithDefault(true)
}
opts = append(opts, b)
buttons = append(buttons, b)
}
row := discord.NewActionRow(discord.NewStringSelectMenu("/skill/swap", "Related skills", opts...))
r.Components = append(r.Components, row)
if !share {
buttons = append(buttons, discord.NewPrimaryButton("Share", fmt.Sprintf("/skill/share/%d", skill.ID)))
}
r.Components = append(r.Components, discord.NewActionRow(buttons...))
}
return r
}

View File

@@ -223,18 +223,6 @@ func main() {
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))
@@ -251,7 +239,6 @@ func main() {
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)
@@ -281,8 +268,6 @@ var (
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) {

View File

@@ -1,10 +0,0 @@
SELECT
gallery_chara_id,
disp_order,
pos_id,
chara_id_1,
chara_id_2,
chara_id_3,
condition_type
FROM home_story_trigger
ORDER BY gallery_chara_id, disp_order

View File

@@ -3,8 +3,8 @@ WITH skill_groups AS (
)
SELECT
g.group_id,
COALESCE(inh_from.id, s1.id, 0) AS skill1,
COALESCE(inh_to.id, s2.id, 0) AS skill2,
IFNULL(s1.id, 0) AS skill1,
IFNULL(s2.id, 0) AS skill2,
IFNULL(s3.id, 0) AS skill3,
IFNULL(m1.id, 0) AS skill_bad
FROM skill_groups g
@@ -12,6 +12,4 @@ FROM skill_groups g
LEFT JOIN skill_data s2 ON g.group_id = s2.group_id AND s2.group_rate = 2
LEFT JOIN skill_data s3 ON g.group_id = s3.group_id AND s3.group_rate = 3
LEFT JOIN skill_data m1 ON g.group_id = m1.group_id AND m1.group_rate = -1
LEFT JOIN skill_data inh_to ON s1.id = inh_to.unique_skill_id_1
LEFT JOIN skill_data inh_from ON s2.unique_skill_id_1 = inh_from.id
ORDER BY g.group_id

File diff suppressed because it is too large Load Diff

View File

@@ -13,7 +13,6 @@ This file is my notes from exploring the database.
- 33 is race names by race id, 28 is race names by race instance id, 31 is race courses, 111 is saddle names
- 65 is player titles, 66 is title descriptions - ties with honor_data?
- 119 is scenario full titles (e.g. The Beginning: URA Finale), 120 is scenario descriptions, 237 is scenario names (e.g. URA Finale)
- 130 is epithet names, 131 is epithet descriptions
# succession factor (sparks)
@@ -193,41 +192,12 @@ target types:
- 22 specific character, target value is character id
- 23 other who triggered the skill
TODO target types only in jp: 2, 7, 11, 22, 23
ability_value_usage can be 1 for plain or 2-6 for aoharu stat skill stat scaling
seems to be activate_lot = 1 means wit check, 0 means guaranteed
tag_id is a slash-separated list of numeric IDs that roughly describe all effects relevant to the skill.
- 101..104 style front, pace, late, end
- 201..204 distance sprint, mile, medium, long
- 301..303 timing early, mid, late race
- 401 affects speed stat or target speed
- 402 affects stamina stat or hp
- 403 affects power stat or acceleration
- 404 affects guts stat
- 405 affects wit stat or vision
- 406 is a debuff of any type, or is a main story self-debuff (creeping anxiety, blatant fear), or is Behold Thine Emperor's Divine Might (both own unique and inherited versions are tagged only 406??)
- 407 modifies gate delay
- 501..502 turf/dirt
- 801..812 scenario skill
600 series applies to skills available in global but are only used in jp.
- 601 ground condition passive
- 602 weather passive
- 603 season passive
- 604 race track passive
- 605 time of day passive
- 606 exchange race passive (kawasaki, funabashi, morioka, ooi)
- 607 distance passive (non/standard)
- 608 track direction or corner count passive
- 609 gate position passive
- 610 ground type passive
- 611 popularity passive
- 612 running style passive
- 613 passive depending on other horses' styles or skills
- 614 base stat threshold passive
- 615 mood passive
# races
- group 1, grade: g1 100, g2 200, g3 300, op 400, pre-op 700

File diff suppressed because it is too large Load Diff

View File

@@ -199,14 +199,6 @@
"chara_id": 1061,
"name": "King Halo"
},
{
"chara_id": 1062,
"name": "Matikanetannhauser"
},
{
"chara_id": 1067,
"name": "Satono Diamond"
},
{
"chara_id": 1068,
"name": "Kitasan Black"

File diff suppressed because it is too large Load Diff

View File

@@ -8,10 +8,5 @@
"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"
}
]

View File

@@ -63,370 +63,282 @@
"skill_group": 1061,
"skill1": 10611
},
{
"skill_group": 1062,
"skill1": 10621
},
{
"skill_group": 10001,
"skill1": 100011,
"skill2": 900011
"skill1": 100011
},
{
"skill_group": 10002,
"skill1": 100021,
"skill2": 900021
"skill1": 100021
},
{
"skill_group": 10003,
"skill1": 100031,
"skill2": 900031
"skill1": 100031
},
{
"skill_group": 10004,
"skill1": 100041,
"skill2": 900041
"skill1": 100041
},
{
"skill_group": 10005,
"skill1": 100051,
"skill2": 900051
"skill1": 100051
},
{
"skill_group": 10006,
"skill1": 100061,
"skill2": 900061
"skill1": 100061
},
{
"skill_group": 10007,
"skill1": 100071,
"skill2": 900071
"skill1": 100071
},
{
"skill_group": 10008,
"skill1": 100081,
"skill2": 900081
"skill1": 100081
},
{
"skill_group": 10009,
"skill1": 100091,
"skill2": 900091
"skill1": 100091
},
{
"skill_group": 10010,
"skill1": 100101,
"skill2": 900101
"skill1": 100101
},
{
"skill_group": 10011,
"skill1": 100111,
"skill2": 900111
"skill1": 100111
},
{
"skill_group": 10012,
"skill1": 100121,
"skill2": 900121
"skill1": 100121
},
{
"skill_group": 10013,
"skill1": 100131,
"skill2": 900131
"skill1": 100131
},
{
"skill_group": 10014,
"skill1": 100141,
"skill2": 900141
"skill1": 100141
},
{
"skill_group": 10015,
"skill1": 100151,
"skill2": 900151
"skill1": 100151
},
{
"skill_group": 10016,
"skill1": 100161,
"skill2": 900161
"skill1": 100161
},
{
"skill_group": 10017,
"skill1": 100171,
"skill2": 900171
"skill1": 100171
},
{
"skill_group": 10018,
"skill1": 100181,
"skill2": 900181
"skill1": 100181
},
{
"skill_group": 10019,
"skill1": 100191,
"skill2": 900191
"skill1": 100191
},
{
"skill_group": 10020,
"skill1": 100201,
"skill2": 900201
"skill1": 100201
},
{
"skill_group": 10021,
"skill1": 100211,
"skill2": 900211
"skill1": 100211
},
{
"skill_group": 10022,
"skill1": 100221,
"skill2": 900221
"skill1": 100221
},
{
"skill_group": 10023,
"skill1": 100231,
"skill2": 900231
"skill1": 100231
},
{
"skill_group": 10024,
"skill1": 100241,
"skill2": 900241
"skill1": 100241
},
{
"skill_group": 10025,
"skill1": 100251,
"skill2": 900251
"skill1": 100251
},
{
"skill_group": 10026,
"skill1": 100261,
"skill2": 900261
"skill1": 100261
},
{
"skill_group": 10027,
"skill1": 100271,
"skill2": 900271
"skill1": 100271
},
{
"skill_group": 10028,
"skill1": 100281,
"skill2": 900281
"skill1": 100281
},
{
"skill_group": 10030,
"skill1": 100301,
"skill2": 900301
"skill1": 100301
},
{
"skill_group": 10032,
"skill1": 100321,
"skill2": 900321
"skill1": 100321
},
{
"skill_group": 10033,
"skill1": 100331,
"skill2": 900331
"skill1": 100331
},
{
"skill_group": 10035,
"skill1": 100351,
"skill2": 900351
"skill1": 100351
},
{
"skill_group": 10037,
"skill1": 100371,
"skill2": 900371
"skill1": 100371
},
{
"skill_group": 10038,
"skill1": 100381,
"skill2": 900381
"skill1": 100381
},
{
"skill_group": 10039,
"skill1": 100391,
"skill2": 900391
"skill1": 100391
},
{
"skill_group": 10040,
"skill1": 100401,
"skill2": 900401
"skill1": 100401
},
{
"skill_group": 10041,
"skill1": 100411,
"skill2": 900411
"skill1": 100411
},
{
"skill_group": 10045,
"skill1": 100451,
"skill2": 900451
"skill1": 100451
},
{
"skill_group": 10046,
"skill1": 100461,
"skill2": 900461
"skill1": 100461
},
{
"skill_group": 10048,
"skill1": 100481,
"skill2": 900481
"skill1": 100481
},
{
"skill_group": 10050,
"skill1": 100501,
"skill2": 900501
"skill1": 100501
},
{
"skill_group": 10052,
"skill1": 100521,
"skill2": 900521
"skill1": 100521
},
{
"skill_group": 10056,
"skill1": 100561,
"skill2": 900561
"skill1": 100561
},
{
"skill_group": 10058,
"skill1": 100581,
"skill2": 900581
"skill1": 100581
},
{
"skill_group": 10059,
"skill1": 100591,
"skill2": 900591
"skill1": 100591
},
{
"skill_group": 10060,
"skill1": 100601,
"skill2": 900601
"skill1": 100601
},
{
"skill_group": 10061,
"skill1": 100611,
"skill2": 900611
},
{
"skill_group": 10062,
"skill1": 100621,
"skill2": 900621
},
{
"skill_group": 10067,
"skill1": 100671,
"skill2": 900671
},
{
"skill_group": 10068,
"skill1": 100681,
"skill2": 900681
"skill1": 100611
},
{
"skill_group": 10069,
"skill1": 100691,
"skill2": 900691
"skill1": 100691
},
{
"skill_group": 10071,
"skill1": 100711,
"skill2": 900711
"skill1": 100711
},
{
"skill_group": 11001,
"skill1": 110011,
"skill2": 910011
"skill1": 110011
},
{
"skill_group": 11003,
"skill1": 110031,
"skill2": 910031
"skill1": 110031
},
{
"skill_group": 11004,
"skill1": 110041,
"skill2": 910041
"skill1": 110041
},
{
"skill_group": 11006,
"skill1": 110061,
"skill2": 910061
"skill1": 110061
},
{
"skill_group": 11011,
"skill1": 110111,
"skill2": 910111
"skill1": 110111
},
{
"skill_group": 11013,
"skill1": 110131,
"skill2": 910131
"skill1": 110131
},
{
"skill_group": 11014,
"skill1": 110141,
"skill2": 910141
"skill1": 110141
},
{
"skill_group": 11015,
"skill1": 110151,
"skill2": 910151
"skill1": 110151
},
{
"skill_group": 11017,
"skill1": 110171,
"skill2": 910171
"skill1": 110171
},
{
"skill_group": 11018,
"skill1": 110181,
"skill2": 910181
"skill1": 110181
},
{
"skill_group": 11023,
"skill1": 110231,
"skill2": 910231
"skill1": 110231
},
{
"skill_group": 11024,
"skill1": 110241,
"skill2": 910241
"skill1": 110241
},
{
"skill_group": 11026,
"skill1": 110261,
"skill2": 910261
"skill1": 110261
},
{
"skill_group": 11030,
"skill1": 110301,
"skill2": 910301
"skill1": 110301
},
{
"skill_group": 11037,
"skill1": 110371,
"skill2": 910371
"skill1": 110371
},
{
"skill_group": 11040,
"skill1": 110401,
"skill2": 910401
"skill1": 110401
},
{
"skill_group": 11045,
"skill1": 110451,
"skill2": 910451
"skill1": 110451
},
{
"skill_group": 11052,
"skill1": 110521,
"skill2": 910521
"skill1": 110521
},
{
"skill_group": 11056,
"skill1": 110561,
"skill2": 910561
"skill1": 110561
},
{
"skill_group": 20001,
"skill1": 200012,
"skill2": 200011,
"skill3": 200014,
"skill_bad": 200013
},
{
@@ -512,7 +424,6 @@
"skill_group": 20015,
"skill1": 200152,
"skill2": 200151,
"skill3": 200154,
"skill_bad": 200153
},
{
@@ -1015,8 +926,7 @@
{
"skill_group": 20117,
"skill1": 201172,
"skill2": 201171,
"skill3": 201173
"skill2": 201171
},
{
"skill_group": 20118,
@@ -1334,11 +1244,6 @@
"skill1": 210052,
"skill2": 210051
},
{
"skill_group": 21006,
"skill1": 210062,
"skill2": 210061
},
{
"skill_group": 30001,
"skill1": 300011
@@ -1381,357 +1286,274 @@
},
{
"skill_group": 90001,
"skill1": 100011,
"skill2": 900011
},
{
"skill_group": 90002,
"skill1": 100021,
"skill2": 900021
},
{
"skill_group": 90003,
"skill1": 100031,
"skill2": 900031
},
{
"skill_group": 90004,
"skill1": 100041,
"skill2": 900041
},
{
"skill_group": 90005,
"skill1": 100051,
"skill2": 900051
},
{
"skill_group": 90006,
"skill1": 100061,
"skill2": 900061
},
{
"skill_group": 90007,
"skill1": 100071,
"skill2": 900071
},
{
"skill_group": 90008,
"skill1": 100081,
"skill2": 900081
},
{
"skill_group": 90009,
"skill1": 100091,
"skill2": 900091
},
{
"skill_group": 90010,
"skill1": 100101,
"skill2": 900101
},
{
"skill_group": 90011,
"skill1": 100111,
"skill2": 900111
},
{
"skill_group": 90012,
"skill1": 100121,
"skill2": 900121
},
{
"skill_group": 90013,
"skill1": 100131,
"skill2": 900131
},
{
"skill_group": 90014,
"skill1": 100141,
"skill2": 900141
},
{
"skill_group": 90015,
"skill1": 100151,
"skill2": 900151
},
{
"skill_group": 90016,
"skill1": 100161,
"skill2": 900161
},
{
"skill_group": 90017,
"skill1": 100171,
"skill2": 900171
},
{
"skill_group": 90018,
"skill1": 100181,
"skill2": 900181
},
{
"skill_group": 90019,
"skill1": 100191,
"skill2": 900191
},
{
"skill_group": 90020,
"skill1": 100201,
"skill2": 900201
},
{
"skill_group": 90021,
"skill1": 100211,
"skill2": 900211
},
{
"skill_group": 90022,
"skill1": 100221,
"skill2": 900221
},
{
"skill_group": 90023,
"skill1": 100231,
"skill2": 900231
},
{
"skill_group": 90024,
"skill1": 100241,
"skill2": 900241
},
{
"skill_group": 90025,
"skill1": 100251,
"skill2": 900251
},
{
"skill_group": 90026,
"skill1": 100261,
"skill2": 900261
},
{
"skill_group": 90027,
"skill1": 100271,
"skill2": 900271
},
{
"skill_group": 90028,
"skill1": 100281,
"skill2": 900281
},
{
"skill_group": 90030,
"skill1": 100301,
"skill2": 900301
},
{
"skill_group": 90032,
"skill1": 100321,
"skill2": 900321
},
{
"skill_group": 90033,
"skill1": 100331,
"skill2": 900331
},
{
"skill_group": 90035,
"skill1": 100351,
"skill2": 900351
},
{
"skill_group": 90037,
"skill1": 100371,
"skill2": 900371
},
{
"skill_group": 90038,
"skill1": 100381,
"skill2": 900381
},
{
"skill_group": 90039,
"skill1": 100391,
"skill2": 900391
},
{
"skill_group": 90040,
"skill1": 100401,
"skill2": 900401
},
{
"skill_group": 90041,
"skill1": 100411,
"skill2": 900411
},
{
"skill_group": 90045,
"skill1": 100451,
"skill2": 900451
},
{
"skill_group": 90046,
"skill1": 100461,
"skill2": 900461
},
{
"skill_group": 90048,
"skill1": 100481,
"skill2": 900481
},
{
"skill_group": 90050,
"skill1": 100501,
"skill2": 900501
},
{
"skill_group": 90052,
"skill1": 100521,
"skill2": 900521
},
{
"skill_group": 90056,
"skill1": 100561,
"skill2": 900561
},
{
"skill_group": 90058,
"skill1": 100581,
"skill2": 900581
},
{
"skill_group": 90059,
"skill1": 100591,
"skill2": 900591
},
{
"skill_group": 90060,
"skill1": 100601,
"skill2": 900601
},
{
"skill_group": 90061,
"skill1": 100611,
"skill2": 900611
},
{
"skill_group": 90062,
"skill1": 100621,
"skill2": 900621
},
{
"skill_group": 90067,
"skill1": 100671,
"skill2": 900671
},
{
"skill_group": 90068,
"skill1": 100681,
"skill2": 900681
},
{
"skill_group": 90069,
"skill1": 100691,
"skill2": 900691
},
{
"skill_group": 90071,
"skill1": 100711,
"skill2": 900711
},
{
"skill_group": 91001,
"skill1": 110011,
"skill2": 910011
},
{
"skill_group": 91003,
"skill1": 110031,
"skill2": 910031
},
{
"skill_group": 91004,
"skill1": 110041,
"skill2": 910041
},
{
"skill_group": 91006,
"skill1": 110061,
"skill2": 910061
},
{
"skill_group": 91011,
"skill1": 110111,
"skill2": 910111
},
{
"skill_group": 91013,
"skill1": 110131,
"skill2": 910131
},
{
"skill_group": 91014,
"skill1": 110141,
"skill2": 910141
},
{
"skill_group": 91015,
"skill1": 110151,
"skill2": 910151
},
{
"skill_group": 91017,
"skill1": 110171,
"skill2": 910171
},
{
"skill_group": 91018,
"skill1": 110181,
"skill2": 910181
},
{
"skill_group": 91023,
"skill1": 110231,
"skill2": 910231
},
{
"skill_group": 91024,
"skill1": 110241,
"skill2": 910241
},
{
"skill_group": 91026,
"skill1": 110261,
"skill2": 910261
},
{
"skill_group": 91030,
"skill1": 110301,
"skill2": 910301
},
{
"skill_group": 91037,
"skill1": 110371,
"skill2": 910371
},
{
"skill_group": 91040,
"skill1": 110401,
"skill2": 910401
},
{
"skill_group": 91045,
"skill1": 110451,
"skill2": 910451
},
{
"skill_group": 91052,
"skill1": 110521,
"skill2": 910521
},
{
"skill_group": 91056,
"skill1": 110561,
"skill2": 910561
},
{

File diff suppressed because it is too large Load Diff

View File

@@ -28997,141 +28997,6 @@
]
]
},
{
"spark_id": 2100601,
"name": "Glittering Star",
"description": "A Spark that gives a skill hint for \"Glittering Star\".",
"spark_group": 21006,
"rarity": 1,
"type": 4,
"effects": [
[
{
"target": 41,
"value1": 210062,
"value2": 1
}
],
[
{
"target": 41,
"value1": 210062,
"value2": 2
}
],
[
{
"target": 41,
"value1": 210062,
"value2": 3
}
],
[
{
"target": 41,
"value1": 210062,
"value2": 4
}
],
[
{
"target": 41,
"value1": 210062,
"value2": 5
}
]
]
},
{
"spark_id": 2100602,
"name": "Glittering Star",
"description": "A Spark that gives a skill hint for \"Glittering Star\".",
"spark_group": 21006,
"rarity": 2,
"type": 4,
"effects": [
[
{
"target": 41,
"value1": 210062,
"value2": 1
}
],
[
{
"target": 41,
"value1": 210062,
"value2": 2
}
],
[
{
"target": 41,
"value1": 210062,
"value2": 3
}
],
[
{
"target": 41,
"value1": 210062,
"value2": 4
}
],
[
{
"target": 41,
"value1": 210062,
"value2": 5
}
]
]
},
{
"spark_id": 2100603,
"name": "Glittering Star",
"description": "A Spark that gives a skill hint for \"Glittering Star\".",
"spark_group": 21006,
"rarity": 3,
"type": 4,
"effects": [
[
{
"target": 41,
"value1": 210062,
"value2": 1
}
],
[
{
"target": 41,
"value1": 210062,
"value2": 2
}
],
[
{
"target": 41,
"value1": 210062,
"value2": 3
}
],
[
{
"target": 41,
"value1": 210062,
"value2": 4
}
],
[
{
"target": 41,
"value1": 210062,
"value2": 5
}
]
]
},
{
"spark_id": 3000101,
"name": "URA Finale",
@@ -29372,126 +29237,6 @@
]
]
},
{
"spark_id": 3000301,
"name": "TS Climax Scenario",
"description": "A Spark that increases Stamina and Guts.",
"spark_group": 30003,
"rarity": 1,
"type": 6,
"effects": [
[
{
"target": 2,
"value1": 10
},
{
"target": 4,
"value1": 10
}
],
[
{
"target": 2,
"value1": 20
},
{
"target": 4,
"value1": 20
}
],
[
{
"target": 2,
"value1": 30
},
{
"target": 4,
"value1": 30
}
]
]
},
{
"spark_id": 3000302,
"name": "TS Climax Scenario",
"description": "A Spark that increases Stamina and Guts.",
"spark_group": 30003,
"rarity": 2,
"type": 6,
"effects": [
[
{
"target": 2,
"value1": 10
},
{
"target": 4,
"value1": 10
}
],
[
{
"target": 2,
"value1": 20
},
{
"target": 4,
"value1": 20
}
],
[
{
"target": 2,
"value1": 30
},
{
"target": 4,
"value1": 30
}
]
]
},
{
"spark_id": 3000303,
"name": "TS Climax Scenario",
"description": "A Spark that increases Stamina and Guts.",
"spark_group": 30003,
"rarity": 3,
"type": 6,
"effects": [
[
{
"target": 2,
"value1": 10
},
{
"target": 4,
"value1": 10
}
],
[
{
"target": 2,
"value1": 20
},
{
"target": 4,
"value1": 20
}
],
[
{
"target": 2,
"value1": 30
},
{
"target": 4,
"value1": 30
}
]
]
},
{
"spark_id": 10010101,
"name": "Shooting Star",
@@ -35630,285 +35375,6 @@
]
]
},
{
"spark_id": 10620101,
"name": "Go, Go, Mun!",
"description": "A Spark that gives a skill hint for \"Go, Go, Mun!\".",
"spark_group": 106201,
"rarity": 1,
"type": 3,
"effects": [
[
{
"target": 41,
"value1": 900621,
"value2": 1
}
],
[
{
"target": 41,
"value1": 900621,
"value2": 2
}
],
[
{
"target": 41,
"value1": 900621,
"value2": 3
}
]
]
},
{
"spark_id": 10620102,
"name": "Go, Go, Mun!",
"description": "A Spark that gives a skill hint for \"Go, Go, Mun!\".",
"spark_group": 106201,
"rarity": 2,
"type": 3,
"effects": [
[
{
"target": 41,
"value1": 900621,
"value2": 1
}
],
[
{
"target": 41,
"value1": 900621,
"value2": 2
}
],
[
{
"target": 41,
"value1": 900621,
"value2": 3
}
]
]
},
{
"spark_id": 10620103,
"name": "Go, Go, Mun!",
"description": "A Spark that gives a skill hint for \"Go, Go, Mun!\".",
"spark_group": 106201,
"rarity": 3,
"type": 3,
"effects": [
[
{
"target": 41,
"value1": 900621,
"value2": 1
}
],
[
{
"target": 41,
"value1": 900621,
"value2": 2
}
],
[
{
"target": 41,
"value1": 900621,
"value2": 3
}
]
]
},
{
"spark_id": 10670101,
"name": "Eternal Encompassing Shine",
"description": "A Spark that gives a skill hint for \"Eternal Encompassing Shine\".",
"spark_group": 106701,
"rarity": 1,
"type": 3,
"effects": [
[
{
"target": 41,
"value1": 900671,
"value2": 1
}
],
[
{
"target": 41,
"value1": 900671,
"value2": 2
}
],
[
{
"target": 41,
"value1": 900671,
"value2": 3
}
]
]
},
{
"spark_id": 10670102,
"name": "Eternal Encompassing Shine",
"description": "A Spark that gives a skill hint for \"Eternal Encompassing Shine\".",
"spark_group": 106701,
"rarity": 2,
"type": 3,
"effects": [
[
{
"target": 41,
"value1": 900671,
"value2": 1
}
],
[
{
"target": 41,
"value1": 900671,
"value2": 2
}
],
[
{
"target": 41,
"value1": 900671,
"value2": 3
}
]
]
},
{
"spark_id": 10670103,
"name": "Eternal Encompassing Shine",
"description": "A Spark that gives a skill hint for \"Eternal Encompassing Shine\".",
"spark_group": 106701,
"rarity": 3,
"type": 3,
"effects": [
[
{
"target": 41,
"value1": 900671,
"value2": 1
}
],
[
{
"target": 41,
"value1": 900671,
"value2": 2
}
],
[
{
"target": 41,
"value1": 900671,
"value2": 3
}
]
]
},
{
"spark_id": 10680101,
"name": "Victory Cheer!",
"description": "A Spark that gives a skill hint for \"Victory Cheer!\".",
"spark_group": 106801,
"rarity": 1,
"type": 3,
"effects": [
[
{
"target": 41,
"value1": 900681,
"value2": 1
}
],
[
{
"target": 41,
"value1": 900681,
"value2": 2
}
],
[
{
"target": 41,
"value1": 900681,
"value2": 3
}
]
]
},
{
"spark_id": 10680102,
"name": "Victory Cheer!",
"description": "A Spark that gives a skill hint for \"Victory Cheer!\".",
"spark_group": 106801,
"rarity": 2,
"type": 3,
"effects": [
[
{
"target": 41,
"value1": 900681,
"value2": 1
}
],
[
{
"target": 41,
"value1": 900681,
"value2": 2
}
],
[
{
"target": 41,
"value1": 900681,
"value2": 3
}
]
]
},
{
"spark_id": 10680103,
"name": "Victory Cheer!",
"description": "A Spark that gives a skill hint for \"Victory Cheer!\".",
"spark_group": 106801,
"rarity": 3,
"type": 3,
"effects": [
[
{
"target": 41,
"value1": 900681,
"value2": 1
}
],
[
{
"target": 41,
"value1": 900681,
"value2": 2
}
],
[
{
"target": 41,
"value1": 900681,
"value2": 3
}
]
]
},
{
"spark_id": 10690101,
"name": "Ambition to Surpass the Sakura",

View File

@@ -1583,78 +1583,6 @@
"skill_pl4": 201072,
"skill_pl5": 201431
},
{
"chara_card_id": 106201,
"chara_id": 1062,
"name": "[Clippety-Tippety-Clop] Matikanetannhauser",
"variant": "[Clippety-Tippety-Clop]",
"sprint": 0,
"mile": 4,
"medium": 7,
"long": 7,
"front": 2,
"pace": 7,
"late": 7,
"end": 3,
"turf": 7,
"dirt": 1,
"unique": 100621,
"skill1": 200482,
"skill2": 201212,
"skill3": 200602,
"skill_pl2": 201621,
"skill_pl3": 200481,
"skill_pl4": 200512,
"skill_pl5": 201211
},
{
"chara_card_id": 106701,
"chara_id": 1067,
"name": "[Natural Brilliance] Satono Diamond",
"variant": "[Natural Brilliance]",
"sprint": 0,
"mile": 5,
"medium": 7,
"long": 7,
"front": 1,
"pace": 6,
"late": 7,
"end": 4,
"turf": 7,
"dirt": 1,
"unique": 100671,
"skill1": 200012,
"skill2": 201692,
"skill3": 201102,
"skill_pl2": 202012,
"skill_pl3": 201691,
"skill_pl4": 200152,
"skill_pl5": 200014
},
{
"chara_card_id": 106801,
"chara_id": 1068,
"name": "[Gilded Shrine to Glory] Kitasan Black",
"variant": "[Gilded Shrine to Glory]",
"sprint": 0,
"mile": 5,
"medium": 7,
"long": 7,
"front": 7,
"pace": 6,
"late": 5,
"end": 1,
"turf": 7,
"dirt": 1,
"unique": 100681,
"skill1": 200432,
"skill2": 201172,
"skill3": 200532,
"skill_pl2": 201102,
"skill_pl3": 200531,
"skill_pl4": 201272,
"skill_pl5": 201173
},
{
"chara_card_id": 106901,
"chara_id": 1069,

View File

@@ -17,43 +17,3 @@ type AffinityRelation struct {
IDC int `json:"chara_c,omitzero"`
Affinity int `json:"affinity"`
}
// Conversation describes a lobby conversation.
type Conversation struct {
// CharacterID is the ID of the character who has the conversation as
// a gallery entry.
CharacterID CharacterID `json:"chara_id"`
// Number is the conversation number within the character's gallery.
Number int `json:"number"`
// Location is the ID of the location the conversation occurs in the lobby.
Location LobbyConversationLocationID `json:"location"`
// 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"`
// Chara2 is the second conversation participant ID.
Chara2 CharacterID `json:"chara_2,omitzero"`
// Chara3 is the third conversation participant ID.
Chara3 CharacterID `json:"chara_3,omitzero"`
// ConditionType is a complete mystery to me.
ConditionType int `json:"condition_type"`
}
type LobbyConversationLocationID int
//go:generate go run golang.org/x/tools/cmd/stringer@v0.41.0 -type LobbyConversationLocationID -trimprefix Lobby -linecomment
const (
LobbyRightFront1 LobbyConversationLocationID = 110 // right side front
LobbyRightFront2 LobbyConversationLocationID = 120 // right side front
LobbyRightFront3 LobbyConversationLocationID = 130 // right side front
LobbyLeftTable1 LobbyConversationLocationID = 210 // left side table
LobbyLeftTable2 LobbyConversationLocationID = 220 // left side table
LobbyBackSeat LobbyConversationLocationID = 310 // center back seat
LobbyPosters1 LobbyConversationLocationID = 410 // center posters
LobbyPosters2 LobbyConversationLocationID = 420 // center posters
LobbyPosters3 LobbyConversationLocationID = 430 // center posters
LobbySchoolMap1 LobbyConversationLocationID = 510 // left side school map
LobbySchoolMap2 LobbyConversationLocationID = 520 // left side school map
LobbySchoolMap3 LobbyConversationLocationID = 530 // left side school map
)

View File

@@ -1,47 +0,0 @@
// Code generated by "stringer -type LobbyConversationLocationID -trimprefix Lobby -linecomment"; DO NOT EDIT.
package horse
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[LobbyRightFront1-110]
_ = x[LobbyRightFront2-120]
_ = x[LobbyRightFront3-130]
_ = x[LobbyLeftTable1-210]
_ = x[LobbyLeftTable2-220]
_ = x[LobbyBackSeat-310]
_ = x[LobbyPosters1-410]
_ = x[LobbyPosters2-420]
_ = x[LobbyPosters3-430]
_ = x[LobbySchoolMap1-510]
_ = x[LobbySchoolMap2-520]
_ = x[LobbySchoolMap3-530]
}
const _LobbyConversationLocationID_name = "right side frontright side frontright side frontleft side tableleft side tablecenter back seatcenter posterscenter posterscenter postersleft side school mapleft side school mapleft side school map"
var _LobbyConversationLocationID_map = map[LobbyConversationLocationID]string{
110: _LobbyConversationLocationID_name[0:16],
120: _LobbyConversationLocationID_name[16:32],
130: _LobbyConversationLocationID_name[32:48],
210: _LobbyConversationLocationID_name[48:63],
220: _LobbyConversationLocationID_name[63:78],
310: _LobbyConversationLocationID_name[78:94],
410: _LobbyConversationLocationID_name[94:108],
420: _LobbyConversationLocationID_name[108:122],
430: _LobbyConversationLocationID_name[122:136],
510: _LobbyConversationLocationID_name[136:156],
520: _LobbyConversationLocationID_name[156:176],
530: _LobbyConversationLocationID_name[176:196],
}
func (i LobbyConversationLocationID) String() string {
if str, ok := _LobbyConversationLocationID_map[i]; ok {
return str
}
return "LobbyConversationLocationID(" + strconv.FormatInt(int64(i), 10) + ")"
}

View File

@@ -46,7 +46,7 @@ type Activation struct {
Precondition string `json:"precondition,omitzero"`
Condition string `json:"condition"`
Duration TenThousandths `json:"duration,omitzero"`
DurScale DurScale `json:"dur_scale"`
DurScale DurScale `json:"dur_scale,omitzero"`
Cooldown TenThousandths `json:"cooldown,omitzero"`
Abilities []Ability `json:"abilities"`
}
@@ -57,7 +57,7 @@ type Ability struct {
ValueUsage AbilityValueUsage `json:"value_usage"`
Value TenThousandths `json:"value"`
Target AbilityTarget `json:"target"`
TargetValue int32 `json:"target_value,omitzero"`
TargetValue int32 `json:"target_value"`
}
func (a Ability) String() string {
@@ -211,9 +211,6 @@ type SkillGroupID int32
// skill with the corresponding group rate.
// Some skill groups contain only Skill2 or SkillBad, while others may have all
// four skills.
//
// As a special case, horsegen lists both unique skills and their inherited
// versions in the skill groups for both.
type SkillGroup struct {
ID SkillGroupID `json:"skill_group"`
// Skill1 is the base version of the skill, either a common (white) skill

4709
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,23 +0,0 @@
{
"name": "zenno",
"version": "0.0.1",
"description": "Zenno Rob Roy: She's read all about Umamusume, and she's always happy to share her knowledge and give recommendations!",
"main": "index.js",
"directories": {},
"scripts": {
"dev": "astro dev",
"build": "astro build",
"preview": "astro preview"
},
"repository": {
"type": "git",
"url": "git@git.sunturtle.xyz:zephyr/horse.git"
},
"keywords": [],
"author": "Branden J Brown <zephyrtronium@hey.com>",
"license": "none",
"dependencies": {
"astro": "^6.0.8",
"nanostores": "^1.2.0"
}
}

View File

@@ -1,420 +0,0 @@
/**
* TypeScript schema for JSON files generated by horsegen.
*/
/**
* Character definitions.
*/
export interface Character {
/**
* Character ID.
*/
chara_id: number;
/**
* Regional name of the character.
* E.g., Special Week for Global, or スペシャルウィーク for JP.
*/
name: string;
}
/**
* Precomputed character pair and trio affinity.
*/
export interface Affinity {
/**
* First character in the relation.
*/
chara_a: number;
/**
* Second character in the relation.
* chara_a < chara_b is an invariant.
*/
chara_b: number;
/**
* Third character in the relation, if it is a trio relation.
* If defined, chara_b < chara_c is an invariant.
*/
chara_c?: number;
/**
* Total base compatibility between characters in the relation.
*/
affinity: number;
}
/**
* Uma or character card definitions.
*/
export interface Uma {
/**
* Uma ID.
*/
chara_card_id: number;
/**
* Character ID that the Uma is a variant of.
*/
chara_id: number;
/**
* Regional name of the Uma, comprised of the variant name and the character name.
* E.g. "[Special Dreamer] Special Week".
*/
name: string;
/**
* Regional variant name.
* E.g. "[Special Dreamer]".
*/
variant: string;
sprint: AptitudeLevel;
mile: AptitudeLevel;
medium: AptitudeLevel;
long: AptitudeLevel;
front: AptitudeLevel;
pace: AptitudeLevel;
late: AptitudeLevel;
end: AptitudeLevel;
turf: AptitudeLevel;
dirt: AptitudeLevel;
/**
* ID of the Uma's unique skill.
*/
unique: number;
/**
* ID of the Uma's first built-in skill.
*/
skill1: number;
/**
* ID of the Uma's second built-in skill.
*/
skill2: number;
/**
* ID of the Uma's third built-in skill.
*/
skill3: number;
/**
* ID of the skill unlocked at potential level 2.
*/
skill_pl2: number;
/**
* ID of the skill unlocked at potential level 3.
*/
skill_pl3: number;
/**
* ID of the skill unlocked at potential level 4.
*/
skill_pl4: number;
/**
* ID of the skill unlocked at potential level 5.
*/
skill_pl5: number;
}
export type AptitudeLevel = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7;
/**
* Race data.
*/
export interface Race {
/**
* Race ID.
*/
race_id: number;
/**
* Regional name of the race.
*/
name: string;
/**
* Thumbnail asset ID number.
*/
thumbnail: number;
/**
* Primary race ID.
* For most races, this is the same as race_id. Some races are alternate
* versions for certain careers; this holds the ID of the normal version of
* the race.
*/
primary: number;
}
/**
* Race saddle data.
*/
export interface Saddle {
/**
* Saddle ID.
*/
saddle_id: number;
/**
* Regional name of the saddle.
*/
name: string;
/**
* IDs of race wins required to earn the saddle.
*/
races: number[];
/**
* Saddle type: 0 for multi-race honors, 3 for G1, 2 for G2, 1 for G3.
*/
type: 0 | 1 | 2 | 3;
/**
* Primary saddle ID.
* Respective for races.
*/
primary: number;
}
/**
* Scenario data.
*/
export interface Scenario {
/**
* Scenario ID.
*/
scenario_id: number;
/**
* Regional scenario name, e.g. "TS Climax".
*/
name: string;
/**
* Regional full title, e.g. "Trackblazer: Start of the Climax".
*/
title: string;
}
/**
* Skill data.
*/
export interface Skill {
/**
* Skill ID.
*/
skill_id: number;
/**
* Regional skill name.
*/
name: string;
/**
* Regional skil description.
*/
description: string;
/**
* Skill group ID.
*/
group: number;
/**
* Skill rarity. 3-5 are uniques for various star levels.
*/
rarity: 1 | 2 | 3 | 4 | 5;
/**
* Upgrade position within the skill's group.
* -1 is for negative (purple) skills.
*/
group_rate: 1 | 2 | 3 | -1;
/**
* Grade value, or the amount of rating gained for having the skill with
* appropriate aptitude.
*/
grade_value?: number;
/**
* Whether the skill requires a wit check.
*/
wit_check: boolean;
/**
* Conditions and results of skill activation.
*/
activations: [Activation] | [Activation, Activation];
/**
* Name of the Uma which owns this skill as a unique, if applicable.
*/
unique_owner?: string;
/**
* SP cost to purchase the skill, if applicable.
*/
sp_cost?: number;
/**
* Skill icon ID.
*/
icon_id: number;
}
/**
* Conditions and results of skill activation.
*/
export interface Activation {
/**
* Precondition which must be satisfied before the condition is checked.
*/
precondition?: string;
/**
* Activation conditions.
*/
condition: string;
/**
* Skill duration in ten thousandths of a second.
* Generally undefined for activations which only affect HP.
*/
duration?: number;
/**
* Special skill duration scaling mode.
*/
dur_scale: 1 | 2 | 3 | 4 | 5 | 7;
/**
* Skill cooldown in ten thousandths of a second.
* A value of 5000000 indicates that the cooldown is forever.
* Generally undefined for passive skills.
*/
cooldown?: number;
/**
* Results applied when the skill's conditions are met.
*/
abilities: [Ability] | [Ability, Ability] | [Ability, Ability, Ability];
}
/**
* Effects applied when a skill activates.
*/
export interface Ability {
/**
* Race mechanic affected by the ability.
*/
type: 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 13 | 21 | 27 | 28 | 31 | 35;
/**
* Special scaling type of the skill value.
*/
value_usage: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 19 | 20 | 22 | 23 | 24 | 25;
/**
* Amount that the skill modifies the race mechanic in ten thousandths of
* whatever is the appropriate unit.
*/
value: number;
/**
* Selector for horses targeted by the ability.
*/
target: 1 | 2 | 4 | 7 | 9 | 10 | 11 | 18 | 19 | 20 | 21 | 22 | 23;
/**
* Argument value for the ability target, when appropriate.
*/
target_value?: number;
}
/**
* Skill groups.
* Skills in a skill group replace each other when purchased.
*
* As a special case, horsegen lists both unique skills and their inherited
* versions in the skill groups for both.
*/
export interface SkillGroup {
/**
* Skill group ID.
*/
skill_group: number;
/**
* Base skill in the skill group, if any.
* Either a common (white) skill or an Uma's own unique.
*
* Some skill groups, e.g. for G1 Averseness, have no base skill.
*/
skill1?: number;
/**
* First upgraded version of a skill, if any.
* A rare (gold) skill, double circle skill, or an inherited unique skill.
*/
skill2?: number;
/**
* Highest upgraded version of a skill, if any.
* Gold version of a skill with a double circle version.
*/
skill3?: number;
/**
* Negative (purple) version of a skill, if any.
*/
skill_bad?: number;
}
/**
* Sparks, or succession factors.
*/
export interface Spark {
/**
* Spark ID.
*/
spark_id: number;
/**
* Regional spark name.
*/
name: string;
/**
* Regional spark description.
*/
description: string;
/**
* Spark group.
* Different star levels of a given spark are different spark IDs but
* share a spark group.
*/
spark_group: number;
/**
* Spark rarity, or star level.
*/
rarity: 1 | 2 | 3;
/**
* Spark type.
* Roughly the spark color, with extra subdivisions for white sparks.
*/
type: 1 | 2 | 5 | 4 | 6 | 7 | 10 | 8 | 11 | 9 | 3;
/**
* Possible effects applied by the spark during inspiration.
* A random element is selected from this list according to unknown
* distributions, then all effects in that selection are applied.
*/
effects: SparkEffect[][];
}
/**
* Effects that a spark can apply.
*/
export interface SparkEffect {
target: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 21 | 22 | 23 | 24 | 31 | 32 | 33 | 34 | 41 | 51 | 61 | 62 | 63 | 64 | 65;
value1?: number;
value2: number;
}
/**
* Lobby conversation data.
*/
export interface Conversation {
/**
* Character who owns the conversation as a gallery entry.
*/
chara_id: number;
/**
* Number of the conversation within the character's conversation gallery.
*/
number: number;
/**
* Location ID of the conversation.
*/
location: 110 | 120 | 130 | 210 | 220 | 310 | 410 | 420 | 430 | 510 | 520 | 530;
/**
* English name of the location, for convenience.
*/
location_name: string;
/**
* First character in the conversation.
* Not necessarily equal to chara_id.
*/
chara_1: number;
/**
* Second character, if present.
*/
chara_2?: number;
/**
* Third character, if present.
*/
chara_3?: number;
/**
* Some unknown number in the game's local database.
*/
condition_type: 0 | 1 | 2 | 3 | 4;
}

View File

@@ -1,35 +0,0 @@
---
// Input to select a character,
// e.g. Special Week (not [Special Dreamer] Special Week).
import { character, type Character } from "../data/character";
interface Props {
id: string;
label?: string;
required?: boolean;
region?: keyof typeof character;
}
export interface Emits {
"chara-change": (ev: CustomEvent<{id: string, chara?: Character}>) => void;
}
const { id, label, required = false, region = "global" } = Astro.props;
---
{label && <label for="id">{label}</label>}
<select class="select-chara" id={id}>
{!required && <option value=""></option>}
{character[region].map((chara) => (
<option value={chara.chara_id}>{chara.name}</option>
))}
</select>
<script is:inline define:vars={{ id, region, character }}>
document.getElementById(id).addEventListener("change", (ev) => {
const chara_id = parseInt(ev.target.value);
const chara = character[region].find((c) => c.chara_id === chara_id);
const detail = chara != null ? {id, chara} : {id};
const b = new CustomEvent("chara-change", { detail, bubbles: true });
ev.target.dispatchEvent(b);
});
</script>

View File

@@ -1,2 +0,0 @@
---
---

View File

@@ -1,27 +0,0 @@
import globalJSON from "../../global/character.json";
/**
* Character definitions.
*/
export interface Character {
/**
* Character ID.
*/
chara_id: number;
/**
* Regional name of the character.
* E.g., Special Week for Global, or スペシャルウィーク for JP.
*/
name: string;
}
const global = globalJSON as Character[];
export const character = {
global,
}
export function searchChara(charas: Character[], id: Character["chara_id"]): Character | undefined {
// TODO(zephyr): binary search
return charas.find((c) => c.chara_id === id);
}

View File

@@ -1,20 +0,0 @@
---
import CharaSelect from "../components/CharaSelect.astro";
import "../styles/normalize.css";
import "../styles/sakura-vars.css";
---
<html>
<body>
<h1>Zenno Rob Roy</h1>
<p>She's read all about Umamusume, and she's always happy to share her knowledge and give recommendations!</p>
<ul>
<li>Discord bot: Prove yourself right about skill details without switching tabs.</li>
<li>Lobby conversations: Get recommendations on unlocking lobby conversations for the archive gallery.</li>
</ul>
<CharaSelect id="chara-test" label="Select character"/>
<script>
document.getElementById("chara-test")!.addEventListener("chara-change", (ev) => console.log("chara change", ev))
</script>
</body>
</html>

View File

@@ -1,379 +0,0 @@
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
/* Document
========================================================================== */
/**
* 1. Correct the line height in all browsers.
* 2. Prevent adjustments of font size after orientation changes in iOS.
*/
html {
line-height: 1.15;
/* 1 */
-webkit-text-size-adjust: 100%;
/* 2 */
}
/* Sections
========================================================================== */
/**
* Remove the margin in all browsers.
*/
body {
margin: 0;
}
/**
* Render the `main` element consistently in IE.
*/
main {
display: block;
}
/**
* Correct the font size and margin on `h1` elements within `section` and
* `article` contexts in Chrome, Firefox, and Safari.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/* Grouping content
========================================================================== */
/**
* 1. Add the correct box sizing in Firefox.
* 2. Show the overflow in Edge and IE.
*/
hr {
box-sizing: content-box;
/* 1 */
height: 0;
/* 1 */
overflow: visible;
/* 2 */
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
pre {
font-family: monospace, monospace;
/* 1 */
font-size: 1em;
/* 2 */
}
/* Text-level semantics
========================================================================== */
/**
* Remove the gray background on active links in IE 10.
*/
a {
background-color: transparent;
}
/**
* 1. Remove the bottom border in Chrome 57-
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
*/
abbr[title] {
border-bottom: none;
/* 1 */
text-decoration: underline;
/* 2 */
text-decoration: underline dotted;
/* 2 */
}
/**
* Add the correct font weight in Chrome, Edge, and Safari.
*/
b,
strong {
font-weight: bolder;
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
code,
kbd,
samp {
font-family: monospace, monospace;
/* 1 */
font-size: 1em;
/* 2 */
}
/**
* Add the correct font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` elements from affecting the line height in
* all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
/* Embedded content
========================================================================== */
/**
* Remove the border on images inside links in IE 10.
*/
img {
border-style: none;
}
/* Forms
========================================================================== */
/**
* 1. Change the font styles in all browsers.
* 2. Remove the margin in Firefox and Safari.
*/
button,
input,
optgroup,
select,
textarea {
font-family: inherit;
/* 1 */
font-size: 100%;
/* 1 */
line-height: 1.15;
/* 1 */
margin: 0;
/* 2 */
}
/**
* Show the overflow in IE.
* 1. Show the overflow in Edge.
*/
button,
input {
/* 1 */
overflow: visible;
}
/**
* Remove the inheritance of text transform in Edge, Firefox, and IE.
* 1. Remove the inheritance of text transform in Firefox.
*/
button,
select {
/* 1 */
text-transform: none;
}
/**
* Correct the inability to style clickable types in iOS and Safari.
*/
button,
[type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
}
/**
* Remove the inner border and padding in Firefox.
*/
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
border-style: none;
padding: 0;
}
/**
* Restore the focus styles unset by the previous rule.
*/
button:-moz-focusring,
[type="button"]:-moz-focusring,
[type="reset"]:-moz-focusring,
[type="submit"]:-moz-focusring {
outline: 1px dotted ButtonText;
}
/**
* Correct the padding in Firefox.
*/
fieldset {
padding: 0.35em 0.75em 0.625em;
}
/**
* 1. Correct the text wrapping in Edge and IE.
* 2. Correct the color inheritance from `fieldset` elements in IE.
* 3. Remove the padding so developers are not caught out when they zero out
* `fieldset` elements in all browsers.
*/
legend {
box-sizing: border-box;
/* 1 */
color: inherit;
/* 2 */
display: table;
/* 1 */
max-width: 100%;
/* 1 */
padding: 0;
/* 3 */
white-space: normal;
/* 1 */
}
/**
* Add the correct vertical alignment in Chrome, Firefox, and Opera.
*/
progress {
vertical-align: baseline;
}
/**
* Remove the default vertical scrollbar in IE 10+.
*/
textarea {
overflow: auto;
}
/**
* 1. Add the correct box sizing in IE 10.
* 2. Remove the padding in IE 10.
*/
[type="checkbox"],
[type="radio"] {
box-sizing: border-box;
/* 1 */
padding: 0;
/* 2 */
}
/**
* Correct the cursor style of increment and decrement buttons in Chrome.
*/
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
/**
* 1. Correct the odd appearance in Chrome and Safari.
* 2. Correct the outline style in Safari.
*/
[type="search"] {
-webkit-appearance: textfield;
/* 1 */
outline-offset: -2px;
/* 2 */
}
/**
* Remove the inner padding in Chrome and Safari on macOS.
*/
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* 1. Correct the inability to style clickable types in iOS and Safari.
* 2. Change font properties to `inherit` in Safari.
*/
::-webkit-file-upload-button {
-webkit-appearance: button;
/* 1 */
font: inherit;
/* 2 */
}
/* Interactive
========================================================================== */
/*
* Add the correct display in Edge, IE 10+, and Firefox.
*/
details {
display: block;
}
/*
* Add the correct display in all browsers.
*/
summary {
display: list-item;
}
/* Misc
========================================================================== */
/**
* Add the correct display in IE 10+.
*/
template {
display: none;
}
/**
* Add the correct display in IE 10.
*/
[hidden] {
display: none;
}

View File

@@ -1,401 +0,0 @@
/* Sakura.css v1.5.0
* ================
* Minimal css theme.
* Project: https://github.com/oxalorg/sakura/
*/
/* data-theme="taiyō" */
:root {
--blossom: #292722;
--fade: #7d7768;
--bg: #ffecec;
--bg-alt: #ffecec;
--text: #292222;
}
[data-theme="iron goddess"] {
--blossom: #424b51;
--fade: #64707a;
--bg: #fff2e2;
--bg-alt: #fffce2;
--text: #2c2923;
}
[data-theme="main sequence"] {
--blossom: #3a5425;
--fade: #698650;
--bg: #fffde5;
--bg-alt: #fff4e5;
--text: #5e592a;
}
[data-theme="sorcery"] {
--blossom: #5a5a69;
--fade: #868698;
--bg: #e5f4e5;
--bg-alt: #e6f4e6;
--text: #323932;
}
[data-theme="cirrus"] {
--blossom: #565a4b;
--fade: #9da587;
--bg: #e5f6fa;
--bg-alt: #e5f6fa;
--text: #31393b;
}
[data-theme="oxygen"] {
--blossom: #162011;
--fade: #343932;
--bg: #e1e2e4;
--bg-alt: #e3e0e3;
--text: #27282c;
}
[data-theme="dauphin"] {
--blossom: #171e1c;
--fade: #485b58;
--bg: #ebe5f8;
--bg-alt: #ebe5f8;
--text: #1c1a20;
}
[data-theme="diamond-burned"] {
--blossom: #0f0d0b;
--fade: #4d4743;
--bg: #f8ebf2;
--bg-alt: #ebe8f4;
--text: #3e363a;
}
[data-theme="chi"] {
--blossom: #908975;
--fade: #fff8e5;
--bg: #110c0c;
--bg-alt: #0a090c;
--text: #cfa9a9;
}
[data-theme="darjeeling"] {
--blossom: #ba949c;
--fade: #f8e1e6;
--bg: #1c160d;
--bg-alt: #1c160d;
--text: #c9b9a0;
}
[data-theme="subgiant"] {
--blossom: #9fad8a;
--fade: #e8f2d7;
--bg: #16130b;
--bg-alt: #16130b;
--text: #bbb396;
}
[data-theme="goblin"] {
--blossom: #7a808e;
--fade: #dae1ef;
--bg: #070905;
--bg-alt: #0a0906;
--text: #acbd9f;
}
[data-theme="altostratus"] {
--blossom: #a8a0b7;
--fade: #e5dbf7;
--bg: #0c0f0f;
--bg-alt: #1a1614;
--text: #8da4a4;
}
[data-theme="silicon"] {
--blossom: #717f63;
--fade: #c4d4b3;
--bg: #050a0f;
--bg-alt: #050a0f;
--text: #838e9a;
}
[data-theme="imperator"] {
--blossom: #93a0a3;
--fade: #f3fbfd;
--bg: #0e0c12;
--bg-alt: #0e0c12;
--text: #a8a1b1;
}
[data-theme="mædi"] {
--blossom: #ccd3b6;
--fade: #fdfbf3;
--bg: #10090f;
--bg-alt: #2f282e;
--text: #9e889a;
}
/* Body */
html {
font-size: 62.5%;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
}
body {
font-size: 1.8rem;
line-height: 1.618;
max-width: 38em;
margin: auto;
color: var(--text);
background-color: var(--bg);
padding: 13px;
}
@media (max-width: 684px) {
body {
font-size: 1.53rem;
}
}
@media (max-width: 382px) {
body {
font-size: 1.35rem;
}
}
h1,
h2,
h3,
h4,
h5,
h6 {
line-height: 1.1;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
font-weight: 700;
margin-top: 3rem;
margin-bottom: 1.5rem;
overflow-wrap: break-word;
word-wrap: break-word;
-ms-word-break: break-all;
word-break: break-word;
}
h1 {
font-size: 2.35em;
}
h2 {
font-size: 2em;
}
h3 {
font-size: 1.75em;
}
h4 {
font-size: 1.5em;
}
h5 {
font-size: 1.25em;
}
h6 {
font-size: 1em;
}
p {
margin-top: 0px;
margin-bottom: 2.5rem;
}
small,
sub,
sup {
font-size: 75%;
}
hr {
border-color: var(--blossom);
}
a {
text-decoration: none;
color: var(--blossom);
}
a:hover {
color: var(--fade);
border-bottom: 2px solid var(--text);
}
ul {
padding-left: 1.4em;
margin-top: 0px;
margin-bottom: 2.5rem;
}
li {
margin-bottom: 0.4em;
}
blockquote {
margin-left: 0px;
margin-right: 0px;
padding-left: 1em;
padding-top: 0.8em;
padding-bottom: 0.8em;
padding-right: 0.8em;
border-left: 5px solid var(--blossom);
margin-bottom: 2.5rem;
background-color: var(--bg-alt);
}
blockquote p {
margin-bottom: 0;
}
img,
video {
height: auto;
max-width: 100%;
margin-top: 0px;
margin-bottom: 2.5rem;
}
/* Pre and Code */
pre {
background-color: var(--bg-alt);
display: block;
padding: 1em;
overflow-x: auto;
margin-top: 0px;
margin-bottom: 2.5rem;
font-size: 0.9em;
}
code,
kbd,
samp {
font-size: 0.9em;
padding: 0 0.5em;
background-color: var(--bg-alt);
white-space: pre-wrap;
}
pre>code {
padding: 0;
background-color: transparent;
white-space: pre;
font-size: 1em;
}
/* Tables */
table {
text-align: justify;
width: 100%;
border-collapse: collapse;
margin-bottom: 2rem;
}
td,
th {
padding: 0.5em;
border-bottom: 1px solid var(--bg-alt);
}
/* Buttons, forms and input */
input,
textarea {
border: 1px solid var(--text);
}
input:focus,
textarea:focus {
border: 1px solid var(--blossom);
}
textarea {
width: 100%;
}
.button,
button,
input[type=submit],
input[type=reset],
input[type=button],
input[type=file]::file-selector-button {
display: inline-block;
padding: 5px 10px;
text-align: center;
text-decoration: none;
white-space: nowrap;
background-color: var(--blossom);
color: var(--bg);
border-radius: 1px;
border: 1px solid var(--blossom);
cursor: pointer;
box-sizing: border-box;
}
.button[disabled],
button[disabled],
input[type=submit][disabled],
input[type=reset][disabled],
input[type=button][disabled],
input[type=file]::file-selector-button[disabled] {
cursor: default;
opacity: 0.5;
}
.button:hover,
button:hover,
input[type=submit]:hover,
input[type=reset]:hover,
input[type=button]:hover,
input[type=file]::file-selector-button:hover {
background-color: var(--fade);
color: var(--bg);
outline: 0;
}
.button:focus-visible,
button:focus-visible,
input[type=submit]:focus-visible,
input[type=reset]:focus-visible,
input[type=button]:focus-visible,
input[type=file]::file-selector-button:focus-visible {
outline-style: solid;
outline-width: 2px;
}
textarea,
select,
input {
color: var(--text);
padding: 6px 10px;
/* The 6px vertically centers text on FF, ignored by Webkit */
margin-bottom: 10px;
background-color: var(--bg-alt);
border: 1px solid var(--bg-alt);
border-radius: 4px;
box-shadow: none;
box-sizing: border-box;
}
textarea:focus,
select:focus,
input:focus {
border: 1px solid var(--blossom);
outline: 0;
}
input[type=checkbox]:focus {
outline: 1px dotted var(--blossom);
}
label,
legend,
fieldset {
display: block;
margin-bottom: 0.5rem;
font-weight: 600;
}

View File

@@ -1,3 +0,0 @@
{
"extends": "astro/tsconfigs/strictest"
}