package common import ( "encoding/json" "fmt" "strconv" ) type CurrencyWarsWeeklyRank struct { Rank uint32 `json:"rank"` Score uint32 `json:"score"` Reward uint32 `json:"reward"` } type CurrencyWarsScoreDivision struct { Rule uint32 `json:"rule"` OCRule uint32 `json:"oc_rule"` WeeklyModify uint32 `json:"weekly_modify"` ExpModify uint32 `json:"exp_modify"` } type CurrencyWarsScoreNode struct { Chapter uint32 `json:"chapter"` Section uint32 `json:"section"` Weekly uint32 `json:"weekly"` Exp uint32 `json:"exp"` } type CurrencyWarsOfferingLevel struct { Level uint32 `json:"level"` ItemCost uint32 `json:"item_cost"` RewardID uint32 `json:"reward_id"` } type CurrencyWarsScore struct { FormatVersion uint32 `json:"format_version"` TargetClientVersion string `json:"target_client_version"` TargetAssemblySHA256 string `json:"target_assembly_sha256"` WeeklyCap uint32 `json:"weekly_cap"` WeeklyRanks []CurrencyWarsWeeklyRank `json:"weekly_ranks"` Divisions map[string]CurrencyWarsScoreDivision `json:"divisions"` Rules map[string][]CurrencyWarsScoreNode `json:"rules"` OfferingLevels []CurrencyWarsOfferingLevel `json:"offering_levels"` } func LoadCurrencyWarsScore(catalog *CurrencyWarsCatalog) (*CurrencyWarsScore, error) { raw, err := ReadResourceFile("resources/CurrencyWarsScore.json") if err != nil { return nil, err } var out CurrencyWarsScore if err = json.Unmarshal(raw, &out); err != nil { return nil, err } if catalog != nil { if out.FormatVersion != 1 || out.TargetClientVersion != catalog.ClientVersion || out.TargetAssemblySHA256 != catalog.Provenance.GameAssemblySHA256 { return nil, fmt.Errorf("CW score revision differs from catalog") } } return &out, nil } func (s *CurrencyWarsScore) CalculateRunScore(divisionID uint32, isOverclock bool, chapter, section uint32, isWon bool) (weeklyScore, expBase, expExtra uint32) { if s == nil { return 0, 0, 0 } divKey := strconv.FormatUint(uint64(divisionID), 10) div, exists := s.Divisions[divKey] if !exists { return 0, 0, 0 } rule := div.Rule if isOverclock && div.OCRule != 0 { rule = div.OCRule } ruleKey := strconv.FormatUint(uint64(rule), 10) nodes, exists := s.Rules[ruleKey] if !exists || len(nodes) == 0 { return 0, 0, 0 } here := chapter*100 + section var best *CurrencyWarsScoreNode for i := range nodes { n := &nodes[i] at := n.Chapter*100 + n.Section if at < here || (isWon && at == here) { best = n } } if best == nil { return 0, 0, 0 } weeklyMod := div.WeeklyModify if weeklyMod == 0 { weeklyMod = 100 } weeklyScore = (best.Weekly * weeklyMod) / 100 expBase = best.Exp if div.ExpModify > 100 { expExtra = (best.Exp * (div.ExpModify - 100)) / 100 } return weeklyScore, expBase, expExtra } func (s *CurrencyWarsScore) OfferingLevel(exp uint32) (level uint32, levelExp uint32) { if s == nil || len(s.OfferingLevels) == 0 { return 0, exp } left := exp for _, row := range s.OfferingLevels { if row.ItemCost == 0 { continue } if left < row.ItemCost { break } left -= row.ItemCost level = row.Level } return level, left }