Add initial calculation string parser (#706)
* Add objgroup.txt loader * Add parser * Add parser * Add tests
This commit is contained in:
parent
dccb930f5c
commit
2ceba68c73
|
@ -0,0 +1,105 @@
|
|||
// Package d2calculation contains code for calculation nodes.
|
||||
package d2calculation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Calculation is the interface of every evaluatable calculation.
|
||||
type Calculation interface {
|
||||
fmt.Stringer
|
||||
Eval() int
|
||||
}
|
||||
|
||||
// BinaryCalculation is a calculation with a binary function or operator.
|
||||
type BinaryCalculation struct {
|
||||
// Left is the left operand.
|
||||
Left Calculation
|
||||
|
||||
// Right is the right operand.
|
||||
Right Calculation
|
||||
|
||||
// Op is the actual operation.
|
||||
Op func(v1, v2 int) int
|
||||
}
|
||||
|
||||
// Eval evaluates the calculation.
|
||||
func (node *BinaryCalculation) Eval() int {
|
||||
return node.Op(node.Left.Eval(), node.Right.Eval())
|
||||
}
|
||||
|
||||
func (node *BinaryCalculation) String() string {
|
||||
return "Binary(" + node.Left.String() + "," + node.Right.String() + ")"
|
||||
}
|
||||
|
||||
// UnaryCalculation is a calculation with a unary function or operator.
|
||||
type UnaryCalculation struct {
|
||||
// Child is the operand.
|
||||
Child Calculation
|
||||
|
||||
// Op is the operation.
|
||||
Op func(v int) int
|
||||
}
|
||||
|
||||
// Eval evaluates the calculation.
|
||||
func (node *UnaryCalculation) Eval() int {
|
||||
return node.Op(node.Child.Eval())
|
||||
}
|
||||
|
||||
func (node *UnaryCalculation) String() string {
|
||||
return "Unary(" + node.Child.String() + ")"
|
||||
}
|
||||
|
||||
// TernaryCalculation is a calculation with a ternary function or operator.
|
||||
type TernaryCalculation struct {
|
||||
// Left is the left operand.
|
||||
Left Calculation
|
||||
|
||||
// Middle is the middle operand.
|
||||
Middle Calculation
|
||||
|
||||
// Right is the right operand.
|
||||
Right Calculation
|
||||
Op func(v1, v2, v3 int) int
|
||||
}
|
||||
|
||||
// Eval evaluates the calculation.
|
||||
func (node *TernaryCalculation) Eval() int {
|
||||
return node.Op(node.Left.Eval(), node.Middle.Eval(), node.Right.Eval())
|
||||
}
|
||||
|
||||
func (node *TernaryCalculation) String() string {
|
||||
return "Ternary(" + node.Left.String() + "," + node.Middle.String() + "," + node.Right.String() + ")"
|
||||
}
|
||||
|
||||
// PropertyReferenceCalculation is the calculation representing a property.
|
||||
type PropertyReferenceCalculation struct {
|
||||
Type string
|
||||
Name string
|
||||
Qualifier string
|
||||
}
|
||||
|
||||
// Eval evaluates the calculation.
|
||||
func (node *PropertyReferenceCalculation) Eval() int {
|
||||
return 1
|
||||
}
|
||||
|
||||
func (node *PropertyReferenceCalculation) String() string {
|
||||
return "Property(" + node.Type + "," + node.Name + "," + node.Qualifier + ")"
|
||||
}
|
||||
|
||||
// ConstantCalculation is a constant value.
|
||||
type ConstantCalculation struct {
|
||||
// Value is the constant value.
|
||||
Value int
|
||||
}
|
||||
|
||||
// Eval evaluates the calculation.
|
||||
func (node *ConstantCalculation) Eval() int {
|
||||
return node.Value
|
||||
}
|
||||
|
||||
func (node *ConstantCalculation) String() string {
|
||||
return strconv.Itoa(node.Value)
|
||||
}
|
|
@ -0,0 +1,188 @@
|
|||
// Package d2lexer contains the code for tokenizing calculation strings.
|
||||
package d2lexer
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
type tokenType int
|
||||
|
||||
const (
|
||||
// Name represents a name token, such as skill, par1 etc.
|
||||
Name tokenType = iota
|
||||
|
||||
// String represents a quoted string token, such as "Sacrifice".
|
||||
String
|
||||
|
||||
// Symbol represents a symbol token, such as '+', '-', '?, '.' etc.
|
||||
Symbol
|
||||
|
||||
// Number represents an integer token.
|
||||
Number
|
||||
|
||||
// EOF is the end-of-file token, generated when the end of data is reached.
|
||||
EOF
|
||||
)
|
||||
|
||||
func (t tokenType) String() string {
|
||||
return []string{
|
||||
"Name",
|
||||
"String",
|
||||
"Symbol",
|
||||
"Number",
|
||||
"EOF",
|
||||
}[t]
|
||||
}
|
||||
|
||||
// Token is a lexical token of a calculation string.
|
||||
type Token struct {
|
||||
Type tokenType
|
||||
Value string
|
||||
}
|
||||
|
||||
func (t *Token) String() string {
|
||||
return "(" + t.Type.String() + ", " + t.Value + ")\n"
|
||||
}
|
||||
|
||||
// Lexer is the tokenizer for calculation strings.
|
||||
type Lexer struct {
|
||||
data []byte
|
||||
CurrentToken Token
|
||||
index int
|
||||
peeked bool
|
||||
nextToken Token
|
||||
}
|
||||
|
||||
// New creates a new Lexer for tokenizing the given data.
|
||||
func New(input []byte) *Lexer {
|
||||
return &Lexer{
|
||||
data: input,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Lexer) peekNext() (byte, error) {
|
||||
if l.index+1 >= len(l.data) {
|
||||
return 0, errors.New("cannot peek")
|
||||
}
|
||||
|
||||
return l.data[l.index+1], nil
|
||||
}
|
||||
|
||||
func (l *Lexer) extractOpToken() Token {
|
||||
c := l.data[l.index]
|
||||
if c == '=' || c == '!' {
|
||||
next, ok := l.peekNext()
|
||||
if ok != nil || next != '=' {
|
||||
panic("Invalid operator at index!" + strconv.Itoa(l.index))
|
||||
} else {
|
||||
l.index += 2
|
||||
return Token{Symbol, string(c) + "="}
|
||||
}
|
||||
}
|
||||
|
||||
if c == '<' || c == '>' {
|
||||
next, ok := l.peekNext()
|
||||
if ok == nil && next == '=' {
|
||||
l.index += 2
|
||||
return Token{Symbol, string(c) + "="}
|
||||
}
|
||||
l.index++
|
||||
|
||||
return Token{Symbol, string(c)}
|
||||
}
|
||||
l.index++
|
||||
|
||||
return Token{Symbol, string(c)}
|
||||
}
|
||||
|
||||
func (l *Lexer) extractNumber() Token {
|
||||
var sb strings.Builder
|
||||
|
||||
for l.index < len(l.data) && unicode.IsDigit(rune(l.data[l.index])) {
|
||||
sb.WriteByte(l.data[l.index])
|
||||
l.index++
|
||||
}
|
||||
|
||||
return Token{Number, sb.String()}
|
||||
}
|
||||
|
||||
func (l *Lexer) extractString() Token {
|
||||
var sb strings.Builder
|
||||
l.index++
|
||||
|
||||
for l.index < len(l.data) && l.data[l.index] != '\'' {
|
||||
sb.WriteByte(l.data[l.index])
|
||||
l.index++
|
||||
}
|
||||
l.index++
|
||||
|
||||
return Token{String, sb.String()}
|
||||
}
|
||||
|
||||
func (l *Lexer) extractName() Token {
|
||||
var sb strings.Builder
|
||||
|
||||
for l.index < len(l.data) &&
|
||||
(unicode.IsLetter(rune(l.data[l.index])) ||
|
||||
unicode.IsDigit(rune(l.data[l.index]))) {
|
||||
sb.WriteByte(l.data[l.index])
|
||||
l.index++
|
||||
}
|
||||
|
||||
return Token{Name, sb.String()}
|
||||
}
|
||||
|
||||
// Peek returns the next token, but does not advance the tokenizer.
|
||||
// The peeked token is cached until the tokenizer advances.
|
||||
func (l *Lexer) Peek() Token {
|
||||
if l.peeked {
|
||||
return l.nextToken
|
||||
}
|
||||
|
||||
if l.index == len(l.data) {
|
||||
l.nextToken = Token{EOF, ""}
|
||||
return l.nextToken
|
||||
}
|
||||
|
||||
for l.index < len(l.data) && unicode.IsSpace(rune(l.data[l.index])) {
|
||||
l.index++
|
||||
}
|
||||
|
||||
if l.index == len(l.data) {
|
||||
l.nextToken = Token{EOF, ""}
|
||||
return l.nextToken
|
||||
}
|
||||
|
||||
switch {
|
||||
case strings.IndexByte("^=!><+-/*.,:?()", l.data[l.index]) != -1:
|
||||
l.nextToken = l.extractOpToken()
|
||||
case unicode.IsDigit(rune(l.data[l.index])):
|
||||
l.nextToken = l.extractNumber()
|
||||
case l.data[l.index] == '\'':
|
||||
l.nextToken = l.extractString()
|
||||
case unicode.IsLetter(rune(l.data[l.index])):
|
||||
l.nextToken = l.extractName()
|
||||
default:
|
||||
panic("Invalid token at index: " + strconv.Itoa(l.index))
|
||||
}
|
||||
|
||||
l.peeked = true
|
||||
|
||||
return l.nextToken
|
||||
}
|
||||
|
||||
// NextToken returns the next token and advances the tokenizer.
|
||||
func (l *Lexer) NextToken() Token {
|
||||
if l.peeked {
|
||||
l.CurrentToken = l.nextToken
|
||||
} else {
|
||||
l.CurrentToken = l.Peek()
|
||||
}
|
||||
|
||||
l.peeked = false
|
||||
|
||||
return l.CurrentToken
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
package d2lexer
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestName(t *testing.T) {
|
||||
lexer := New([]byte("correct horse battery staple andromeda13142 n1n2n4"))
|
||||
|
||||
expected := []Token{
|
||||
{Name, "correct"},
|
||||
{Name, "horse"},
|
||||
{Name, "battery"},
|
||||
{Name, "staple"},
|
||||
{Name, "andromeda13142"},
|
||||
{Name, "n1n2n4"},
|
||||
}
|
||||
|
||||
for _, want := range expected {
|
||||
got := lexer.NextToken()
|
||||
if got.Type != Name || got.Value != want.Value {
|
||||
t.Errorf("Got: %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
eof := lexer.NextToken()
|
||||
if eof.Type != EOF {
|
||||
t.Errorf("Did not reach EOF")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNumber(t *testing.T) {
|
||||
lexer := New([]byte("12 2325 53252 312 3411"))
|
||||
|
||||
expected := []Token{
|
||||
{Number, "12"},
|
||||
{Number, "2325"},
|
||||
{Number, "53252"},
|
||||
{Number, "312"},
|
||||
{Number, "3411"},
|
||||
}
|
||||
|
||||
for _, want := range expected {
|
||||
got := lexer.NextToken()
|
||||
if got.Type != Number || got.Value != want.Value {
|
||||
t.Errorf("Got: %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
eof := lexer.NextToken()
|
||||
if eof.Type != EOF {
|
||||
t.Errorf("Did not reach EOF")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSymbol(t *testing.T) {
|
||||
lexer := New([]byte("((+-==>>>=!=<=<=<*//*)?(::.,.:?"))
|
||||
|
||||
expected := []Token{
|
||||
{Symbol, "("},
|
||||
{Symbol, "("},
|
||||
{Symbol, "+"},
|
||||
{Symbol, "-"},
|
||||
{Symbol, "=="},
|
||||
{Symbol, ">"},
|
||||
{Symbol, ">"},
|
||||
{Symbol, ">="},
|
||||
{Symbol, "!="},
|
||||
{Symbol, "<="},
|
||||
{Symbol, "<="},
|
||||
{Symbol, "<"},
|
||||
{Symbol, "*"},
|
||||
{Symbol, "/"},
|
||||
{Symbol, "/"},
|
||||
{Symbol, "*"},
|
||||
{Symbol, ")"},
|
||||
{Symbol, "?"},
|
||||
{Symbol, "("},
|
||||
{Symbol, ":"},
|
||||
{Symbol, ":"},
|
||||
{Symbol, "."},
|
||||
{Symbol, ","},
|
||||
{Symbol, "."},
|
||||
{Symbol, ":"},
|
||||
{Symbol, "?"},
|
||||
}
|
||||
|
||||
for _, want := range expected {
|
||||
got := lexer.NextToken()
|
||||
if got.Type != Symbol || got.Value != want.Value {
|
||||
t.Errorf("Got: %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
eof := lexer.NextToken()
|
||||
if eof.Type != EOF {
|
||||
t.Errorf("Did not reach EOF")
|
||||
}
|
||||
}
|
||||
|
||||
func TestString(t *testing.T) {
|
||||
lexer := New([]byte(`correct 'horse' 'battery staple' 'andromeda13142 ' n1n2n4`))
|
||||
|
||||
expected := []Token{
|
||||
{Name, "correct"},
|
||||
{String, "horse"},
|
||||
{String, "battery staple"},
|
||||
{String, "andromeda13142 "},
|
||||
{Name, "n1n2n4"},
|
||||
}
|
||||
|
||||
for _, want := range expected {
|
||||
got := lexer.NextToken()
|
||||
if got.Type != want.Type || got.Value != want.Value {
|
||||
t.Errorf("Got: %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
eof := lexer.NextToken()
|
||||
if eof.Type != EOF {
|
||||
t.Errorf("Did not reach EOF")
|
||||
}
|
||||
}
|
||||
|
||||
func TestActualConstructions(t *testing.T) {
|
||||
lexer := New([]byte("skill('Sacrifice'.blvl) > 3 ? min(50, lvl) : skill('Sacrifice'.lvl) * ln12"))
|
||||
|
||||
expected := []Token{
|
||||
{Name, "skill"},
|
||||
{Symbol, "("},
|
||||
{String, "Sacrifice"},
|
||||
{Symbol, "."},
|
||||
{Name, "blvl"},
|
||||
{Symbol, ")"},
|
||||
{Symbol, ">"},
|
||||
{Number, "3"},
|
||||
{Symbol, "?"},
|
||||
{Name, "min"},
|
||||
{Symbol, "("},
|
||||
{Number, "50"},
|
||||
{Symbol, ","},
|
||||
{Name, "lvl"},
|
||||
{Symbol, ")"},
|
||||
{Symbol, ":"},
|
||||
{Name, "skill"},
|
||||
{Symbol, "("},
|
||||
{String, "Sacrifice"},
|
||||
{Symbol, "."},
|
||||
{Name, "lvl"},
|
||||
{Symbol, ")"},
|
||||
{Symbol, "*"},
|
||||
{Name, "ln12"},
|
||||
}
|
||||
|
||||
for _, want := range expected {
|
||||
got := lexer.NextToken()
|
||||
if got.Type != want.Type || got.Value != want.Value {
|
||||
t.Errorf("Got: %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
eof := lexer.NextToken()
|
||||
if eof.Type != EOF {
|
||||
t.Errorf("Did not reach EOF")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
// Package d2parser contains the code for parsing calculation strings.
|
||||
package d2parser
|
|
@ -0,0 +1,197 @@
|
|||
package d2parser
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
type binaryOperation struct {
|
||||
Operator string
|
||||
Precedence int
|
||||
IsRightAssociated bool
|
||||
Function func(v1, v2 int) int
|
||||
}
|
||||
|
||||
type unaryOperation struct {
|
||||
Operator string
|
||||
Precedence int
|
||||
Function func(v int) int
|
||||
}
|
||||
|
||||
type ternaryOperation struct {
|
||||
Operator string
|
||||
Marker string
|
||||
Precedence int
|
||||
IsRightAssociated bool
|
||||
Function func(v1, v2, v3 int) int
|
||||
}
|
||||
|
||||
func getUnaryOperations() map[string]unaryOperation {
|
||||
return map[string]unaryOperation{
|
||||
"+": {
|
||||
"+",
|
||||
4,
|
||||
func(v int) int {
|
||||
return v
|
||||
},
|
||||
},
|
||||
"-": {
|
||||
"-",
|
||||
4,
|
||||
func(v int) int {
|
||||
return -v
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getTernaryOperations() map[string]ternaryOperation {
|
||||
return map[string]ternaryOperation{
|
||||
"?": {
|
||||
"?",
|
||||
":",
|
||||
0,
|
||||
true,
|
||||
func(v1, v2, v3 int) int {
|
||||
if v1 != 0 {
|
||||
return v2
|
||||
}
|
||||
return v3
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getBinaryOperations() map[string]binaryOperation { //nolint:funlen // No reason to split function, just creates the operations.
|
||||
return map[string]binaryOperation{
|
||||
"==": {
|
||||
"==",
|
||||
1,
|
||||
false,
|
||||
func(v1, v2 int) int {
|
||||
if v1 == v2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
},
|
||||
},
|
||||
"!=": {
|
||||
"!=",
|
||||
1,
|
||||
false,
|
||||
func(v1, v2 int) int {
|
||||
if v1 != v2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
},
|
||||
},
|
||||
"<": {
|
||||
"<",
|
||||
2,
|
||||
false,
|
||||
func(v1, v2 int) int {
|
||||
if v1 < v2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
},
|
||||
},
|
||||
">": {
|
||||
">",
|
||||
2,
|
||||
false,
|
||||
func(v1, v2 int) int {
|
||||
if v1 > v2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
},
|
||||
},
|
||||
"<=": {
|
||||
"<=",
|
||||
2,
|
||||
false,
|
||||
func(v1, v2 int) int {
|
||||
if v1 <= v2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
},
|
||||
},
|
||||
">=": {
|
||||
">=",
|
||||
2,
|
||||
false,
|
||||
func(v1, v2 int) int {
|
||||
if v1 >= v2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
},
|
||||
},
|
||||
"+": {
|
||||
"+",
|
||||
3,
|
||||
false,
|
||||
func(v1, v2 int) int {
|
||||
return v1 + v2
|
||||
},
|
||||
},
|
||||
"-": {
|
||||
"-",
|
||||
3,
|
||||
false,
|
||||
func(v1, v2 int) int {
|
||||
return v1 - v2
|
||||
},
|
||||
},
|
||||
"*": {
|
||||
"*",
|
||||
5,
|
||||
false,
|
||||
func(v1, v2 int) int {
|
||||
return v1 * v2
|
||||
},
|
||||
},
|
||||
"/": {
|
||||
"/",
|
||||
5,
|
||||
false,
|
||||
func(v1, v2 int) int {
|
||||
return v1 / v2
|
||||
},
|
||||
},
|
||||
"^": {
|
||||
"^",
|
||||
6,
|
||||
true,
|
||||
func(v1, v2 int) int {
|
||||
return int(math.Pow(float64(v1), float64(v2)))
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getFunctions() map[string]func(v1, v2 int) int {
|
||||
return map[string]func(v1, v2 int) int{
|
||||
"min": func(v1, v2 int) int {
|
||||
if v1 < v2 {
|
||||
return v1
|
||||
}
|
||||
return v2
|
||||
},
|
||||
"max": func(v1, v2 int) int {
|
||||
if v1 > v2 {
|
||||
return v1
|
||||
}
|
||||
return v2
|
||||
},
|
||||
"rand": func(v1, v2 int) int {
|
||||
if rand.Int()%2 == 0 { //nolint:gosec // Secure random not necessary.
|
||||
return v1
|
||||
}
|
||||
return v2
|
||||
},
|
||||
}
|
||||
}
|
|
@ -0,0 +1,312 @@
|
|||
package d2parser
|
||||
|
||||
import (
|
||||
"log"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2calculation"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2calculation/d2lexer"
|
||||
)
|
||||
|
||||
// Parser is a parser for calculations used for skill and missiles.
|
||||
type Parser struct {
|
||||
lex *d2lexer.Lexer
|
||||
|
||||
binaryOperations map[string]binaryOperation
|
||||
unaryOperations map[string]unaryOperation
|
||||
ternaryOperations map[string]ternaryOperation
|
||||
fixedFunctions map[string]func(v1, v2 int) int
|
||||
|
||||
currentType string
|
||||
currentName string
|
||||
}
|
||||
|
||||
// New creates a new parser.
|
||||
func New() *Parser {
|
||||
return &Parser{
|
||||
binaryOperations: getBinaryOperations(),
|
||||
unaryOperations: getUnaryOperations(),
|
||||
ternaryOperations: getTernaryOperations(),
|
||||
fixedFunctions: getFunctions(),
|
||||
}
|
||||
}
|
||||
|
||||
// SetCurrentReference sets the current reference type and name, such as "skill" and skill name.
|
||||
func (parser *Parser) SetCurrentReference(propType, propName string) {
|
||||
parser.currentType = propType
|
||||
parser.currentName = propName
|
||||
}
|
||||
|
||||
// Parse parses the calculation string and creates a Calculation tree.
|
||||
func (parser *Parser) Parse(calc string) d2calculation.Calculation {
|
||||
calc = strings.TrimSpace(calc)
|
||||
if calc == "" {
|
||||
return &d2calculation.ConstantCalculation{Value: 0}
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Printf("Error parsing calculation: %v", calc)
|
||||
}
|
||||
}()
|
||||
|
||||
parser.lex = d2lexer.New([]byte(calc))
|
||||
|
||||
return parser.parseLevel(0)
|
||||
}
|
||||
|
||||
func (parser *Parser) peek() d2lexer.Token {
|
||||
return parser.lex.Peek()
|
||||
}
|
||||
|
||||
func (parser *Parser) consume() d2lexer.Token {
|
||||
return parser.lex.NextToken()
|
||||
}
|
||||
|
||||
func (parser *Parser) parseLevel(level int) d2calculation.Calculation {
|
||||
node := parser.parseProduction()
|
||||
|
||||
t := parser.peek()
|
||||
if t.Type == d2lexer.EOF {
|
||||
return node
|
||||
}
|
||||
|
||||
for {
|
||||
if t.Type != d2lexer.Symbol {
|
||||
break
|
||||
}
|
||||
|
||||
op, ok := parser.binaryOperations[t.Value]
|
||||
if !ok || op.Precedence < level {
|
||||
break
|
||||
}
|
||||
|
||||
parser.consume()
|
||||
|
||||
var nextLevel int
|
||||
|
||||
if op.IsRightAssociated {
|
||||
nextLevel = op.Precedence
|
||||
} else {
|
||||
nextLevel = op.Precedence + 1
|
||||
}
|
||||
|
||||
otherCalculation := parser.parseLevel(nextLevel)
|
||||
node = &d2calculation.BinaryCalculation{
|
||||
Left: node,
|
||||
Right: otherCalculation,
|
||||
Op: op.Function,
|
||||
}
|
||||
t = parser.peek()
|
||||
}
|
||||
|
||||
for {
|
||||
if t.Type != d2lexer.Symbol {
|
||||
break
|
||||
}
|
||||
|
||||
op, ok := parser.ternaryOperations[t.Value]
|
||||
if !ok || op.Precedence < level {
|
||||
break
|
||||
}
|
||||
|
||||
parser.consume()
|
||||
|
||||
var nextLevel int
|
||||
|
||||
if op.IsRightAssociated {
|
||||
nextLevel = op.Precedence
|
||||
} else {
|
||||
nextLevel = op.Precedence + 1
|
||||
}
|
||||
|
||||
middleCalculation := parser.parseLevel(nextLevel)
|
||||
|
||||
t = parser.peek()
|
||||
if t.Type != d2lexer.Symbol || t.Value != op.Marker {
|
||||
panic("Invalid ternary! " + t.Value + ", expected: " + op.Marker)
|
||||
}
|
||||
|
||||
parser.consume()
|
||||
rightCalculation := parser.parseLevel(nextLevel)
|
||||
|
||||
node = &d2calculation.TernaryCalculation{
|
||||
Left: node,
|
||||
Middle: middleCalculation,
|
||||
Right: rightCalculation,
|
||||
Op: op.Function,
|
||||
}
|
||||
t = parser.peek()
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
func (parser *Parser) parseProduction() d2calculation.Calculation {
|
||||
t := parser.peek()
|
||||
|
||||
switch {
|
||||
case t.Type == d2lexer.Symbol:
|
||||
if t.Value == "(" {
|
||||
parser.consume()
|
||||
node := parser.parseLevel(0)
|
||||
|
||||
t = parser.peek()
|
||||
if t.Type != d2lexer.Symbol ||
|
||||
t.Value != ")" {
|
||||
if t.Type == d2lexer.EOF { // Ignore unclosed final parenthesis due to syntax error in original Fire Wall calculation.
|
||||
return node
|
||||
}
|
||||
|
||||
panic("Parenthesis not closed!")
|
||||
}
|
||||
|
||||
parser.consume()
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
op, ok := parser.unaryOperations[t.Value]
|
||||
if !ok {
|
||||
panic("Invalid unary symbol: " + t.Value)
|
||||
}
|
||||
|
||||
parser.consume()
|
||||
node := parser.parseLevel(op.Precedence)
|
||||
|
||||
return &d2calculation.UnaryCalculation{
|
||||
Child: node,
|
||||
Op: op.Function,
|
||||
}
|
||||
|
||||
case t.Type == d2lexer.Name || t.Type == d2lexer.Number:
|
||||
return parser.parseLeafCalculation()
|
||||
default:
|
||||
panic("Expected parenthesis, unary operator, function or value!")
|
||||
}
|
||||
}
|
||||
|
||||
func (parser *Parser) parseLeafCalculation() d2calculation.Calculation {
|
||||
t := parser.peek()
|
||||
|
||||
if t.Type == d2lexer.Number {
|
||||
val, err := strconv.Atoi(t.Value)
|
||||
if err != nil {
|
||||
panic("Invalid number: " + t.Value)
|
||||
}
|
||||
|
||||
parser.consume()
|
||||
|
||||
return &d2calculation.ConstantCalculation{Value: val}
|
||||
}
|
||||
|
||||
if t.Value == "skill" ||
|
||||
t.Value == "miss" ||
|
||||
t.Value == "stat" {
|
||||
return parser.parseProperty()
|
||||
}
|
||||
|
||||
if parser.fixedFunctions[t.Value] != nil {
|
||||
return parser.parseFunction(t.Value)
|
||||
}
|
||||
|
||||
if t.Type == d2lexer.Name {
|
||||
parser.consume()
|
||||
|
||||
return &d2calculation.PropertyReferenceCalculation{
|
||||
Type: parser.currentType,
|
||||
Name: parser.currentName,
|
||||
Qualifier: t.Value,
|
||||
}
|
||||
}
|
||||
|
||||
panic(t.Value + " is not a function, property, or number!")
|
||||
}
|
||||
|
||||
func (parser *Parser) parseFunction(name string) d2calculation.Calculation {
|
||||
function := parser.fixedFunctions[name]
|
||||
parser.consume()
|
||||
|
||||
t := parser.peek()
|
||||
if t.Value != "(" {
|
||||
panic("Invalid function!")
|
||||
}
|
||||
|
||||
parser.consume()
|
||||
|
||||
firstParam := parser.parseLevel(0)
|
||||
|
||||
t = parser.peek()
|
||||
if t.Type != d2lexer.Symbol || t.Value != "," {
|
||||
panic("Invalid function!")
|
||||
}
|
||||
|
||||
parser.consume()
|
||||
|
||||
secondParam := parser.parseLevel(0)
|
||||
|
||||
t = parser.peek()
|
||||
if t.Value != ")" {
|
||||
panic("Invalid function!")
|
||||
}
|
||||
|
||||
parser.consume()
|
||||
|
||||
return &d2calculation.BinaryCalculation{
|
||||
Left: firstParam,
|
||||
Right: secondParam,
|
||||
Op: function,
|
||||
}
|
||||
}
|
||||
|
||||
func (parser *Parser) parseProperty() d2calculation.Calculation {
|
||||
t := parser.peek()
|
||||
propType := t.Value
|
||||
t = parser.consume()
|
||||
|
||||
t = parser.peek()
|
||||
if t.Value != "(" {
|
||||
panic("Invalid property: " + propType + ", open parenthesis missing.")
|
||||
}
|
||||
|
||||
parser.consume()
|
||||
|
||||
t = parser.peek()
|
||||
if t.Type != d2lexer.String {
|
||||
panic("Property name must be in quotes: " + propType)
|
||||
}
|
||||
|
||||
propName := t.Value
|
||||
|
||||
parser.consume()
|
||||
|
||||
t = parser.peek()
|
||||
if t.Type != d2lexer.Symbol || t.Value != "." {
|
||||
panic("Property name must be followed by dot: " + propType)
|
||||
}
|
||||
|
||||
parser.consume()
|
||||
|
||||
t = parser.peek()
|
||||
if t.Type != d2lexer.Name {
|
||||
panic("Invalid propery qualifier: " + propType)
|
||||
}
|
||||
|
||||
propQual := t.Value
|
||||
|
||||
parser.consume()
|
||||
|
||||
t = parser.peek()
|
||||
if t.Value != ")" {
|
||||
panic("Invalid property: " + propType + ", closed parenthesis missing.")
|
||||
}
|
||||
|
||||
parser.consume()
|
||||
|
||||
return &d2calculation.PropertyReferenceCalculation{
|
||||
Type: propType,
|
||||
Name: propName,
|
||||
Qualifier: propQual,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,295 @@
|
|||
package d2parser
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/rand"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestEmptyInput(t *testing.T) {
|
||||
parser := New()
|
||||
|
||||
table := []struct {
|
||||
expr string
|
||||
result int
|
||||
}{
|
||||
{"", 0},
|
||||
{" ", 0},
|
||||
{"\t\t \t\t \t", 0},
|
||||
}
|
||||
|
||||
for _, row := range table {
|
||||
c := parser.Parse(row.expr)
|
||||
res := c.Eval()
|
||||
|
||||
if res != row.result {
|
||||
t.Errorf("Expression %v gave wrong result, got %d, want %d", row.expr, res, row.result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestConstantExpression(t *testing.T) {
|
||||
parser := New()
|
||||
|
||||
table := []struct {
|
||||
expr string
|
||||
result int
|
||||
}{
|
||||
{"0", 0},
|
||||
{"5", 5},
|
||||
{"455", 455},
|
||||
{"789", 789},
|
||||
{"3242", 3242},
|
||||
{"45454", 45454},
|
||||
}
|
||||
|
||||
for _, row := range table {
|
||||
c := parser.Parse(row.expr)
|
||||
res := c.Eval()
|
||||
|
||||
if res != row.result {
|
||||
t.Errorf("Expression %v gave wrong result, got %d, want %d", row.expr, res, row.result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnaryOperations(t *testing.T) {
|
||||
parser := New()
|
||||
|
||||
table := []struct {
|
||||
expr string
|
||||
result int
|
||||
}{
|
||||
{"+0", 0},
|
||||
{"-0", 0},
|
||||
{"+455", 455},
|
||||
{"++455", 455},
|
||||
{"+++455", 455},
|
||||
{"-455", -455},
|
||||
{"--455", 455},
|
||||
{"---455", -455},
|
||||
{"+-+789", -789},
|
||||
{"-++3242", -3242},
|
||||
{"++--+-+45454", -45454},
|
||||
}
|
||||
|
||||
for _, row := range table {
|
||||
c := parser.Parse(row.expr)
|
||||
res := c.Eval()
|
||||
|
||||
if res != row.result {
|
||||
t.Errorf("Expression %v gave wrong result, got %d, want %d", row.expr, res, row.result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestArithmeticBinaryOperations(t *testing.T) {
|
||||
parser := New()
|
||||
|
||||
table := []struct {
|
||||
expr string
|
||||
result int
|
||||
}{
|
||||
{"1 + 2", 3},
|
||||
{"54+56", 54 + 56},
|
||||
{"9212-2121", 9212 - 2121},
|
||||
{"1+2-5", -2},
|
||||
{"5-3-1", 1},
|
||||
{"4*5", 20},
|
||||
{"512/2", 256},
|
||||
{"10/9", 1},
|
||||
{"1/3*5", 0},
|
||||
{"2^3^2", int(math.Pow(2., 9.))},
|
||||
{"4^2*2+1", 33},
|
||||
}
|
||||
|
||||
for _, row := range table {
|
||||
c := parser.Parse(row.expr)
|
||||
res := c.Eval()
|
||||
|
||||
if res != row.result {
|
||||
t.Errorf("Expression %v gave wrong result, got %d, want %d", row.expr, res, row.result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParentheses(t *testing.T) {
|
||||
parser := New()
|
||||
|
||||
table := []struct {
|
||||
expr string
|
||||
result int
|
||||
}{
|
||||
{"(1+2)*5", 15},
|
||||
{"(99-98)/2", 0},
|
||||
{"((3+2)*6)/3", 10},
|
||||
{"(3+2)*(6/3)", 10},
|
||||
{"(20+10)/6/5", 1},
|
||||
{"(20+10)/(6/5)", 30},
|
||||
}
|
||||
|
||||
for _, row := range table {
|
||||
c := parser.Parse(row.expr)
|
||||
res := c.Eval()
|
||||
|
||||
if res != row.result {
|
||||
t.Errorf("Expression %v gave wrong result, got %d, want %d", row.expr, res, row.result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLackFinalParethesis(t *testing.T) {
|
||||
parser := New()
|
||||
|
||||
table := []struct {
|
||||
expr string
|
||||
result int
|
||||
}{
|
||||
{"(3+2)*(6/3", 10},
|
||||
{"(20+10)/(6/5", 30},
|
||||
}
|
||||
|
||||
for _, row := range table {
|
||||
c := parser.Parse(row.expr)
|
||||
res := c.Eval()
|
||||
|
||||
if res != row.result {
|
||||
t.Errorf("Expression %v gave wrong result, got %d, want %d", row.expr, res, row.result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogicalBinaryOperations(t *testing.T) {
|
||||
parser := New()
|
||||
|
||||
table := []struct {
|
||||
expr string
|
||||
result bool
|
||||
}{
|
||||
{"1 < 2", true},
|
||||
{"1 < -5", false},
|
||||
{"1 <= 5", true},
|
||||
{"1 <= 10", true},
|
||||
{"5 <= 1", false},
|
||||
{"1 <= 1", true},
|
||||
{"5 > 10", false},
|
||||
{"54 >= 100", false},
|
||||
{"45 >= 45", true},
|
||||
{"10 == 10", true},
|
||||
{"10 == 1", false},
|
||||
{"10 != 1", true},
|
||||
{"10 != 10", false},
|
||||
}
|
||||
|
||||
for _, row := range table {
|
||||
c := parser.Parse(row.expr)
|
||||
res := c.Eval()
|
||||
|
||||
if (res == 0 && row.result) || (res != 0 && !row.result) {
|
||||
t.Errorf("Expression %v gave wrong result, got %d, want %v", row.expr, res, row.result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogicalAndArithmetic(t *testing.T) {
|
||||
parser := New()
|
||||
|
||||
table := []struct {
|
||||
expr string
|
||||
result bool
|
||||
}{
|
||||
{"(1 < 2)*(5 < 10)", true},
|
||||
{"(1 < -5)+(1 == 5)", false},
|
||||
{"(5 > 10)*(10 == 10)", false},
|
||||
{"(45 >= 45)+(1 > 500000)", true},
|
||||
{"(10 == 10)*(30 > 50)+(5 >= 5)", true},
|
||||
}
|
||||
|
||||
for _, row := range table {
|
||||
c := parser.Parse(row.expr)
|
||||
res := c.Eval()
|
||||
|
||||
if (res == 0 && row.result) || (res != 0 && !row.result) {
|
||||
t.Errorf("Expression %v gave wrong result, got %d, want %v", row.expr, res, row.result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTernaryOperator(t *testing.T) {
|
||||
parser := New()
|
||||
|
||||
table := []struct {
|
||||
expr string
|
||||
result int
|
||||
}{
|
||||
{"5 > 1 ? 3 : 5", 3},
|
||||
{"5 <= 1 ? 3 : 5", 5},
|
||||
{"(1 < 10)*(5 < 3) ? 43 : 5 == 5 ? 1 : 2", 1},
|
||||
{"(1 < 10)*(5 < 3) ? 43 : 5 != 5 ? 1 : 2", 2},
|
||||
{"(1 < 10)*(5 > 3) ? 43 : 5 == 5 ? 1 : 2", 43},
|
||||
{"(1 < 10)*(5 > 3) ? 43 != 0 ? 65 : 32 : 5 == 5 ? 1 : 2", 65},
|
||||
{"(1 < 10)*(5 > 3) ? 43 == 0 ? 65 : 32 : 5 == 5 ? 1 : 2", 32},
|
||||
}
|
||||
|
||||
for _, row := range table {
|
||||
c := parser.Parse(row.expr)
|
||||
res := c.Eval()
|
||||
|
||||
if res != row.result {
|
||||
t.Errorf("Expression %v gave wrong result, got %d, want %d", row.expr, res, row.result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuiltinFunctions(t *testing.T) {
|
||||
parser := New()
|
||||
|
||||
table := []struct {
|
||||
expr string
|
||||
result int
|
||||
}{
|
||||
{"min(5, 2)", 2},
|
||||
{"min(4^6, 5+10)", 15},
|
||||
{"max(10, 4*3)", 12},
|
||||
{"max(50-2, 50-3)", 48},
|
||||
}
|
||||
|
||||
for _, row := range table {
|
||||
c := parser.Parse(row.expr)
|
||||
res := c.Eval()
|
||||
|
||||
if res != row.result {
|
||||
t.Errorf("Expression %v gave wrong result, got %d, want %d", row.expr, res, row.result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRandFunction(t *testing.T) {
|
||||
parser := New()
|
||||
c := parser.Parse("rand(1,5)")
|
||||
|
||||
rand.Seed(1)
|
||||
|
||||
res1 := []int{c.Eval(), c.Eval(), c.Eval(), c.Eval(), c.Eval()}
|
||||
|
||||
rand.Seed(1)
|
||||
|
||||
res2 := []int{c.Eval(), c.Eval(), c.Eval(), c.Eval(), c.Eval()}
|
||||
|
||||
for i := 0; i < len(res1); i++ {
|
||||
t.Logf("%d, %d", res1[i], res2[i])
|
||||
|
||||
if res1[i] != res2[i] {
|
||||
t.Error("Results not equal.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSimpleExpression(b *testing.B) {
|
||||
parser := New()
|
||||
expr := "(1 < 10)*(5 > 3) ? 43 == 0 ? 65 : 32 : 5 == 5 ? 1 : 2"
|
||||
|
||||
for n := 0; n < b.N; n++ {
|
||||
parser.Parse(expr)
|
||||
}
|
||||
}
|
|
@ -4,124 +4,126 @@ import (
|
|||
"log"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2calculation"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2calculation/d2parser"
|
||||
)
|
||||
|
||||
// SkillDescriptionRecord is a single row from skilldesc.txt and is used for
|
||||
// generating text strings for skills.
|
||||
type SkillDescriptionRecord struct {
|
||||
Name string // skilldesc
|
||||
SkillPage string // SkillPage
|
||||
SkillRow string // SkillRow
|
||||
SkillColumn string // SkillColumn
|
||||
ListRow string // ListRow
|
||||
ListPool string // ListPool
|
||||
IconCel string // IconCel
|
||||
NameKey string // str name
|
||||
ShortKey string // str short
|
||||
LongKey string // str long
|
||||
AltKey string // str alt
|
||||
ManaKey string // str mana
|
||||
Descdam string // descdam
|
||||
DdamCalc1 string // ddam calc1
|
||||
DdamCalc2 string // ddam calc2
|
||||
P1dmelem string // p1dmelem
|
||||
P1dmmin string // p1dmmin
|
||||
P1dmmax string // p1dmmax
|
||||
P2dmelem string // p2dmelem
|
||||
P2dmmin string // p2dmmin
|
||||
P2dmmax string // p2dmmax
|
||||
P3dmelem string // p3dmelem
|
||||
P3dmmin string // p3dmmin
|
||||
P3dmmax string // p3dmmax
|
||||
Descatt string // descatt
|
||||
Descmissile1 string // descmissile1
|
||||
Descmissile2 string // descmissile2
|
||||
Descmissile3 string // descmissile3
|
||||
Descline1 string // descline1
|
||||
Desctexta1 string // desctexta1
|
||||
Desctextb1 string // desctextb1
|
||||
Desccalca1 string // desccalca1
|
||||
Desccalcb1 string // desccalcb1
|
||||
Descline2 string // descline2
|
||||
Desctexta2 string // desctexta2
|
||||
Desctextb2 string // desctextb2
|
||||
Desccalca2 string // desccalca2
|
||||
Desccalcb2 string // desccalcb2
|
||||
Descline3 string // descline3
|
||||
Desctexta3 string // desctexta3
|
||||
Desctextb3 string // desctextb3
|
||||
Desccalca3 string // desccalca3
|
||||
Desccalcb3 string // desccalcb3
|
||||
Descline4 string // descline4
|
||||
Desctexta4 string // desctexta4
|
||||
Desctextb4 string // desctextb4
|
||||
Desccalca4 string // desccalca4
|
||||
Desccalcb4 string // desccalcb4
|
||||
Descline5 string // descline5
|
||||
Desctexta5 string // desctexta5
|
||||
Desctextb5 string // desctextb5
|
||||
Desccalca5 string // desccalca5
|
||||
Desccalcb5 string // desccalcb5
|
||||
Descline6 string // descline6
|
||||
Desctexta6 string // desctexta6
|
||||
Desctextb6 string // desctextb6
|
||||
Desccalca6 string // desccalca6
|
||||
Desccalcb6 string // desccalcb6
|
||||
Dsc2line1 string // dsc2line1
|
||||
Dsc2texta1 string // dsc2texta1
|
||||
Dsc2textb1 string // dsc2textb1
|
||||
Dsc2calca1 string // dsc2calca1
|
||||
Dsc2calcb1 string // dsc2calcb1
|
||||
Dsc2line2 string // dsc2line2
|
||||
Dsc2texta2 string // dsc2texta2
|
||||
Dsc2textb2 string // dsc2textb2
|
||||
Dsc2calca2 string // dsc2calca2
|
||||
Dsc2calcb2 string // dsc2calcb2
|
||||
Dsc2line3 string // dsc2line3
|
||||
Dsc2texta3 string // dsc2texta3
|
||||
Dsc2textb3 string // dsc2textb3
|
||||
Dsc2calca3 string // dsc2calca3
|
||||
Dsc2calcb3 string // dsc2calcb3
|
||||
Dsc2line4 string // dsc2line4
|
||||
Dsc2texta4 string // dsc2texta4
|
||||
Dsc2textb4 string // dsc2textb4
|
||||
Dsc2calca4 string // dsc2calca4
|
||||
Dsc2calcb4 string // dsc2calcb4
|
||||
Dsc3line1 string // dsc3line1
|
||||
Dsc3texta1 string // dsc3texta1
|
||||
Dsc3textb1 string // dsc3textb1
|
||||
Dsc3calca1 string // dsc3calca1
|
||||
Dsc3calcb1 string // dsc3calcb1
|
||||
Dsc3line2 string // dsc3line2
|
||||
Dsc3texta2 string // dsc3texta2
|
||||
Dsc3textb2 string // dsc3textb2
|
||||
Dsc3calca2 string // dsc3calca2
|
||||
Dsc3calcb2 string // dsc3calcb2
|
||||
Dsc3line3 string // dsc3line3
|
||||
Dsc3texta3 string // dsc3texta3
|
||||
Dsc3textb3 string // dsc3textb3
|
||||
Dsc3calca3 string // dsc3calca3
|
||||
Dsc3calcb3 string // dsc3calcb3
|
||||
Dsc3line4 string // dsc3line4
|
||||
Dsc3texta4 string // dsc3texta4
|
||||
Dsc3textb4 string // dsc3textb4
|
||||
Dsc3calca4 string // dsc3calca4
|
||||
Dsc3calcb4 string // dsc3calcb4
|
||||
Dsc3line5 string // dsc3line5
|
||||
Dsc3texta5 string // dsc3texta5
|
||||
Dsc3textb5 string // dsc3textb5
|
||||
Dsc3calca5 string // dsc3calca5
|
||||
Dsc3calcb5 string // dsc3calcb5
|
||||
Dsc3line6 string // dsc3line6
|
||||
Dsc3texta6 string // dsc3texta6
|
||||
Dsc3textb6 string // dsc3textb6
|
||||
Dsc3calca6 string // dsc3calca6
|
||||
Dsc3calcb6 string // dsc3calcb6
|
||||
Dsc3line7 string // dsc3line7
|
||||
Dsc3texta7 string // dsc3texta7
|
||||
Dsc3textb7 string // dsc3textb7
|
||||
Dsc3calca7 string // dsc3calca7
|
||||
Dsc3calcb7 string // dsc3calcb7
|
||||
Name string // skilldesc
|
||||
SkillPage string // SkillPage
|
||||
SkillRow string // SkillRow
|
||||
SkillColumn string // SkillColumn
|
||||
ListRow string // ListRow
|
||||
ListPool string // ListPool
|
||||
IconCel string // IconCel
|
||||
NameKey string // str name
|
||||
ShortKey string // str short
|
||||
LongKey string // str long
|
||||
AltKey string // str alt
|
||||
ManaKey string // str mana
|
||||
Descdam string // descdam
|
||||
DdamCalc1 d2calculation.Calculation // ddam calc1
|
||||
DdamCalc2 d2calculation.Calculation // ddam calc2
|
||||
P1dmelem string // p1dmelem
|
||||
P1dmmin d2calculation.Calculation // p1dmmin
|
||||
P1dmmax d2calculation.Calculation // p1dmmax
|
||||
P2dmelem string // p2dmelem
|
||||
P2dmmin d2calculation.Calculation // p2dmmin
|
||||
P2dmmax d2calculation.Calculation // p2dmmax
|
||||
P3dmelem string // p3dmelem
|
||||
P3dmmin d2calculation.Calculation // p3dmmin
|
||||
P3dmmax d2calculation.Calculation // p3dmmax
|
||||
Descatt string // descatt
|
||||
Descmissile1 string // descmissile1
|
||||
Descmissile2 string // descmissile2
|
||||
Descmissile3 string // descmissile3
|
||||
Descline1 string // descline1
|
||||
Desctexta1 string // desctexta1
|
||||
Desctextb1 string // desctextb1
|
||||
Desccalca1 d2calculation.Calculation // desccalca1
|
||||
Desccalcb1 d2calculation.Calculation // desccalcb1
|
||||
Descline2 string // descline2
|
||||
Desctexta2 string // desctexta2
|
||||
Desctextb2 string // desctextb2
|
||||
Desccalca2 d2calculation.Calculation // desccalca2
|
||||
Desccalcb2 d2calculation.Calculation // desccalcb2
|
||||
Descline3 string // descline3
|
||||
Desctexta3 string // desctexta3
|
||||
Desctextb3 string // desctextb3
|
||||
Desccalca3 d2calculation.Calculation // desccalca3
|
||||
Desccalcb3 d2calculation.Calculation // desccalcb3
|
||||
Descline4 string // descline4
|
||||
Desctexta4 string // desctexta4
|
||||
Desctextb4 string // desctextb4
|
||||
Desccalca4 d2calculation.Calculation // desccalca4
|
||||
Desccalcb4 d2calculation.Calculation // desccalcb4
|
||||
Descline5 string // descline5
|
||||
Desctexta5 string // desctexta5
|
||||
Desctextb5 string // desctextb5
|
||||
Desccalca5 d2calculation.Calculation // desccalca5
|
||||
Desccalcb5 d2calculation.Calculation // desccalcb5
|
||||
Descline6 string // descline6
|
||||
Desctexta6 string // desctexta6
|
||||
Desctextb6 string // desctextb6
|
||||
Desccalca6 d2calculation.Calculation // desccalca6
|
||||
Desccalcb6 d2calculation.Calculation // desccalcb6
|
||||
Dsc2line1 string // dsc2line1
|
||||
Dsc2texta1 string // dsc2texta1
|
||||
Dsc2textb1 string // dsc2textb1
|
||||
Dsc2calca1 d2calculation.Calculation // dsc2calca1
|
||||
Dsc2calcb1 d2calculation.Calculation // dsc2calcb1
|
||||
Dsc2line2 string // dsc2line2
|
||||
Dsc2texta2 string // dsc2texta2
|
||||
Dsc2textb2 string // dsc2textb2
|
||||
Dsc2calca2 d2calculation.Calculation // dsc2calca2
|
||||
Dsc2calcb2 d2calculation.Calculation // dsc2calcb2
|
||||
Dsc2line3 string // dsc2line3
|
||||
Dsc2texta3 string // dsc2texta3
|
||||
Dsc2textb3 string // dsc2textb3
|
||||
Dsc2calca3 d2calculation.Calculation // dsc2calca3
|
||||
Dsc2calcb3 d2calculation.Calculation // dsc2calcb3
|
||||
Dsc2line4 string // dsc2line4
|
||||
Dsc2texta4 string // dsc2texta4
|
||||
Dsc2textb4 string // dsc2textb4
|
||||
Dsc2calca4 d2calculation.Calculation // dsc2calca4
|
||||
Dsc2calcb4 d2calculation.Calculation // dsc2calcb4
|
||||
Dsc3line1 string // dsc3line1
|
||||
Dsc3texta1 string // dsc3texta1
|
||||
Dsc3textb1 string // dsc3textb1
|
||||
Dsc3calca1 d2calculation.Calculation // dsc3calca1
|
||||
Dsc3calcb1 d2calculation.Calculation // dsc3calcb1
|
||||
Dsc3line2 string // dsc3line2
|
||||
Dsc3texta2 string // dsc3texta2
|
||||
Dsc3textb2 string // dsc3textb2
|
||||
Dsc3calca2 d2calculation.Calculation // dsc3calca2
|
||||
Dsc3calcb2 d2calculation.Calculation // dsc3calcb2
|
||||
Dsc3line3 string // dsc3line3
|
||||
Dsc3texta3 string // dsc3texta3
|
||||
Dsc3textb3 string // dsc3textb3
|
||||
Dsc3calca3 d2calculation.Calculation // dsc3calca3
|
||||
Dsc3calcb3 d2calculation.Calculation // dsc3calcb3
|
||||
Dsc3line4 string // dsc3line4
|
||||
Dsc3texta4 string // dsc3texta4
|
||||
Dsc3textb4 string // dsc3textb4
|
||||
Dsc3calca4 d2calculation.Calculation // dsc3calca4
|
||||
Dsc3calcb4 d2calculation.Calculation // dsc3calcb4
|
||||
Dsc3line5 string // dsc3line5
|
||||
Dsc3texta5 string // dsc3texta5
|
||||
Dsc3textb5 string // dsc3textb5
|
||||
Dsc3calca5 d2calculation.Calculation // dsc3calca5
|
||||
Dsc3calcb5 d2calculation.Calculation // dsc3calcb5
|
||||
Dsc3line6 string // dsc3line6
|
||||
Dsc3texta6 string // dsc3texta6
|
||||
Dsc3textb6 string // dsc3textb6
|
||||
Dsc3calca6 d2calculation.Calculation // dsc3calca6
|
||||
Dsc3calcb6 d2calculation.Calculation // dsc3calcb6
|
||||
Dsc3line7 string // dsc3line7
|
||||
Dsc3texta7 string // dsc3texta7
|
||||
Dsc3textb7 string // dsc3textb7
|
||||
Dsc3calca7 d2calculation.Calculation // dsc3calca7
|
||||
Dsc3calcb7 d2calculation.Calculation // dsc3calcb7
|
||||
}
|
||||
|
||||
// SkillDescriptions stores all of the SkillDescriptionRecords
|
||||
|
@ -132,6 +134,9 @@ var SkillDescriptions map[string]*SkillDescriptionRecord
|
|||
func LoadSkillDescriptions(file []byte) { //nolint:funlen // doesn't make sense to split
|
||||
SkillDescriptions = make(map[string]*SkillDescriptionRecord)
|
||||
|
||||
parser := d2parser.New()
|
||||
parser.SetCurrentReference("skill", "TODO: connect skill with description!") //nolint:godox // TODO: Connect skill with description.
|
||||
|
||||
d := d2common.LoadDataDictionary(file)
|
||||
for d.Next() {
|
||||
record := &SkillDescriptionRecord{
|
||||
|
@ -148,17 +153,17 @@ func LoadSkillDescriptions(file []byte) { //nolint:funlen // doesn't make sense
|
|||
d.String("str alt"),
|
||||
d.String("str mana"),
|
||||
d.String("descdam"),
|
||||
d.String("ddam calc1"),
|
||||
d.String("ddam calc2"),
|
||||
parser.Parse(d.String("ddam calc1")),
|
||||
parser.Parse(d.String("ddam calc2")),
|
||||
d.String("p1dmelem"),
|
||||
d.String("p1dmmin"),
|
||||
d.String("p1dmmax"),
|
||||
parser.Parse(d.String("p1dmmin")),
|
||||
parser.Parse(d.String("p1dmmax")),
|
||||
d.String("p2dmelem"),
|
||||
d.String("p2dmmin"),
|
||||
d.String("p2dmmax"),
|
||||
parser.Parse(d.String("p2dmmin")),
|
||||
parser.Parse(d.String("p2dmmax")),
|
||||
d.String("p3dmelem"),
|
||||
d.String("p3dmmin"),
|
||||
d.String("p3dmmax"),
|
||||
parser.Parse(d.String("p3dmmin")),
|
||||
parser.Parse(d.String("p3dmmax")),
|
||||
d.String("descatt"),
|
||||
d.String("descmissile1"),
|
||||
d.String("descmissile2"),
|
||||
|
@ -166,88 +171,88 @@ func LoadSkillDescriptions(file []byte) { //nolint:funlen // doesn't make sense
|
|||
d.String("descline1"),
|
||||
d.String("desctexta1"),
|
||||
d.String("desctextb1"),
|
||||
d.String("desccalca1"),
|
||||
d.String("desccalcb1"),
|
||||
parser.Parse(d.String("desccalca1")),
|
||||
parser.Parse(d.String("desccalcb1")),
|
||||
d.String("descline2"),
|
||||
d.String("desctexta2"),
|
||||
d.String("desctextb2"),
|
||||
d.String("desccalca2"),
|
||||
d.String("desccalcb2"),
|
||||
parser.Parse(d.String("desccalca2")),
|
||||
parser.Parse(d.String("desccalcb2")),
|
||||
d.String("descline3"),
|
||||
d.String("desctexta3"),
|
||||
d.String("desctextb3"),
|
||||
d.String("desccalca3"),
|
||||
d.String("desccalcb3"),
|
||||
parser.Parse(d.String("desccalca3")),
|
||||
parser.Parse(d.String("desccalcb3")),
|
||||
d.String("descline4"),
|
||||
d.String("desctexta4"),
|
||||
d.String("desctextb4"),
|
||||
d.String("desccalca4"),
|
||||
d.String("desccalcb4"),
|
||||
parser.Parse(d.String("desccalca4")),
|
||||
parser.Parse(d.String("desccalcb4")),
|
||||
d.String("descline5"),
|
||||
d.String("desctexta5"),
|
||||
d.String("desctextb5"),
|
||||
d.String("desccalca5"),
|
||||
d.String("desccalcb5"),
|
||||
parser.Parse(d.String("desccalca5")),
|
||||
parser.Parse(d.String("desccalcb5")),
|
||||
d.String("descline6"),
|
||||
d.String("desctexta6"),
|
||||
d.String("desctextb6"),
|
||||
d.String("desccalca6"),
|
||||
d.String("desccalcb6"),
|
||||
parser.Parse(d.String("desccalca6")),
|
||||
parser.Parse(d.String("desccalcb6")),
|
||||
d.String("dsc2line1"),
|
||||
d.String("dsc2texta1"),
|
||||
d.String("dsc2textb1"),
|
||||
d.String("dsc2calca1"),
|
||||
d.String("dsc2calcb1"),
|
||||
parser.Parse(d.String("dsc2calca1")),
|
||||
parser.Parse(d.String("dsc2calcb1")),
|
||||
d.String("dsc2line2"),
|
||||
d.String("dsc2texta2"),
|
||||
d.String("dsc2textb2"),
|
||||
d.String("dsc2calca2"),
|
||||
d.String("dsc2calcb2"),
|
||||
parser.Parse(d.String("dsc2calca2")),
|
||||
parser.Parse(d.String("dsc2calcb2")),
|
||||
d.String("dsc2line3"),
|
||||
d.String("dsc2texta3"),
|
||||
d.String("dsc2textb3"),
|
||||
d.String("dsc2calca3"),
|
||||
d.String("dsc2calcb3"),
|
||||
parser.Parse(d.String("dsc2calca3")),
|
||||
parser.Parse(d.String("dsc2calcb3")),
|
||||
d.String("dsc2line4"),
|
||||
d.String("dsc2texta4"),
|
||||
d.String("dsc2textb4"),
|
||||
d.String("dsc2calca4"),
|
||||
d.String("dsc2calcb4"),
|
||||
parser.Parse(d.String("dsc2calca4")),
|
||||
parser.Parse(d.String("dsc2calcb4")),
|
||||
d.String("dsc3line1"),
|
||||
d.String("dsc3texta1"),
|
||||
d.String("dsc3textb1"),
|
||||
d.String("dsc3calca1"),
|
||||
d.String("dsc3calcb1"),
|
||||
parser.Parse(d.String("dsc3calca1")),
|
||||
parser.Parse(d.String("dsc3calcb1")),
|
||||
d.String("dsc3line2"),
|
||||
d.String("dsc3texta2"),
|
||||
d.String("dsc3textb2"),
|
||||
d.String("dsc3calca2"),
|
||||
d.String("dsc3calcb2"),
|
||||
parser.Parse(d.String("dsc3calca2")),
|
||||
parser.Parse(d.String("dsc3calcb2")),
|
||||
d.String("dsc3line3"),
|
||||
d.String("dsc3texta3"),
|
||||
d.String("dsc3textb3"),
|
||||
d.String("dsc3calca3"),
|
||||
d.String("dsc3calcb3"),
|
||||
parser.Parse(d.String("dsc3calca3")),
|
||||
parser.Parse(d.String("dsc3calcb3")),
|
||||
d.String("dsc3line4"),
|
||||
d.String("dsc3texta4"),
|
||||
d.String("dsc3textb4"),
|
||||
d.String("dsc3calca4"),
|
||||
d.String("dsc3calcb4"),
|
||||
parser.Parse(d.String("dsc3calca4")),
|
||||
parser.Parse(d.String("dsc3calcb4")),
|
||||
d.String("dsc3line5"),
|
||||
d.String("dsc3texta5"),
|
||||
d.String("dsc3textb5"),
|
||||
d.String("dsc3calca5"),
|
||||
d.String("dsc3calcb5"),
|
||||
parser.Parse(d.String("dsc3calca5")),
|
||||
parser.Parse(d.String("dsc3calcb5")),
|
||||
d.String("dsc3line6"),
|
||||
d.String("dsc3texta6"),
|
||||
d.String("dsc3textb6"),
|
||||
d.String("dsc3calca6"),
|
||||
d.String("dsc3calcb6"),
|
||||
parser.Parse(d.String("dsc3calca6")),
|
||||
parser.Parse(d.String("dsc3calcb6")),
|
||||
d.String("dsc3line7"),
|
||||
d.String("dsc3texta7"),
|
||||
d.String("dsc3textb7"),
|
||||
d.String("dsc3calca7"),
|
||||
d.String("dsc3calcb7"),
|
||||
parser.Parse(d.String("dsc3calca7")),
|
||||
parser.Parse(d.String("dsc3calcb7")),
|
||||
}
|
||||
|
||||
SkillDescriptions[record.Name] = record
|
||||
|
|
|
@ -4,6 +4,8 @@ import (
|
|||
"log"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2calculation"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2calculation/d2parser"
|
||||
)
|
||||
|
||||
// SkillDetails has all of the SkillRecords
|
||||
|
@ -16,9 +18,9 @@ type SkillRecord struct {
|
|||
Skill string
|
||||
Charclass string
|
||||
Skilldesc string
|
||||
Prgcalc1 string
|
||||
Prgcalc2 string
|
||||
Prgcalc3 string
|
||||
Prgcalc1 d2calculation.Calculation
|
||||
Prgcalc2 d2calculation.Calculation
|
||||
Prgcalc3 d2calculation.Calculation
|
||||
Srvmissile string
|
||||
Srvmissilea string
|
||||
Srvmissileb string
|
||||
|
@ -26,20 +28,20 @@ type SkillRecord struct {
|
|||
Srvoverlay string
|
||||
Aurastate string
|
||||
Auratargetstate string
|
||||
Auralencalc string
|
||||
Aurarangecalc string
|
||||
Auralencalc d2calculation.Calculation
|
||||
Aurarangecalc d2calculation.Calculation
|
||||
Aurastat1 string
|
||||
Aurastatcalc1 string
|
||||
Aurastatcalc1 d2calculation.Calculation
|
||||
Aurastat2 string
|
||||
Aurastatcalc2 string
|
||||
Aurastatcalc2 d2calculation.Calculation
|
||||
Aurastat3 string
|
||||
Aurastatcalc3 string
|
||||
Aurastatcalc3 d2calculation.Calculation
|
||||
Aurastat4 string
|
||||
Aurastatcalc4 string
|
||||
Aurastatcalc4 d2calculation.Calculation
|
||||
Aurastat5 string
|
||||
Aurastatcalc5 string
|
||||
Aurastatcalc5 d2calculation.Calculation
|
||||
Aurastat6 string
|
||||
Aurastatcalc6 string
|
||||
Aurastatcalc6 d2calculation.Calculation
|
||||
Auraevent1 string
|
||||
Auraevent2 string
|
||||
Auraevent3 string
|
||||
|
@ -48,31 +50,31 @@ type SkillRecord struct {
|
|||
Passivestate string
|
||||
Passiveitype string
|
||||
Passivestat1 string
|
||||
Passivecalc1 string
|
||||
Passivecalc1 d2calculation.Calculation
|
||||
Passivestat2 string
|
||||
Passivecalc2 string
|
||||
Passivecalc2 d2calculation.Calculation
|
||||
Passivestat3 string
|
||||
Passivecalc3 string
|
||||
Passivecalc3 d2calculation.Calculation
|
||||
Passivestat4 string
|
||||
Passivecalc4 string
|
||||
Passivecalc4 d2calculation.Calculation
|
||||
Passivestat5 string
|
||||
Passivecalc5 string
|
||||
Passivecalc5 d2calculation.Calculation
|
||||
Passiveevent string
|
||||
Passiveeventfunc string
|
||||
Summon string
|
||||
Pettype string
|
||||
Petmax string
|
||||
Petmax d2calculation.Calculation
|
||||
Summode string
|
||||
Sumskill1 string
|
||||
Sumsk1calc string
|
||||
Sumsk1calc d2calculation.Calculation
|
||||
Sumskill2 string
|
||||
Sumsk2calc string
|
||||
Sumsk2calc d2calculation.Calculation
|
||||
Sumskill3 string
|
||||
Sumsk3calc string
|
||||
Sumsk3calc d2calculation.Calculation
|
||||
Sumskill4 string
|
||||
Sumsk4calc string
|
||||
Sumsk4calc d2calculation.Calculation
|
||||
Sumskill5 string
|
||||
Sumsk5calc string
|
||||
Sumsk5calc d2calculation.Calculation
|
||||
Sumoverlay string
|
||||
Stsound string
|
||||
Stsoundclass string
|
||||
|
@ -91,12 +93,9 @@ type SkillRecord struct {
|
|||
Cltmissileb string
|
||||
Cltmissilec string
|
||||
Cltmissiled string
|
||||
Cltcalc1 string
|
||||
Cltcalc1Desc string
|
||||
Cltcalc2 string
|
||||
Cltcalc2Desc string
|
||||
Cltcalc3 string
|
||||
Cltcalc3Desc string
|
||||
Cltcalc1 d2calculation.Calculation
|
||||
Cltcalc2 d2calculation.Calculation
|
||||
Cltcalc3 d2calculation.Calculation
|
||||
Range string
|
||||
Itypea1 string
|
||||
Itypea2 string
|
||||
|
@ -113,35 +112,23 @@ type SkillRecord struct {
|
|||
Monanim string
|
||||
ItemCastSound string
|
||||
ItemCastOverlay string
|
||||
Skpoints string
|
||||
Skpoints d2calculation.Calculation
|
||||
Reqskill1 string
|
||||
Reqskill2 string
|
||||
Reqskill3 string
|
||||
State1 string
|
||||
State2 string
|
||||
State3 string
|
||||
Perdelay string
|
||||
Calc1 string
|
||||
Calc1Desc string
|
||||
Calc2 string
|
||||
Calc2Desc string
|
||||
Calc3 string
|
||||
Calc3Desc string
|
||||
Calc4 string
|
||||
Calc4Desc string
|
||||
Param1Desc string
|
||||
Param2Desc string
|
||||
Param3Desc string
|
||||
Param4Desc string
|
||||
Param5Desc string
|
||||
Param6Desc string
|
||||
Param7Desc string
|
||||
Param8Desc string
|
||||
ToHitCalc string
|
||||
DmgSymPerCalc string
|
||||
Perdelay d2calculation.Calculation
|
||||
Calc1 d2calculation.Calculation
|
||||
Calc2 d2calculation.Calculation
|
||||
Calc3 d2calculation.Calculation
|
||||
Calc4 d2calculation.Calculation
|
||||
ToHitCalc d2calculation.Calculation
|
||||
DmgSymPerCalc d2calculation.Calculation
|
||||
EType string
|
||||
EDmgSymPerCalc string
|
||||
ELenSymPerCalc string
|
||||
EDmgSymPerCalc d2calculation.Calculation
|
||||
ELenSymPerCalc d2calculation.Calculation
|
||||
ID int
|
||||
Srvstfunc int
|
||||
Srvdofunc int
|
||||
|
@ -277,8 +264,13 @@ type SkillRecord struct {
|
|||
func LoadSkills(file []byte) {
|
||||
SkillDetails = make(map[int]*SkillRecord)
|
||||
|
||||
parser := d2parser.New()
|
||||
|
||||
d := d2common.LoadDataDictionary(file)
|
||||
for d.Next() {
|
||||
name := d.String("skill")
|
||||
parser.SetCurrentReference("skill", name)
|
||||
|
||||
record := &SkillRecord{
|
||||
Skill: d.String("skill"),
|
||||
ID: d.Number("Id"),
|
||||
|
@ -290,9 +282,9 @@ func LoadSkills(file []byte) {
|
|||
Srvprgfunc1: d.Number("srvprgfunc1"),
|
||||
Srvprgfunc2: d.Number("srvprgfunc2"),
|
||||
Srvprgfunc3: d.Number("srvprgfunc3"),
|
||||
Prgcalc1: d.String("prgcalc1"),
|
||||
Prgcalc2: d.String("prgcalc2"),
|
||||
Prgcalc3: d.String("prgcalc3"),
|
||||
Prgcalc1: parser.Parse(d.String("prgcalc1")),
|
||||
Prgcalc2: parser.Parse(d.String("prgcalc2")),
|
||||
Prgcalc3: parser.Parse(d.String("prgcalc3")),
|
||||
Prgdam: d.Number("prgdam"),
|
||||
Srvmissile: d.String("srvmissile"),
|
||||
Decquant: d.Bool("decquant"),
|
||||
|
@ -304,20 +296,20 @@ func LoadSkills(file []byte) {
|
|||
Aurafilter: d.Number("aurafilter"),
|
||||
Aurastate: d.String("aurastate"),
|
||||
Auratargetstate: d.String("auratargetstate"),
|
||||
Auralencalc: d.String("auralencalc"),
|
||||
Aurarangecalc: d.String("aurarangecalc"),
|
||||
Auralencalc: parser.Parse(d.String("auralencalc")),
|
||||
Aurarangecalc: parser.Parse(d.String("aurarangecalc")),
|
||||
Aurastat1: d.String("aurastat1"),
|
||||
Aurastatcalc1: d.String("aurastatcalc1"),
|
||||
Aurastatcalc1: parser.Parse(d.String("aurastatcalc1")),
|
||||
Aurastat2: d.String("aurastat2"),
|
||||
Aurastatcalc2: d.String("aurastatcalc2"),
|
||||
Aurastatcalc2: parser.Parse(d.String("aurastatcalc2")),
|
||||
Aurastat3: d.String("aurastat3"),
|
||||
Aurastatcalc3: d.String("aurastatcalc3"),
|
||||
Aurastatcalc3: parser.Parse(d.String("aurastatcalc3")),
|
||||
Aurastat4: d.String("aurastat4"),
|
||||
Aurastatcalc4: d.String("aurastatcalc4"),
|
||||
Aurastatcalc4: parser.Parse(d.String("aurastatcalc4")),
|
||||
Aurastat5: d.String("aurastat5"),
|
||||
Aurastatcalc5: d.String("aurastatcalc5"),
|
||||
Aurastatcalc5: parser.Parse(d.String("aurastatcalc5")),
|
||||
Aurastat6: d.String("aurastat6"),
|
||||
Aurastatcalc6: d.String("aurastatcalc6"),
|
||||
Aurastatcalc6: parser.Parse(d.String("aurastatcalc6")),
|
||||
Auraevent1: d.String("auraevent1"),
|
||||
Auraeventfunc1: d.Number("auraeventfunc1"),
|
||||
Auraevent2: d.String("auraevent2"),
|
||||
|
@ -329,31 +321,31 @@ func LoadSkills(file []byte) {
|
|||
Passivestate: d.String("passivestate"),
|
||||
Passiveitype: d.String("passiveitype"),
|
||||
Passivestat1: d.String("passivestat1"),
|
||||
Passivecalc1: d.String("passivecalc1"),
|
||||
Passivecalc1: parser.Parse(d.String("passivecalc1")),
|
||||
Passivestat2: d.String("passivestat2"),
|
||||
Passivecalc2: d.String("passivecalc2"),
|
||||
Passivecalc2: parser.Parse(d.String("passivecalc2")),
|
||||
Passivestat3: d.String("passivestat3"),
|
||||
Passivecalc3: d.String("passivecalc3"),
|
||||
Passivecalc3: parser.Parse(d.String("passivecalc3")),
|
||||
Passivestat4: d.String("passivestat4"),
|
||||
Passivecalc4: d.String("passivecalc4"),
|
||||
Passivecalc4: parser.Parse(d.String("passivecalc4")),
|
||||
Passivestat5: d.String("passivestat5"),
|
||||
Passivecalc5: d.String("passivecalc5"),
|
||||
Passivecalc5: parser.Parse(d.String("passivecalc5")),
|
||||
Passiveevent: d.String("passiveevent"),
|
||||
Passiveeventfunc: d.String("passiveeventfunc"),
|
||||
Summon: d.String("summon"),
|
||||
Pettype: d.String("pettype"),
|
||||
Petmax: d.String("petmax"),
|
||||
Petmax: parser.Parse(d.String("petmax")),
|
||||
Summode: d.String("summode"),
|
||||
Sumskill1: d.String("sumskill1"),
|
||||
Sumsk1calc: d.String("sumsk1calc"),
|
||||
Sumsk1calc: parser.Parse(d.String("sumsk1calc")),
|
||||
Sumskill2: d.String("sumskill2"),
|
||||
Sumsk2calc: d.String("sumsk2calc"),
|
||||
Sumsk2calc: parser.Parse(d.String("sumsk2calc")),
|
||||
Sumskill3: d.String("sumskill3"),
|
||||
Sumsk3calc: d.String("sumsk3calc"),
|
||||
Sumsk3calc: parser.Parse(d.String("sumsk3calc")),
|
||||
Sumskill4: d.String("sumskill4"),
|
||||
Sumsk4calc: d.String("sumsk4calc"),
|
||||
Sumsk4calc: parser.Parse(d.String("sumsk4calc")),
|
||||
Sumskill5: d.String("sumskill5"),
|
||||
Sumsk5calc: d.String("sumsk5calc"),
|
||||
Sumsk5calc: parser.Parse(d.String("sumsk5calc")),
|
||||
Sumumod: d.Number("sumumod"),
|
||||
Sumoverlay: d.String("sumoverlay"),
|
||||
Stsuccessonly: d.Bool("stsuccessonly"),
|
||||
|
@ -381,12 +373,9 @@ func LoadSkills(file []byte) {
|
|||
Cltmissileb: d.String("cltmissileb"),
|
||||
Cltmissilec: d.String("cltmissilec"),
|
||||
Cltmissiled: d.String("cltmissiled"),
|
||||
Cltcalc1: d.String("cltcalc1"),
|
||||
Cltcalc1Desc: d.String("*cltcalc1 desc"),
|
||||
Cltcalc2: d.String("cltcalc2"),
|
||||
Cltcalc2Desc: d.String("*cltcalc2 desc"),
|
||||
Cltcalc3: d.String("cltcalc3"),
|
||||
Cltcalc3Desc: d.String("*cltcalc3 desc"),
|
||||
Cltcalc1: parser.Parse(d.String("cltcalc1")),
|
||||
Cltcalc2: parser.Parse(d.String("cltcalc2")),
|
||||
Cltcalc3: parser.Parse(d.String("cltcalc3")),
|
||||
Warp: d.Bool("warp"),
|
||||
Immediate: d.Bool("immediate"),
|
||||
Enhanceable: d.Bool("enhanceable"),
|
||||
|
@ -431,7 +420,7 @@ func LoadSkills(file []byte) {
|
|||
ItemCltCheckStart: d.Bool("ItemCltCheckStart"),
|
||||
ItemCastSound: d.String("ItemCastSound"),
|
||||
ItemCastOverlay: d.String("ItemCastOverlay"),
|
||||
Skpoints: d.String("skpoints"),
|
||||
Skpoints: parser.Parse(d.String("skpoints")),
|
||||
Reqlevel: d.Number("reqlevel"),
|
||||
Maxlvl: d.Number("maxlvl"),
|
||||
Reqstr: d.Number("reqstr"),
|
||||
|
@ -460,40 +449,28 @@ func LoadSkills(file []byte) {
|
|||
InTown: d.Bool("InTown"),
|
||||
Aura: d.Bool("aura"),
|
||||
Periodic: d.Bool("periodic"),
|
||||
Perdelay: d.String("perdelay"),
|
||||
Perdelay: parser.Parse(d.String("perdelay")),
|
||||
Finishing: d.Bool("finishing"),
|
||||
Passive: d.Bool("passive"),
|
||||
Progressive: d.Bool("progressive"),
|
||||
General: d.Bool("general"),
|
||||
Scroll: d.Bool("scroll"),
|
||||
Calc1: d.String("calc1"),
|
||||
Calc1Desc: d.String("*calc1 desc"),
|
||||
Calc2: d.String("calc2"),
|
||||
Calc2Desc: d.String("*calc2 desc"),
|
||||
Calc3: d.String("calc3"),
|
||||
Calc3Desc: d.String("*calc3 desc"),
|
||||
Calc4: d.String("calc4"),
|
||||
Calc4Desc: d.String("*calc4 desc"),
|
||||
Calc1: parser.Parse(d.String("calc1")),
|
||||
Calc2: parser.Parse(d.String("calc2")),
|
||||
Calc3: parser.Parse(d.String("calc3")),
|
||||
Calc4: parser.Parse(d.String("calc4")),
|
||||
Param1: d.Number("Param1"),
|
||||
Param1Desc: d.String("*Param1 Description"),
|
||||
Param2: d.Number("Param2"),
|
||||
Param2Desc: d.String("*Param2 Description"),
|
||||
Param3: d.Number("Param3"),
|
||||
Param3Desc: d.String("*Param3 Description"),
|
||||
Param4: d.Number("Param4"),
|
||||
Param4Desc: d.String("*Param4 Description"),
|
||||
Param5: d.Number("Param5"),
|
||||
Param5Desc: d.String("*Param5 Description"),
|
||||
Param6: d.Number("Param6"),
|
||||
Param6Desc: d.String("*Param6 Description"),
|
||||
Param7: d.Number("Param7"),
|
||||
Param7Desc: d.String("*Param7 Description"),
|
||||
Param8: d.Number("Param8"),
|
||||
Param8Desc: d.String("*Param8 Description"),
|
||||
InGame: d.Bool("InGame"),
|
||||
ToHit: d.Number("ToHit"),
|
||||
LevToHit: d.Number("LevToHit"),
|
||||
ToHitCalc: d.String("ToHitCalc"),
|
||||
ToHitCalc: parser.Parse(d.String("ToHitCalc")),
|
||||
ResultFlags: d.Number("ResultFlags"),
|
||||
HitFlags: d.Number("HitFlags"),
|
||||
HitClass: d.Number("HitClass"),
|
||||
|
@ -512,7 +489,7 @@ func LoadSkills(file []byte) {
|
|||
MaxLevDam3: d.Number("MaxLevDam3"),
|
||||
MaxLevDam4: d.Number("MaxLevDam4"),
|
||||
MaxLevDam5: d.Number("MaxLevDam5"),
|
||||
DmgSymPerCalc: d.String("DmgSymPerCalc"),
|
||||
DmgSymPerCalc: parser.Parse(d.String("DmgSymPerCalc")),
|
||||
EType: d.String("EType"),
|
||||
EMin: d.Number("EMin"),
|
||||
EMinLev1: d.Number("EMinLev1"),
|
||||
|
@ -526,12 +503,12 @@ func LoadSkills(file []byte) {
|
|||
EMaxLev3: d.Number("EMaxLev3"),
|
||||
EMaxLev4: d.Number("EMaxLev4"),
|
||||
EMaxLev5: d.Number("EMaxLev5"),
|
||||
EDmgSymPerCalc: d.String("EDmgSymPerCalc"),
|
||||
EDmgSymPerCalc: parser.Parse(d.String("EDmgSymPerCalc")),
|
||||
ELen: d.Number("ELen"),
|
||||
ELevLen1: d.Number("ELevLen1"),
|
||||
ELevLen2: d.Number("ELevLen2"),
|
||||
ELevLen3: d.Number("ELevLen3"),
|
||||
ELenSymPerCalc: d.String("ELenSymPerCalc"),
|
||||
ELenSymPerCalc: parser.Parse(d.String("ELenSymPerCalc")),
|
||||
Aitype: d.Number("aitype"),
|
||||
Aibonus: d.Number("aibonus"),
|
||||
CostMult: d.Number("cost mult"),
|
||||
|
|
Loading…
Reference in New Issue