update nip rule
This commit is contained in:
@@ -118,6 +118,24 @@ func (r Rules) EvaluateTiers(it data.Item, tierRulesIndexes []int) (Rule, Rule)
|
||||
|
||||
var fixedPropsList = map[string]int{"type": 0, "quality": 0, "class": 0, "name": 0, "flag": 0, "color": 0, "prefix": 0, "suffix": 0}
|
||||
|
||||
// flagBit* are the bits Evaluate sets on the runtime `flag` value AND the
|
||||
// rewriter (replaceStringPropertiesInStage1) recognises. flagAllBits is the
|
||||
// disjunction of every supported flag bit: the rewriter enumerates all subsets
|
||||
// of flagAllBits when expanding bit tests for the `==`/`!=` operators (expr-lang
|
||||
// has no bitwise operators). To add a new flag bit, update Evaluate to set it,
|
||||
// add a case in the rewriter's name->bit switch, AND fold it into flagAllBits
|
||||
// so the enumeration sees it.
|
||||
const (
|
||||
flagBitEthereal = 0x400000
|
||||
flagBitRuneword = 0x4000000
|
||||
flagAllBits = flagBitEthereal | flagBitRuneword
|
||||
)
|
||||
|
||||
var (
|
||||
maxClassSkillsLayer = maxAliasLayer(stat.AddClassSkills)
|
||||
maxSkillTabLayer = maxAliasLayer(stat.AddSkillTab)
|
||||
)
|
||||
|
||||
func NewRule(rawRule string, filename string, lineNumber int) (Rule, error) {
|
||||
rule := sanitizeLine(rawRule)
|
||||
|
||||
@@ -252,14 +270,19 @@ func (r Rule) Evaluate(it data.Item) (RuleResult, error) {
|
||||
case "name":
|
||||
stage1Props["name"] = it.ID
|
||||
case "flag":
|
||||
// 0x400000 (eth) | 0x4000000 (runeword) kolbot style
|
||||
// 0x400000 (eth) | 0x4000000 (runeword) kolbot style. Bit values are
|
||||
// shared with the rewriter (replaceStringPropertiesInStage1) via the
|
||||
// package-level flagBit* constants so the rewriter's enumeration of
|
||||
// possible flag-states stays in lock-step with the values written
|
||||
// here — adding a third bit requires editing both this writer AND
|
||||
// the rewriter, but the constants make the dependency discoverable.
|
||||
currentFlag := 0
|
||||
|
||||
if it.Ethereal {
|
||||
currentFlag |= 0x400000
|
||||
currentFlag |= flagBitEthereal
|
||||
}
|
||||
if it.IsRuneword {
|
||||
currentFlag |= 0x4000000
|
||||
currentFlag |= flagBitRuneword
|
||||
}
|
||||
|
||||
stage1Props["flag"] = currentFlag
|
||||
@@ -489,16 +512,47 @@ func replaceStringPropertiesInStage1(stage1 string) (string, error) {
|
||||
case "name":
|
||||
replaceWith = strings.ReplaceAll(prop[0], prop[4], fmt.Sprintf("%d", item.GetIDByName(prop[4])))
|
||||
case "flag":
|
||||
val := 0
|
||||
switch strings.ToLower(prop[4]) {
|
||||
// [flag] is a bitmask at runtime (ethereal | runeword), so equality must be
|
||||
// a bit test, not a scalar compare. Previously "[flag] == ethereal" rewrote
|
||||
// to "flag == 0x400000", which evaluated FALSE on an ethereal runeword (whose
|
||||
// flag is 0x4400000 == eth|rw). expr-lang has no bitwise operators, so we
|
||||
// enumerate the two states the chosen bit can produce. flagAllBits below
|
||||
// MUST stay in sync with the writer in Evaluate — every bit Evaluate can
|
||||
// set must appear here, otherwise the negation form may miss valid items.
|
||||
name := strings.ToLower(prop[4])
|
||||
var bit int
|
||||
switch name {
|
||||
case "runeword":
|
||||
val = 0x4000000
|
||||
bit = flagBitRuneword
|
||||
case "ethereal":
|
||||
val = 0x400000
|
||||
bit = flagBitEthereal
|
||||
default:
|
||||
val = 1
|
||||
bit = 1
|
||||
}
|
||||
switch {
|
||||
case bit == 1:
|
||||
// Unknown flag name — preserve legacy behaviour (replace value with 1).
|
||||
replaceWith = strings.ReplaceAll(prop[0], prop[4], "1")
|
||||
case prop[3] == "==":
|
||||
switch bit {
|
||||
case flagBitRuneword:
|
||||
replaceWith = fmt.Sprintf("(flag == %d || flag == %d)", flagBitRuneword, flagBitRuneword|flagBitEthereal)
|
||||
case flagBitEthereal:
|
||||
replaceWith = fmt.Sprintf("(flag == %d || flag == %d)", flagBitEthereal, flagBitRuneword|flagBitEthereal)
|
||||
}
|
||||
|
||||
case prop[3] == "!=":
|
||||
switch bit {
|
||||
case flagBitRuneword:
|
||||
replaceWith = fmt.Sprintf("(flag == 0 || flag == %d)", flagBitEthereal)
|
||||
case flagBitEthereal:
|
||||
replaceWith = fmt.Sprintf("(flag == 0 || flag == %d)", flagBitRuneword)
|
||||
}
|
||||
default:
|
||||
// Comparison operators other than ==/!= are nonsensical for a bitmask
|
||||
// but kept as scalar compares so exotic legacy rules don't suddenly fail.
|
||||
replaceWith = strings.ReplaceAll(prop[0], prop[4], fmt.Sprintf("%d", bit))
|
||||
}
|
||||
replaceWith = strings.ReplaceAll(prop[0], prop[4], fmt.Sprintf("%d", val))
|
||||
case "prefix", "suffix":
|
||||
// Handle prefix/suffix IDs
|
||||
replaceWith = strings.ReplaceAll(prop[0], prop[4], prop[4])
|
||||
@@ -541,9 +595,8 @@ func (r Rule) ValidateStats() error {
|
||||
func evaluateClassSkillsSum(it data.Item) int {
|
||||
// Check all class skills stats
|
||||
totalClassSkills := 0
|
||||
maxLayer := 6 // in aliases.go the max layer for class skills is 6 (itemaddassassinskills)
|
||||
|
||||
for layer := 0; layer <= maxLayer; layer++ {
|
||||
for layer := 0; layer <= maxClassSkillsLayer; layer++ {
|
||||
if itemStat, found := it.FindStat(stat.AddClassSkills, layer); found && itemStat.Value > 0 {
|
||||
totalClassSkills += itemStat.Value
|
||||
}
|
||||
@@ -554,9 +607,8 @@ func evaluateClassSkillsSum(it data.Item) int {
|
||||
func evaluateSkillTabSum(it data.Item) int {
|
||||
// Check all skill tab stats
|
||||
totalSkillTabs := 0
|
||||
maxLayer := 50 // in aliases.go the max layer for skill tabs is 50 (itemaddmartialartsskilltab)
|
||||
|
||||
for layer := 0; layer <= maxLayer; layer++ {
|
||||
for layer := 0; layer <= maxSkillTabLayer; layer++ {
|
||||
if itemStat, found := it.FindStat(stat.AddSkillTab, layer); found && itemStat.Value > 0 {
|
||||
totalSkillTabs += itemStat.Value
|
||||
}
|
||||
@@ -565,6 +617,23 @@ func evaluateSkillTabSum(it data.Item) int {
|
||||
return totalSkillTabs
|
||||
}
|
||||
|
||||
func maxAliasLayer(statID stat.ID) int {
|
||||
maxLayer := 0
|
||||
for _, statData := range statAliases {
|
||||
if len(statData) == 0 || stat.ID(statData[0]) != statID {
|
||||
continue
|
||||
}
|
||||
layer := 0
|
||||
if len(statData) > 1 {
|
||||
layer = statData[1]
|
||||
}
|
||||
if layer > maxLayer {
|
||||
maxLayer = layer
|
||||
}
|
||||
}
|
||||
return maxLayer
|
||||
}
|
||||
|
||||
// MaxQuantity returns the maximum quantity of items that character can have, 0 means no limit
|
||||
func (r Rule) MaxQuantity() int {
|
||||
return r.maxQuantity
|
||||
|
||||
Reference in New Issue
Block a user