Compare commits

5 Commits
Author SHA1 Message Date
zephyr 55aa03aa41 umadump/replay: start of race replay json decoding 2026-09-20 11:44:09 -04:00
zephyr 0ffd2c099a horse, mdb: include id in lobby conversations
ci/woodpecker/push/horsebot Pipeline was successful
ci/woodpecker/push/zenno Pipeline was successful
2026-09-17 12:59:28 -04:00
zephyr 6828b1bd88 horse, mdb: put skill groups in skills
ci/woodpecker/push/horsebot Pipeline was successful
ci/woodpecker/push/zenno Pipeline was successful
Fixes #13.
2026-09-15 11:00:10 -04:00
zephyr 78aee43e5f zenno: format
ci/woodpecker/push/horsebot Pipeline was successful
ci/woodpecker/push/zenno Pipeline was successful
why the h*ck does vscode not format my .ts files on save even though i
have it configured to always format on save!!!!!!
2026-09-14 17:21:51 -04:00
zephyr 745c9d01dd zenno/doc/frbm: delete jbc sprint
Fixes #46.
2026-09-14 17:20:40 -04:00
24 changed files with 1704 additions and 200 deletions
+2
View File
@@ -28,6 +28,8 @@ type AffinityDetail struct {
// Conversation describes a lobby conversation.
type Conversation struct {
// ID is the conversation ID.
ID int32 `json:"id"`
// CharacterID is the ID of the character who has the conversation as
// a gallery entry.
CharacterID CharacterID `json:"chara_id"`
+8 -7
View File
@@ -89,13 +89,14 @@ func Umas(ctx context.Context, db *sqlitex.Pool) ([]horse.Uma, error) {
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),
ID: s.ColumnInt32(0),
CharacterID: horse.CharacterID(s.ColumnInt(1)),
Number: s.ColumnInt(2),
Location: horse.LobbyConversationLocationID(s.ColumnInt(3)),
Chara1: horse.CharacterID(s.ColumnInt(4)),
Chara2: horse.CharacterID(s.ColumnInt(5)),
Chara3: horse.CharacterID(s.ColumnInt(6)),
ConditionType: s.ColumnInt(7),
}
})
}
+11
View File
@@ -238,12 +238,14 @@ func TestConversations(t *testing.T) {
}
want := []horse.Conversation{
{
ID: 1,
CharacterID: 1001,
Number: 1,
Location: 410,
Chara1: 1001,
},
{
ID: 2,
CharacterID: 1001,
Number: 2,
Location: 510,
@@ -251,6 +253,7 @@ func TestConversations(t *testing.T) {
ConditionType: 1,
},
{
ID: 3,
CharacterID: 1001,
Number: 3,
Location: 310,
@@ -258,6 +261,7 @@ func TestConversations(t *testing.T) {
ConditionType: 1,
},
{
ID: 76,
CharacterID: 1001,
Number: 4,
Location: 120,
@@ -266,6 +270,7 @@ func TestConversations(t *testing.T) {
ConditionType: 2,
},
{
ID: 77,
CharacterID: 1001,
Number: 5,
Location: 520,
@@ -274,6 +279,7 @@ func TestConversations(t *testing.T) {
ConditionType: 3,
},
{
ID: 126,
CharacterID: 1001,
Number: 6,
Location: 430,
@@ -283,12 +289,14 @@ func TestConversations(t *testing.T) {
ConditionType: 1,
},
{
ID: 4,
CharacterID: 1002,
Number: 1,
Location: 310,
Chara1: 1002,
},
{
ID: 5,
CharacterID: 1002,
Number: 2,
Location: 210,
@@ -296,6 +304,7 @@ func TestConversations(t *testing.T) {
ConditionType: 1,
},
{
ID: 6,
CharacterID: 1002,
Number: 3,
Location: 110,
@@ -303,6 +312,7 @@ func TestConversations(t *testing.T) {
ConditionType: 1,
},
{
ID: 78,
CharacterID: 1002,
Number: 4,
Location: 520,
@@ -311,6 +321,7 @@ func TestConversations(t *testing.T) {
ConditionType: 3,
},
{
ID: 79,
CharacterID: 1002,
Number: 5,
Location: 220,
+101 -55
View File
@@ -18,6 +18,8 @@ var (
skillGroupSQL string
//go:embed sql/skill.sql
skillSQL string
//go:embed sql/skill-group-skills.sql
skillGroupSkillsSQL string
)
// SkillGroups retrieves all skill groups.
@@ -35,84 +37,128 @@ func SkillGroups(ctx context.Context, db *sqlitex.Pool) ([]horse.SkillGroup, err
// 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),
// 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 sk []horse.Skill
{
stmt := conn.Prep(skillSQL)
defer stmt.Reset()
for {
ok, err := stmt.Step()
if err != nil {
return nil, err
}
if !ok {
break
}
s := horse.Skill{
ID: horse.SkillID(stmt.ColumnInt(0)),
Name: stmt.ColumnText(1),
Description: stmt.ColumnText(2),
GroupSkills: make([]horse.GroupSkill, 0, 3),
Group: horse.SkillGroupID(stmt.ColumnInt32(3)),
Rarity: int8(stmt.ColumnInt(5)),
GroupRate: int8(stmt.ColumnInt(6)),
GradeValue: stmt.ColumnInt32(7),
WitCheck: stmt.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)),
Precondition: stmt.ColumnText(9),
Condition: stmt.ColumnText(10),
Duration: horse.TenThousandths(stmt.ColumnInt(11)),
DurScale: horse.DurScale(stmt.ColumnInt(12)),
Cooldown: horse.TenThousandths(stmt.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(stmt.ColumnInt(14)),
ValueUsage: horse.AbilityValueUsage(stmt.ColumnInt(15)),
Value: horse.TenThousandths(stmt.ColumnInt(16)),
Target: horse.AbilityTarget(stmt.ColumnInt(17)),
TargetValue: stmt.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(stmt.ColumnInt(19)),
ValueUsage: horse.AbilityValueUsage(stmt.ColumnInt(20)),
Value: horse.TenThousandths(stmt.ColumnInt(21)),
Target: horse.AbilityTarget(stmt.ColumnInt(22)),
TargetValue: stmt.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),
Type: horse.AbilityType(stmt.ColumnInt(24)),
ValueUsage: horse.AbilityValueUsage(stmt.ColumnInt(25)),
Value: horse.TenThousandths(stmt.ColumnInt(26)),
Target: horse.AbilityTarget(stmt.ColumnInt(27)),
TargetValue: stmt.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)),
Precondition: stmt.ColumnText(29),
Condition: stmt.ColumnText(30),
Duration: horse.TenThousandths(stmt.ColumnInt(31)),
DurScale: horse.DurScale(stmt.ColumnInt(32)),
Cooldown: horse.TenThousandths(stmt.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(stmt.ColumnInt(34)),
ValueUsage: horse.AbilityValueUsage(stmt.ColumnInt(35)),
Value: horse.TenThousandths(stmt.ColumnInt(36)),
Target: horse.AbilityTarget(stmt.ColumnInt(37)),
TargetValue: stmt.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(stmt.ColumnInt(39)),
ValueUsage: horse.AbilityValueUsage(stmt.ColumnInt(40)),
Value: horse.TenThousandths(stmt.ColumnInt(41)),
Target: horse.AbilityTarget(stmt.ColumnInt(42)),
TargetValue: stmt.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),
Type: horse.AbilityType(stmt.ColumnInt(44)),
ValueUsage: horse.AbilityValueUsage(stmt.ColumnInt(45)),
Value: horse.TenThousandths(stmt.ColumnInt(46)),
Target: horse.AbilityTarget(stmt.ColumnInt(47)),
TargetValue: stmt.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),
UniqueOwner: stmt.ColumnText(52), // TODO(zeph): should be id, not name
Tags: parseTags(stmt.ColumnText(54)),
SPCost: stmt.ColumnInt(49),
IconID: stmt.ColumnInt(53),
}
})
sk = append(sk, s)
}
}
stmt := conn.Prep(skillGroupSkillsSQL)
defer stmt.Reset()
cur := sk
for {
ok, err := stmt.Step()
if err != nil {
return nil, err
}
if !ok {
break
}
// We sort skills by ID first, so we can add group skills in a single pass.
id := stmt.ColumnInt(0)
for len(cur) != 0 && cur[0].ID != horse.SkillID(id) {
cur = cur[1:]
}
g := horse.GroupSkill{
ID: horse.SkillID(stmt.ColumnInt(1)),
GroupRate: int8(stmt.ColumnInt(2)),
Rarity: int8(stmt.ColumnInt(3)),
}
cur[0].GroupSkills = append(cur[0].GroupSkills, g)
}
return sk, nil
}
func parseTags(s string) []uint16 {
+87
View File
@@ -49,6 +49,11 @@ func TestSkills(t *testing.T) {
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.",
GroupSkills: []horse.GroupSkill{
{ID: 100351, GroupRate: 1, Rarity: 4},
{ID: 10351, GroupRate: 1, Rarity: 3},
{ID: 900351, GroupRate: 2, Rarity: 1},
},
Group: 1035,
Rarity: 3,
GroupRate: 1,
@@ -81,6 +86,10 @@ func TestSkills(t *testing.T) {
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.",
GroupSkills: []horse.GroupSkill{
{ID: 100011, GroupRate: 1, Rarity: 5},
{ID: 900011, GroupRate: 2, Rarity: 1},
},
Group: 10001,
Rarity: 5,
GroupRate: 1,
@@ -120,6 +129,11 @@ func TestSkills(t *testing.T) {
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.",
GroupSkills: []horse.GroupSkill{
{ID: 100351, GroupRate: 1, Rarity: 4},
{ID: 10351, GroupRate: 1, Rarity: 3},
{ID: 900351, GroupRate: 2, Rarity: 1},
},
Group: 10035,
Rarity: 4,
GroupRate: 1,
@@ -152,6 +166,10 @@ func TestSkills(t *testing.T) {
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.",
GroupSkills: []horse.GroupSkill{
{ID: 110241, GroupRate: 1, Rarity: 5},
{ID: 910241, GroupRate: 2, Rarity: 1},
},
Group: 11024,
Rarity: 5,
GroupRate: 1,
@@ -200,6 +218,12 @@ func TestSkills(t *testing.T) {
ID: 200011,
Name: "Right-Handed ◎",
Description: "Increase performance on right-handed tracks.",
GroupSkills: []horse.GroupSkill{
{ID: 200013, GroupRate: -1, Rarity: 1},
{ID: 200012, GroupRate: 1, Rarity: 1},
{ID: 200011, GroupRate: 2, Rarity: 1},
{ID: 200014, GroupRate: 3, Rarity: 2},
},
Group: 20001,
Rarity: 1,
GroupRate: 2,
@@ -231,6 +255,12 @@ func TestSkills(t *testing.T) {
ID: 200012,
Name: "Right-Handed ○",
Description: "Moderately increase performance on right-handed tracks.",
GroupSkills: []horse.GroupSkill{
{ID: 200013, GroupRate: -1, Rarity: 1},
{ID: 200012, GroupRate: 1, Rarity: 1},
{ID: 200011, GroupRate: 2, Rarity: 1},
{ID: 200014, GroupRate: 3, Rarity: 2},
},
Group: 20001,
Rarity: 1,
GroupRate: 1,
@@ -262,6 +292,12 @@ func TestSkills(t *testing.T) {
ID: 200013,
Name: "Right-Handed ×",
Description: "Moderately decrease performance on right-handed tracks.",
GroupSkills: []horse.GroupSkill{
{ID: 200013, GroupRate: -1, Rarity: 1},
{ID: 200012, GroupRate: 1, Rarity: 1},
{ID: 200011, GroupRate: 2, Rarity: 1},
{ID: 200014, GroupRate: 3, Rarity: 2},
},
Group: 20001,
Rarity: 1,
GroupRate: -1,
@@ -293,6 +329,12 @@ func TestSkills(t *testing.T) {
ID: 200014,
Name: "Right-Handed Demon",
Description: "Increase proficiency in right-handed tracks, increasing Speed and Power.",
GroupSkills: []horse.GroupSkill{
{ID: 200013, GroupRate: -1, Rarity: 1},
{ID: 200012, GroupRate: 1, Rarity: 1},
{ID: 200011, GroupRate: 2, Rarity: 1},
{ID: 200014, GroupRate: 3, Rarity: 2},
},
Group: 20001,
Rarity: 2,
GroupRate: 3,
@@ -331,6 +373,11 @@ func TestSkills(t *testing.T) {
ID: 200021,
Name: "Left-Handed ◎",
Description: "Increase performance on left-handed tracks.",
GroupSkills: []horse.GroupSkill{
{ID: 200023, GroupRate: -1, Rarity: 1},
{ID: 200022, GroupRate: 1, Rarity: 1},
{ID: 200021, GroupRate: 2, Rarity: 1},
},
Group: 20002,
Rarity: 1,
GroupRate: 2,
@@ -362,6 +409,11 @@ func TestSkills(t *testing.T) {
ID: 200022,
Name: "Left-Handed ○",
Description: "Moderately increase performance on left-handed tracks.",
GroupSkills: []horse.GroupSkill{
{ID: 200023, GroupRate: -1, Rarity: 1},
{ID: 200022, GroupRate: 1, Rarity: 1},
{ID: 200021, GroupRate: 2, Rarity: 1},
},
Group: 20002,
Rarity: 1,
GroupRate: 1,
@@ -393,6 +445,11 @@ func TestSkills(t *testing.T) {
ID: 200023,
Name: "Left-Handed ×",
Description: "Moderately decrease performance on left-handed tracks.",
GroupSkills: []horse.GroupSkill{
{ID: 200023, GroupRate: -1, Rarity: 1},
{ID: 200022, GroupRate: 1, Rarity: 1},
{ID: 200021, GroupRate: 2, Rarity: 1},
},
Group: 20002,
Rarity: 1,
GroupRate: -1,
@@ -424,6 +481,10 @@ func TestSkills(t *testing.T) {
ID: 200361,
Name: "Beeline Burst",
Description: "Increase velocity on a straight.",
GroupSkills: []horse.GroupSkill{
{ID: 200362, GroupRate: 1, Rarity: 1},
{ID: 200361, GroupRate: 2, Rarity: 2},
},
Group: 20036,
Rarity: 2,
GroupRate: 2,
@@ -455,6 +516,10 @@ func TestSkills(t *testing.T) {
ID: 200362,
Name: "Straightaway Adept",
Description: "Slightly increase velocity on a straight.",
GroupSkills: []horse.GroupSkill{
{ID: 200362, GroupRate: 1, Rarity: 1},
{ID: 200361, GroupRate: 2, Rarity: 2},
},
Group: 20036,
Rarity: 1,
GroupRate: 1,
@@ -486,6 +551,9 @@ func TestSkills(t *testing.T) {
ID: 200831,
Name: "Subdued Front Runners",
Description: "Slightly increase fatigue for front runners early-race.",
GroupSkills: []horse.GroupSkill{
{ID: 200831, GroupRate: 1, Rarity: 1},
},
Group: 20083,
Rarity: 1,
GroupRate: 1,
@@ -517,6 +585,9 @@ func TestSkills(t *testing.T) {
ID: 201801,
Name: "♡ 3D Nail Art",
Description: "Moderately decrease performance on firm ground.",
GroupSkills: []horse.GroupSkill{
{ID: 201801, GroupRate: -1, Rarity: 1},
},
Group: 20180,
Rarity: 1,
GroupRate: -1,
@@ -548,6 +619,9 @@ func TestSkills(t *testing.T) {
ID: 300011,
Name: "Unquenched Thirst",
Description: "Moderately increase performance with the desire to race.",
GroupSkills: []horse.GroupSkill{
{ID: 300011, GroupRate: 1, Rarity: 1},
},
Group: 30001,
Rarity: 1,
GroupRate: 1,
@@ -579,6 +653,10 @@ func TestSkills(t *testing.T) {
ID: 900011,
Name: "Shooting Star",
Description: "Slightly increase velocity and very minimally increase acceleration after passing another runner toward the front late-race.",
GroupSkills: []horse.GroupSkill{
{ID: 100011, GroupRate: 1, Rarity: 5},
{ID: 900011, GroupRate: 2, Rarity: 1},
},
Group: 10001,
Rarity: 1,
GroupRate: 2,
@@ -618,6 +696,11 @@ func TestSkills(t *testing.T) {
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.",
GroupSkills: []horse.GroupSkill{
{ID: 100351, GroupRate: 1, Rarity: 4},
{ID: 10351, GroupRate: 1, Rarity: 3},
{ID: 900351, GroupRate: 2, Rarity: 1},
},
Group: 10035,
Rarity: 1,
GroupRate: 2,
@@ -650,6 +733,10 @@ func TestSkills(t *testing.T) {
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.",
GroupSkills: []horse.GroupSkill{
{ID: 110241, GroupRate: 1, Rarity: 5},
{ID: 910241, GroupRate: 2, Rarity: 1},
},
Group: 11024,
Rarity: 1,
GroupRate: 2,
+1
View File
@@ -1,4 +1,5 @@
SELECT
id,
gallery_chara_id,
disp_order,
pos_id,
+43
View File
@@ -0,0 +1,43 @@
WITH g AS (
SELECT
l.id AS l,
r.id AS r,
r.group_rate,
r.rarity
FROM skill_data l
JOIN skill_data r ON l.group_id = r.group_id
UNION ALL
SELECT
s.id AS l,
i.id AS r,
i.group_rate,
i.rarity
FROM skill_data s
JOIN skill_data i ON s.id IN (i.unique_skill_id_1, i.unique_skill_id_2)
UNION ALL
SELECT
s.id AS l,
i.id AS r,
i.group_rate,
i.rarity
FROM skill_data s
JOIN skill_data i ON i.id IN (s.unique_skill_id_1, s.unique_skill_id_2)
UNION ALL
SELECT
l.id AS l,
r.id AS r,
r.group_rate,
r.rarity
FROM skill_data i
JOIN skill_data l ON l.id IN (i.unique_skill_id_1, i.unique_skill_id_2)
JOIN skill_data r ON r.id IN (i.unique_skill_id_1, i.unique_skill_id_2)
WHERE l.id != r.id
)
SELECT * FROM g
ORDER BY l, group_rate, rarity DESC
+7
View File
@@ -30,6 +30,7 @@ type Skill struct {
ID SkillID `json:"skill_id"`
Name string `json:"name"`
Description string `json:"description"`
GroupSkills []GroupSkill `json:"group_skills"`
Group SkillGroupID `json:"group"`
Rarity int8 `json:"rarity"`
GroupRate int8 `json:"group_rate"`
@@ -42,6 +43,12 @@ type Skill struct {
IconID int `json:"icon_id"`
}
type GroupSkill struct {
ID SkillID `json:"skill_id"`
GroupRate int8 `json:"group_rate"`
Rarity int8 `json:"rarity"`
}
// Activation is the parameters controlling when a skill activates.
type Activation struct {
Precondition string `json:"precondition,omitzero"`
+35
View File
@@ -0,0 +1,35 @@
// Code generated by "stringer -type CharaGradeType -linecomment -trimprefix CharaGrade"; DO NOT EDIT.
package replay
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[CharaGradeNone-0]
_ = x[CharaGradeDebut-1]
_ = x[CharaGradeNoWin-2]
_ = x[CharaGradeOpen-3]
_ = x[CharaGradeG3Silver-4]
_ = x[CharaGradeG3Gold-5]
_ = x[CharaGradeG2Silver-6]
_ = x[CharaGradeG2Gold-7]
_ = x[CharaGradeG1Bronze-8]
_ = x[CharaGradeG1Silver-9]
_ = x[CharaGradeG1Gold-10]
_ = x[charaGradeMax-11]
}
const _CharaGradeType_name = "NONEDebutNoWinOpenG3SilverG3GoldG2SilverG2GoldG1BronzeG1SilverG1GoldcharaGradeMax"
var _CharaGradeType_index = [...]uint8{0, 4, 9, 14, 18, 26, 32, 40, 46, 54, 62, 68, 81}
func (i CharaGradeType) String() string {
idx := int(i) - 0
if i < 0 || idx >= len(_CharaGradeType_index)-1 {
return "CharaGradeType(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _CharaGradeType_name[_CharaGradeType_index[idx]:_CharaGradeType_index[idx+1]]
}
@@ -0,0 +1,27 @@
// Code generated by "stringer -type CourseDistanceType -linecomment -trimprefix Distance"; DO NOT EDIT.
package replay
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[DistanceSprint-1]
_ = x[DistanceMile-2]
_ = x[DistanceMedium-3]
_ = x[DistanceLong-4]
}
const _CourseDistanceType_name = "ShortMileMiddleLong"
var _CourseDistanceType_index = [...]uint8{0, 5, 9, 15, 19}
func (i CourseDistanceType) String() string {
idx := int(i) - 1
if i < 1 || idx >= len(_CourseDistanceType_index)-1 {
return "CourseDistanceType(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _CourseDistanceType_name[_CourseDistanceType_index[idx]:_CourseDistanceType_index[idx+1]]
}
+27
View File
@@ -0,0 +1,27 @@
// Code generated by "stringer -type GroundCondition -linecomment"; DO NOT EDIT.
package replay
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[GroundFirm-1]
_ = x[GroundGood-2]
_ = x[GroundSoft-3]
_ = x[GroundHeavy-4]
}
const _GroundCondition_name = "GoodSoftHardBad"
var _GroundCondition_index = [...]uint8{0, 4, 8, 12, 15}
func (i GroundCondition) String() string {
idx := int(i) - 1
if i < 1 || idx >= len(_GroundCondition_index)-1 {
return "GroundCondition(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _GroundCondition_name[_GroundCondition_index[idx]:_GroundCondition_index[idx+1]]
}
+28
View File
@@ -0,0 +1,28 @@
// Code generated by "stringer -type InitialLaneType -trimprefix InitialLane"; DO NOT EDIT.
package replay
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[InitialLaneExtraSpaceAfter9-1]
_ = x[InitialLaneEquidistant-2]
_ = x[InitialLaneExtraSpaceAfter14-3]
_ = x[InitialLaneExtraSpaceAfter8-4]
_ = x[initialLaneMax-5]
}
const _InitialLaneType_name = "ExtraSpaceAfter9EquidistantExtraSpaceAfter14ExtraSpaceAfter8initialLaneMax"
var _InitialLaneType_index = [...]uint8{0, 16, 27, 44, 60, 74}
func (i InitialLaneType) String() string {
idx := int(i) - 1
if i < 1 || idx >= len(_InitialLaneType_index)-1 {
return "InitialLaneType(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _InitialLaneType_name[_InitialLaneType_index[idx]:_InitialLaneType_index[idx+1]]
}
@@ -0,0 +1,26 @@
// Code generated by "stringer -type MainStoryRaceGimmickType -linecomment"; DO NOT EDIT.
package replay
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[GimmickNone-0]
_ = x[GimmickSpecial00-1]
_ = x[gimmickMax-2]
}
const _MainStoryRaceGimmickType_name = "NONESpecial_00gimmickMax"
var _MainStoryRaceGimmickType_index = [...]uint8{0, 4, 14, 24}
func (i MainStoryRaceGimmickType) String() string {
idx := int(i) - 0
if i < 0 || idx >= len(_MainStoryRaceGimmickType_index)-1 {
return "MainStoryRaceGimmickType(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _MainStoryRaceGimmickType_name[_MainStoryRaceGimmickType_index[idx]:_MainStoryRaceGimmickType_index[idx+1]]
}
+29
View File
@@ -0,0 +1,29 @@
// Code generated by "stringer -type RaceDifficulty -trimprefix Difficulty"; DO NOT EDIT.
package replay
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[DifficultyEasy-1]
_ = x[DifficultyNormal-2]
_ = x[DifficultyHard-3]
_ = x[DifficultyVeryHard-4]
_ = x[DifficultyExtreme-5]
_ = x[difficultyMax-6]
}
const _RaceDifficulty_name = "EasyNormalHardVeryHardExtremedifficultyMax"
var _RaceDifficulty_index = [...]uint8{0, 4, 10, 14, 22, 29, 42}
func (i RaceDifficulty) String() string {
idx := int(i) - 1
if i < 1 || idx >= len(_RaceDifficulty_index)-1 {
return "RaceDifficulty(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _RaceDifficulty_name[_RaceDifficulty_index[idx]:_RaceDifficulty_index[idx+1]]
}
+29
View File
@@ -0,0 +1,29 @@
// Code generated by "stringer -type RaceTime -trimprefix Time"; DO NOT EDIT.
package replay
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[TimeMin-0]
_ = x[TimeMorning-1]
_ = x[TimeDaytime-2]
_ = x[TimeEvening-3]
_ = x[TimeNight-4]
_ = x[TimeMax-5]
}
const _RaceTime_name = "MinMorningDaytimeEveningNightMax"
var _RaceTime_index = [...]uint8{0, 3, 10, 17, 24, 29, 32}
func (i RaceTime) String() string {
idx := int(i) - 0
if i < 0 || idx >= len(_RaceTime_index)-1 {
return "RaceTime(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _RaceTime_name[_RaceTime_index[idx]:_RaceTime_index[idx+1]]
}
+48
View File
@@ -0,0 +1,48 @@
// Code generated by "stringer -type RaceType -linecomment -trimprefix RaceType"; DO NOT EDIT.
package replay
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[RaceTypeNone-0]
_ = x[RaceTypePvP-1]
_ = x[RaceTypeTutorial-2]
_ = x[RaceTypeStory-3]
_ = x[RaceTypeStoryCondition-4]
_ = x[RaceTypeChampions-5]
_ = x[RaceTypeSingle-6]
_ = x[RaceTypeSingleModeScenarioTeamRace-7]
_ = x[RaceTypeRoomMatch-8]
_ = x[RaceTypePractice-9]
_ = x[RaceTypeDaily-10]
_ = x[RaceTypeTeamBuilding-11]
_ = x[RaceTypeLegend-12]
_ = x[RaceTypeChallengeMatch-13]
_ = x[RaceTypeTeamStadium-14]
_ = x[RaceTypeHeroes-16]
_ = x[raceTypeMaxInclusive-16]
}
const (
_RaceType_name_0 = "NONEPvPTutorialStoryStoryConditionChampionsSingleSingleModeScenarioTeamRaceRoomMatchPracticeDailyTeamBuildingLegendChallengeMatchTeamStadium"
_RaceType_name_1 = "Heroes"
)
var (
_RaceType_index_0 = [...]uint8{0, 4, 7, 15, 20, 34, 43, 49, 75, 84, 92, 97, 109, 115, 129, 140}
)
func (i RaceType) String() string {
switch {
case 0 <= i && i <= 14:
return _RaceType_name_0[_RaceType_index_0[i]:_RaceType_index_0[i+1]]
case i == 16:
return _RaceType_name_1
default:
return "RaceType(" + strconv.FormatInt(int64(i), 10) + ")"
}
}
+29
View File
@@ -0,0 +1,29 @@
// Code generated by "stringer -type RaceWeather -trimprefix Weather"; DO NOT EDIT.
package replay
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[WeatherMin-0]
_ = x[WeatherSunny-1]
_ = x[WeatherCloudy-2]
_ = x[WeatherRainy-3]
_ = x[WeatherSnow-4]
_ = x[WeatherMax-5]
}
const _RaceWeather_name = "MinSunnyCloudyRainySnowMax"
var _RaceWeather_index = [...]uint8{0, 3, 8, 14, 19, 23, 26}
func (i RaceWeather) String() string {
idx := int(i) - 0
if i < 0 || idx >= len(_RaceWeather_index)-1 {
return "RaceWeather(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _RaceWeather_name[_RaceWeather_index[idx]:_RaceWeather_index[idx+1]]
}
+920
View File
@@ -0,0 +1,920 @@
package replay
import (
"fmt"
"strings"
"sync"
"git.sunturtle.xyz/zephyr/horse"
)
type Race struct {
RaceType RaceType `json:"raceType"`
IsExistPlayerRace bool `json:"isExistPlayerRace"`
IsExistGhostRace bool `json:"isExistGhostRace"`
IsExistFollowRace bool `json:"isExistFollowRace"`
IsMultiplePlayerRace bool `json:"isMultiplePlayerRace"`
RandomSeed int32 `json:"randomSeed"`
SingleRaceProgramID int32 `json:"singleRaceProgramId"`
OpponentEvaluate int32 `json:"opponentEvaluate"`
SelfEvaluate int32 `json:"selfEvaluate"`
SupportCardScoreBonus int32 `json:"supportCardScoreBonus"`
ScoreCalcTeamID int32 `json:"scoreCalcTeamId"`
RaceNo int32 `json:"raceNo"`
RaceCourseSet RaceCourseSet `json:"raceCourseSet"`
FenceSet struct{} `json:"fenceSet"`
RaceTrack struct{} `json:"raceTrack"`
GoalGate int32 `json:"goalGate"`
GoalGateFlower int32 `json:"goalGateFlower"`
InitialLaneType InitialLaneType `json:"initialLaneType"`
RotationCategory Rotation `json:"rotationCategory"`
ResultBoardConditionType ResultBoardConditionType `json:"resultBoardConditionType"`
CourseSectionDistance float32 `json:"courseSectionDistance"`
CourseDistanceType CourseDistanceType `json:"courseDistanceType"`
CourseFurlongNum int32 `json:"courseFurlongNum"`
IsHalfGate bool `json:"isHalfGate"`
IsHorseNumVariationGate bool `json:"isHorseNumVariationGate"`
TurfVisionType TurfVisionType `json:"turfVisionType"`
GroundCondition GroundCondition `json:"groundCondition"`
Weather RaceWeather `json:"weather"`
Season Season `json:"season"`
Time RaceTime `json:"time"`
BaseSpeed float32 `json:"baseSpeed"`
BorderTimeScaled float32 `json:"borderTimeScaled"`
ChallengeMatchDifficulty RaceDifficulty `json:"challengeMatchDifficulty"`
NumRaceHorses int32 `json:"numRaceHorses"`
PostNumberMax int32 `json:"postNumberMax"`
PlayerHorseIndex int32 `json:"playerHorseIndex"`
OverridePlayerHorseIndex int32 `json:"overridePlayerHorseIndex"`
PlayerTeamMemberArray []RaceHorse `json:"playerTeamMemberArray"`
PlayerTeamTopFinishOrderHorse RaceHorse `json:"playerTeamTopFinishOrderHorse"`
IsGateInPopularityInitialized bool `json:"isGateInPopularityInitialized"`
RaceHorse []RaceHorse `json:"raceHorse"`
RaceBibMaster struct{} `json:"raceBibMaster"`
RaceMaster struct{} `json:"raceMaster"`
RaceInstanceMaster struct{} `json:"raceInstanceMaster"`
SimDataBase64 string `json:"simDataBase64"`
SimData struct{} `json:"simData"`
SimReader struct{} `json:"simReader"`
EpisodeRaceReplayID int32 `json:"episodeRaceReplayId"`
IsNotSimulateExport bool `json:"isNotSimulateExport"`
LaneDistanceMax float32 `json:"laneDistanceMax"`
ReplayCheckInfo struct{} `json:"replayCheckInfo"`
ReplayCheckInfoDaily struct{} `json:"replayCheckInfoDaily"`
ReplayCheckInfoLegend struct{} `json:"replayCheckInfoLegend"`
IsDailyLegendRace bool `json:"isDailyLegendRace"`
ReplayCheckInfoChallengeMatch struct{} `json:"replayCheckInfoChallengeMatch"`
RaceRewardSingle RaceRewardSingle `json:"raceRewardSingle"`
ResultHorseIndex int32 `json:"resultHorseIndex"`
PrevGradeType CharaGradeType `json:"prevGradeType"`
MainStoryRaceGimmickType MainStoryRaceGimmickType `json:"mainStoryRaceGimmickType"`
IsMainStoryRaceMatchGimmick bool `json:"isMainStoryRaceMatchGimmick"`
UnlockFlags uint32 `json:"unlockFlags"`
PhaseCalculator struct{} `json:"phaseCalculator"`
HorseIndexByFinishOrder []int32 `json:"horseIndexByFinishOrder"`
HorseIndexByPopularity []int32 `json:"horseIndexByPopularity"`
}
type RaceType int32
//go:generate go run golang.org/x/tools/cmd/stringer@v0.41.0 -type RaceType -linecomment -trimprefix RaceType
const (
RaceTypeNone RaceType = iota // NONE
RaceTypePvP
RaceTypeTutorial
RaceTypeStory
RaceTypeStoryCondition
RaceTypeChampions
RaceTypeSingle
RaceTypeSingleModeScenarioTeamRace
RaceTypeRoomMatch
RaceTypePractice
RaceTypeDaily
RaceTypeTeamBuilding
RaceTypeLegend
RaceTypeChallengeMatch
RaceTypeTeamStadium
// no value 15
RaceTypeHeroes RaceType = 16
raceTypeMaxInclusive
)
func (r RaceType) AppendText(b []byte) ([]byte, error) {
return append(b, r.String()...), nil
}
func (r RaceType) MarshalText() ([]byte, error) {
return r.AppendText(nil)
}
var raceTypeNames = sync.OnceValue(func() map[string]RaceType {
m := make(map[string]RaceType, raceTypeMaxInclusive)
for r := RaceTypeNone; r <= raceTypeMaxInclusive; r++ {
s := r.String()
if strings.HasPrefix(s, "RaceType(") {
continue
}
m[r.String()] = r
}
return m
})
func (r *RaceType) UnmarshalText(b []byte) error {
n, ok := raceTypeNames()[string(b)]
*r = n
if !ok {
return fmt.Errorf("unknown race type %q", b)
}
return nil
}
type RaceCourseSet struct {
ID horse.RacecourseID `json:"id"`
RaceTrackID horse.RaceTrackID `json:"raceTrackId"`
Distance int32 `json:"distance"`
Ground int `json:"ground"`
Inout int `json:"inout"`
Turn int `json:"turn"`
FenceSet int `json:"fenceSet"`
FloatLaneMax int `json:"floatLaneMax"`
CourseSetStatusID int `json:"courseSetStatusId"`
FinishTimeMin int `json:"finishTimeMin"`
FinishTimeMinRandomRange int `json:"finishTimeMinRandomRange"`
FinishTimeMax int `json:"finishTimeMax"`
FinishTimeMaxRandomRange int `json:"finishTimeMaxRandomRange"`
}
type InitialLaneType int8
//go:generate go run golang.org/x/tools/cmd/stringer@v0.41.0 -type InitialLaneType -trimprefix InitialLane
const (
InitialLaneExtraSpaceAfter9 InitialLaneType = iota + 1
InitialLaneEquidistant
InitialLaneExtraSpaceAfter14
InitialLaneExtraSpaceAfter8
initialLaneMax
)
func (r InitialLaneType) AppendText(b []byte) ([]byte, error) {
return append(b, r.String()...), nil
}
func (r InitialLaneType) MarshalText() ([]byte, error) {
return r.AppendText(nil)
}
var initialLaneNames = sync.OnceValue(func() map[string]InitialLaneType {
m := make(map[string]InitialLaneType, initialLaneMax)
for r := InitialLaneExtraSpaceAfter9; r < initialLaneMax; r++ {
s := r.String()
if strings.HasPrefix(s, "InitialLaneType(") {
continue
}
m[r.String()] = r
}
return m
})
func (r *InitialLaneType) UnmarshalText(b []byte) error {
n, ok := initialLaneNames()[string(b)]
*r = n
if !ok {
return fmt.Errorf("unknown initial lane type type %q", b)
}
return nil
}
type Rotation int8
//go:generate go run golang.org/x/tools/cmd/stringer@v0.41.0 -type Rotation -trimprefix Rotation
const (
RotationRight Rotation = iota + 1
RotationLeft
RotationStraightRight
RotationStraightLeft
)
func (r Rotation) AppendText(b []byte) ([]byte, error) {
return append(b, r.String()...), nil
}
func (r Rotation) MarshalText() ([]byte, error) {
return r.AppendText(nil)
}
func (r *Rotation) UnmarshalText(b []byte) error {
switch string(b) {
case "Right":
*r = RotationRight
case "Left":
*r = RotationLeft
case "StraightRight":
*r = RotationStraightRight
case "StraightLeft":
*r = RotationStraightLeft
default:
*r = 0
return fmt.Errorf("unknown rotation type %q", b)
}
return nil
}
type ResultBoardConditionType int8
//go:generate go run golang.org/x/tools/cmd/stringer@v0.41.0 -type ResultBoardConditionType -linecomment
const (
ResultBoardTurfNone ResultBoardConditionType = iota + 1 // Turf_None
ResultBoardTurfDirt // Turf_Dirt
ResultBoardDirtNone // Dirt_None
ResultBoardDirtTurf // Dirt_Turf
)
func (r ResultBoardConditionType) AppendText(b []byte) ([]byte, error) {
return append(b, r.String()...), nil
}
func (r ResultBoardConditionType) MarshalText() ([]byte, error) {
return r.AppendText(nil)
}
func (r *ResultBoardConditionType) UnmarshalText(b []byte) error {
switch string(b) {
case "Turf_None":
*r = ResultBoardTurfNone
case "Turf_Dirt":
*r = ResultBoardTurfDirt
case "Dirt_None":
*r = ResultBoardDirtNone
case "Dirt_Turf":
*r = ResultBoardDirtTurf
default:
*r = 0
return fmt.Errorf("unknown result board type %q", b)
}
return nil
}
type CourseDistanceType int8
//go:generate go run golang.org/x/tools/cmd/stringer@v0.41.0 -type CourseDistanceType -linecomment -trimprefix Distance
const (
DistanceSprint CourseDistanceType = iota + 1 // Short
DistanceMile
DistanceMedium // Middle
DistanceLong
)
func (r CourseDistanceType) AppendText(b []byte) ([]byte, error) {
return append(b, r.String()...), nil
}
func (r CourseDistanceType) MarshalText() ([]byte, error) {
return r.AppendText(nil)
}
func (r *CourseDistanceType) UnmarshalText(b []byte) error {
switch string(b) {
case "Short":
*r = DistanceSprint
case "Mile":
*r = DistanceMile
case "Middle":
*r = DistanceMedium
case "Long":
*r = DistanceLong
default:
*r = 0
return fmt.Errorf("unknown distance type %q", b)
}
return nil
}
type TurfVisionType int8
//go:generate go run golang.org/x/tools/cmd/stringer@v0.41.0 -type TurfVisionType -trimprefix TurfVision
const (
TurfVisionURA TurfVisionType = iota + 1
TurfVisionNAU
TurfVisionStand
turfVisionMax
)
func (r TurfVisionType) AppendText(b []byte) ([]byte, error) {
return append(b, r.String()...), nil
}
func (r TurfVisionType) MarshalText() ([]byte, error) {
return r.AppendText(nil)
}
var turfVisionNames = sync.OnceValue(func() map[string]TurfVisionType {
m := make(map[string]TurfVisionType, turfVisionMax)
for r := TurfVisionURA; r < turfVisionMax; r++ {
s := r.String()
if strings.HasPrefix(s, "TurfVisionType(") {
continue
}
m[r.String()] = r
}
return m
})
func (r *TurfVisionType) UnmarshalText(b []byte) error {
n, ok := turfVisionNames()[string(b)]
*r = n
if !ok {
return fmt.Errorf("unknown turf vision type %q", b)
}
return nil
}
type GroundCondition int8
//go:generate go run golang.org/x/tools/cmd/stringer@v0.41.0 -type GroundCondition -linecomment
const (
GroundFirm GroundCondition = iota + 1 // Good
GroundGood // Soft
GroundSoft // Hard
GroundHeavy // Bad
)
func (r GroundCondition) AppendText(b []byte) ([]byte, error) {
return append(b, r.String()...), nil
}
func (r GroundCondition) MarshalText() ([]byte, error) {
return r.AppendText(nil)
}
func (r *GroundCondition) UnmarshalText(b []byte) error {
switch string(b) {
case "Good":
*r = GroundFirm
case "Soft":
*r = GroundGood
case "Hard":
*r = GroundSoft
case "Bad":
*r = GroundHeavy
default:
*r = 0
return fmt.Errorf("unknown ground condition type %q", b)
}
return nil
}
type RaceWeather int8
//go:generate go run golang.org/x/tools/cmd/stringer@v0.41.0 -type RaceWeather -trimprefix Weather
const (
WeatherMin RaceWeather = iota
WeatherSunny
WeatherCloudy
WeatherRainy
WeatherSnow
WeatherMax
)
func (r RaceWeather) AppendText(b []byte) ([]byte, error) {
return append(b, r.String()...), nil
}
func (r RaceWeather) MarshalText() ([]byte, error) {
return r.AppendText(nil)
}
func (r *RaceWeather) UnmarshalText(b []byte) error {
switch string(b) {
case "Min", "NONE":
*r = WeatherMin
case "Sunny":
*r = WeatherSunny
case "Cloudy":
*r = WeatherCloudy
case "Rainy":
*r = WeatherRainy
case "Snow":
*r = WeatherSnow
case "Max":
*r = WeatherMax
default:
*r = 0
return fmt.Errorf("unknown race weather %q", b)
}
return nil
}
type Season int8
//go:generate go run golang.org/x/tools/cmd/stringer@v0.41.0 -type Season -trimprefix Season
const (
SeasonMin Season = iota
SeasonSpring
SeasonSummer
SeasonFall
SeasonWinter
SeasonCherryBlossom
SeasonMax
)
func (r Season) AppendText(b []byte) ([]byte, error) {
return append(b, r.String()...), nil
}
func (r Season) MarshalText() ([]byte, error) {
return r.AppendText(nil)
}
func (r *Season) UnmarshalText(b []byte) error {
switch string(b) {
case "Min", "NONE":
*r = SeasonMin
case "Spring":
*r = SeasonSpring
case "Summer":
*r = SeasonSummer
case "Fall":
*r = SeasonFall
case "Winter":
*r = SeasonWinter
case "CherryBlossom":
*r = SeasonCherryBlossom
case "Max":
*r = SeasonMax
default:
*r = 0
return fmt.Errorf("unknown season %q", b)
}
return nil
}
type RaceTime int8
//go:generate go run golang.org/x/tools/cmd/stringer@v0.41.0 -type RaceTime -trimprefix Time
const (
TimeMin RaceTime = iota
TimeMorning
TimeDaytime
TimeEvening
TimeNight
TimeMax
)
func (r RaceTime) AppendText(b []byte) ([]byte, error) {
return append(b, r.String()...), nil
}
func (r RaceTime) MarshalText() ([]byte, error) {
return r.AppendText(nil)
}
func (r *RaceTime) UnmarshalText(b []byte) error {
switch string(b) {
case "Min":
*r = TimeMin
case "Morning":
*r = TimeMorning
case "Daytime":
*r = TimeDaytime
case "Evening":
*r = TimeEvening
case "Night":
*r = TimeNight
case "Max":
*r = TimeMax
default:
*r = 0
return fmt.Errorf("unknown race time %q", b)
}
return nil
}
type RaceDifficulty int8
//go:generate go run golang.org/x/tools/cmd/stringer@v0.41.0 -type RaceDifficulty -trimprefix Difficulty
const (
DifficultyEasy RaceDifficulty = iota + 1
DifficultyNormal
DifficultyHard
DifficultyVeryHard
DifficultyExtreme
difficultyMax
)
func (r RaceDifficulty) AppendText(b []byte) ([]byte, error) {
return append(b, r.String()...), nil
}
func (r RaceDifficulty) MarshalText() ([]byte, error) {
return r.AppendText(nil)
}
var difficultyNames = sync.OnceValue(func() map[string]RaceDifficulty {
m := make(map[string]RaceDifficulty, difficultyMax)
for r := DifficultyEasy; r < difficultyMax; r++ {
s := r.String()
if strings.HasPrefix(s, "RaceDifficulty(") {
continue
}
m[r.String()] = r
}
// extra one for pure pvp races
m["UNKNOWN"] = 0
return m
})
func (r *RaceDifficulty) UnmarshalText(b []byte) error {
n, ok := difficultyNames()[string(b)]
*r = n
if !ok {
return fmt.Errorf("unknown turf vision type %q", b)
}
return nil
}
type RaceParam struct {
RawSpeed int `json:"rawSpeed"`
RawStamina int `json:"rawStamina"`
RawPow int `json:"rawPow"`
RawGuts int `json:"rawGuts"`
RawWiz int `json:"rawWiz"`
BaseSpeed float32 `json:"baseSpeed"`
BaseStamina float32 `json:"baseStamina"`
BasePow float32 `json:"basePow"`
BaseGuts float32 `json:"baseGuts"`
BaseWiz float32 `json:"baseWiz"`
Motivation string `json:"motivation"`
MotivationCoef float32 `json:"motivationCoef"`
}
type SkillArray struct {
SkillID int `json:"skill_id"`
Level int `json:"level"`
}
type RaceResultArray struct {
Turn int `json:"turn"`
ProgramID int `json:"program_id"`
Weather int `json:"weather"`
GroundCondition int `json:"ground_condition"`
RunningStyle int `json:"running_style"`
Popularity int `json:"popularity"`
ResultRank int `json:"result_rank"`
ResultTime int `json:"result_time"`
PrizeMoney int `json:"prize_money"`
}
type ResponseHorseData struct {
FrameOrder int `json:"frame_order"`
ViewerID int64 `json:"viewer_id"`
TrainerName string `json:"trainer_name"`
OwnerViewerID int `json:"owner_viewer_id"`
OwnerTrainerName string `json:"owner_trainer_name"`
SingleModeCharaID int `json:"single_mode_chara_id"`
TrainedCharaID int `json:"trained_chara_id"`
NicknameID int `json:"nickname_id"`
CharaID int `json:"chara_id"`
CardID int `json:"card_id"`
MobID int `json:"mob_id"`
Rarity int `json:"rarity"`
TalentLevel int `json:"talent_level"`
SkillArray []SkillArray `json:"skill_array"`
Stamina int `json:"stamina"`
Speed int `json:"speed"`
Pow int `json:"pow"`
Guts int `json:"guts"`
Wiz int `json:"wiz"`
RunningStyle int `json:"running_style"`
RaceDressID int `json:"race_dress_id"`
CharaColorType int `json:"chara_color_type"`
NpcType int `json:"npc_type"`
FinalGrade int `json:"final_grade"`
Popularity int `json:"popularity"`
PopularityMarkRankArray []int `json:"popularity_mark_rank_array"`
ProperDistanceShort int `json:"proper_distance_short"`
ProperDistanceMile int `json:"proper_distance_mile"`
ProperDistanceMiddle int `json:"proper_distance_middle"`
ProperDistanceLong int `json:"proper_distance_long"`
ProperRunningStyleNige int `json:"proper_running_style_nige"`
ProperRunningStyleSenko int `json:"proper_running_style_senko"`
ProperRunningStyleSashi int `json:"proper_running_style_sashi"`
ProperRunningStyleOikomi int `json:"proper_running_style_oikomi"`
ProperGroundTurf int `json:"proper_ground_turf"`
ProperGroundDirt int `json:"proper_ground_dirt"`
Motivation int `json:"motivation"`
WinSaddleIDArray []int `json:"win_saddle_id_array"`
RaceResultArray []RaceResultArray `json:"race_result_array"`
TeamID int `json:"team_id"`
TeamMemberID int `json:"team_member_id"`
TeamRank int `json:"team_rank"`
SingleModeWinCount int `json:"single_mode_win_count"`
ItemIDArray []any `json:"item_id_array"`
MotivationChangeFlag int `json:"motivation_change_flag"`
FrameOrderChangeFlag int `json:"frame_order_change_flag"`
}
type RaceRecord struct {
}
type FactorDataArray struct {
FactorLv int `json:"factorLv"`
FactorID int `json:"factorId"`
BaseFactorID int `json:"baseFactorId"`
UpgradeHistoryList []any `json:"upgradeHistoryList"`
}
type FavoriteData struct {
}
type SuccessionCharaList struct {
PositionID int `json:"positionId"`
CardID int `json:"cardId"`
Rarity int `json:"rarity"`
Level int `json:"level"`
Rank int `json:"rank"`
FactorDataArray []FactorDataArray `json:"factorDataArray"`
SortedFactorList []any `json:"sortedFactorList"`
SortedFactorListForProfileCard []any `json:"sortedFactorListForProfileCard"`
OwnerViewerID int `json:"ownerViewerId"`
IsPlayer bool `json:"isPlayer"`
WinSaddleArray []any `json:"winSaddleArray"`
WinSaddleIDArray []int `json:"winSaddleIdArray"`
}
type Master struct {
}
type AcquiredSkillArray struct {
MasterID int `json:"masterId"`
Level int `json:"level"`
Master Master `json:"master"`
}
type SupportCardArray struct {
Position int `json:"position"`
SupportCardID int `json:"supportCardId"`
LimitBreakCount int `json:"limitBreakCount"`
Exp int `json:"exp"`
}
type SingleModeRaceResultArray struct {
Turn int `json:"turn"`
ProgramID int `json:"programId"`
RaceInstanceID int `json:"raceInstanceId"`
FrameOrder int `json:"frameOrder"`
NpcCount int `json:"npcCount"`
Weather int `json:"weather"`
GroundCondition int `json:"groundCondition"`
RunningStyle int `json:"runningStyle"`
ResultRank int `json:"resultRank"`
ScenarioID int `json:"scenarioId"`
}
type MasterCardData struct {
}
type MasterCharaData struct {
}
type MasterCardRarityData struct {
}
type TrainedCharaDataAccessor struct {
}
type TrainedCharaData struct {
ID int `json:"id"`
IsSaved bool `json:"isSaved"`
ViewerID int64 `json:"viewerId"`
OwnerViewerID int `json:"ownerViewerId"`
OwnerTrainedCharaID int `json:"ownerTrainedCharaId"`
UseType int `json:"useType"`
CardID int `json:"cardId"`
NickNameID int `json:"nickNameId"`
NickNameIDArray []int `json:"nickNameIdArray"`
Stamina int `json:"stamina"`
Speed int `json:"speed"`
Power int `json:"power"`
Guts int `json:"guts"`
Wiz int `json:"wiz"`
Fans int `json:"fans"`
Rank int `json:"rank"`
RankScore int `json:"rankScore"`
RunningStyle int `json:"runningStyle"`
ProperGroundTurf int `json:"properGroundTurf"`
ProperGroundDirt int `json:"properGroundDirt"`
ProperDistanceShort int `json:"properDistanceShort"`
ProperDistanceMile int `json:"properDistanceMile"`
ProperDistanceMiddle int `json:"properDistanceMiddle"`
ProperDistanceLong int `json:"properDistanceLong"`
ProperRunningStyleNige int `json:"properRunningStyleNige"`
ProperRunningStyleSenko int `json:"properRunningStyleSenko"`
ProperRunningStyleSashi int `json:"properRunningStyleSashi"`
ProperRunningStyleOikomi int `json:"properRunningStyleOikomi"`
SuccessionCount int `json:"successionCount"`
FactorDataArray []FactorDataArray `json:"factorDataArray"`
CreateTime string `json:"createTime"`
ScenarioID int `json:"scenarioId"`
TalentLevel int `json:"talentLevel"`
CharaGrade int `json:"charaGrade"`
Rarity int `json:"rarity"`
IsLock bool `json:"isLock"`
FavoriteData FavoriteData `json:"favoriteData"`
CachedCreateTimeTimeStamp int `json:"cachedCreateTimeTimeStamp"`
SortedFactorList []any `json:"sortedFactorList"`
SortedFactorProfileCardList []any `json:"sortedFactorProfileCardList"`
FactorListIncludingSuccession []any `json:"factorListIncludingSuccession"`
SuccessionCharaList []SuccessionCharaList `json:"successionCharaList"`
IsSuccessionHistoryInitialized bool `json:"isSuccessionHistoryInitialized"`
SuccessionHistoryList []any `json:"successionHistoryList"`
AcquiredSkillArray []AcquiredSkillArray `json:"acquiredSkillArray"`
SupportCardArray []SupportCardArray `json:"supportCardArray"`
SingleModeRaceResultArray []SingleModeRaceResultArray `json:"singleModeRaceResultArray"`
WinSaddleArray []any `json:"winSaddleArray"`
WinSaddleIDArray []int `json:"winSaddleIdArray"`
CacheCharaID int `json:"cacheCharaId"`
MasterCardData MasterCardData `json:"masterCardData"`
MasterCharaData MasterCharaData `json:"masterCharaData"`
MasterCardRarityData MasterCardRarityData `json:"masterCardRarityData"`
SingleTotalRaceNum int `json:"singleTotalRaceNum"`
SingleWinNum int `json:"singleWinNum"`
TrainedCharaDataAccessor TrainedCharaDataAccessor `json:"trainedCharaDataAccessor"`
}
type PlayerTeamMember struct {
HorseIndex int `json:"horseIndex"`
PostNumber int `json:"postNumber"`
CharaID int `json:"charaId"`
CharaName string `json:"charaName"`
FinishOrder int `json:"finishOrder"`
FinishTimeRaw float32 `json:"finishTimeRaw"`
FinishTimeScaled float32 `json:"finishTimeScaled"`
FinishDiffTimeFromPrev float32 `json:"finishDiffTimeFromPrev"`
RaceParam RaceParam `json:"raceParam"`
ResponseHorseData ResponseHorseData `json:"responseHorseData"`
Popularity int `json:"popularity"`
PopularityRankLeft int `json:"popularityRankLeft"`
PopularityRankCenter int `json:"popularityRankCenter"`
PopularityRankRight int `json:"popularityRankRight"`
GateInPopularity int `json:"gateInPopularity"`
Rarity string `json:"rarity"`
TrainerName string `json:"trainerName"`
IsGhost bool `json:"isGhost"`
IsRunningStyleExInitialized bool `json:"isRunningStyleExInitialized"`
RunningStyleEx string `json:"runningStyleEx"`
Defeat string `json:"defeat"`
RaceDressID int `json:"raceDressId"`
RaceDressIDWithOption int `json:"raceDressIdWithOption"`
RunningType string `json:"runningType"`
ActiveProperDistance string `json:"activeProperDistance"`
ActiveProperGroundType string `json:"activeProperGroundType"`
MobID int `json:"mobId"`
RaceRecord RaceRecord `json:"raceRecord"`
FinishOrderRawScore int `json:"finishOrderRawScore"`
TrainedCharaData TrainedCharaData `json:"trainedCharaData"`
}
type PlayerTeamTopFinishOrderHorse struct {
HorseIndex int `json:"horseIndex"`
PostNumber int `json:"postNumber"`
CharaID int `json:"charaId"`
CharaName string `json:"charaName"`
FinishOrder int `json:"finishOrder"`
FinishTimeRaw float32 `json:"finishTimeRaw"`
FinishTimeScaled float32 `json:"finishTimeScaled"`
FinishDiffTimeFromPrev float32 `json:"finishDiffTimeFromPrev"`
RaceParam RaceParam `json:"raceParam"`
ResponseHorseData ResponseHorseData `json:"responseHorseData"`
Popularity int `json:"popularity"`
PopularityRankLeft int `json:"popularityRankLeft"`
PopularityRankCenter int `json:"popularityRankCenter"`
PopularityRankRight int `json:"popularityRankRight"`
GateInPopularity int `json:"gateInPopularity"`
Rarity string `json:"rarity"`
TrainerName string `json:"trainerName"`
IsGhost bool `json:"isGhost"`
IsRunningStyleExInitialized bool `json:"isRunningStyleExInitialized"`
RunningStyleEx string `json:"runningStyleEx"`
Defeat string `json:"defeat"`
RaceDressID int `json:"raceDressId"`
RaceDressIDWithOption int `json:"raceDressIdWithOption"`
RunningType string `json:"runningType"`
ActiveProperDistance string `json:"activeProperDistance"`
ActiveProperGroundType string `json:"activeProperGroundType"`
MobID int `json:"mobId"`
RaceRecord RaceRecord `json:"raceRecord"`
FinishOrderRawScore int `json:"finishOrderRawScore"`
TrainedCharaData TrainedCharaData `json:"trainedCharaData"`
}
type RaceHorse struct {
HorseIndex int `json:"horseIndex"`
PostNumber int `json:"postNumber"`
CharaID int `json:"charaId"`
CharaName string `json:"charaName"`
FinishOrder int `json:"finishOrder"`
FinishTimeRaw float32 `json:"finishTimeRaw"`
FinishTimeScaled float32 `json:"finishTimeScaled"`
FinishDiffTimeFromPrev float32 `json:"finishDiffTimeFromPrev"`
RaceParam RaceParam `json:"raceParam"`
ResponseHorseData ResponseHorseData `json:"responseHorseData"`
Popularity int `json:"popularity"`
PopularityRankLeft int `json:"popularityRankLeft"`
PopularityRankCenter int `json:"popularityRankCenter"`
PopularityRankRight int `json:"popularityRankRight"`
GateInPopularity int `json:"gateInPopularity"`
Rarity string `json:"rarity"`
TrainerName string `json:"trainerName"`
IsGhost bool `json:"isGhost"`
IsRunningStyleExInitialized bool `json:"isRunningStyleExInitialized"`
RunningStyleEx string `json:"runningStyleEx"`
Defeat string `json:"defeat"`
RaceDressID int `json:"raceDressId"`
RaceDressIDWithOption int `json:"raceDressIdWithOption"`
RunningType string `json:"runningType"`
ActiveProperDistance string `json:"activeProperDistance"`
ActiveProperGroundType string `json:"activeProperGroundType"`
MobID int `json:"mobId"`
RaceRecord RaceRecord `json:"raceRecord"`
FinishOrderRawScore int `json:"finishOrderRawScore"`
TrainedCharaData TrainedCharaData `json:"trainedCharaData,omitempty"`
}
type RaceRewardSingle struct {
// TODO(zeph): this
}
type CharaGradeType int8
//go:generate go run golang.org/x/tools/cmd/stringer@v0.41.0 -type CharaGradeType -linecomment -trimprefix CharaGrade
const (
CharaGradeNone CharaGradeType = iota // NONE
CharaGradeDebut
CharaGradeNoWin
CharaGradeOpen
CharaGradeG3Silver
CharaGradeG3Gold
CharaGradeG2Silver
CharaGradeG2Gold
CharaGradeG1Bronze
CharaGradeG1Silver
CharaGradeG1Gold
charaGradeMax
)
func (r CharaGradeType) AppendText(b []byte) ([]byte, error) {
return append(b, r.String()...), nil
}
func (r CharaGradeType) MarshalText() ([]byte, error) {
return r.AppendText(nil)
}
var charaGradeNames = sync.OnceValue(func() map[string]CharaGradeType {
m := make(map[string]CharaGradeType, raceTypeMaxInclusive)
for r := CharaGradeNone; r < charaGradeMax; r++ {
s := r.String()
if strings.HasPrefix(s, "CharaGradeType(") {
continue
}
m[r.String()] = r
}
return m
})
func (r *CharaGradeType) UnmarshalText(b []byte) error {
n, ok := charaGradeNames()[string(b)]
*r = n
if !ok {
return fmt.Errorf("unknown chara grade type %q", b)
}
return nil
}
type MainStoryRaceGimmickType int8
//go:generate go run golang.org/x/tools/cmd/stringer@v0.41.0 -type MainStoryRaceGimmickType -linecomment
const (
GimmickNone MainStoryRaceGimmickType = iota // NONE
GimmickSpecial00 // Special_00
gimmickMax
)
func (r MainStoryRaceGimmickType) AppendText(b []byte) ([]byte, error) {
return append(b, r.String()...), nil
}
func (r MainStoryRaceGimmickType) MarshalText() ([]byte, error) {
return r.AppendText(nil)
}
var mainStoryGimmickNames = sync.OnceValue(func() map[string]MainStoryRaceGimmickType {
m := make(map[string]MainStoryRaceGimmickType, raceTypeMaxInclusive)
for r := GimmickNone; r < gimmickMax; r++ {
s := r.String()
if strings.HasPrefix(s, "MainStoryRaceGimmickType(") {
continue
}
m[r.String()] = r
}
return m
})
func (r *MainStoryRaceGimmickType) UnmarshalText(b []byte) error {
n, ok := mainStoryGimmickNames()[string(b)]
*r = n
if !ok {
return fmt.Errorf("unknown main story race gimmick type %q", b)
}
return nil
}
@@ -0,0 +1,27 @@
// Code generated by "stringer -type ResultBoardConditionType -linecomment"; DO NOT EDIT.
package replay
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[ResultBoardTurfNone-1]
_ = x[ResultBoardTurfDirt-2]
_ = x[ResultBoardDirtNone-3]
_ = x[ResultBoardDirtTurf-4]
}
const _ResultBoardConditionType_name = "Turf_NoneTurf_DirtDirt_NoneDirt_Turf"
var _ResultBoardConditionType_index = [...]uint8{0, 9, 18, 27, 36}
func (i ResultBoardConditionType) String() string {
idx := int(i) - 1
if i < 1 || idx >= len(_ResultBoardConditionType_index)-1 {
return "ResultBoardConditionType(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _ResultBoardConditionType_name[_ResultBoardConditionType_index[idx]:_ResultBoardConditionType_index[idx+1]]
}
+27
View File
@@ -0,0 +1,27 @@
// Code generated by "stringer -type Rotation -trimprefix Rotation"; DO NOT EDIT.
package replay
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[RotationRight-1]
_ = x[RotationLeft-2]
_ = x[RotationStraightRight-3]
_ = x[RotationStraightLeft-4]
}
const _Rotation_name = "RightLeftStraightRightStraightLeft"
var _Rotation_index = [...]uint8{0, 5, 9, 22, 34}
func (i Rotation) String() string {
idx := int(i) - 1
if i < 1 || idx >= len(_Rotation_index)-1 {
return "Rotation(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _Rotation_name[_Rotation_index[idx]:_Rotation_index[idx+1]]
}
+30
View File
@@ -0,0 +1,30 @@
// Code generated by "stringer -type Season -trimprefix Season"; DO NOT EDIT.
package replay
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[SeasonMin-0]
_ = x[SeasonSpring-1]
_ = x[SeasonSummer-2]
_ = x[SeasonFall-3]
_ = x[SeasonWinter-4]
_ = x[SeasonCherryBlossom-5]
_ = x[SeasonMax-6]
}
const _Season_name = "MinSpringSummerFallWinterCherryBlossomMax"
var _Season_index = [...]uint8{0, 3, 9, 15, 19, 25, 38, 41}
func (i Season) String() string {
idx := int(i) - 0
if i < 0 || idx >= len(_Season_index)-1 {
return "Season(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _Season_name[_Season_index[idx]:_Season_index[idx+1]]
}
+27
View File
@@ -0,0 +1,27 @@
// Code generated by "stringer -type TurfVisionType -trimprefix TurfVision"; DO NOT EDIT.
package replay
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[TurfVisionURA-1]
_ = x[TurfVisionNAU-2]
_ = x[TurfVisionStand-3]
_ = x[turfVisionMax-4]
}
const _TurfVisionType_name = "URANAUStandturfVisionMax"
var _TurfVisionType_index = [...]uint8{0, 3, 6, 11, 24}
func (i TurfVisionType) String() string {
idx := int(i) - 1
if i < 1 || idx >= len(_TurfVisionType_index)-1 {
return "TurfVisionType(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _TurfVisionType_name[_TurfVisionType_index[idx]:_TurfVisionType_index[idx+1]]
}
+10 -5
View File
@@ -49,11 +49,16 @@ export function convoCharas(c: Conversation): number[] {
export function requiredCharas(c: Conversation): number[] {
switch (c.condition_type) {
case Required.None: return []
case Required.All: return convoCharas(c);
case Required.Chara1: return [c.chara_1];
case Required.Chara2: return [c.chara_2!];
case Required.Chara3: return [c.chara_3!];
case Required.None:
return [];
case Required.All:
return convoCharas(c);
case Required.Chara1:
return [c.chara_1];
case Required.Chara2:
return [c.chara_2!];
case Required.Chara3:
return [c.chara_3!];
}
}
+6 -14
View File
@@ -1143,22 +1143,14 @@
>. (This race is why I made it.)
</p>
<Sec h={3} id="jbc-sprint">JBC Sprint (Ooi ver.)</Sec>
<div id="jbc-sprint" class="hidden target:block">
<h3>JBC Sprint</h3>
<p>
An even more anti-front track is Ooi 1200 Dirt. This one is actively malicious. Visually, it looks like late race starts on a
corner, but the portion before the stretch is a special <i>neither corner nor straight</i> property. That means Angling won't activate,
and VPP is delayed (though still within the accel period).
</p>
<p>
Fortunately, JBC Sprint is after summer, which means you should be able to stat diff your opponents. If you are planning to
win this race, you may want to prioritize a bit of extra speed training, or take Front Straights/Corners. If MANT, don't be
too surprised if you lose a clock or five to a Taiki Shuttle rival.
</p>
<p>
Since the 1 Jul update, the JBC races take place at a randomly selected one of the NAR courses (Ooi, Kawasaki, Funabashi,
Morioka) each year. If you're hunting for a completionist title on a front runner, you have the option of just not picking an
Ooi JBC Sprint; the others are all Angling tracks.
It used to be the case that Oi 1200 Dirt had a strange neither-straight-nor-corner segment at the start of late race so that
Angling wouldn't activate. As of the 1 Jul update, the corner is now connected to the final straight, so there is no longer
anything remarkable about this track.
</p>
</div>
<Sec h={3} id="3k">Kikuka Sho &amp; Tenno Sho (Spring)</Sec>
<p>