Fix broken negative stats, update some stat description (#79)
* Fix broken negative stats, update some stat description * ### * #2 * curses is necro, frw on armor is velocity percent ( unused) * Update rules to accept negative value fix a bug with unique grand charm tz [name] == grandcharm && [quality] == unique # ([fireresist] + [coldresist] + [lightresist]) >= -75 Single stat rules like [coldresist] >= -75 require the stat to exist expressions like ([fireresist] + [coldresist] + [lightresist]) >= -75 treat missing stats as 0 Unidentified items with any stat requirements need identification first * LevelReq + identifiedName added for all Crafted items * Fix issue with rule.go * Update stat throw damage and basename: GrandCharm -- Grand Charm * Adjusting rule for ItemLevelReq = 0 * update rule again
This commit is contained in:
@@ -47,7 +47,7 @@ const (
|
|||||||
Gold
|
Gold
|
||||||
StashGold
|
StashGold
|
||||||
EnhancedDefense
|
EnhancedDefense
|
||||||
EnhancedDamageMax
|
EnhancedDamageMin
|
||||||
EnhancedDamage
|
EnhancedDamage
|
||||||
AttackRating
|
AttackRating
|
||||||
ChanceToBlock
|
ChanceToBlock
|
||||||
@@ -411,7 +411,7 @@ var StringStats = []string{
|
|||||||
"gold",
|
"gold",
|
||||||
"stashgold",
|
"stashgold",
|
||||||
"enhanceddefense",
|
"enhanceddefense",
|
||||||
"enhanceddamagemax",
|
"enhanceddamagemin",
|
||||||
"enhanceddamage",
|
"enhanceddamage",
|
||||||
"attackrating",
|
"attackrating",
|
||||||
"chancetoblock",
|
"chancetoblock",
|
||||||
@@ -780,8 +780,8 @@ var StatStringMap = map[int]map[int]string{
|
|||||||
14: {0: "Gold: #"},
|
14: {0: "Gold: #"},
|
||||||
15: {0: "Gold in Bank: #"},
|
15: {0: "Gold in Bank: #"},
|
||||||
16: {0: "+#% Enhanced Defense"}, // enhanceddefense
|
16: {0: "+#% Enhanced Defense"}, // enhanceddefense
|
||||||
17: {0: "+#% Enhanced Maximum Damage (Based on Character Level)"}, // itemmaxdamagepercent
|
17: {0: "+#% Enhanced Damage (Max)"}, // enhanceddamagemax
|
||||||
18: {0: "+#% Enhanced Damage"}, // enhanceddamage
|
18: {0: "+#% Enhanced Damage (Min)"}, // enhanceddamagemin
|
||||||
19: {0: "+# to Attack Rating"}, // tohit
|
19: {0: "+# to Attack Rating"}, // tohit
|
||||||
20: {0: "#% Increased Chance of Blocking"}, // toblock
|
20: {0: "#% Increased Chance of Blocking"}, // toblock
|
||||||
21: {
|
21: {
|
||||||
@@ -839,13 +839,13 @@ var StatStringMap = map[int]map[int]string{
|
|||||||
64: {0: "stamdrainmindam ????"},
|
64: {0: "stamdrainmindam ????"},
|
||||||
65: {0: "stamdrainmaxdam ????"},
|
65: {0: "stamdrainmaxdam ????"},
|
||||||
66: {0: "stunlength ????"},
|
66: {0: "stunlength ????"},
|
||||||
67: {0: "+#% Faster Run/Walk"},
|
67: {0: "#% Velocity"},
|
||||||
68: {0: "#"}, // attackrate
|
68: {0: "#"}, // attackrate
|
||||||
69: {0: "otheranimrate ????"},
|
69: {0: "otheranimrate ????"},
|
||||||
70: {0: "Quantity: #"},
|
70: {0: "Quantity: #"},
|
||||||
71: {0: "Value: #"},
|
71: {0: "Value: #"},
|
||||||
72: {0: "Durability: # of #"}, // durability
|
72: {0: "Durability: # of #"}, // durability
|
||||||
73: {0: "#"}, // maxdurability
|
73: {0: "# Max Durability"}, // maxdurability
|
||||||
74: {0: "Replenish Life +#"}, // hpregen
|
74: {0: "Replenish Life +#"}, // hpregen
|
||||||
75: {0: "Increase Maximum Durability #%"}, //itemmaxdurabilitypercent
|
75: {0: "Increase Maximum Durability #%"}, //itemmaxdurabilitypercent
|
||||||
76: {0: "Increase Maximum Life #%"}, //itemmaxmanapercent
|
76: {0: "Increase Maximum Life #%"}, //itemmaxmanapercent
|
||||||
@@ -1178,8 +1178,8 @@ var StatStringMap = map[int]map[int]string{
|
|||||||
156: {0: "Piercing Attack"}, // itempierce
|
156: {0: "Piercing Attack"}, // itempierce
|
||||||
157: {0: "Fires Magic Arrows"}, // itemmagicarrow
|
157: {0: "Fires Magic Arrows"}, // itemmagicarrow
|
||||||
158: {0: "Fires Explosive Arrows or Bolts"}, // itemexplosivearrow
|
158: {0: "Fires Explosive Arrows or Bolts"}, // itemexplosivearrow
|
||||||
159: {0: "itemthrowmindamage ????"},
|
159: {0: "# To Minimum Damage"},
|
||||||
160: {0: "itemthrowmaxdamage ????"},
|
160: {0: "+# Maximum Damage"},
|
||||||
161: {0: "itemskillhandofathena ????"},
|
161: {0: "itemskillhandofathena ????"},
|
||||||
162: {0: "itemskillstaminapercent ????"},
|
162: {0: "itemskillstaminapercent ????"},
|
||||||
163: {0: "itemskillpassivestaminapercent ????"},
|
163: {0: "itemskillpassivestaminapercent ????"},
|
||||||
@@ -1214,7 +1214,7 @@ var StatStringMap = map[int]map[int]string{
|
|||||||
8: "+# to Fire Skills (Sorceress only)", // fireskilltab
|
8: "+# to Fire Skills (Sorceress only)", // fireskilltab
|
||||||
9: "+# to Lightning Skills (Sorceress only)", // lightningskilltab
|
9: "+# to Lightning Skills (Sorceress only)", // lightningskilltab
|
||||||
10: "+# to Cold Skills (Sorceress only)", // coldskilltab
|
10: "+# to Cold Skills (Sorceress only)", // coldskilltab
|
||||||
16: "+# to Curses Skills (Sorceress only)", // cursesskilltab
|
16: "+# to Curses Skills (Necromancer only)", // cursesskilltab
|
||||||
17: "+# to Poison and Bone Skills (Necromancer only)", // poisonandboneskilltab
|
17: "+# to Poison and Bone Skills (Necromancer only)", // poisonandboneskilltab
|
||||||
18: "+# to Summoning Skills (Necromancer only)", // necromancersummoningskilltab
|
18: "+# to Summoning Skills (Necromancer only)", // necromancersummoningskilltab
|
||||||
24: "+# to Paladin Combat Skills (Paladin only)", // palicombatskilltab
|
24: "+# to Paladin Combat Skills (Paladin only)", // palicombatskilltab
|
||||||
@@ -1239,6 +1239,7 @@ var StatStringMap = map[int]map[int]string{
|
|||||||
195: {
|
195: {
|
||||||
1: "#% Chance to cast level # [Skill] on attack", //itemskillonattack
|
1: "#% Chance to cast level # [Skill] on attack", //itemskillonattack
|
||||||
2: "itemskillonattacklevel ????",
|
2: "itemskillonattacklevel ????",
|
||||||
|
3395: "#% Chance to cast level 3 Chain Lightning on attack",
|
||||||
},
|
},
|
||||||
196: {
|
196: {
|
||||||
1: "#% Chance to cast level # [Skill] when you Kill an Enemy", //itemskillonkill
|
1: "#% Chance to cast level # [Skill] when you Kill an Enemy", //itemskillonkill
|
||||||
@@ -1261,6 +1262,8 @@ var StatStringMap = map[int]map[int]string{
|
|||||||
201: {
|
201: {
|
||||||
1: "#% Chance to cast level # [Skill] when struck", //itemskillongethit
|
1: "#% Chance to cast level # [Skill] when struck", //itemskillongethit
|
||||||
2: "itemskillongethitlevel ????",
|
2: "itemskillongethitlevel ????",
|
||||||
|
5903: "#% Chance to cast level 15 Poison Nova when struck",
|
||||||
|
7751: "#% Chance to cast level 7 Fist of Heavens when struck",
|
||||||
},
|
},
|
||||||
202: {0: "unused202 ????"},
|
202: {0: "unused202 ????"},
|
||||||
203: {0: "unused203 ????"},
|
203: {0: "unused203 ????"},
|
||||||
@@ -1268,6 +1271,7 @@ var StatStringMap = map[int]map[int]string{
|
|||||||
1: "itemchargedskill ????",
|
1: "itemchargedskill ????",
|
||||||
2: "itemchargedskilllevel ????",
|
2: "itemchargedskilllevel ????",
|
||||||
3461: "Teleport (charged)",
|
3461: "Teleport (charged)",
|
||||||
|
17795: "Venom level 3 (charged)",
|
||||||
},
|
},
|
||||||
205: {0: "unused204 ????"},
|
205: {0: "unused204 ????"},
|
||||||
206: {0: "unused205 ????"},
|
206: {0: "unused205 ????"},
|
||||||
|
|||||||
@@ -146,14 +146,16 @@ func (gd *GameReader) getStatsList(statListPtr uintptr) stat.Stats {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var stats = make([]stat.Data, 0)
|
var stats = make([]stat.Data, 0)
|
||||||
|
|
||||||
statBuffer := gd.Process.ReadBytesFromMemory(uintptr(statList), statCount*10)
|
statBuffer := gd.Process.ReadBytesFromMemory(uintptr(statList), statCount*10)
|
||||||
for i := 0; i < int(statCount); i++ {
|
for i := 0; i < int(statCount); i++ {
|
||||||
offset := uint(i * 8)
|
offset := uint(i * 8)
|
||||||
|
|
||||||
statLayer := ReadUIntFromBuffer(statBuffer, offset, Uint16)
|
statLayer := ReadUIntFromBuffer(statBuffer, offset, Uint16)
|
||||||
statEnum := ReadUIntFromBuffer(statBuffer, offset+0x2, Uint16)
|
statEnum := ReadUIntFromBuffer(statBuffer, offset+0x2, Uint16)
|
||||||
statValue := ReadUIntFromBuffer(statBuffer, offset+0x4, Uint32)
|
statValue := ReadIntFromBuffer(statBuffer, offset+0x4, Uint32)
|
||||||
|
|
||||||
value := int(statValue)
|
value := statValue
|
||||||
switch stat.ID(statEnum) {
|
switch stat.ID(statEnum) {
|
||||||
case stat.Life,
|
case stat.Life,
|
||||||
stat.MaxLife,
|
stat.MaxLife,
|
||||||
@@ -161,16 +163,16 @@ func (gd *GameReader) getStatsList(statListPtr uintptr) stat.Stats {
|
|||||||
stat.MaxMana,
|
stat.MaxMana,
|
||||||
stat.Stamina,
|
stat.Stamina,
|
||||||
stat.MaxStamina:
|
stat.MaxStamina:
|
||||||
value = int(statValue >> 8)
|
value = statValue >> 8
|
||||||
case stat.ColdLength,
|
case stat.ColdLength,
|
||||||
stat.PoisonLength:
|
stat.PoisonLength:
|
||||||
value = int(statValue / 25)
|
value = statValue / 25
|
||||||
case stat.DeadlyStrikePerLevel:
|
case stat.DeadlyStrikePerLevel:
|
||||||
value = int(float64(statValue) / .8)
|
value = int(float64(statValue) / .8)
|
||||||
case stat.HitCausesMonsterToFlee:
|
case stat.HitCausesMonsterToFlee:
|
||||||
value = int(float64(statValue) / 1.28)
|
value = int(float64(statValue) / 1.28)
|
||||||
case stat.AttackRatingUndeadPerLevel:
|
case stat.AttackRatingUndeadPerLevel:
|
||||||
value = int(statValue / 2)
|
value = statValue / 2
|
||||||
case stat.MagicFindPerLevel,
|
case stat.MagicFindPerLevel,
|
||||||
stat.ExtraGoldPerLevel,
|
stat.ExtraGoldPerLevel,
|
||||||
stat.DamageDemonPerLevel,
|
stat.DamageDemonPerLevel,
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ func (gd *GameReader) Inventory(rawPlayerUnits RawPlayerUnits, hover data.HoverD
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case item.QualityRare:
|
case item.QualityRare, item.QualityCrafted:
|
||||||
// Set item name from rare affixes
|
// Set item name from rare affixes
|
||||||
if prefix, exists := item.RarePrefixDesc[int(rarePrefix)]; exists {
|
if prefix, exists := item.RarePrefixDesc[int(rarePrefix)]; exists {
|
||||||
if suffix, exists := item.RareSuffixDesc[int(rareSuffix)]; exists {
|
if suffix, exists := item.RareSuffixDesc[int(rareSuffix)]; exists {
|
||||||
@@ -233,7 +233,7 @@ func (gd *GameReader) Inventory(rawPlayerUnits RawPlayerUnits, hover data.HoverD
|
|||||||
if len(prefixParts) > 0 {
|
if len(prefixParts) > 0 {
|
||||||
nameParts = append(nameParts, prefixParts...)
|
nameParts = append(nameParts, prefixParts...)
|
||||||
}
|
}
|
||||||
nameParts = append(nameParts, string(itm.Name))
|
nameParts = append(nameParts, itm.Desc().Name)
|
||||||
if len(suffixParts) > 0 {
|
if len(suffixParts) > 0 {
|
||||||
nameParts = append(nameParts, suffixParts...)
|
nameParts = append(nameParts, suffixParts...)
|
||||||
}
|
}
|
||||||
@@ -436,7 +436,7 @@ func (gd *GameReader) Inventory(rawPlayerUnits RawPlayerUnits, hover data.HoverD
|
|||||||
maxReq := calculateItemLevelReq(itm, baseDesc)
|
maxReq := calculateItemLevelReq(itm, baseDesc)
|
||||||
|
|
||||||
// Check magic/rare affixes
|
// Check magic/rare affixes
|
||||||
if itm.Identified && (itm.Quality == item.QualityMagic || itm.Quality == item.QualityRare) {
|
if itm.Identified && (itm.Quality == item.QualityMagic || itm.Quality == item.QualityRare || itm.Quality == item.QualityCrafted) {
|
||||||
maxReq = updateMaxReqFromAffixes(maxReq, itm.Affixes)
|
maxReq = updateMaxReqFromAffixes(maxReq, itm.Affixes)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -631,6 +631,43 @@ func calculateItemLevelReq(itm *data.Item, baseDesc item.Description) int {
|
|||||||
// Start with base item's requirement
|
// Start with base item's requirement
|
||||||
maxReq := baseDesc.RequiredLevel
|
maxReq := baseDesc.RequiredLevel
|
||||||
|
|
||||||
|
// Handle Crafted items first as they have special calculation rules
|
||||||
|
if itm.Quality == item.QualityCrafted {
|
||||||
|
// Count number of affixes and find highest level requirement
|
||||||
|
affixCount := 0
|
||||||
|
maxAffixReq := 0
|
||||||
|
|
||||||
|
for _, prefixID := range itm.Affixes.Magic.Prefixes {
|
||||||
|
if prefix, exists := item.MagicPrefixDesc[int(prefixID)]; exists && prefixID != 0 {
|
||||||
|
affixCount++
|
||||||
|
if prefix.LevelReq > maxAffixReq {
|
||||||
|
maxAffixReq = prefix.LevelReq
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, suffixID := range itm.Affixes.Magic.Suffixes {
|
||||||
|
if suffix, exists := item.MagicSuffixDesc[int(suffixID)]; exists && suffixID != 0 {
|
||||||
|
affixCount++
|
||||||
|
if suffix.LevelReq > maxAffixReq {
|
||||||
|
maxAffixReq = suffix.LevelReq
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Base calculation
|
||||||
|
levelReq := maxAffixReq + (3 * affixCount)
|
||||||
|
// Add 10 to final level req
|
||||||
|
levelReq += 10
|
||||||
|
|
||||||
|
// Cap at 98 if needed (Maximum possible)
|
||||||
|
if levelReq > 99 {
|
||||||
|
levelReq = 98
|
||||||
|
}
|
||||||
|
|
||||||
|
return levelReq
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle Unique/Set items and their special upgrade cases
|
||||||
if itm.Quality == item.QualityUnique || itm.Quality == item.QualitySet {
|
if itm.Quality == item.QualityUnique || itm.Quality == item.QualitySet {
|
||||||
itemCode := baseDesc.Code
|
itemCode := baseDesc.Code
|
||||||
normalCode := baseDesc.NormalCode
|
normalCode := baseDesc.NormalCode
|
||||||
@@ -655,6 +692,7 @@ func calculateItemLevelReq(itm *data.Item, baseDesc item.Description) int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply upgrade requirements
|
||||||
if itemCode == eliteCode {
|
if itemCode == eliteCode {
|
||||||
if originalCode == normalCode {
|
if originalCode == normalCode {
|
||||||
// Double upgraded: Normal -> Exceptional -> Elite
|
// Double upgraded: Normal -> Exceptional -> Elite
|
||||||
@@ -679,7 +717,7 @@ func calculateItemLevelReq(itm *data.Item, baseDesc item.Description) int {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else { // Set item
|
} else if itm.Quality == item.QualitySet {
|
||||||
for _, setItemInfo := range item.SetItems {
|
for _, setItemInfo := range item.SetItems {
|
||||||
if setItemInfo.ID == int(itm.UniqueSetID) {
|
if setItemInfo.ID == int(itm.UniqueSetID) {
|
||||||
if setItemInfo.LevelReq > maxReq {
|
if setItemInfo.LevelReq > maxReq {
|
||||||
@@ -691,6 +729,5 @@ func calculateItemLevelReq(itm *data.Item, baseDesc item.Description) int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return maxReq
|
return maxReq
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,13 @@ type Process struct {
|
|||||||
moduleBaseSize uint32
|
moduleBaseSize uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
Int8 = 1 // signed 8-bit integer
|
||||||
|
Int16 = 2 // signed 16-bit integer
|
||||||
|
Int32 = 4 // signed 32-bit integer
|
||||||
|
Int64 = 8 // signed 64-bit integer
|
||||||
|
)
|
||||||
|
|
||||||
func NewProcess() (Process, error) {
|
func NewProcess() (Process, error) {
|
||||||
module, err := getGameModule()
|
module, err := getGameModule()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -144,6 +151,22 @@ func bytesToUint(bytes []byte, size IntType) uint {
|
|||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
func ReadIntFromBuffer(bytes []byte, offset uint, size IntType) int {
|
||||||
|
return bytesToInt(bytes[offset:offset+uint(size)], size)
|
||||||
|
}
|
||||||
|
func bytesToInt(bytes []byte, size IntType) int {
|
||||||
|
switch size {
|
||||||
|
case Int8:
|
||||||
|
return int(int8(bytes[0]))
|
||||||
|
case Int16:
|
||||||
|
return int(int16(binary.LittleEndian.Uint16(bytes)))
|
||||||
|
case Int32:
|
||||||
|
return int(int32(binary.LittleEndian.Uint32(bytes)))
|
||||||
|
case Int64:
|
||||||
|
return int(int64(binary.LittleEndian.Uint64(bytes)))
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
func (p Process) ReadStringFromMemory(address uintptr, size uint) string {
|
func (p Process) ReadStringFromMemory(address uintptr, size uint) string {
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
|
|||||||
@@ -136,6 +136,7 @@ func NewRule(rawRule string, filename string, lineNumber int) (Rule, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r Rule) Evaluate(it data.Item) (RuleResult, error) {
|
func (r Rule) Evaluate(it data.Item) (RuleResult, error) {
|
||||||
|
// Stage 1: Basic properties evaluation
|
||||||
stage1Props := make(map[string]int)
|
stage1Props := make(map[string]int)
|
||||||
for prop := range fixedPropsList {
|
for prop := range fixedPropsList {
|
||||||
switch prop {
|
switch prop {
|
||||||
@@ -185,9 +186,42 @@ func (r Rule) Evaluate(it data.Item) (RuleResult, error) {
|
|||||||
return RuleResultNoMatch, nil
|
return RuleResultNoMatch, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
stage2Result := true
|
// If we have no stage2 (no stat requirements), allow full match even for unidentified items
|
||||||
if r.stage2 != nil {
|
if r.stage2 == nil {
|
||||||
|
return RuleResultFullMatch, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// From here on we have stat requirements - return partial match for unidentified items
|
||||||
|
if !it.Identified {
|
||||||
|
return RuleResultPartial, nil
|
||||||
|
}
|
||||||
|
|
||||||
stage2Props := make(map[string]int)
|
stage2Props := make(map[string]int)
|
||||||
|
|
||||||
|
// We only want to default to 0 if we find at least one of the required resists
|
||||||
|
hasAnyResist := false
|
||||||
|
stage2 := strings.ToLower(strings.Split(r.RawLine, "#")[1])
|
||||||
|
isResistSum := strings.Contains(stage2, "resist") && (strings.Contains(stage2, "+") || strings.Contains(stage2, "-"))
|
||||||
|
|
||||||
|
// First pass - check if we have any of the required resists
|
||||||
|
if isResistSum {
|
||||||
|
for _, statName := range r.requiredStats {
|
||||||
|
statData, found := statAliases[statName]
|
||||||
|
if !found {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
layer := 0
|
||||||
|
if len(statData) > 1 {
|
||||||
|
layer = statData[1]
|
||||||
|
}
|
||||||
|
if _, found := it.FindStat(stat.ID(statData[0]), layer); found {
|
||||||
|
hasAnyResist = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second pass - evaluate stats
|
||||||
for _, statName := range r.requiredStats {
|
for _, statName := range r.requiredStats {
|
||||||
statData, found := statAliases[statName]
|
statData, found := statAliases[statName]
|
||||||
if !found {
|
if !found {
|
||||||
@@ -198,26 +232,28 @@ func (r Rule) Evaluate(it data.Item) (RuleResult, error) {
|
|||||||
if len(statData) > 1 {
|
if len(statData) > 1 {
|
||||||
layer = statData[1]
|
layer = statData[1]
|
||||||
}
|
}
|
||||||
itemStat, _ := it.FindStat(stat.ID(statData[0]), layer)
|
|
||||||
|
itemStat, found := it.FindStat(stat.ID(statData[0]), layer)
|
||||||
|
if found {
|
||||||
stage2Props[statName] = itemStat.Value
|
stage2Props[statName] = itemStat.Value
|
||||||
|
} else if isResistSum && hasAnyResist {
|
||||||
|
// Only default to 0 for resist sums if we found at least one resist
|
||||||
|
stage2Props[statName] = 0
|
||||||
|
} else {
|
||||||
|
return RuleResultNoMatch, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := expr.Run(r.stage2, stage2Props)
|
res, err := expr.Run(r.stage2, stage2Props)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return RuleResultNoMatch, fmt.Errorf("error evaluating rule: %w", err)
|
return RuleResultNoMatch, fmt.Errorf("error evaluating rule: %w", err)
|
||||||
}
|
}
|
||||||
stage2Result = res.(bool)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 100% rule match, we can return here
|
// 100% rule match, we can return here
|
||||||
if stage1Result.(bool) && stage2Result {
|
if res.(bool) {
|
||||||
return RuleResultFullMatch, nil
|
return RuleResultFullMatch, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// If Stage 1 matches and the item is NOT identified, let's return a partial match, we can not be 100% sure if all the stats are matching
|
|
||||||
if stage1Result.(bool) && !it.Identified {
|
|
||||||
return RuleResultPartial, nil
|
|
||||||
}
|
|
||||||
return RuleResultNoMatch, nil
|
return RuleResultNoMatch, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user