129 lines
3.1 KiB
Go
129 lines
3.1 KiB
Go
package element
|
||
|
||
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。
|
||
func initFullTableMatrix() {
|
||
for i := 0; i < maxMatrixSize; i++ {
|
||
for j := 0; j < maxMatrixSize; j++ {
|
||
matrix[i][j] = 1.0
|
||
}
|
||
}
|
||
|
||
enToID := initSkillTypes()
|
||
initTypeRelations(enToID)
|
||
}
|
||
|
||
func initSkillTypes() map[string]int {
|
||
var cfg skillTypesFile
|
||
mustUnmarshalJSON(skillTypesJSON, &cfg, "skillTypes.json")
|
||
|
||
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))
|
||
}
|
||
|
||
elementNameMap[item.ID] = strings.ToUpper(strings.Join(item.EN, "_"))
|
||
if item.IsDou == 0 {
|
||
validSingleElementIDs[item.ID] = true
|
||
enToID[item.EN[0]] = item.ID
|
||
}
|
||
}
|
||
|
||
for _, item := range cfg.Root.Item {
|
||
if item.IsDou == 0 {
|
||
continue
|
||
}
|
||
|
||
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}
|
||
}
|
||
|
||
return enToID
|
||
}
|
||
|
||
func initTypeRelations(enToID map[string]int) {
|
||
var cfg typeRelationFile
|
||
mustUnmarshalJSON(typesRelationJSON, &cfg, "typesRelation.json")
|
||
|
||
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))
|
||
}
|
||
|
||
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
|
||
}
|
||
}
|
||
}
|
||
|
||
func mustUnmarshalJSON(data []byte, target any, name string) {
|
||
if err := json.Unmarshal(data, target); err != nil {
|
||
panic(fmt.Sprintf("parse %s: %v", name, err))
|
||
}
|
||
}
|
||
|
||
func mustValidElementID(id int, kind string) {
|
||
if id <= 0 || id >= maxMatrixSize {
|
||
panic(fmt.Sprintf("%s id out of range: %d", kind, id))
|
||
}
|
||
}
|