feat(i18n): integrate i18next for internationalization support and add initial translation setup
This commit is contained in:
15
internal/model/hero_template.go
Normal file
15
internal/model/hero_template.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package model
|
||||
|
||||
// HeroTemplate represents template hero data from herodata.json.
|
||||
type HeroTemplate struct {
|
||||
Code string `json:"code"`
|
||||
Name string `json:"name"`
|
||||
BaseAtk float64 `json:"baseAtk"`
|
||||
BaseDef float64 `json:"baseDef"`
|
||||
BaseHp float64 `json:"baseHp"`
|
||||
BaseSpd float64 `json:"baseSpd"`
|
||||
BaseCr float64 `json:"baseCr"`
|
||||
BaseCd float64 `json:"baseCd"`
|
||||
BaseEff float64 `json:"baseEff"`
|
||||
BaseRes float64 `json:"baseRes"`
|
||||
}
|
||||
106
internal/model/optimizer.go
Normal file
106
internal/model/optimizer.go
Normal file
@@ -0,0 +1,106 @@
|
||||
package model
|
||||
|
||||
// OptimizeStat represents a stat type/value pair.
|
||||
type OptimizeStat struct {
|
||||
Type string `json:"type"`
|
||||
Value float64 `json:"value"`
|
||||
}
|
||||
|
||||
// OptimizeItem represents the minimal item shape needed by the optimizer.
|
||||
type OptimizeItem struct {
|
||||
ID interface{} `json:"id"`
|
||||
Gear string `json:"gear"`
|
||||
Set string `json:"set"`
|
||||
F string `json:"f"`
|
||||
Main *OptimizeStat `json:"main,omitempty"`
|
||||
Substats []OptimizeStat `json:"substats,omitempty"`
|
||||
}
|
||||
|
||||
// OptimizeHero represents the minimal hero shape needed by the optimizer.
|
||||
type OptimizeHero struct {
|
||||
ID interface{} `json:"id"`
|
||||
Code string `json:"code"`
|
||||
Name string `json:"name"`
|
||||
Atk float64 `json:"atk"`
|
||||
Def float64 `json:"def"`
|
||||
Hp float64 `json:"hp"`
|
||||
Spd float64 `json:"spd"`
|
||||
Cr float64 `json:"cr"`
|
||||
Cd float64 `json:"cd"`
|
||||
Eff float64 `json:"eff"`
|
||||
Res float64 `json:"res"`
|
||||
BaseAtk float64 `json:"baseAtk"`
|
||||
BaseDef float64 `json:"baseDef"`
|
||||
BaseHp float64 `json:"baseHp"`
|
||||
BaseSpd float64 `json:"baseSpd"`
|
||||
BaseCr float64 `json:"baseCr"`
|
||||
BaseCd float64 `json:"baseCd"`
|
||||
BaseEff float64 `json:"baseEff"`
|
||||
BaseRes float64 `json:"baseRes"`
|
||||
}
|
||||
|
||||
// StatRange defines a min/max filter.
|
||||
type StatRange struct {
|
||||
Min *float64 `json:"min,omitempty"`
|
||||
Max *float64 `json:"max,omitempty"`
|
||||
}
|
||||
|
||||
// SetFilters defines set filter groups.
|
||||
type SetFilters struct {
|
||||
Set1 []string `json:"set1"`
|
||||
Set2 []string `json:"set2"`
|
||||
Set3 []string `json:"set3"`
|
||||
}
|
||||
|
||||
// BonusStats are hero-specific bonus modifiers.
|
||||
type BonusStats struct {
|
||||
Atk float64 `json:"atk"`
|
||||
Def float64 `json:"def"`
|
||||
Hp float64 `json:"hp"`
|
||||
AtkPct float64 `json:"atkPct"`
|
||||
DefPct float64 `json:"defPct"`
|
||||
HpPct float64 `json:"hpPct"`
|
||||
Spd float64 `json:"spd"`
|
||||
Cr float64 `json:"cr"`
|
||||
Cd float64 `json:"cd"`
|
||||
Eff float64 `json:"eff"`
|
||||
Res float64 `json:"res"`
|
||||
FinalAtkMultiplier float64 `json:"finalAtkMultiplier"`
|
||||
FinalDefMultiplier float64 `json:"finalDefMultiplier"`
|
||||
FinalHpMultiplier float64 `json:"finalHpMultiplier"`
|
||||
}
|
||||
|
||||
// OptimizeRequest represents optimizer input.
|
||||
type OptimizeRequest struct {
|
||||
HeroID string `json:"heroId"`
|
||||
SetFilters SetFilters `json:"setFilters"`
|
||||
StatFilters map[string]StatRange `json:"statFilters"`
|
||||
MainStatFilters map[string]string `json:"mainStatFilters"`
|
||||
WeightValues map[string]float64 `json:"weightValues"`
|
||||
BonusStats BonusStats `json:"bonusStats"`
|
||||
MaxItemsPerSlot int `json:"maxItemsPerSlot"`
|
||||
MaxCombos int `json:"maxCombos"`
|
||||
MaxResults int `json:"maxResults"`
|
||||
}
|
||||
|
||||
// OptimizeResult is a single build result.
|
||||
type OptimizeResult struct {
|
||||
Key string `json:"key"`
|
||||
Sets string `json:"sets"`
|
||||
Atk float64 `json:"atk"`
|
||||
Def float64 `json:"def"`
|
||||
Hp float64 `json:"hp"`
|
||||
Spd float64 `json:"spd"`
|
||||
Cr float64 `json:"cr"`
|
||||
Cd float64 `json:"cd"`
|
||||
Acc float64 `json:"acc"`
|
||||
Res float64 `json:"res"`
|
||||
Score float64 `json:"score"`
|
||||
Items []OptimizeItem `json:"items"`
|
||||
}
|
||||
|
||||
// OptimizeResponse is the optimizer output.
|
||||
type OptimizeResponse struct {
|
||||
TotalCombos int `json:"totalCombos"`
|
||||
Results []OptimizeResult `json:"results"`
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"equipment-analyzer/internal/capture"
|
||||
"equipment-analyzer/internal/config"
|
||||
"equipment-analyzer/internal/model"
|
||||
"equipment-analyzer/internal/optimizer"
|
||||
"equipment-analyzer/internal/utils"
|
||||
"github.com/wailsapp/wails/v2/pkg/runtime"
|
||||
)
|
||||
@@ -83,6 +84,71 @@ func (a *App) Shutdown(ctx context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
// OptimizeBuilds runs the optimizer on latest parsed data.
|
||||
func (a *App) OptimizeBuilds(req model.OptimizeRequest) (*model.OptimizeResponse, error) {
|
||||
log.Printf("[service] OptimizeBuilds entry heroId=%s", req.HeroID)
|
||||
parsedResult, err := a.GetLatestParsedDataFromDatabase()
|
||||
if err != nil {
|
||||
log.Printf("[service] OptimizeBuilds get data failed: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
if parsedResult == nil || (len(parsedResult.Items) == 0 && len(parsedResult.Heroes) == 0) {
|
||||
log.Printf("[service] OptimizeBuilds no data items=%d heroes=%d", len(parsedResult.Items), len(parsedResult.Heroes))
|
||||
return &model.OptimizeResponse{TotalCombos: 0, Results: []model.OptimizeResult{}}, nil
|
||||
}
|
||||
|
||||
items, err := optimizer.ParseItems(parsedResult.Items)
|
||||
if err != nil {
|
||||
log.Printf("[service] OptimizeBuilds parse items failed: %v", err)
|
||||
return nil, fmt.Errorf("parse items failed: %w", err)
|
||||
}
|
||||
logMissingSetStats(parsedResult.Items)
|
||||
heroes, err := optimizer.ParseHeroes(parsedResult.Heroes)
|
||||
if err != nil {
|
||||
log.Printf("[service] OptimizeBuilds parse heroes failed: %v", err)
|
||||
return nil, fmt.Errorf("parse heroes failed: %w", err)
|
||||
}
|
||||
templates, err := a.parserService.GetHeroTemplates()
|
||||
if err != nil {
|
||||
log.Printf("[service] OptimizeBuilds hero templates missing: %v", err)
|
||||
return nil, fmt.Errorf("未读取到英雄信息数据")
|
||||
}
|
||||
templateHeroes := make([]model.OptimizeHero, 0, len(templates))
|
||||
for _, t := range templates {
|
||||
templateHeroes = append(templateHeroes, model.OptimizeHero{
|
||||
Code: t.Code,
|
||||
Name: t.Name,
|
||||
BaseAtk: t.BaseAtk,
|
||||
BaseDef: t.BaseDef,
|
||||
BaseHp: t.BaseHp,
|
||||
BaseSpd: t.BaseSpd,
|
||||
BaseCr: t.BaseCr,
|
||||
BaseCd: t.BaseCd,
|
||||
BaseEff: t.BaseEff,
|
||||
BaseRes: t.BaseRes,
|
||||
Atk: t.BaseAtk,
|
||||
Def: t.BaseDef,
|
||||
Hp: t.BaseHp,
|
||||
Spd: t.BaseSpd,
|
||||
Cr: t.BaseCr,
|
||||
Cd: t.BaseCd,
|
||||
Eff: t.BaseEff,
|
||||
Res: t.BaseRes,
|
||||
})
|
||||
}
|
||||
// Use template heroes for optimizer to match the template-based selection.
|
||||
heroes = templateHeroes
|
||||
|
||||
log.Printf("[service] OptimizeBuilds parsed items=%d heroes=%d", len(items), len(heroes))
|
||||
resp, err := optimizer.Optimize(items, heroes, req)
|
||||
if err != nil {
|
||||
log.Printf("[service] OptimizeBuilds optimize failed: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
log.Printf("[service] OptimizeBuilds done results=%d totalCombos=%d", len(resp.Results), resp.TotalCombos)
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// GetNetworkInterfaces returns available network interfaces.
|
||||
func (a *App) GetNetworkInterfaces() ([]model.NetworkInterface, error) {
|
||||
interfaces, err := capture.GetNetworkInterfaces()
|
||||
@@ -93,6 +159,11 @@ func (a *App) GetNetworkInterfaces() ([]model.NetworkInterface, error) {
|
||||
return interfaces, nil
|
||||
}
|
||||
|
||||
// GetHeroTemplates returns template heroes from local herodata.json.
|
||||
func (a *App) GetHeroTemplates() ([]model.HeroTemplate, error) {
|
||||
return a.parserService.GetHeroTemplates()
|
||||
}
|
||||
|
||||
// StartCapture starts capture on the given interface.
|
||||
func (a *App) StartCapture(interfaceName string) error {
|
||||
if a.captureService.IsCapturing() {
|
||||
@@ -329,6 +400,7 @@ func (a *App) GetLatestParsedDataFromDatabase() (*model.ParsedResult, error) {
|
||||
return nil, fmt.Errorf("failed to unmarshal items: %w", err)
|
||||
}
|
||||
}
|
||||
logMissingSetStats(items)
|
||||
|
||||
var heroes []interface{}
|
||||
if heroesJSON != "" {
|
||||
@@ -424,6 +496,95 @@ func (a *App) GetAllAppSettings() (map[string]string, error) {
|
||||
return a.databaseService.GetAllAppSettings()
|
||||
}
|
||||
|
||||
func logMissingSetStats(items []interface{}) {
|
||||
if len(items) == 0 {
|
||||
return
|
||||
}
|
||||
var total int
|
||||
var emptyF int
|
||||
var emptySet int
|
||||
var healthF int
|
||||
var healthSet int
|
||||
var mapHp int
|
||||
setCounts := map[string]int{}
|
||||
uncategorized := 0
|
||||
emptySetByF := map[string]int{}
|
||||
emptySetByGear := map[string]int{}
|
||||
ingameSetMap := map[string]string{
|
||||
"set_acc": "HitSet",
|
||||
"set_att": "AttackSet",
|
||||
"set_coop": "UnitySet",
|
||||
"set_counter": "CounterSet",
|
||||
"set_cri_dmg": "DestructionSet",
|
||||
"set_cri": "CriticalSet",
|
||||
"set_def": "DefenseSet",
|
||||
"set_immune": "ImmunitySet",
|
||||
"set_max_hp": "HealthSet",
|
||||
"set_penetrate": "PenetrationSet",
|
||||
"set_rage": "RageSet",
|
||||
"set_res": "ResistSet",
|
||||
"set_revenge": "RevengeSet",
|
||||
"set_scar": "InjurySet",
|
||||
"set_speed": "SpeedSet",
|
||||
"set_vampire": "LifestealSet",
|
||||
"set_shield": "ProtectionSet",
|
||||
"set_torrent": "TorrentSet",
|
||||
"set_revenant": "ReversalSet",
|
||||
"set_riposte": "RiposteSet",
|
||||
"set_chase": "PursuitSet",
|
||||
"set_opener": "WarfareSet",
|
||||
}
|
||||
for _, raw := range items {
|
||||
item, ok := raw.(map[string]interface{})
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
total++
|
||||
if f, ok := item["f"]; !ok || f == nil || f == "" {
|
||||
emptyF++
|
||||
} else {
|
||||
if f == "set_max_hp" {
|
||||
healthF++
|
||||
}
|
||||
}
|
||||
setValue, _ := item["set"].(string)
|
||||
if setValue == "" {
|
||||
emptySet++
|
||||
fValue, _ := item["f"].(string)
|
||||
if fValue != "" {
|
||||
emptySetByF[fValue] = emptySetByF[fValue] + 1
|
||||
}
|
||||
if gear, ok := item["gear"].(string); ok && gear != "" {
|
||||
emptySetByGear[gear] = emptySetByGear[gear] + 1
|
||||
}
|
||||
if fValue != "" {
|
||||
if mapped, ok := ingameSetMap[fValue]; ok {
|
||||
setCounts[mapped] = setCounts[mapped] + 1
|
||||
} else {
|
||||
uncategorized++
|
||||
}
|
||||
} else {
|
||||
uncategorized++
|
||||
}
|
||||
} else {
|
||||
setCounts[setValue] = setCounts[setValue] + 1
|
||||
}
|
||||
if set, ok := item["set"].(string); ok && set == "HealthSet" {
|
||||
healthSet++
|
||||
}
|
||||
if f, ok := item["f"]; ok && f == "set_max_hp" {
|
||||
mapHp++
|
||||
}
|
||||
}
|
||||
log.Printf("[service] set stats: total=%d empty_f=%d empty_set=%d set_max_hp=%d HealthSet=%d mapped_hp=%d", total, emptyF, emptySet, healthF, healthSet, mapHp)
|
||||
log.Printf("[service] set counts: %+v", setCounts)
|
||||
log.Printf("[service] uncategorized items: %d", uncategorized)
|
||||
if emptySet > 0 {
|
||||
log.Printf("[service] empty set by f: %+v", emptySetByF)
|
||||
log.Printf("[service] empty set by gear: %+v", emptySetByGear)
|
||||
}
|
||||
}
|
||||
|
||||
// StartCaptureWithFilter allows frontend to provide a custom BPF filter.
|
||||
func (a *App) StartCaptureWithFilter(interfaceName string, filter string) error {
|
||||
a.logger.Info("StartCaptureWithFilter requested", "interface", interfaceName, "filter", filter)
|
||||
|
||||
@@ -10,8 +10,12 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -19,6 +23,9 @@ type ParserService struct {
|
||||
config *config.Config
|
||||
logger *utils.Logger
|
||||
hexParser *parser.HexParser
|
||||
heroBase map[string]heroBaseStats
|
||||
heroOnce sync.Once
|
||||
heroErr error
|
||||
}
|
||||
|
||||
func NewParserService(cfg *config.Config, logger *utils.Logger) *ParserService {
|
||||
@@ -26,6 +33,7 @@ func NewParserService(cfg *config.Config, logger *utils.Logger) *ParserService {
|
||||
config: cfg,
|
||||
logger: logger,
|
||||
hexParser: parser.NewHexParser(),
|
||||
heroBase: make(map[string]heroBaseStats),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,6 +215,8 @@ func (ps *ParserService) convertSingleItem(item map[string]interface{}) map[stri
|
||||
// convertUnits 转换英雄数据
|
||||
func (ps *ParserService) convertUnits(rawUnits []interface{}) []map[string]interface{} {
|
||||
var convertedUnits []map[string]interface{}
|
||||
ps.ensureHeroBaseData()
|
||||
|
||||
|
||||
for _, rawUnit := range rawUnits {
|
||||
if unitMap, ok := rawUnit.(map[string]interface{}); ok {
|
||||
@@ -225,6 +235,12 @@ func (ps *ParserService) convertUnits(rawUnits []interface{}) []map[string]inter
|
||||
convertedUnit["awaken"] = z
|
||||
}
|
||||
|
||||
if code, ok := unitMap["code"].(string); ok && code != "" {
|
||||
if base, ok := ps.heroBase[code]; ok {
|
||||
ps.applyHeroBase(convertedUnit, base)
|
||||
}
|
||||
}
|
||||
|
||||
convertedUnits = append(convertedUnits, convertedUnit)
|
||||
}
|
||||
}
|
||||
@@ -520,3 +536,232 @@ func (ps *ParserService) convertItemsAllWithLog(rawItems []interface{}) []map[st
|
||||
}
|
||||
return convertedItems
|
||||
}
|
||||
|
||||
|
||||
type heroBaseStats struct {
|
||||
Atk float64
|
||||
Def float64
|
||||
Hp float64
|
||||
Spd float64
|
||||
Cr float64
|
||||
Cd float64
|
||||
Eff float64
|
||||
Res float64
|
||||
}
|
||||
|
||||
type heroDataEntry struct {
|
||||
Code string `json:"code"`
|
||||
Name string `json:"name"`
|
||||
CalculatedStatus struct {
|
||||
Lv60SixStarFullyAwakened struct {
|
||||
Atk float64 `json:"atk"`
|
||||
Def float64 `json:"def"`
|
||||
Hp float64 `json:"hp"`
|
||||
Spd float64 `json:"spd"`
|
||||
Chc float64 `json:"chc"`
|
||||
Chd float64 `json:"chd"`
|
||||
Eff float64 `json:"eff"`
|
||||
Efr float64 `json:"efr"`
|
||||
} `json:"lv60SixStarFullyAwakened"`
|
||||
} `json:"calculatedStatus"`
|
||||
}
|
||||
|
||||
func (ps *ParserService) ensureHeroBaseData() {
|
||||
ps.heroOnce.Do(func() {
|
||||
homeDir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
ps.heroErr = err
|
||||
ps.logger.Error("load hero data failed", "error", err)
|
||||
return
|
||||
}
|
||||
path := filepath.Join(homeDir, ".equipment-analyzer", "herodata.json")
|
||||
body, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
ps.heroErr = err
|
||||
ps.logger.Error("load hero data failed", "error", err)
|
||||
return
|
||||
}
|
||||
var raw map[string]heroDataEntry
|
||||
if err := json.Unmarshal(body, &raw); err != nil {
|
||||
ps.heroErr = err
|
||||
ps.logger.Error("load hero data failed", "error", err)
|
||||
return
|
||||
}
|
||||
for _, entry := range raw {
|
||||
if entry.Code == "" {
|
||||
continue
|
||||
}
|
||||
stats := entry.CalculatedStatus.Lv60SixStarFullyAwakened
|
||||
ps.heroBase[entry.Code] = heroBaseStats{
|
||||
Atk: stats.Atk,
|
||||
Def: stats.Def,
|
||||
Hp: stats.Hp,
|
||||
Spd: stats.Spd,
|
||||
Cr: stats.Chc * 100,
|
||||
Cd: stats.Chd * 100,
|
||||
Eff: stats.Eff * 100,
|
||||
Res: stats.Efr * 100,
|
||||
}
|
||||
}
|
||||
ps.logger.Info("hero base data loaded", "count", len(ps.heroBase))
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
func (ps *ParserService) FillHeroBase(heroes []model.OptimizeHero) error {
|
||||
ps.ensureHeroBaseData()
|
||||
if len(ps.heroBase) == 0 {
|
||||
return fmt.Errorf("hero base data not loaded")
|
||||
}
|
||||
for i := range heroes {
|
||||
code := heroes[i].Code
|
||||
if code == "" {
|
||||
continue
|
||||
}
|
||||
base, ok := ps.heroBase[code]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if heroes[i].BaseAtk == 0 {
|
||||
heroes[i].BaseAtk = base.Atk
|
||||
}
|
||||
if heroes[i].BaseDef == 0 {
|
||||
heroes[i].BaseDef = base.Def
|
||||
}
|
||||
if heroes[i].BaseHp == 0 {
|
||||
heroes[i].BaseHp = base.Hp
|
||||
}
|
||||
if heroes[i].BaseSpd == 0 {
|
||||
heroes[i].BaseSpd = base.Spd
|
||||
}
|
||||
if heroes[i].BaseCr == 0 {
|
||||
heroes[i].BaseCr = base.Cr
|
||||
}
|
||||
if heroes[i].BaseCd == 0 {
|
||||
heroes[i].BaseCd = base.Cd
|
||||
}
|
||||
if heroes[i].BaseEff == 0 {
|
||||
heroes[i].BaseEff = base.Eff
|
||||
}
|
||||
if heroes[i].BaseRes == 0 {
|
||||
heroes[i].BaseRes = base.Res
|
||||
}
|
||||
|
||||
if heroes[i].Atk == 0 {
|
||||
heroes[i].Atk = base.Atk
|
||||
}
|
||||
if heroes[i].Def == 0 {
|
||||
heroes[i].Def = base.Def
|
||||
}
|
||||
if heroes[i].Hp == 0 {
|
||||
heroes[i].Hp = base.Hp
|
||||
}
|
||||
if heroes[i].Spd == 0 {
|
||||
heroes[i].Spd = base.Spd
|
||||
}
|
||||
if heroes[i].Cr == 0 {
|
||||
heroes[i].Cr = base.Cr
|
||||
}
|
||||
if heroes[i].Cd == 0 {
|
||||
heroes[i].Cd = base.Cd
|
||||
}
|
||||
if heroes[i].Eff == 0 {
|
||||
heroes[i].Eff = base.Eff
|
||||
}
|
||||
if heroes[i].Res == 0 {
|
||||
heroes[i].Res = base.Res
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ps *ParserService) GetHeroTemplates() ([]model.HeroTemplate, error) {
|
||||
homeDir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
path := filepath.Join(homeDir, ".equipment-analyzer", "herodata.json")
|
||||
body, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var raw map[string]heroDataEntry
|
||||
if err := json.Unmarshal(body, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
list := make([]model.HeroTemplate, 0, len(raw))
|
||||
for _, entry := range raw {
|
||||
if entry.Code == "" {
|
||||
continue
|
||||
}
|
||||
stats := entry.CalculatedStatus.Lv60SixStarFullyAwakened
|
||||
list = append(list, model.HeroTemplate{
|
||||
Code: entry.Code,
|
||||
Name: entry.Name,
|
||||
BaseAtk: stats.Atk,
|
||||
BaseDef: stats.Def,
|
||||
BaseHp: stats.Hp,
|
||||
BaseSpd: stats.Spd,
|
||||
BaseCr: stats.Chc * 100,
|
||||
BaseCd: stats.Chd * 100,
|
||||
BaseEff: stats.Eff * 100,
|
||||
BaseRes: stats.Efr * 100,
|
||||
})
|
||||
}
|
||||
sort.Slice(list, func(i, j int) bool {
|
||||
return list[i].Name < list[j].Name
|
||||
})
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func (ps *ParserService) applyHeroBase(unit map[string]interface{}, base heroBaseStats) {
|
||||
if _, ok := unit["baseAtk"]; !ok {
|
||||
unit["baseAtk"] = base.Atk
|
||||
}
|
||||
if _, ok := unit["baseDef"]; !ok {
|
||||
unit["baseDef"] = base.Def
|
||||
}
|
||||
if _, ok := unit["baseHp"]; !ok {
|
||||
unit["baseHp"] = base.Hp
|
||||
}
|
||||
if _, ok := unit["baseSpd"]; !ok {
|
||||
unit["baseSpd"] = base.Spd
|
||||
}
|
||||
if _, ok := unit["baseCr"]; !ok {
|
||||
unit["baseCr"] = base.Cr
|
||||
}
|
||||
if _, ok := unit["baseCd"]; !ok {
|
||||
unit["baseCd"] = base.Cd
|
||||
}
|
||||
if _, ok := unit["baseEff"]; !ok {
|
||||
unit["baseEff"] = base.Eff
|
||||
}
|
||||
if _, ok := unit["baseRes"]; !ok {
|
||||
unit["baseRes"] = base.Res
|
||||
}
|
||||
|
||||
if _, ok := unit["atk"]; !ok {
|
||||
unit["atk"] = base.Atk
|
||||
}
|
||||
if _, ok := unit["def"]; !ok {
|
||||
unit["def"] = base.Def
|
||||
}
|
||||
if _, ok := unit["hp"]; !ok {
|
||||
unit["hp"] = base.Hp
|
||||
}
|
||||
if _, ok := unit["spd"]; !ok {
|
||||
unit["spd"] = base.Spd
|
||||
}
|
||||
if _, ok := unit["cr"]; !ok {
|
||||
unit["cr"] = base.Cr
|
||||
}
|
||||
if _, ok := unit["cd"]; !ok {
|
||||
unit["cd"] = base.Cd
|
||||
}
|
||||
if _, ok := unit["eff"]; !ok {
|
||||
unit["eff"] = base.Eff
|
||||
}
|
||||
if _, ok := unit["res"]; !ok {
|
||||
unit["res"] = base.Res
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user