1 Commits
Author SHA1 Message Date
zephyr 55aa03aa41 umadump/replay: start of race replay json decoding 2026-09-20 11:44:09 -04:00
17 changed files with 1324 additions and 20 deletions
+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]]
}
+2 -3
View File
@@ -771,17 +771,16 @@ 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 = basePower + 0.5 * Math.max(rawPower - 1200, 0) + (powerSkillBonus ?? 0); const power = rawPower + (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 : 1) * (spotStruggled ? 0.98 : 1); const activity = rushed ? 0.8 : spotStruggled ? 0.98 : 1;
return Math.sqrt((power - 1200) * 130) * 0.001 * sdc * activity; return Math.sqrt((power - 1200) * 130) * 0.001 * sdc * activity;
} }
+7 -6
View File
@@ -224,10 +224,10 @@
}, },
]); ]);
const fcSeries: ComputedSeries[] = $derived([ const fcSeries: ComputedSeries[] = $derived([
{ label: 'Front Runner', y: (x, raw) => conservePowerAccel(distance(raceLen), RunningStyle.FrontRunner, raw, x) }, { label: 'Front Runner', y: (x) => conservePowerAccel(distance(raceLen), RunningStyle.FrontRunner, x) },
{ label: 'Pace Chaser', y: (x, raw) => conservePowerAccel(distance(raceLen), RunningStyle.PaceChaser, raw, x) }, { label: 'Pace Chaser', y: (x) => conservePowerAccel(distance(raceLen), RunningStyle.PaceChaser, x) },
{ label: 'Late Surger', y: (x, raw) => conservePowerAccel(distance(raceLen), RunningStyle.LateSurger, raw, x) }, { label: 'Late Surger', y: (x) => conservePowerAccel(distance(raceLen), RunningStyle.LateSurger, x) },
{ label: 'End Closer', y: (x, raw) => conservePowerAccel(distance(raceLen), RunningStyle.EndCloser, raw, x) }, { label: 'End Closer', y: (x) => conservePowerAccel(distance(raceLen), RunningStyle.EndCloser, x) },
]); ]);
</script> </script>
@@ -528,8 +528,9 @@
</div> </div>
</div> </div>
<p> <p>
Rushed and <a href="#spot-struggle">spot struggle</a> reduce both the duration and effectiveness of full charge, potentially to The exact mechanics of conserving power are unclear at this time. What has been confirmed is that rushed and <a
zero. In practice, this appears to be a concern primarily on sprints, which already have a -55% penalty to full charge duration. href="#spot-struggle">spot struggle</a
> 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>
+6 -11
View File
@@ -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: (x, raw) => race.conservePowerAccel(distanceType, style, raw, x, 0, false, false) }, { label: 'Conserved Power', y: (_raw, x) => race.conservePowerAccel(distanceType, style, x, 0, false, false) },
{ label: 'Rushed', y: (x, raw) => race.conservePowerAccel(distanceType, style, raw, x, 0, false, true) }, { label: 'Rushed', y: (_raw, x) => race.conservePowerAccel(distanceType, style, x, 0, false, true) },
styleIsFront styleIsFront
? { label: 'Spot Struggled', y: (x, raw) => race.conservePowerAccel(distanceType, style, raw, x, 0, true, false) } ? { label: 'Spot Struggled', y: (_raw, x) => race.conservePowerAccel(distanceType, style, x, 0, true, false) }
: null, : null,
]); ]);
const gutsSpurt: Array<ComputedSeries | null> = $derived([ const gutsSpurt: Array<ComputedSeries | null> = $derived([
@@ -329,16 +329,11 @@
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>
{@render statChart(race.Stat.Power, conservePower, 'Acceleration (m/s²)', [0, 0.35], { len: true, style: true })}
<p> <p>
The duration of Fully Charged does not depend directly on stats, but rather on a hidden <i>conserved power</i> value which This mechanic does not appear to be well understood, in particular how long the acceleration bonus lasts and how the rushed
increases per horse throughout the race. Conserved power does not increase while <a href="#spot-struggle">spot struggling</a>, and spot struggle multipliers apply.
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> </p>
{@render statChart(race.Stat.Power, conservePower, 'Acceleration (m/s²)', [0, 0.35], { len: true, style: true })}
<Sec h={2} id="guts">Guts</Sec> <Sec h={2} id="guts">Guts</Sec>