120 lines
3.3 KiB
Go
120 lines
3.3 KiB
Go
package common
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"encoding/hex"
|
||
|
|
"encoding/json"
|
||
|
|
"fmt"
|
||
|
|
)
|
||
|
|
|
||
|
|
// CurrencyWarsOrbReward describes a reference-authored declarative reward.
|
||
|
|
// These are not asserted to be original Client roll rates.
|
||
|
|
type CurrencyWarsOrbReward struct {
|
||
|
|
Reward string
|
||
|
|
Amount, ItemID, Count, Rarity, Star uint32
|
||
|
|
Category string
|
||
|
|
}
|
||
|
|
|
||
|
|
type CurrencyWarsOrbRecipe struct {
|
||
|
|
ID uint32
|
||
|
|
Status, Engine string
|
||
|
|
Chapters []uint32
|
||
|
|
Choices [][]CurrencyWarsOrbReward
|
||
|
|
}
|
||
|
|
|
||
|
|
type CurrencyWarsOrbRecipes struct {
|
||
|
|
Format uint32 `json:"format_version"`
|
||
|
|
Source string `json:"source_kind"`
|
||
|
|
Binary string `json:"binary_sha256"`
|
||
|
|
Excel string `json:"excel_json_sha256"`
|
||
|
|
Custom string `json:"custom_json_sha256"`
|
||
|
|
Orbs []struct {
|
||
|
|
ID uint32 `json:"id"`
|
||
|
|
Bonus uint32 `json:"bonus_id"`
|
||
|
|
} `json:"orbs"`
|
||
|
|
Basic []struct {
|
||
|
|
ID uint32 `json:"id"`
|
||
|
|
Kind string `json:"kind"`
|
||
|
|
Amount uint32 `json:"amount"`
|
||
|
|
} `json:"basic_bonuses"`
|
||
|
|
Recipes []CurrencyWarsOrbRecipe `json:"recipes"`
|
||
|
|
Equipment []struct {
|
||
|
|
ID uint32 `json:"id"`
|
||
|
|
Category string `json:"category"`
|
||
|
|
} `json:"equipment"`
|
||
|
|
}
|
||
|
|
|
||
|
|
func LoadCurrencyWarsOrbRecipes() (*CurrencyWarsOrbRecipes, error) {
|
||
|
|
raw, err := ReadResourceFile("resources/CurrencyWarsOrbRecipes.json")
|
||
|
|
if err != nil {
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
var out CurrencyWarsOrbRecipes
|
||
|
|
if err = json.Unmarshal(raw, &out); err != nil {
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
if out.Format != 1 || out.Source != "reference-server-authored-orb-recipes" {
|
||
|
|
return nil, fmt.Errorf("CW Orb recipe format/source differs")
|
||
|
|
}
|
||
|
|
for _, value := range []string{out.Binary, out.Excel, out.Custom} {
|
||
|
|
h, err := hex.DecodeString(value)
|
||
|
|
if err != nil || len(h) != 32 {
|
||
|
|
return nil, fmt.Errorf("CW Orb recipe provenance missing")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
seen := map[uint32]bool{}
|
||
|
|
for _, orb := range out.Orbs {
|
||
|
|
if orb.ID == 0 || orb.Bonus == 0 || seen[orb.ID] {
|
||
|
|
return nil, fmt.Errorf("CW Orb recipe identity invalid")
|
||
|
|
}
|
||
|
|
seen[orb.ID] = true
|
||
|
|
}
|
||
|
|
seen = map[uint32]bool{}
|
||
|
|
for _, recipe := range out.Recipes {
|
||
|
|
if recipe.ID == 0 || seen[recipe.ID] || len(recipe.Choices) == 0 {
|
||
|
|
return nil, fmt.Errorf("CW Orb custom recipe identity/choices invalid")
|
||
|
|
}
|
||
|
|
seen[recipe.ID] = true
|
||
|
|
}
|
||
|
|
return &out, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (r *CurrencyWarsOrbRecipes) Choices(orbID, chapter uint32) ([][]CurrencyWarsOrbReward, error) {
|
||
|
|
for _, recipe := range r.Recipes {
|
||
|
|
if recipe.ID != orbID {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
if recipe.Status != "Implemented" || recipe.Engine != "Orb" {
|
||
|
|
return nil, fmt.Errorf("CW Orb %d recipe is not implemented", orbID)
|
||
|
|
}
|
||
|
|
if len(recipe.Chapters) > 0 {
|
||
|
|
found := false
|
||
|
|
for _, ch := range recipe.Chapters {
|
||
|
|
found = found || ch == chapter
|
||
|
|
}
|
||
|
|
if !found {
|
||
|
|
return nil, fmt.Errorf("CW Orb %d is not applicable to chapter %d", orbID, chapter)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return recipe.Choices, nil
|
||
|
|
}
|
||
|
|
var bonus uint32
|
||
|
|
for _, orb := range r.Orbs {
|
||
|
|
if orb.ID == orbID {
|
||
|
|
bonus = orb.Bonus
|
||
|
|
break
|
||
|
|
}
|
||
|
|
}
|
||
|
|
for _, basic := range r.Basic {
|
||
|
|
if basic.ID != bonus {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
switch basic.Kind {
|
||
|
|
case "Gold", "Exp", "Refresh", "GlobalHp":
|
||
|
|
if basic.Amount == 0 {
|
||
|
|
return nil, fmt.Errorf("CW Orb %d has a zero/implicit basic amount", orbID)
|
||
|
|
}
|
||
|
|
return [][]CurrencyWarsOrbReward{{{Reward: basic.Kind, Amount: basic.Amount}}}, nil
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return nil, fmt.Errorf("CW Orb %d requires an unresolved bonus-pool recipe", orbID)
|
||
|
|
}
|