Compare commits
7
Commits
3bf17944b3
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1cf3af5f79 | ||
|
|
0ffd2c099a | ||
|
|
6828b1bd88 | ||
|
|
78aee43e5f | ||
|
|
745c9d01dd | ||
|
|
e00fe0965a | ||
|
|
caa19dd85a |
@@ -28,6 +28,8 @@ type AffinityDetail struct {
|
|||||||
|
|
||||||
// Conversation describes a lobby conversation.
|
// Conversation describes a lobby conversation.
|
||||||
type Conversation struct {
|
type Conversation struct {
|
||||||
|
// ID is the conversation ID.
|
||||||
|
ID int32 `json:"id"`
|
||||||
// CharacterID is the ID of the character who has the conversation as
|
// CharacterID is the ID of the character who has the conversation as
|
||||||
// a gallery entry.
|
// a gallery entry.
|
||||||
CharacterID CharacterID `json:"chara_id"`
|
CharacterID CharacterID `json:"chara_id"`
|
||||||
|
|||||||
+8
-7
@@ -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) {
|
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 load(ctx, db, make([]horse.Conversation, 0, 1024), conversationSQL, func(s *sqlite.Stmt) horse.Conversation {
|
||||||
return horse.Conversation{
|
return horse.Conversation{
|
||||||
CharacterID: horse.CharacterID(s.ColumnInt(0)),
|
ID: s.ColumnInt32(0),
|
||||||
Number: s.ColumnInt(1),
|
CharacterID: horse.CharacterID(s.ColumnInt(1)),
|
||||||
Location: horse.LobbyConversationLocationID(s.ColumnInt(2)),
|
Number: s.ColumnInt(2),
|
||||||
Chara1: horse.CharacterID(s.ColumnInt(3)),
|
Location: horse.LobbyConversationLocationID(s.ColumnInt(3)),
|
||||||
Chara2: horse.CharacterID(s.ColumnInt(4)),
|
Chara1: horse.CharacterID(s.ColumnInt(4)),
|
||||||
Chara3: horse.CharacterID(s.ColumnInt(5)),
|
Chara2: horse.CharacterID(s.ColumnInt(5)),
|
||||||
ConditionType: s.ColumnInt(6),
|
Chara3: horse.CharacterID(s.ColumnInt(6)),
|
||||||
|
ConditionType: s.ColumnInt(7),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -238,12 +238,14 @@ func TestConversations(t *testing.T) {
|
|||||||
}
|
}
|
||||||
want := []horse.Conversation{
|
want := []horse.Conversation{
|
||||||
{
|
{
|
||||||
|
ID: 1,
|
||||||
CharacterID: 1001,
|
CharacterID: 1001,
|
||||||
Number: 1,
|
Number: 1,
|
||||||
Location: 410,
|
Location: 410,
|
||||||
Chara1: 1001,
|
Chara1: 1001,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
ID: 2,
|
||||||
CharacterID: 1001,
|
CharacterID: 1001,
|
||||||
Number: 2,
|
Number: 2,
|
||||||
Location: 510,
|
Location: 510,
|
||||||
@@ -251,6 +253,7 @@ func TestConversations(t *testing.T) {
|
|||||||
ConditionType: 1,
|
ConditionType: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
ID: 3,
|
||||||
CharacterID: 1001,
|
CharacterID: 1001,
|
||||||
Number: 3,
|
Number: 3,
|
||||||
Location: 310,
|
Location: 310,
|
||||||
@@ -258,6 +261,7 @@ func TestConversations(t *testing.T) {
|
|||||||
ConditionType: 1,
|
ConditionType: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
ID: 76,
|
||||||
CharacterID: 1001,
|
CharacterID: 1001,
|
||||||
Number: 4,
|
Number: 4,
|
||||||
Location: 120,
|
Location: 120,
|
||||||
@@ -266,6 +270,7 @@ func TestConversations(t *testing.T) {
|
|||||||
ConditionType: 2,
|
ConditionType: 2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
ID: 77,
|
||||||
CharacterID: 1001,
|
CharacterID: 1001,
|
||||||
Number: 5,
|
Number: 5,
|
||||||
Location: 520,
|
Location: 520,
|
||||||
@@ -274,6 +279,7 @@ func TestConversations(t *testing.T) {
|
|||||||
ConditionType: 3,
|
ConditionType: 3,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
ID: 126,
|
||||||
CharacterID: 1001,
|
CharacterID: 1001,
|
||||||
Number: 6,
|
Number: 6,
|
||||||
Location: 430,
|
Location: 430,
|
||||||
@@ -283,12 +289,14 @@ func TestConversations(t *testing.T) {
|
|||||||
ConditionType: 1,
|
ConditionType: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
ID: 4,
|
||||||
CharacterID: 1002,
|
CharacterID: 1002,
|
||||||
Number: 1,
|
Number: 1,
|
||||||
Location: 310,
|
Location: 310,
|
||||||
Chara1: 1002,
|
Chara1: 1002,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
ID: 5,
|
||||||
CharacterID: 1002,
|
CharacterID: 1002,
|
||||||
Number: 2,
|
Number: 2,
|
||||||
Location: 210,
|
Location: 210,
|
||||||
@@ -296,6 +304,7 @@ func TestConversations(t *testing.T) {
|
|||||||
ConditionType: 1,
|
ConditionType: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
ID: 6,
|
||||||
CharacterID: 1002,
|
CharacterID: 1002,
|
||||||
Number: 3,
|
Number: 3,
|
||||||
Location: 110,
|
Location: 110,
|
||||||
@@ -303,6 +312,7 @@ func TestConversations(t *testing.T) {
|
|||||||
ConditionType: 1,
|
ConditionType: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
ID: 78,
|
||||||
CharacterID: 1002,
|
CharacterID: 1002,
|
||||||
Number: 4,
|
Number: 4,
|
||||||
Location: 520,
|
Location: 520,
|
||||||
@@ -311,6 +321,7 @@ func TestConversations(t *testing.T) {
|
|||||||
ConditionType: 3,
|
ConditionType: 3,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
ID: 79,
|
||||||
CharacterID: 1002,
|
CharacterID: 1002,
|
||||||
Number: 5,
|
Number: 5,
|
||||||
Location: 220,
|
Location: 220,
|
||||||
|
|||||||
+101
-55
@@ -18,6 +18,8 @@ var (
|
|||||||
skillGroupSQL string
|
skillGroupSQL string
|
||||||
//go:embed sql/skill.sql
|
//go:embed sql/skill.sql
|
||||||
skillSQL string
|
skillSQL string
|
||||||
|
//go:embed sql/skill-group-skills.sql
|
||||||
|
skillGroupSkillsSQL string
|
||||||
)
|
)
|
||||||
|
|
||||||
// SkillGroups retrieves all skill groups.
|
// SkillGroups retrieves all skill groups.
|
||||||
@@ -35,84 +37,128 @@ func SkillGroups(ctx context.Context, db *sqlitex.Pool) ([]horse.SkillGroup, err
|
|||||||
|
|
||||||
// Skills retrieves all skills.
|
// Skills retrieves all skills.
|
||||||
func Skills(ctx context.Context, db *sqlitex.Pool) ([]horse.Skill, error) {
|
func Skills(ctx context.Context, db *sqlitex.Pool) ([]horse.Skill, error) {
|
||||||
return load(ctx, db, nil, skillSQL, func(s *sqlite.Stmt) horse.Skill {
|
// We don't use func load here because we have multiple queries to run.
|
||||||
return horse.Skill{
|
conn, err := db.Take(ctx)
|
||||||
ID: horse.SkillID(s.ColumnInt(0)),
|
defer db.Put(conn)
|
||||||
Name: s.ColumnText(1),
|
if err != nil {
|
||||||
Description: s.ColumnText(2),
|
return nil, err
|
||||||
Group: horse.SkillGroupID(s.ColumnInt32(3)),
|
}
|
||||||
Rarity: int8(s.ColumnInt(5)),
|
var sk []horse.Skill
|
||||||
GroupRate: int8(s.ColumnInt(6)),
|
{
|
||||||
GradeValue: s.ColumnInt32(7),
|
stmt := conn.Prep(skillSQL)
|
||||||
WitCheck: s.ColumnBool(8),
|
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{
|
Activations: trimActivations([]horse.Activation{
|
||||||
{
|
{
|
||||||
Precondition: s.ColumnText(9),
|
Precondition: stmt.ColumnText(9),
|
||||||
Condition: s.ColumnText(10),
|
Condition: stmt.ColumnText(10),
|
||||||
Duration: horse.TenThousandths(s.ColumnInt(11)),
|
Duration: horse.TenThousandths(stmt.ColumnInt(11)),
|
||||||
DurScale: horse.DurScale(s.ColumnInt(12)),
|
DurScale: horse.DurScale(stmt.ColumnInt(12)),
|
||||||
Cooldown: horse.TenThousandths(s.ColumnInt(13)),
|
Cooldown: horse.TenThousandths(stmt.ColumnInt(13)),
|
||||||
Abilities: trimAbilities([]horse.Ability{
|
Abilities: trimAbilities([]horse.Ability{
|
||||||
{
|
{
|
||||||
Type: horse.AbilityType(s.ColumnInt(14)),
|
Type: horse.AbilityType(stmt.ColumnInt(14)),
|
||||||
ValueUsage: horse.AbilityValueUsage(s.ColumnInt(15)),
|
ValueUsage: horse.AbilityValueUsage(stmt.ColumnInt(15)),
|
||||||
Value: horse.TenThousandths(s.ColumnInt(16)),
|
Value: horse.TenThousandths(stmt.ColumnInt(16)),
|
||||||
Target: horse.AbilityTarget(s.ColumnInt(17)),
|
Target: horse.AbilityTarget(stmt.ColumnInt(17)),
|
||||||
TargetValue: s.ColumnInt32(18),
|
TargetValue: stmt.ColumnInt32(18),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Type: horse.AbilityType(s.ColumnInt(19)),
|
Type: horse.AbilityType(stmt.ColumnInt(19)),
|
||||||
ValueUsage: horse.AbilityValueUsage(s.ColumnInt(20)),
|
ValueUsage: horse.AbilityValueUsage(stmt.ColumnInt(20)),
|
||||||
Value: horse.TenThousandths(s.ColumnInt(21)),
|
Value: horse.TenThousandths(stmt.ColumnInt(21)),
|
||||||
Target: horse.AbilityTarget(s.ColumnInt(22)),
|
Target: horse.AbilityTarget(stmt.ColumnInt(22)),
|
||||||
TargetValue: s.ColumnInt32(23),
|
TargetValue: stmt.ColumnInt32(23),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Type: horse.AbilityType(s.ColumnInt(24)),
|
Type: horse.AbilityType(stmt.ColumnInt(24)),
|
||||||
ValueUsage: horse.AbilityValueUsage(s.ColumnInt(25)),
|
ValueUsage: horse.AbilityValueUsage(stmt.ColumnInt(25)),
|
||||||
Value: horse.TenThousandths(s.ColumnInt(26)),
|
Value: horse.TenThousandths(stmt.ColumnInt(26)),
|
||||||
Target: horse.AbilityTarget(s.ColumnInt(27)),
|
Target: horse.AbilityTarget(stmt.ColumnInt(27)),
|
||||||
TargetValue: s.ColumnInt32(28),
|
TargetValue: stmt.ColumnInt32(28),
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Precondition: s.ColumnText(29),
|
Precondition: stmt.ColumnText(29),
|
||||||
Condition: s.ColumnText(30),
|
Condition: stmt.ColumnText(30),
|
||||||
Duration: horse.TenThousandths(s.ColumnInt(31)),
|
Duration: horse.TenThousandths(stmt.ColumnInt(31)),
|
||||||
DurScale: horse.DurScale(s.ColumnInt(32)),
|
DurScale: horse.DurScale(stmt.ColumnInt(32)),
|
||||||
Cooldown: horse.TenThousandths(s.ColumnInt(33)),
|
Cooldown: horse.TenThousandths(stmt.ColumnInt(33)),
|
||||||
Abilities: trimAbilities([]horse.Ability{
|
Abilities: trimAbilities([]horse.Ability{
|
||||||
{
|
{
|
||||||
Type: horse.AbilityType(s.ColumnInt(34)),
|
Type: horse.AbilityType(stmt.ColumnInt(34)),
|
||||||
ValueUsage: horse.AbilityValueUsage(s.ColumnInt(35)),
|
ValueUsage: horse.AbilityValueUsage(stmt.ColumnInt(35)),
|
||||||
Value: horse.TenThousandths(s.ColumnInt(36)),
|
Value: horse.TenThousandths(stmt.ColumnInt(36)),
|
||||||
Target: horse.AbilityTarget(s.ColumnInt(37)),
|
Target: horse.AbilityTarget(stmt.ColumnInt(37)),
|
||||||
TargetValue: s.ColumnInt32(38),
|
TargetValue: stmt.ColumnInt32(38),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Type: horse.AbilityType(s.ColumnInt(39)),
|
Type: horse.AbilityType(stmt.ColumnInt(39)),
|
||||||
ValueUsage: horse.AbilityValueUsage(s.ColumnInt(40)),
|
ValueUsage: horse.AbilityValueUsage(stmt.ColumnInt(40)),
|
||||||
Value: horse.TenThousandths(s.ColumnInt(41)),
|
Value: horse.TenThousandths(stmt.ColumnInt(41)),
|
||||||
Target: horse.AbilityTarget(s.ColumnInt(42)),
|
Target: horse.AbilityTarget(stmt.ColumnInt(42)),
|
||||||
TargetValue: s.ColumnInt32(43),
|
TargetValue: stmt.ColumnInt32(43),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Type: horse.AbilityType(s.ColumnInt(44)),
|
Type: horse.AbilityType(stmt.ColumnInt(44)),
|
||||||
ValueUsage: horse.AbilityValueUsage(s.ColumnInt(45)),
|
ValueUsage: horse.AbilityValueUsage(stmt.ColumnInt(45)),
|
||||||
Value: horse.TenThousandths(s.ColumnInt(46)),
|
Value: horse.TenThousandths(stmt.ColumnInt(46)),
|
||||||
Target: horse.AbilityTarget(s.ColumnInt(47)),
|
Target: horse.AbilityTarget(stmt.ColumnInt(47)),
|
||||||
TargetValue: s.ColumnInt32(48),
|
TargetValue: stmt.ColumnInt32(48),
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
UniqueOwner: s.ColumnText(52), // TODO(zeph): should be id, not name
|
UniqueOwner: stmt.ColumnText(52), // TODO(zeph): should be id, not name
|
||||||
Tags: parseTags(s.ColumnText(54)),
|
Tags: parseTags(stmt.ColumnText(54)),
|
||||||
SPCost: s.ColumnInt(49),
|
SPCost: stmt.ColumnInt(49),
|
||||||
IconID: s.ColumnInt(53),
|
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 {
|
func parseTags(s string) []uint16 {
|
||||||
|
|||||||
@@ -49,6 +49,11 @@ func TestSkills(t *testing.T) {
|
|||||||
ID: 10351,
|
ID: 10351,
|
||||||
Name: "V Is for Victory!",
|
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.",
|
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,
|
Group: 1035,
|
||||||
Rarity: 3,
|
Rarity: 3,
|
||||||
GroupRate: 1,
|
GroupRate: 1,
|
||||||
@@ -81,6 +86,10 @@ func TestSkills(t *testing.T) {
|
|||||||
ID: 100011,
|
ID: 100011,
|
||||||
Name: "Shooting Star",
|
Name: "Shooting Star",
|
||||||
Description: "Ride the momentum to increase velocity and very slightly increase acceleration after passing another runner toward the front late-race.",
|
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,
|
Group: 10001,
|
||||||
Rarity: 5,
|
Rarity: 5,
|
||||||
GroupRate: 1,
|
GroupRate: 1,
|
||||||
@@ -120,6 +129,11 @@ func TestSkills(t *testing.T) {
|
|||||||
ID: 100351,
|
ID: 100351,
|
||||||
Name: "Our Ticket to Win!",
|
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.",
|
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,
|
Group: 10035,
|
||||||
Rarity: 4,
|
Rarity: 4,
|
||||||
GroupRate: 1,
|
GroupRate: 1,
|
||||||
@@ -152,6 +166,10 @@ func TestSkills(t *testing.T) {
|
|||||||
ID: 110241,
|
ID: 110241,
|
||||||
Name: "Flowery☆Maneuver",
|
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.",
|
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,
|
Group: 11024,
|
||||||
Rarity: 5,
|
Rarity: 5,
|
||||||
GroupRate: 1,
|
GroupRate: 1,
|
||||||
@@ -200,6 +218,12 @@ func TestSkills(t *testing.T) {
|
|||||||
ID: 200011,
|
ID: 200011,
|
||||||
Name: "Right-Handed ◎",
|
Name: "Right-Handed ◎",
|
||||||
Description: "Increase performance on right-handed tracks.",
|
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,
|
Group: 20001,
|
||||||
Rarity: 1,
|
Rarity: 1,
|
||||||
GroupRate: 2,
|
GroupRate: 2,
|
||||||
@@ -231,6 +255,12 @@ func TestSkills(t *testing.T) {
|
|||||||
ID: 200012,
|
ID: 200012,
|
||||||
Name: "Right-Handed ○",
|
Name: "Right-Handed ○",
|
||||||
Description: "Moderately increase performance on right-handed tracks.",
|
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,
|
Group: 20001,
|
||||||
Rarity: 1,
|
Rarity: 1,
|
||||||
GroupRate: 1,
|
GroupRate: 1,
|
||||||
@@ -262,6 +292,12 @@ func TestSkills(t *testing.T) {
|
|||||||
ID: 200013,
|
ID: 200013,
|
||||||
Name: "Right-Handed ×",
|
Name: "Right-Handed ×",
|
||||||
Description: "Moderately decrease performance on right-handed tracks.",
|
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,
|
Group: 20001,
|
||||||
Rarity: 1,
|
Rarity: 1,
|
||||||
GroupRate: -1,
|
GroupRate: -1,
|
||||||
@@ -293,6 +329,12 @@ func TestSkills(t *testing.T) {
|
|||||||
ID: 200014,
|
ID: 200014,
|
||||||
Name: "Right-Handed Demon",
|
Name: "Right-Handed Demon",
|
||||||
Description: "Increase proficiency in right-handed tracks, increasing Speed and Power.",
|
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,
|
Group: 20001,
|
||||||
Rarity: 2,
|
Rarity: 2,
|
||||||
GroupRate: 3,
|
GroupRate: 3,
|
||||||
@@ -331,6 +373,11 @@ func TestSkills(t *testing.T) {
|
|||||||
ID: 200021,
|
ID: 200021,
|
||||||
Name: "Left-Handed ◎",
|
Name: "Left-Handed ◎",
|
||||||
Description: "Increase performance on left-handed tracks.",
|
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,
|
Group: 20002,
|
||||||
Rarity: 1,
|
Rarity: 1,
|
||||||
GroupRate: 2,
|
GroupRate: 2,
|
||||||
@@ -362,6 +409,11 @@ func TestSkills(t *testing.T) {
|
|||||||
ID: 200022,
|
ID: 200022,
|
||||||
Name: "Left-Handed ○",
|
Name: "Left-Handed ○",
|
||||||
Description: "Moderately increase performance on left-handed tracks.",
|
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,
|
Group: 20002,
|
||||||
Rarity: 1,
|
Rarity: 1,
|
||||||
GroupRate: 1,
|
GroupRate: 1,
|
||||||
@@ -393,6 +445,11 @@ func TestSkills(t *testing.T) {
|
|||||||
ID: 200023,
|
ID: 200023,
|
||||||
Name: "Left-Handed ×",
|
Name: "Left-Handed ×",
|
||||||
Description: "Moderately decrease performance on left-handed tracks.",
|
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,
|
Group: 20002,
|
||||||
Rarity: 1,
|
Rarity: 1,
|
||||||
GroupRate: -1,
|
GroupRate: -1,
|
||||||
@@ -424,6 +481,10 @@ func TestSkills(t *testing.T) {
|
|||||||
ID: 200361,
|
ID: 200361,
|
||||||
Name: "Beeline Burst",
|
Name: "Beeline Burst",
|
||||||
Description: "Increase velocity on a straight.",
|
Description: "Increase velocity on a straight.",
|
||||||
|
GroupSkills: []horse.GroupSkill{
|
||||||
|
{ID: 200362, GroupRate: 1, Rarity: 1},
|
||||||
|
{ID: 200361, GroupRate: 2, Rarity: 2},
|
||||||
|
},
|
||||||
Group: 20036,
|
Group: 20036,
|
||||||
Rarity: 2,
|
Rarity: 2,
|
||||||
GroupRate: 2,
|
GroupRate: 2,
|
||||||
@@ -455,6 +516,10 @@ func TestSkills(t *testing.T) {
|
|||||||
ID: 200362,
|
ID: 200362,
|
||||||
Name: "Straightaway Adept",
|
Name: "Straightaway Adept",
|
||||||
Description: "Slightly increase velocity on a straight.",
|
Description: "Slightly increase velocity on a straight.",
|
||||||
|
GroupSkills: []horse.GroupSkill{
|
||||||
|
{ID: 200362, GroupRate: 1, Rarity: 1},
|
||||||
|
{ID: 200361, GroupRate: 2, Rarity: 2},
|
||||||
|
},
|
||||||
Group: 20036,
|
Group: 20036,
|
||||||
Rarity: 1,
|
Rarity: 1,
|
||||||
GroupRate: 1,
|
GroupRate: 1,
|
||||||
@@ -486,6 +551,9 @@ func TestSkills(t *testing.T) {
|
|||||||
ID: 200831,
|
ID: 200831,
|
||||||
Name: "Subdued Front Runners",
|
Name: "Subdued Front Runners",
|
||||||
Description: "Slightly increase fatigue for front runners early-race.",
|
Description: "Slightly increase fatigue for front runners early-race.",
|
||||||
|
GroupSkills: []horse.GroupSkill{
|
||||||
|
{ID: 200831, GroupRate: 1, Rarity: 1},
|
||||||
|
},
|
||||||
Group: 20083,
|
Group: 20083,
|
||||||
Rarity: 1,
|
Rarity: 1,
|
||||||
GroupRate: 1,
|
GroupRate: 1,
|
||||||
@@ -517,6 +585,9 @@ func TestSkills(t *testing.T) {
|
|||||||
ID: 201801,
|
ID: 201801,
|
||||||
Name: "♡ 3D Nail Art",
|
Name: "♡ 3D Nail Art",
|
||||||
Description: "Moderately decrease performance on firm ground.",
|
Description: "Moderately decrease performance on firm ground.",
|
||||||
|
GroupSkills: []horse.GroupSkill{
|
||||||
|
{ID: 201801, GroupRate: -1, Rarity: 1},
|
||||||
|
},
|
||||||
Group: 20180,
|
Group: 20180,
|
||||||
Rarity: 1,
|
Rarity: 1,
|
||||||
GroupRate: -1,
|
GroupRate: -1,
|
||||||
@@ -548,6 +619,9 @@ func TestSkills(t *testing.T) {
|
|||||||
ID: 300011,
|
ID: 300011,
|
||||||
Name: "Unquenched Thirst",
|
Name: "Unquenched Thirst",
|
||||||
Description: "Moderately increase performance with the desire to race.",
|
Description: "Moderately increase performance with the desire to race.",
|
||||||
|
GroupSkills: []horse.GroupSkill{
|
||||||
|
{ID: 300011, GroupRate: 1, Rarity: 1},
|
||||||
|
},
|
||||||
Group: 30001,
|
Group: 30001,
|
||||||
Rarity: 1,
|
Rarity: 1,
|
||||||
GroupRate: 1,
|
GroupRate: 1,
|
||||||
@@ -579,6 +653,10 @@ func TestSkills(t *testing.T) {
|
|||||||
ID: 900011,
|
ID: 900011,
|
||||||
Name: "Shooting Star",
|
Name: "Shooting Star",
|
||||||
Description: "Slightly increase velocity and very minimally increase acceleration after passing another runner toward the front late-race.",
|
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,
|
Group: 10001,
|
||||||
Rarity: 1,
|
Rarity: 1,
|
||||||
GroupRate: 2,
|
GroupRate: 2,
|
||||||
@@ -618,6 +696,11 @@ func TestSkills(t *testing.T) {
|
|||||||
ID: 900351,
|
ID: 900351,
|
||||||
Name: "Our Ticket to Win!",
|
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.",
|
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,
|
Group: 10035,
|
||||||
Rarity: 1,
|
Rarity: 1,
|
||||||
GroupRate: 2,
|
GroupRate: 2,
|
||||||
@@ -650,6 +733,10 @@ func TestSkills(t *testing.T) {
|
|||||||
ID: 910241,
|
ID: 910241,
|
||||||
Name: "Flowery☆Maneuver",
|
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.",
|
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,
|
Group: 11024,
|
||||||
Rarity: 1,
|
Rarity: 1,
|
||||||
GroupRate: 2,
|
GroupRate: 2,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
SELECT
|
SELECT
|
||||||
|
id,
|
||||||
gallery_chara_id,
|
gallery_chara_id,
|
||||||
disp_order,
|
disp_order,
|
||||||
pos_id,
|
pos_id,
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -30,6 +30,7 @@ type Skill struct {
|
|||||||
ID SkillID `json:"skill_id"`
|
ID SkillID `json:"skill_id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
|
GroupSkills []GroupSkill `json:"group_skills"`
|
||||||
Group SkillGroupID `json:"group"`
|
Group SkillGroupID `json:"group"`
|
||||||
Rarity int8 `json:"rarity"`
|
Rarity int8 `json:"rarity"`
|
||||||
GroupRate int8 `json:"group_rate"`
|
GroupRate int8 `json:"group_rate"`
|
||||||
@@ -42,6 +43,12 @@ type Skill struct {
|
|||||||
IconID int `json:"icon_id"`
|
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.
|
// Activation is the parameters controlling when a skill activates.
|
||||||
type Activation struct {
|
type Activation struct {
|
||||||
Precondition string `json:"precondition,omitzero"`
|
Precondition string `json:"precondition,omitzero"`
|
||||||
|
|||||||
@@ -49,11 +49,16 @@ export function convoCharas(c: Conversation): number[] {
|
|||||||
|
|
||||||
export function requiredCharas(c: Conversation): number[] {
|
export function requiredCharas(c: Conversation): number[] {
|
||||||
switch (c.condition_type) {
|
switch (c.condition_type) {
|
||||||
case Required.None: return []
|
case Required.None:
|
||||||
case Required.All: return convoCharas(c);
|
return [];
|
||||||
case Required.Chara1: return [c.chara_1];
|
case Required.All:
|
||||||
case Required.Chara2: return [c.chara_2!];
|
return convoCharas(c);
|
||||||
case Required.Chara3: return [c.chara_3!];
|
case Required.Chara1:
|
||||||
|
return [c.chara_1];
|
||||||
|
case Required.Chara2:
|
||||||
|
return [c.chara_2!];
|
||||||
|
case Required.Chara3:
|
||||||
|
return [c.chara_3!];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -771,16 +771,17 @@ export function conservePowerAccel(
|
|||||||
distanceType: Distance,
|
distanceType: Distance,
|
||||||
style: RunningStyle,
|
style: RunningStyle,
|
||||||
rawPower: number,
|
rawPower: number,
|
||||||
|
basePower: number,
|
||||||
powerSkillBonus?: number,
|
powerSkillBonus?: number,
|
||||||
spotStruggled?: boolean,
|
spotStruggled?: boolean,
|
||||||
rushed?: boolean,
|
rushed?: boolean,
|
||||||
): number {
|
): number {
|
||||||
const power = rawPower + (powerSkillBonus ?? 0);
|
const power = basePower + 0.5 * Math.max(rawPower - 1200, 0) + (powerSkillBonus ?? 0);
|
||||||
if (power <= 1200) {
|
if (power <= 1200) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
const sdc = conserveStratDistCoef[style][distanceType];
|
const sdc = conserveStratDistCoef[style][distanceType];
|
||||||
const activity = rushed ? 0.8 : spotStruggled ? 0.98 : 1;
|
const activity = (rushed ? 0.8 : 1) * (spotStruggled ? 0.98 : 1);
|
||||||
return Math.sqrt((power - 1200) * 130) * 0.001 * sdc * activity;
|
return Math.sqrt((power - 1200) * 130) * 0.001 * sdc * activity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -224,10 +224,10 @@
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
const fcSeries: ComputedSeries[] = $derived([
|
const fcSeries: ComputedSeries[] = $derived([
|
||||||
{ label: 'Front Runner', y: (x) => conservePowerAccel(distance(raceLen), RunningStyle.FrontRunner, x) },
|
{ label: 'Front Runner', y: (x, raw) => conservePowerAccel(distance(raceLen), RunningStyle.FrontRunner, raw, x) },
|
||||||
{ label: 'Pace Chaser', y: (x) => conservePowerAccel(distance(raceLen), RunningStyle.PaceChaser, x) },
|
{ label: 'Pace Chaser', y: (x, raw) => conservePowerAccel(distance(raceLen), RunningStyle.PaceChaser, raw, x) },
|
||||||
{ label: 'Late Surger', y: (x) => conservePowerAccel(distance(raceLen), RunningStyle.LateSurger, x) },
|
{ label: 'Late Surger', y: (x, raw) => conservePowerAccel(distance(raceLen), RunningStyle.LateSurger, raw, x) },
|
||||||
{ label: 'End Closer', y: (x) => conservePowerAccel(distance(raceLen), RunningStyle.EndCloser, x) },
|
{ label: 'End Closer', y: (x, raw) => conservePowerAccel(distance(raceLen), RunningStyle.EndCloser, raw, x) },
|
||||||
]);
|
]);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -528,9 +528,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p>
|
<p>
|
||||||
The exact mechanics of conserving power are unclear at this time. What has been confirmed is that rushed and <a
|
Rushed and <a href="#spot-struggle">spot struggle</a> reduce both the duration and effectiveness of full charge, potentially to
|
||||||
href="#spot-struggle">spot struggle</a
|
zero. In practice, this appears to be a concern primarily on sprints, which already have a -55% penalty to full charge duration.
|
||||||
> both reduce the chance for it to fire.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<Sec h={3} id="lane-combo">Lane Combo</Sec>
|
<Sec h={3} id="lane-combo">Lane Combo</Sec>
|
||||||
@@ -1143,22 +1142,14 @@
|
|||||||
>. (This race is why I made it.)
|
>. (This race is why I made it.)
|
||||||
</p>
|
</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>
|
<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
|
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
|
||||||
corner, but the portion before the stretch is a special <i>neither corner nor straight</i> property. That means Angling won't activate,
|
Angling wouldn't activate. As of the 1 Jul update, the corner is now connected to the final straight, so there is no longer
|
||||||
and VPP is delayed (though still within the accel period).
|
anything remarkable about this track.
|
||||||
</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.
|
|
||||||
</p>
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Sec h={3} id="3k">Kikuka Sho & Tenno Sho (Spring)</Sec>
|
<Sec h={3} id="3k">Kikuka Sho & Tenno Sho (Spring)</Sec>
|
||||||
<p>
|
<p>
|
||||||
|
|||||||
@@ -17,8 +17,107 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const raceGroups = [
|
||||||
|
[1, 'Common'],
|
||||||
|
[2, 'Daily Race'],
|
||||||
|
[3, '"Training Practice"'],
|
||||||
|
[4, '"Story Condition"'],
|
||||||
|
[5, '"Team Building"'],
|
||||||
|
[6, 'Practice'],
|
||||||
|
[7, 'Career-Exclusive'],
|
||||||
|
[8, 'Legend Race'],
|
||||||
|
[9, 'Team Trials'],
|
||||||
|
[10, 'Unity Cup Team Race'],
|
||||||
|
[11, "Champions' Meet"],
|
||||||
|
[12, 'Room Match'],
|
||||||
|
[13, '"Challenge Match"'],
|
||||||
|
[14, 'League of Heroes Race'],
|
||||||
|
[61, 'Custom G1'],
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
const raceGrades = [
|
||||||
|
[100, 'G1'],
|
||||||
|
[200, 'G2'],
|
||||||
|
[300, 'G3'],
|
||||||
|
[400, 'OP'],
|
||||||
|
[700, 'Pre-OP'],
|
||||||
|
[800, 'Maiden'],
|
||||||
|
[900, 'Debut'],
|
||||||
|
[999, 'Daily Race or Room Match (?)'],
|
||||||
|
[1000, 'Unity Cup Team Race (?)'],
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
const raceTimes = [
|
||||||
|
[1, 'Morning (unused)'],
|
||||||
|
[2, 'Daytime'],
|
||||||
|
[3, 'Evening'],
|
||||||
|
[4, 'Night'],
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
const raceInitialLanes = [
|
||||||
|
[1, 9, 0.03333333],
|
||||||
|
[2, 0, 0],
|
||||||
|
[3, 14, 0.10333333],
|
||||||
|
[4, 8, 0.03333333],
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
const raceAreas = [
|
||||||
|
[0, 'Hokkaido'],
|
||||||
|
[1, 'Tohoku'],
|
||||||
|
[2, 'Kanto'],
|
||||||
|
[3, 'Western Japan'],
|
||||||
|
[4, 'Kokura'],
|
||||||
|
[5, 'France'],
|
||||||
|
[6, 'America'],
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
const raceLoops = [
|
||||||
|
[1, 'None'],
|
||||||
|
[2, 'Inner'],
|
||||||
|
[3, 'Outer'],
|
||||||
|
[4, 'Outer→Inner'],
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
const raceRotations = [
|
||||||
|
[1, 'Right'],
|
||||||
|
[2, 'Left'],
|
||||||
|
[3, 'Rightward Stretch (unused)'],
|
||||||
|
[4, 'Leftward Stretch'],
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
const raceCourseThresholds = [
|
||||||
|
[1, 1, 0],
|
||||||
|
[2, 2, 0],
|
||||||
|
[3, 3, 0],
|
||||||
|
[4, 4, 0],
|
||||||
|
[5, 5, 0],
|
||||||
|
[6, 1, 2],
|
||||||
|
[7, 2, 3],
|
||||||
|
[8, 2, 4],
|
||||||
|
[9, 3, 5],
|
||||||
|
[10, 2, 5],
|
||||||
|
[11, 4, 5],
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
const raceSaddleTypes = [
|
||||||
|
[0, 'Special'],
|
||||||
|
[1, 'G3'],
|
||||||
|
[2, 'G2'],
|
||||||
|
[3, 'G1'],
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
const racePermissions = [
|
||||||
|
[1, 'Junior'],
|
||||||
|
[2, 'Classic'],
|
||||||
|
[3, 'Classic and Senior'],
|
||||||
|
[4, 'Senior'],
|
||||||
|
[5, 'Finale'],
|
||||||
|
] as const;
|
||||||
|
|
||||||
const skills = $derived({
|
const skills = $derived({
|
||||||
rickey: skillMap.get(100981),
|
rickey: skillMap.get(100981),
|
||||||
|
right1: skillMap.get(200012),
|
||||||
|
left1: skillMap.get(200022),
|
||||||
fall2: skillMap.get(200191),
|
fall2: skillMap.get(200191),
|
||||||
fall1: skillMap.get(200192),
|
fall1: skillMap.get(200192),
|
||||||
fallX: skillMap.get(200193),
|
fallX: skillMap.get(200193),
|
||||||
@@ -299,6 +398,10 @@
|
|||||||
in-game shows a "Connecting..." indicator while it loads, it probably isn't in the mdb. Notably, this includes everything
|
in-game shows a "Connecting..." indicator while it loads, it probably isn't in the mdb. Notably, this includes everything
|
||||||
related to career event outcomes. (Event information on sites like GameTora and GameWith are massive crowd-sourced efforts.)
|
related to career event outcomes. (Event information on sites like GameTora and GameWith are massive crowd-sourced efforts.)
|
||||||
</p>
|
</p>
|
||||||
|
<p>Since I see this question about weekly, allow me to reiterate.</p>
|
||||||
|
<p class="text-4xl font-bold">
|
||||||
|
Support card event outcomes are not in master.mdb or any other locally stored file. Not even the list of possible skills.
|
||||||
|
</p>
|
||||||
<p>
|
<p>
|
||||||
This document is oriented toward programmers with understanding of SQL databases. Mentions of <Mono>Gallop::</Mono> are references
|
This document is oriented toward programmers with understanding of SQL databases. Mentions of <Mono>Gallop::</Mono> are references
|
||||||
to types visible in decompilations of the game, but no C# knowledge is needed.
|
to types visible in decompilations of the game, but no C# knowledge is needed.
|
||||||
@@ -330,6 +433,363 @@
|
|||||||
>, but a few categories that have useful strings are missing from there.
|
>, but a few categories that have useful strings are missing from there.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<Sec h={2} id="race">Races</Sec>
|
||||||
|
<p>First, some terminology, as the game uses it internally. (Some UI phrasing disagrees.)</p>
|
||||||
|
<p>
|
||||||
|
A <i>race</i> is an organized running competition, typically held annually. A <i>race instance</i> is a single holding of a
|
||||||
|
race at a specific date and time; this includes special race instances like Team Trials races, Aim for the Stars races,
|
||||||
|
&c. Race instances are held on a given <i>race course</i>, which is a fixed-length segment of a physical location called a
|
||||||
|
<i>race track</i>. A <i>win saddle</i> is a given horse's victory of a race or a specific group of races, e.g. Classic Triple Crown
|
||||||
|
or Dual Grand Prix. This section will cover races, race instances, race tracks, race courses, and win saddles.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<Mono>text_data</Mono> categories relevant to races include:
|
||||||
|
</p>
|
||||||
|
<ul class="ml-4 list-disc pb-4">
|
||||||
|
<li>32 and 33 are both race names, the latter for jikkyo (the announcer's lines).</li>
|
||||||
|
<li>
|
||||||
|
28 is race instance names. 29 is abbreviated race instance names, e.g. <Mono>Mile Ch.</Mono> instead of <Mono
|
||||||
|
>Mile Championship</Mono
|
||||||
|
>.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
31 and 34 are race track full names, the former for jikkyo, e.g. <Mono>Kyoto Racecourse</Mono>. 35 is race track names
|
||||||
|
without "Racecourse".
|
||||||
|
</li>
|
||||||
|
<li>111 is win saddle names.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<Sec h={3} id="race-race">Race Info</Sec>
|
||||||
|
<p>
|
||||||
|
Races are defined in <Mono>race</Mono>, which is quite a direct name innit.
|
||||||
|
</p>
|
||||||
|
<ul class="ml-4 list-disc pb-4">
|
||||||
|
<li>
|
||||||
|
Race ID is just <Mono>id</Mono>.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Mono>group</Mono> is the game situation where the race occurs.
|
||||||
|
<table class="table-fixed border text-center">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col" class="px-2">Group</th>
|
||||||
|
<th scope="col" class="px-2">Meaning</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{#each raceGroups as [id, name] (id)}
|
||||||
|
<tr class="even:bg-mist-300 dark:even:bg-mist-900">
|
||||||
|
<td class="px-2">{id}</td>
|
||||||
|
<td class="px-2">{name}</td>
|
||||||
|
</tr>
|
||||||
|
{/each}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Mono>grade</Mono> defines the race grade.
|
||||||
|
<table class="table-fixed border text-center">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col" class="px-2">Grade ID</th>
|
||||||
|
<th scope="col" class="px-2">Meaning</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{#each raceGrades as [id, name] (id)}
|
||||||
|
<tr class="even:bg-mist-300 dark:even:bg-mist-900">
|
||||||
|
<td class="px-2">{id}</td>
|
||||||
|
<td class="px-2">{name}</td>
|
||||||
|
</tr>
|
||||||
|
{/each}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</li>
|
||||||
|
<li><Mono>course_set</Mono> gives the <a href="#race-course">race course</a> where the race occurs.</li>
|
||||||
|
<li><Mono>thumbnail_id</Mono> is the resource ID of the race's thumbnail image.</li>
|
||||||
|
<li><Mono>entry_num</Mono> is the maximum number of horses that can run the race.</li>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
Some races are ostensibly defined twice to account for variant races run during some characters' careers, e.g. Maruzensky's
|
||||||
|
five opponent Spring Stakes, McQueen/Ryan/Rice's Kyoto Takarazuka Kinen, &c.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<Sec h={3} id="race-instances">Race Instances</Sec>
|
||||||
|
<p>
|
||||||
|
The table is <Mono>race_instance</Mono>.
|
||||||
|
</p>
|
||||||
|
<ul class="ml-4 list-disc pb-4">
|
||||||
|
<li><Mono>id</Mono> is the race instance ID.</li>
|
||||||
|
<li><Mono>race_id</Mono> joins with <Mono>race.id</Mono>.</li>
|
||||||
|
<li>
|
||||||
|
<Mono>npc_group_id</Mono> should define the NPC racers allowed to appear in the race instance, although I haven't looked into
|
||||||
|
it.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Mono>date</Mono> gives the month and day-of-month when the race instance occurs, expressed as M×100+d – 1 Jan is
|
||||||
|
101 and 31 Dec is 1231. This appears to decide the season that the race instance occurs in and thus the applicable green skill.
|
||||||
|
E.g., we can see in career that Challenge Cup is offered on the Early December turn, but its race instance has a <Mono
|
||||||
|
>date</Mono
|
||||||
|
> of 1130 (i.e. 30 Nov), so it is a fall rather than winter race. All races occur in 2019.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Mono>time</Mono> is the time of day that the race instance is held.
|
||||||
|
<table class="table-fixed border text-center">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col" class="px-2">Time</th>
|
||||||
|
<th scope="col" class="px-2">Meaning</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{#each raceTimes as [id, name] (id)}
|
||||||
|
<tr class="even:bg-mist-300 dark:even:bg-mist-900">
|
||||||
|
<td class="px-2">{id}</td>
|
||||||
|
<td class="px-2">{name}</td>
|
||||||
|
</tr>
|
||||||
|
{/each}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Mono>clock_time</Mono> has a value of 1605 for one race and is otherwise always 0. It might be a specific hour and minute that
|
||||||
|
a race instance occurs, but I'm not sure why that would ever matter.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Mono>race_number</Mono> takes every value between -1 and 12, but I couldn't find any explanation for it.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
Similarly to races, some race instances are ostensibly defined twice to account for variant races run during some characters'
|
||||||
|
careers.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<Sec h={3} id="race-track">Race Tracks</Sec>
|
||||||
|
<p>
|
||||||
|
Since race tracks are the physical locations where races are held, there are not many rows in <Mono>race_track</Mono>. Most of
|
||||||
|
its purpose is to define appearance characteristics, but some fields are mechanically relevant.
|
||||||
|
</p>
|
||||||
|
<ul class="ml-4 list-disc pb-4">
|
||||||
|
<li><Mono>id</Mono> is the race track ID.</li>
|
||||||
|
<li>
|
||||||
|
<Mono>initial_lane_type</Mono> describes the starting lane positions of each horse by determining the location and width of the
|
||||||
|
gap between posts.
|
||||||
|
<table class="table-fixed border text-center">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col" class="px-2">ID</th>
|
||||||
|
<th scope="col" class="px-2">Gap After Gate</th>
|
||||||
|
<th scope="col" class="px-2">Gap Width (CW)</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{#each raceInitialLanes as [id, gate, w] (id)}
|
||||||
|
<tr class="even:bg-mist-300 dark:even:bg-mist-900">
|
||||||
|
<td>{id}</td>
|
||||||
|
<td>{gate}</td>
|
||||||
|
<td>{w}</td>
|
||||||
|
</tr>
|
||||||
|
{/each}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
Horses in gates
|
||||||
|
<i>after</i> the Gap After Gate listed in this table have the gap width added to their starting lane.
|
||||||
|
<Mono>initial_lane_type</Mono> is 2 on Oi, Kawasaki, and Funabashi; 3 on Longchamp; 4 on Morioka; and 1 elsewhere. (The race mechanics
|
||||||
|
doc's
|
||||||
|
<a
|
||||||
|
href="https://docs.google.com/document/d/15VzW9W2tXBBTibBRbZ8IVpW6HaMX8H0RP03kq6Az7Xg/edit?tab=t.0#heading=h.ohdxzwro17n5"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer">description of initial lane</a
|
||||||
|
>
|
||||||
|
uses horse index rather than gate number and describes lanes in units of horse lanes rather than course widths.)
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Mono>area</Mono> defines the geographic region where the race track exists.
|
||||||
|
<table class="table-fixed border text-center">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col" class="px-2">ID</th>
|
||||||
|
<th scope="col" class="px-2">Region</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{#each raceAreas as [id, name] (id)}
|
||||||
|
<tr class="even:bg-mist-300 dark:even:bg-mist-900">
|
||||||
|
<td class="px-2">{id}</td>
|
||||||
|
<td class="px-2">{name}</td>
|
||||||
|
</tr>
|
||||||
|
{/each}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<Sec h={3} id="race-course">Race Courses</Sec>
|
||||||
|
<p>
|
||||||
|
Race courses are physical segments of race tracks. They are defined in <Mono>race_course_set</Mono>.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Most tracks have one or two turf loops (the "(Inner)" and "(Outer)" or sometimes "(Outer→Inner)") and one dirt loop. The
|
||||||
|
length of a race course is determined solely by the position of the gates: since the race course is a physical structure with
|
||||||
|
the audience stands in a specific location, and since said audience wants to see the race finish clearly, courses of all
|
||||||
|
lengths end at the same place on the front stretch. The straight opposite the front stretch is called the backstretch. Corners
|
||||||
|
are counted backward from the front stretch in the order 4, 3, 2, 1; all races except Ibis Summer Dash include corners 3 and
|
||||||
|
4, while long and sometimes medium races run corners multiple times. Some courses start on an extra segment of the track which
|
||||||
|
is <i>neither straight nor corner</i> (which means <Mono>straight_random==1</Mono> skills won't fire there).
|
||||||
|
</p>
|
||||||
|
<ul class="ml-4 list-disc pb-4">
|
||||||
|
<li><Mono>id</Mono> gives the race course ID.</li>
|
||||||
|
<li><Mono>race_track_id</Mono> joins with <Mono>race_track.id</Mono>.</li>
|
||||||
|
<li><Mono>distance</Mono> is the race course length in meters.</li>
|
||||||
|
<li><Mono>ground</Mono> is 1 for turf and 2 for dirt.</li>
|
||||||
|
<li>
|
||||||
|
<Mono>inout</Mono> gives the loop for the surface type where the race occurs.
|
||||||
|
<table class="table-fixed border text-center">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col" class="px-2">ID</th>
|
||||||
|
<th scope="col" class="px-2">Loop</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{#each raceLoops as [id, name] (id)}
|
||||||
|
<tr class="even:bg-mist-300 dark:even:bg-mist-900">
|
||||||
|
<td class="px-2">{id}</td>
|
||||||
|
<td class="px-2">{name}</td>
|
||||||
|
</tr>
|
||||||
|
{/each}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Mono>turn</Mono> gives the handedness of the track, i.e. the direction from horses to the rail as they round the track's corners.
|
||||||
|
<table class="table-fixed border text-center">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col" class="px-2">ID</th>
|
||||||
|
<th scope="col" class="px-2">Handedness</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{#each raceRotations as [id, name] (id)}
|
||||||
|
<tr class="even:bg-mist-300 dark:even:bg-mist-900">
|
||||||
|
<td class="px-2">{id}</td>
|
||||||
|
<td class="px-2">{name}</td>
|
||||||
|
</tr>
|
||||||
|
{/each}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
Stretch types have no corners and do not activate <Skill skill={skills.right1} /> or <Skill skill={skills.left1} /> or their variants.
|
||||||
|
Niigata 1000 is the only such race course in the game.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Mono>float_lane_max</Mono> gives the <i>initial</i> race course width in units of ten thousandths of course widths. (Confusingly,
|
||||||
|
no race course has a width of 1 course width.) Some race courses have locations where the lane max changes, but these are defined
|
||||||
|
as events and are not in the mdb.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Mono>course_set_status_id</Mono> joins with <Mono>race_course_set_status.course_set_status_id</Mono> to define the stat thresholds.
|
||||||
|
A value of 0 means no thresholds.
|
||||||
|
<table class="table-fixed border text-center">
|
||||||
|
<caption><Mono>race_course_set_status</Mono></caption>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col" class="px-2"><Mono>course_set_status_id</Mono></th>
|
||||||
|
<th scope="col" class="px-2"><Mono>target_status_1</Mono></th>
|
||||||
|
<th scope="col" class="px-2"><Mono>target_status_2</Mono></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{#each raceCourseThresholds as [id, stat1, stat2] (id)}
|
||||||
|
<tr class="even:bg-mist-300 dark:even:bg-mist-900">
|
||||||
|
<td class="px-2">{id}</td>
|
||||||
|
<td class="px-2">{stat1}</td>
|
||||||
|
<td class="px-2">{stat2}</td>
|
||||||
|
</tr>
|
||||||
|
{/each}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
Status of 1 is Speed, 2 is Power, and so on up to 5 for Wit. 0 means no (second) threshold.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
Characteristics like straight and corner locations, slopes, lane max changes, &c. are <i>not</i> in the mdb. They are defined
|
||||||
|
as assets instead and must be extracted using special tools.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<Sec h={3} id="race-saddle">Win Saddles</Sec>
|
||||||
|
<p>
|
||||||
|
<Mono>single_mode_wins_saddle</Mono> defines the awards given to the horse (not the player) for winning a race or specific group
|
||||||
|
of races. These are the medals displayed as important wins for a horse at the end of a career. They are now purely aesthetic, but
|
||||||
|
I am documenting them anyway because I have the notes already since they used to determine affinity.
|
||||||
|
</p>
|
||||||
|
<ul class="ml-4 list-disc pb-4">
|
||||||
|
<li><Mono>id</Mono> is the win saddle ID.</li>
|
||||||
|
<li><Mono>priority</Mono> is the sort order for win saddles.</li>
|
||||||
|
<li>
|
||||||
|
<Mono>group_id</Mono> associates multiple win saddles for the same race, for horses whose careers have special versions of some
|
||||||
|
races.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Mono>win_saddle_type</Mono> is the type of the win saddle, used to determine the color of the medal displayed.
|
||||||
|
<table class="table-fixed border text-center">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col" class="px-2">ID</th>
|
||||||
|
<th scope="col" class="px-2">Type</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{#each raceSaddleTypes as [id, name] (id)}
|
||||||
|
<tr class="even:bg-mist-300 dark:even:bg-mist-900">
|
||||||
|
<td class="px-2">{id}</td>
|
||||||
|
<td class="px-2">{name}</td>
|
||||||
|
</tr>
|
||||||
|
{/each}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
Special win saddles are for win saddles requiring multiple wins, e.g. Classic Triple Crown.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Mono>race_instance_id_1</Mono> through <Mono>race_instance_id_8</Mono> define the race instance IDs that must be won to be awarded
|
||||||
|
the win saddle. Columns beyond <Mono>race_instance_id_3</Mono> are unused.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<Sec h={3} id="race-program">Single Mode Program</Sec>
|
||||||
|
<p>
|
||||||
|
The table <Mono>single_mode_program</Mono> defines the race instances offered each turn in a career. Confusingly, races that permit
|
||||||
|
both classic and senior year horses are only defined here once.
|
||||||
|
</p>
|
||||||
|
<ul class="ml-4 list-disc pb-4">
|
||||||
|
<li><Mono>race_instance_id</Mono> joins with <Mono>race_instance.id</Mono>.</li>
|
||||||
|
<li>
|
||||||
|
<Mono>race_permission</Mono> gives the career years that offer the race. (More precisely, it gives the age ranges of horses that
|
||||||
|
are permitted to enter.)
|
||||||
|
<table class="table-fixed border text-center">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col" class="px-2">ID</th>
|
||||||
|
<th scope="col" class="px-2">Meaning</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{#each racePermissions as [id, name] (id)}
|
||||||
|
<tr class="even:bg-mist-300 dark:even:bg-mist-900">
|
||||||
|
<td class="px-2">{id}</td>
|
||||||
|
<td class="px-2">{name}</td>
|
||||||
|
</tr>
|
||||||
|
{/each}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</li>
|
||||||
|
<li><Mono>month</Mono> and <Mono>half</Mono> give the turn that the race is held.</li>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
I was unable to identify whether any of the columns indicate maiden races, despite the UI restrictions on when they can
|
||||||
|
appear.
|
||||||
|
</p>
|
||||||
|
|
||||||
<Sec h={2} id="skills">Skills</Sec>
|
<Sec h={2} id="skills">Skills</Sec>
|
||||||
<p>
|
<p>
|
||||||
Relevant <Mono>text_data</Mono> categories include 47 for skill names and 48 for skill descriptions. Otherwise, info for skills
|
Relevant <Mono>text_data</Mono> categories include 47 for skill names and 48 for skill descriptions. Otherwise, info for skills
|
||||||
@@ -816,6 +1276,9 @@
|
|||||||
Relevant <Mono>text_data</Mono> categories include 75 for name including variant, 76 for variant alone, 77 for character name. Category
|
Relevant <Mono>text_data</Mono> categories include 75 for name including variant, 76 for variant alone, 77 for character name. Category
|
||||||
151 gives support card effect names, 154 gives effect descriptions, 150 gives unique effect names, and 155 gives unique effect descriptions.
|
151 gives support card effect names, 154 gives effect descriptions, 150 gives unique effect names, and 155 gives unique effect descriptions.
|
||||||
</p>
|
</p>
|
||||||
|
<p class="text-4xl font-bold">
|
||||||
|
Support card event outcomes are not in master.mdb or any other locally stored file. Not even the list of possible skills.
|
||||||
|
</p>
|
||||||
|
|
||||||
<Sec h={3} id="support_card_data">Support Card Data</Sec>
|
<Sec h={3} id="support_card_data">Support Card Data</Sec>
|
||||||
<p>
|
<p>
|
||||||
|
|||||||
@@ -58,10 +58,10 @@
|
|||||||
]);
|
]);
|
||||||
const laneChange: ComputedSeries[] = [{ label: 'Lane Change Target Speed', y: (x) => race.laneChangeSpeed(x) }];
|
const laneChange: ComputedSeries[] = [{ label: 'Lane Change Target Speed', y: (x) => race.laneChangeSpeed(x) }];
|
||||||
const conservePower: Array<ComputedSeries | null> = $derived([
|
const conservePower: Array<ComputedSeries | null> = $derived([
|
||||||
{ label: 'Conserved Power', y: (_raw, x) => race.conservePowerAccel(distanceType, style, x, 0, false, false) },
|
{ label: 'Conserved Power', y: (x, raw) => race.conservePowerAccel(distanceType, style, raw, x, 0, false, false) },
|
||||||
{ label: 'Rushed', y: (_raw, x) => race.conservePowerAccel(distanceType, style, x, 0, false, true) },
|
{ label: 'Rushed', y: (x, raw) => race.conservePowerAccel(distanceType, style, raw, x, 0, false, true) },
|
||||||
styleIsFront
|
styleIsFront
|
||||||
? { label: 'Spot Struggled', y: (_raw, x) => race.conservePowerAccel(distanceType, style, x, 0, true, false) }
|
? { label: 'Spot Struggled', y: (x, raw) => race.conservePowerAccel(distanceType, style, raw, x, 0, true, false) }
|
||||||
: null,
|
: null,
|
||||||
]);
|
]);
|
||||||
const gutsSpurt: Array<ComputedSeries | null> = $derived([
|
const gutsSpurt: Array<ComputedSeries | null> = $derived([
|
||||||
@@ -329,11 +329,16 @@
|
|||||||
Bonus acceleration at spurt start from the Charge Up/Fully Charged mechanic. Scales with base power plus passive skills, so
|
Bonus acceleration at spurt start from the Charge Up/Fully Charged mechanic. Scales with base power plus passive skills, so
|
||||||
modifiers for ground conditions and career mode do not apply.
|
modifiers for ground conditions and career mode do not apply.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
|
||||||
This mechanic does not appear to be well understood, in particular how long the acceleration bonus lasts and how the rushed
|
|
||||||
and spot struggle multipliers apply.
|
|
||||||
</p>
|
|
||||||
{@render statChart(race.Stat.Power, conservePower, 'Acceleration (m/s²)', [0, 0.35], { len: true, style: true })}
|
{@render statChart(race.Stat.Power, conservePower, 'Acceleration (m/s²)', [0, 0.35], { len: true, style: true })}
|
||||||
|
<p>
|
||||||
|
The duration of Fully Charged does not depend directly on stats, but rather on a hidden <i>conserved power</i> value which
|
||||||
|
increases per horse throughout the race. Conserved power does not increase while <a href="#spot-struggle">spot struggling</a>,
|
||||||
|
so for front runners, the duration may scale negatively with guts. It also does not increase while running in any
|
||||||
|
<a href="#poskeep">position keep mode</a>
|
||||||
|
other than pace-down, so its duration may have a very slight negative correlation with wit.
|
||||||
|
<a href="#rushed">Rushed</a> additionally prevents accumulating conserved power, so full charge duration may scale positively with
|
||||||
|
wit amortized across races. Otherwise, power conservation rate depends on running style.
|
||||||
|
</p>
|
||||||
|
|
||||||
<Sec h={2} id="guts">Guts</Sec>
|
<Sec h={2} id="guts">Guts</Sec>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user