Files
ismdata/ism.go
T

429 lines
18 KiB
Go

package main
import (
"bytes"
"encoding/json"
"io"
"time"
"git.sunturtle.xyz/zephyr/horse"
)
type SupportCardID int32 // package horse doesn't have this yet
type OldWorkSingleIdleMode struct {
Chara SingleModeChara `json:"charaInfo"`
StartTime int64 `json:"startTime"`
EndTime int64 `json:"endTime"`
ProgressLog OldIdleSingleModeProgressLog `json:"progressLogInfo"`
}
type ProgressInfo struct {
Chara SingleModeChara `json:"chara_info"`
StartTime string `json:"start_time"`
EndTime string `json:"end_time"`
DressID int32 `json:"dress_id"`
}
type WorkIdleSingleMode struct {
ProgressInfo ProgressInfo `json:"progress_info"`
ProgressLog IdleSingleModeProgressLog `json:"progress_log_info"`
End End `json:"end_info"`
OldChara *SingleModeChara `json:"chara_info"`
}
type Skill struct {
SkillID horse.SkillID `json:"skill_id"`
Level int32 `json:"level"`
}
type SkillTip struct {
GroupID horse.SkillGroupID `json:"group_id"`
Rarity int32 `json:"rarity"`
Level int32 `json:"level"`
}
type SingleModeSupportCard struct {
Position int32 `json:"position"`
SupportCardID SupportCardID `json:"support_card_id"`
LimitBreakCount int32 `json:"limit_break_count"`
Exp int32 `json:"exp"`
TrainingPartnerState int32 `json:"training_partner_state"`
OwnerViewerID int64 `json:"owner_viewer_id"`
RentalType int32 `json:"rental_type"`
}
type GroupOuting struct {
CharaID horse.CharacterID `json:"chara_id"`
IsOuting int32 `json:"is_outing"`
StoryStep int32 `json:"story_step"`
}
type Evaluation struct {
TargetID int32 `json:"target_id"`
TrainingPartner int32 `json:"training_partner_id"`
Evaluation int32 `json:"evaluation"`
IsOuting int32 `json:"is_outing"`
StoryStep int32 `json:"story_step"`
IsAppear int32 `json:"is_appear"`
GroupOutingInfo []GroupOuting `json:"group_outing_info_array"`
}
type TrainingLevel struct {
CommandID int32 `json:"command_id"`
Level int32 `json:"level"`
}
type GuestOuting struct {
SupportCardID SupportCardID `json:"support_card_id"`
StoryStep int32 `json:"story_step"`
GroupOutingInfo []GroupOuting `json:"group_outing_info_array"`
}
type SingleModeSkillUpgrade struct {
ConditionID int32 `json:"condition_id"`
TotalCount int32 `json:"total_count"`
CurrentCount int32 `json:"current_count"`
}
type SingleModeChara struct {
SingleModeCharaID int32 `json:"single_mode_chara_id"`
CardID horse.UmaID `json:"card_id"`
CharaGrade int32 `json:"chara_grade"`
Speed int32 `json:"speed"`
Stamina int32 `json:"stamina"`
Power int32 `json:"power"`
Wiz int32 `json:"wiz"`
Guts int32 `json:"guts"`
Vital int32 `json:"vital"`
MaxSpeed int32 `json:"max_speed"`
MaxStamina int32 `json:"max_stamina"`
MaxPower int32 `json:"max_power"`
MaxWiz int32 `json:"max_wiz"`
MaxGuts int32 `json:"max_guts"`
DefaultMaxSpeed int32 `json:"default_max_speed"`
DefaultMaxStamina int32 `json:"default_max_stamina"`
DefaultMaxPower int32 `json:"default_max_power"`
DefaultMaxWiz int32 `json:"default_max_wiz"`
DefaultMaxGuts int32 `json:"default_max_guts"`
MaxVital int32 `json:"max_vital"`
Motivation int32 `json:"motivation"`
Fans int32 `json:"fans"`
Rarity int32 `json:"rarity"`
RaceProgramID int32 `json:"race_program_id"`
ReserveRaceProgramID int32 `json:"reserve_race_program_id"`
RaceRunningStyle int32 `json:"race_running_style"`
IsShortRace int32 `json:"is_short_race"`
TalentLevel int32 `json:"talent_level"`
Skills []Skill `json:"skill_array"`
DisableSkillIDs []horse.SkillID `json:"disable_skill_id_array"`
SkillTips []SkillTip `json:"skill_tips_array"`
SupportCards []SingleModeSupportCard `json:"support_card_array"`
SuccessionTrainedCharaID1 int32 `json:"succession_trained_chara_id_1"`
SuccessionTrainedCharaID2 int32 `json:"succession_trained_chara_id_2"`
ProperDistanceShort horse.AptitudeLevel `json:"proper_distance_short"`
ProperDistanceMile horse.AptitudeLevel `json:"proper_distance_mile"`
ProperDistanceMiddle horse.AptitudeLevel `json:"proper_distance_middle"`
ProperDistanceLong horse.AptitudeLevel `json:"proper_distance_long"`
ProperRunningStyleNige horse.AptitudeLevel `json:"proper_running_style_nige"`
ProperRunningStyleSenko horse.AptitudeLevel `json:"proper_running_style_senko"`
ProperRunningStyleSashi horse.AptitudeLevel `json:"proper_running_style_sashi"`
ProperRunningStyleOikomi horse.AptitudeLevel `json:"proper_running_style_oikomi"`
ProperGroundTurf horse.AptitudeLevel `json:"proper_ground_turf"`
ProperGroundDirt horse.AptitudeLevel `json:"proper_ground_dirt"`
Turn int32 `json:"turn"`
SkillPoint int32 `json:"skill_point"`
ShortCutState int32 `json:"short_cut_state"`
State int32 `json:"state"`
PlayingState int32 `json:"playing_state"`
ScenarioID horse.ScenarioID `json:"scenario_id"`
RouteID int32 `json:"route_id"`
StartTime string `json:"start_time"`
Evaluations []Evaluation `json:"evaluation_info_array"`
TrainingLevels []TrainingLevel `json:"training_level_info_array"`
NicknameIDs []int32 `json:"nickname_id_array"`
CharaEffectIDs []int32 `json:"chara_effect_id_array"`
RouteRaceIDs []int32 `json:"route_race_id_array"`
GuestOutings []GuestOuting `json:"guest_outing_info_array"`
SkillUpgrades []SingleModeSkillUpgrade `json:"skill_upgrade_info_array"`
}
type OldCharaEffectLog struct {
CharaEffectID int32 `json:"charaEffectId"`
IsActive bool `json:"isActive"`
}
type CharaEffectLog struct {
CharaEffectID int32 `json:"chara_effect_id"`
IsActive bool `json:"is_active"`
}
type IdleSingleModeSignedInt struct {
Sign int32 `json:"sign"`
Value int32 `json:"value"`
}
type OldIdleSingleModeGainInfo struct {
Speed IdleSingleModeSignedInt `json:"speed"`
Stamina IdleSingleModeSignedInt `json:"stamina"`
Power IdleSingleModeSignedInt `json:"power"`
Wiz IdleSingleModeSignedInt `json:"wiz"`
Guts IdleSingleModeSignedInt `json:"guts"`
MaxSpeed int32 `json:"maxSpeed"`
MaxStamina int32 `json:"maxStamina"`
MaxPower int32 `json:"maxPower"`
MaxWiz int32 `json:"maxWiz"`
MaxGuts int32 `json:"maxGuts"`
ProperDistanceShort horse.AptitudeLevel `json:"properDistanceShort"`
ProperDistanceMile horse.AptitudeLevel `json:"properDistanceMile"`
ProperDistanceMiddle horse.AptitudeLevel `json:"properDistanceMiddle"`
ProperDistanceLong horse.AptitudeLevel `json:"properDistanceLong"`
ProperRunningStyleNige horse.AptitudeLevel `json:"properRunningStyleNige"`
ProperRunningStyleSenko horse.AptitudeLevel `json:"properRunningStyleSenko"`
ProperRunningStyleSashi horse.AptitudeLevel `json:"properRunningStyleSashi"`
ProperRunningStyleOikomi horse.AptitudeLevel `json:"properRunningStyleOikomi"`
ProperGroundTurf horse.AptitudeLevel `json:"properGroundTurf"`
ProperGroundDirt horse.AptitudeLevel `json:"properGroundDirt"`
SkillPoint int32 `json:"skillPoint"`
SkillTips []SkillTip `json:"skillTips"`
}
type IdleSingleModeGainInfo struct {
Speed IdleSingleModeSignedInt `json:"speed"`
Stamina IdleSingleModeSignedInt `json:"stamina"`
Power IdleSingleModeSignedInt `json:"power"`
Wiz IdleSingleModeSignedInt `json:"wiz"`
Guts IdleSingleModeSignedInt `json:"guts"`
MaxSpeed int32 `json:"max_speed"`
MaxStamina int32 `json:"max_stamina"`
MaxPower int32 `json:"max_power"`
MaxWiz int32 `json:"max_wiz"`
MaxGuts int32 `json:"max_guts"`
ProperDistanceShort horse.AptitudeLevel `json:"proper_distance_short"`
ProperDistanceMile horse.AptitudeLevel `json:"proper_distance_mile"`
ProperDistanceMiddle horse.AptitudeLevel `json:"proper_distance_middle"`
ProperDistanceLong horse.AptitudeLevel `json:"proper_distance_long"`
ProperRunningStyleNige horse.AptitudeLevel `json:"proper_running_style_nige"`
ProperRunningStyleSenko horse.AptitudeLevel `json:"proper_running_style_senko"`
ProperRunningStyleSashi horse.AptitudeLevel `json:"proper_running_style_sashi"`
ProperRunningStyleOikomi horse.AptitudeLevel `json:"proper_running_style_oikomi"`
ProperGroundTurf horse.AptitudeLevel `json:"proper_ground_turf"`
ProperGroundDirt horse.AptitudeLevel `json:"proper_ground_dirt"`
SkillPoint int32 `json:"skill_point"`
SkillTips []SkillTip `json:"skill_tips_array"`
}
type OldIdleSingleModeSupportCardGain struct {
SupportCardID SupportCardID `json:"supportCardId"`
GainInfo OldIdleSingleModeGainInfo `json:"gainInfo"`
}
type IdleSingleModeSupportCardGain struct {
SupportCardID SupportCardID `json:"support_card_id"`
GainInfo IdleSingleModeGainInfo `json:"gain_info"`
}
type OldFactor struct {
FactorID horse.SparkID `json:"factorId"`
Level int32 `json:"level"`
}
type Factor struct {
FactorID horse.SparkID `json:"factor_id"`
Level int32 `json:"level"`
}
type OldIdleSingleModeSuccessionFactorGain struct {
Year int32 `json:"year"`
GainFactorInfo []OldFactor `json:"gainFactorInfoArray"`
}
type IdleSingleModeSuccessionFactorGain struct {
Year int32 `json:"year"`
GainFactorInfo []Factor `json:"gain_factor_info_array"`
}
type SingleRaceHistory struct {
Turn int32 `json:"turn"`
ProgramID int32 `json:"program_id"`
Weather int32 `json:"weather"`
GroundCondition int32 `json:"ground_condition"`
RunningStyle int32 `json:"running_style"`
ResultRank int32 `json:"result_rank"`
FrameOrder int32 `json:"frame_order"`
NPCCount int32 `json:"npc_count"`
}
type RaceReward struct {
ItemType int32 `json:"item_type"`
ItemID int32 `json:"item_id"`
ItemNum int32 `json:"item_num"`
}
type RaceRewardLimit struct {
RewardID int32 `json:"reward_id"`
ItemType int32 `json:"item_type"`
ItemID int32 `json:"item_id"`
ItemNum int32 `json:"item_num"`
RestCount int32 `json:"rest_count"`
}
type CharaRaceReward struct {
ResultRank int32 `json:"result_rank"`
ResultTime int32 `json:"result_time"`
RaceReward []RaceReward `json:"race_reward"`
RaceRewardBonus []RaceReward `json:"race_reward_bonus"`
RaceRewardPlusBonus []RaceReward `json:"race_reward_plus_bonus"`
RaceRewardBonusWin []RaceReward `json:"race_reward_bonus_win"`
RaceRewardLimit []RaceRewardLimit `json:"race_reward_limit"`
GainedFans int32 `json:"gained_fans"`
CampaignIDs []int32 `json:"campaign_id_array"`
}
type IdleSingleModeRaceHistory struct {
RaceHistory SingleRaceHistory `json:"race_history"`
RaceRewardInfo CharaRaceReward `json:"race_reward_info"`
LoseTipsID int32 `json:"lose_tips_id"`
}
type OldIdleSingleModeProgressLog struct {
CharaEffectLog []OldCharaEffectLog `json:"charaEffectLog"`
SupportCardGains []OldIdleSingleModeSupportCardGain `json:"supportCardGainInfo"`
EventGain OldIdleSingleModeGainInfo `json:"eventGainInfo"`
SuccessionGain OldIdleSingleModeGainInfo `json:"successionGainInfo"`
SuccessionFactorGains []OldIdleSingleModeSuccessionFactorGain `json:"successionFactorGainArray"`
RaceHistory []IdleSingleModeRaceHistory `json:"raceHistoryArray"`
GainSkillIDs []horse.SkillID `json:"gainSkillIdArray"`
TotalSkillPoint int32 `json:"totalSkillPoint"`
}
type IdleSingleModeProgressLog struct {
CharaEffectLog []CharaEffectLog `json:"chara_effect_log_array"`
SupportCardGains []IdleSingleModeSupportCardGain `json:"support_card_gain_info_array"`
EventGain IdleSingleModeGainInfo `json:"event_gain_info"`
SuccessionGain IdleSingleModeGainInfo `json:"succession_gain_info"`
SuccessionFactorGains []IdleSingleModeSuccessionFactorGain `json:"succession_factor_gain_array"`
RaceHistory []IdleSingleModeRaceHistory `json:"race_history_array"`
GainSkillIDs []horse.SkillID `json:"gain_skill_id_array"`
TotalSkillPoint int32 `json:"total_skill_point"`
}
type AddItem struct {
ItemID int32 `json:"item_id"`
Number int32 `json:"number"`
}
type RewardSummary struct {
AddItem []AddItem `json:"add_item_list"`
}
type End struct {
Chara SingleModeChara `json:"chara_info"`
CharaButWerseterIsOverworked *SingleModeChara `json:"chara_starting_info"`
RewardSummary RewardSummary `json:"reward_summary_info"`
}
func loadISM(r io.Reader) (WorkIdleSingleMode, error) {
// Since we have two potential types to read at the top level,
// decode one message and try it both ways.
var b json.RawMessage
var err error
if err = json.NewDecoder(r).Decode(&b); err != nil {
return WorkIdleSingleMode{}, err
}
{
var ism WorkIdleSingleMode
d := json.NewDecoder(bytes.NewReader(b))
d.DisallowUnknownFields()
err = d.Decode(&ism)
if err == nil {
// NOTE(zeph): this is for no error
// If old fields are populated, move them to the correct ones.
if ism.End.CharaButWerseterIsOverworked != nil {
ism.End.Chara = *ism.End.CharaButWerseterIsOverworked
ism.End.CharaButWerseterIsOverworked = nil
}
if ism.OldChara != nil {
ism.ProgressInfo.Chara = *ism.OldChara
ism.OldChara = nil
}
return ism, nil
}
}
{
var ism OldWorkSingleIdleMode
d := json.NewDecoder(bytes.NewReader(b))
d.DisallowUnknownFields()
// Use a new error variable here.
// If this fails, we want to return the reason we didn't use the API type instead.
if err := d.Decode(&ism); err == nil {
// NOTE(zeph): this is for no error
return unold(ism), nil
}
}
// NOTE(zeph): this is the error from decoding the API type, not the validation type.
return WorkIdleSingleMode{}, err
}
func unold(old OldWorkSingleIdleMode) WorkIdleSingleMode {
return WorkIdleSingleMode{
ProgressInfo: ProgressInfo{
Chara: old.Chara,
StartTime: time.Unix(old.StartTime, 0).Format(time.DateTime),
EndTime: time.Unix(old.EndTime, 0).Format(time.DateTime),
},
ProgressLog: IdleSingleModeProgressLog{
CharaEffectLog: unoldEffects(old.ProgressLog.CharaEffectLog),
SupportCardGains: unoldCardGains(old.ProgressLog.SupportCardGains),
EventGain: IdleSingleModeGainInfo(old.ProgressLog.EventGain),
SuccessionGain: IdleSingleModeGainInfo(old.ProgressLog.SuccessionGain),
SuccessionFactorGains: unoldFactorGains(old.ProgressLog.SuccessionFactorGains),
RaceHistory: old.ProgressLog.RaceHistory,
GainSkillIDs: old.ProgressLog.GainSkillIDs,
TotalSkillPoint: old.ProgressLog.TotalSkillPoint,
},
// We could try to roll up starting numbers plus gains,
// but only a few of these files exist anyway.
// Not worth the effort.
End: End{},
}
}
func unoldEffects(olds []OldCharaEffectLog) []CharaEffectLog {
new := make([]CharaEffectLog, len(olds))
for i, old := range olds {
new[i] = CharaEffectLog(old)
}
return new
}
func unoldCardGains(olds []OldIdleSingleModeSupportCardGain) []IdleSingleModeSupportCardGain {
new := make([]IdleSingleModeSupportCardGain, len(olds))
for i, old := range olds {
new[i] = IdleSingleModeSupportCardGain{
SupportCardID: old.SupportCardID,
GainInfo: IdleSingleModeGainInfo(old.GainInfo),
}
}
return new
}
func unoldFactorGains(olds []OldIdleSingleModeSuccessionFactorGain) []IdleSingleModeSuccessionFactorGain {
new := make([]IdleSingleModeSuccessionFactorGain, len(olds))
for i, old := range olds {
new[i] = IdleSingleModeSuccessionFactorGain{
Year: old.Year,
GainFactorInfo: unoldFactors(old.GainFactorInfo),
}
}
return new
}
func unoldFactors(olds []OldFactor) []Factor {
new := make([]Factor, len(olds))
for i, old := range olds {
new[i] = Factor(old)
}
return new
}