2025-11-06 17:25:16 +00:00
|
|
|
|
package element
|
|
|
|
|
|
|
2026-04-29 04:53:26 +08:00
|
|
|
|
import (
|
|
|
|
|
|
_ "embed"
|
|
|
|
|
|
"encoding/json"
|
|
|
|
|
|
"fmt"
|
|
|
|
|
|
"strings"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
//go:embed data/skillTypes.json
|
|
|
|
|
|
var skillTypesJSON []byte
|
|
|
|
|
|
|
|
|
|
|
|
//go:embed data/typesRelation.json
|
|
|
|
|
|
var typesRelationJSON []byte
|
|
|
|
|
|
|
|
|
|
|
|
type skillTypesFile struct {
|
|
|
|
|
|
Root struct {
|
|
|
|
|
|
Item []skillTypeItem `json:"item"`
|
|
|
|
|
|
} `json:"root"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type skillTypeItem struct {
|
|
|
|
|
|
ID int `json:"id"`
|
|
|
|
|
|
CN string `json:"cn"`
|
|
|
|
|
|
Att string `json:"att"`
|
|
|
|
|
|
IsDou int `json:"is_dou"`
|
|
|
|
|
|
EN []string `json:"en"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type typeRelationFile struct {
|
|
|
|
|
|
Root struct {
|
|
|
|
|
|
Relation []typeRelationItem `json:"relation"`
|
|
|
|
|
|
} `json:"root"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type typeRelationItem struct {
|
|
|
|
|
|
Type string `json:"type"`
|
|
|
|
|
|
Opponent []typeRelationOpponent `json:"opponent"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type typeRelationOpponent struct {
|
|
|
|
|
|
Type string `json:"type"`
|
|
|
|
|
|
Multiple float64 `json:"multiple"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化全属性克制矩阵。数据来自 seer-types-relation,默认关系为 1.0。
|
2025-11-06 17:25:16 +00:00
|
|
|
|
func initFullTableMatrix() {
|
|
|
|
|
|
for i := 0; i < maxMatrixSize; i++ {
|
|
|
|
|
|
for j := 0; j < maxMatrixSize; j++ {
|
|
|
|
|
|
matrix[i][j] = 1.0
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-29 04:53:26 +08:00
|
|
|
|
enToID := initSkillTypes()
|
|
|
|
|
|
initTypeRelations(enToID)
|
|
|
|
|
|
}
|
2025-11-06 17:25:16 +00:00
|
|
|
|
|
2026-04-29 04:53:26 +08:00
|
|
|
|
func initSkillTypes() map[string]int {
|
|
|
|
|
|
var cfg skillTypesFile
|
|
|
|
|
|
mustUnmarshalJSON(skillTypesJSON, &cfg, "skillTypes.json")
|
2025-11-06 17:25:16 +00:00
|
|
|
|
|
2026-04-29 04:53:26 +08:00
|
|
|
|
enToID := make(map[string]int, len(cfg.Root.Item))
|
|
|
|
|
|
for _, item := range cfg.Root.Item {
|
|
|
|
|
|
mustValidElementID(item.ID, "skill type")
|
|
|
|
|
|
if len(item.EN) == 0 {
|
|
|
|
|
|
panic(fmt.Sprintf("skill type %d has no en name", item.ID))
|
|
|
|
|
|
}
|
2025-11-06 17:25:16 +00:00
|
|
|
|
|
2026-04-29 04:53:26 +08:00
|
|
|
|
elementNameMap[item.ID] = strings.ToUpper(strings.Join(item.EN, "_"))
|
|
|
|
|
|
if item.IsDou == 0 {
|
|
|
|
|
|
validSingleElementIDs[item.ID] = true
|
|
|
|
|
|
enToID[item.EN[0]] = item.ID
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-06 17:25:16 +00:00
|
|
|
|
|
2026-04-29 04:53:26 +08:00
|
|
|
|
for _, item := range cfg.Root.Item {
|
|
|
|
|
|
if item.IsDou == 0 {
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
2025-11-06 17:25:16 +00:00
|
|
|
|
|
2026-04-29 04:53:26 +08:00
|
|
|
|
if len(item.EN) != 2 {
|
|
|
|
|
|
panic(fmt.Sprintf("dual skill type %d must have two en names", item.ID))
|
|
|
|
|
|
}
|
|
|
|
|
|
primaryID, ok := enToID[item.EN[0]]
|
|
|
|
|
|
if !ok {
|
|
|
|
|
|
panic(fmt.Sprintf("dual skill type %d references unknown primary type %q", item.ID, item.EN[0]))
|
|
|
|
|
|
}
|
|
|
|
|
|
secondaryID, ok := enToID[item.EN[1]]
|
|
|
|
|
|
if !ok {
|
|
|
|
|
|
panic(fmt.Sprintf("dual skill type %d references unknown secondary type %q", item.ID, item.EN[1]))
|
|
|
|
|
|
}
|
|
|
|
|
|
dualElementMap[item.ID] = [2]int{primaryID, secondaryID}
|
|
|
|
|
|
}
|
2025-11-06 17:25:16 +00:00
|
|
|
|
|
2026-04-29 04:53:26 +08:00
|
|
|
|
return enToID
|
|
|
|
|
|
}
|
2025-11-06 17:25:16 +00:00
|
|
|
|
|
2026-04-29 04:53:26 +08:00
|
|
|
|
func initTypeRelations(enToID map[string]int) {
|
|
|
|
|
|
var cfg typeRelationFile
|
|
|
|
|
|
mustUnmarshalJSON(typesRelationJSON, &cfg, "typesRelation.json")
|
2025-11-06 17:25:16 +00:00
|
|
|
|
|
2026-04-29 04:53:26 +08:00
|
|
|
|
for _, relation := range cfg.Root.Relation {
|
|
|
|
|
|
attackerID, ok := enToID[relation.Type]
|
|
|
|
|
|
if !ok {
|
|
|
|
|
|
panic(fmt.Sprintf("type relation references unknown attacker type %q", relation.Type))
|
|
|
|
|
|
}
|
2025-11-06 17:25:16 +00:00
|
|
|
|
|
2026-04-29 04:53:26 +08:00
|
|
|
|
for _, opponent := range relation.Opponent {
|
|
|
|
|
|
defenderID, ok := enToID[opponent.Type]
|
|
|
|
|
|
if !ok {
|
|
|
|
|
|
panic(fmt.Sprintf("type relation references unknown defender type %q", opponent.Type))
|
|
|
|
|
|
}
|
|
|
|
|
|
matrix[attackerID][defenderID] = opponent.Multiple
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-06 17:25:16 +00:00
|
|
|
|
|
2026-04-29 04:53:26 +08:00
|
|
|
|
func mustUnmarshalJSON(data []byte, target any, name string) {
|
|
|
|
|
|
if err := json.Unmarshal(data, target); err != nil {
|
|
|
|
|
|
panic(fmt.Sprintf("parse %s: %v", name, err))
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-06 17:25:16 +00:00
|
|
|
|
|
2026-04-29 04:53:26 +08:00
|
|
|
|
func mustValidElementID(id int, kind string) {
|
|
|
|
|
|
if id <= 0 || id >= maxMatrixSize {
|
|
|
|
|
|
panic(fmt.Sprintf("%s id out of range: %d", kind, id))
|
|
|
|
|
|
}
|
2025-11-06 17:25:16 +00:00
|
|
|
|
}
|