Linking Item.LevelReq to stat(92) stat.LevelRequire + nip parser, Upped item levelreq (#78)
* Linking Item.LevelReq to stat(92) stat.LevelRequire . Update nip parser * LevelReq for upgraded items LevelReq is now accurate for upgraded and double upgraded set/unique items Fixed an issue with levelreq not working with socketed jewels on items.
This commit is contained in:
@@ -346,8 +346,16 @@ func (gd *GameReader) Inventory(rawPlayerUnits RawPlayerUnits, hover data.HoverD
|
|||||||
|
|
||||||
// Process socket information
|
// Process socket information
|
||||||
if location == item.LocationSocket {
|
if location == item.LocationSocket {
|
||||||
// Set level requirement for socketed item
|
if itm.Desc().Code == "jew" {
|
||||||
if itm.Quality == item.QualityUnique {
|
// Base requirement for jewels
|
||||||
|
itm.LevelReq = item.Desc[itm.ID].RequiredLevel
|
||||||
|
|
||||||
|
// For magic/rare jewels, check affixes
|
||||||
|
if itm.Quality == item.QualityMagic || itm.Quality == item.QualityRare {
|
||||||
|
itm.LevelReq = updateMaxReqFromAffixes(itm.LevelReq, itm.Affixes)
|
||||||
|
}
|
||||||
|
// Rainbow facets
|
||||||
|
} else if itm.Quality == item.QualityUnique {
|
||||||
for _, uniqueInfo := range item.UniqueItems {
|
for _, uniqueInfo := range item.UniqueItems {
|
||||||
if uniqueInfo.Code == itm.Desc().Code {
|
if uniqueInfo.Code == itm.Desc().Code {
|
||||||
itm.LevelReq = uniqueInfo.LevelReq
|
itm.LevelReq = uniqueInfo.LevelReq
|
||||||
@@ -355,7 +363,7 @@ func (gd *GameReader) Inventory(rawPlayerUnits RawPlayerUnits, hover data.HoverD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Normal socketed items (like runes) just use base requirement
|
// Normal socketed items (runes,gems) just use base requirement
|
||||||
itm.LevelReq = item.Desc[itm.ID].RequiredLevel
|
itm.LevelReq = item.Desc[itm.ID].RequiredLevel
|
||||||
}
|
}
|
||||||
itemExtraData := uintptr(gd.Process.ReadUInt(unitDataPtr+0xA0, Uint64))
|
itemExtraData := uintptr(gd.Process.ReadUInt(unitDataPtr+0xA0, Uint64))
|
||||||
@@ -424,35 +432,21 @@ func (gd *GameReader) Inventory(rawPlayerUnits RawPlayerUnits, hover data.HoverD
|
|||||||
// Build final inventory
|
// Build final inventory
|
||||||
inventory.AllItems = make([]data.Item, len(allItems))
|
inventory.AllItems = make([]data.Item, len(allItems))
|
||||||
for i, itm := range allItems {
|
for i, itm := range allItems {
|
||||||
maxReq := item.Desc[itm.ID].RequiredLevel
|
baseDesc := item.Desc[itm.ID]
|
||||||
|
maxReq := calculateItemLevelReq(itm, baseDesc)
|
||||||
|
|
||||||
// Check unique/set level requirements
|
// Check magic/rare affixes
|
||||||
if itm.Quality == item.QualityUnique {
|
if itm.Identified && (itm.Quality == item.QualityMagic || itm.Quality == item.QualityRare) {
|
||||||
for _, uniqueInfo := range item.UniqueItems {
|
maxReq = updateMaxReqFromAffixes(maxReq, itm.Affixes)
|
||||||
if uniqueInfo.ID == int(itm.UniqueSetID) && itm.Identified {
|
|
||||||
if uniqueInfo.LevelReq > maxReq {
|
|
||||||
maxReq = uniqueInfo.LevelReq
|
|
||||||
}
|
|
||||||
itm.IdentifiedName = uniqueInfo.Name
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if itm.Quality == item.QualitySet {
|
|
||||||
for setItemName, setItemInfo := range item.SetItems {
|
|
||||||
if setItemInfo.ID == int(itm.UniqueSetID) && itm.Identified {
|
|
||||||
if setItemInfo.LevelReq > maxReq {
|
|
||||||
maxReq = setItemInfo.LevelReq
|
|
||||||
}
|
|
||||||
itm.IdentifiedName = string(setItemName)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check socketed items
|
// Check socketed items
|
||||||
for _, socketItem := range itm.Sockets {
|
for _, socketItem := range itm.Sockets {
|
||||||
if socketItem.LevelReq > maxReq {
|
socketBaseDesc := item.Desc[socketItem.ID]
|
||||||
maxReq = socketItem.LevelReq
|
socketReq := calculateItemLevelReq(&socketItem, socketBaseDesc)
|
||||||
|
|
||||||
|
if socketReq > maxReq {
|
||||||
|
maxReq = socketReq
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check affixes on magic socketed items
|
// Check affixes on magic socketed items
|
||||||
@@ -461,12 +455,14 @@ func (gd *GameReader) Inventory(rawPlayerUnits RawPlayerUnits, hover data.HoverD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check item's own affixes for magic/rare items
|
|
||||||
if itm.Identified && (itm.Quality == item.QualityMagic || itm.Quality == item.QualityRare) {
|
|
||||||
maxReq = updateMaxReqFromAffixes(maxReq, itm.Affixes)
|
|
||||||
}
|
|
||||||
|
|
||||||
itm.LevelReq = maxReq
|
itm.LevelReq = maxReq
|
||||||
|
// Update stat 92 (LevelRequire) so we can use with .nip
|
||||||
|
for it, s := range itm.Stats {
|
||||||
|
if s.ID == stat.LevelRequire {
|
||||||
|
itm.Stats[it].Value = maxReq
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
inventory.AllItems[i] = *itm
|
inventory.AllItems[i] = *itm
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -492,6 +488,15 @@ func (gd *GameReader) getItemStats(statsListExPtr uintptr) (stat.Stats, stat.Sta
|
|||||||
fullStats := gd.getStatsList(statsListExPtr + 0xA8)
|
fullStats := gd.getStatsList(statsListExPtr + 0xA8)
|
||||||
baseStats := gd.getStatsList(statsListExPtr + 0x30)
|
baseStats := gd.getStatsList(statsListExPtr + 0x30)
|
||||||
|
|
||||||
|
// Create empty LevelRequire stat .We will update it from inventory
|
||||||
|
if _, found := fullStats.FindStat(stat.LevelRequire, 0); !found {
|
||||||
|
fullStats = append(fullStats, stat.Data{
|
||||||
|
ID: stat.LevelRequire,
|
||||||
|
Value: 0,
|
||||||
|
Layer: 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Flags and last stat list pointers
|
// Flags and last stat list pointers
|
||||||
flags := gd.Process.ReadUInt(statsListExPtr+0x1C, Uint64)
|
flags := gd.Process.ReadUInt(statsListExPtr+0x1C, Uint64)
|
||||||
lastStatsList := uintptr(gd.Process.ReadUInt(statsListExPtr+0x90, Uint64))
|
lastStatsList := uintptr(gd.Process.ReadUInt(statsListExPtr+0x90, Uint64))
|
||||||
@@ -622,3 +627,70 @@ func updateMaxReqFromAffixes(currentMax int, affixes data.ItemAffixes) int {
|
|||||||
}
|
}
|
||||||
return maxReq
|
return maxReq
|
||||||
}
|
}
|
||||||
|
func calculateItemLevelReq(itm *data.Item, baseDesc item.Description) int {
|
||||||
|
// Start with base item's requirement
|
||||||
|
maxReq := baseDesc.RequiredLevel
|
||||||
|
|
||||||
|
if itm.Quality == item.QualityUnique || itm.Quality == item.QualitySet {
|
||||||
|
itemCode := baseDesc.Code
|
||||||
|
normalCode := baseDesc.NormalCode
|
||||||
|
exceptionalCode := baseDesc.UberCode
|
||||||
|
eliteCode := baseDesc.UltraCode
|
||||||
|
|
||||||
|
// Find the original item tier by looking up the unique/set item
|
||||||
|
var originalCode string
|
||||||
|
if itm.Quality == item.QualityUnique {
|
||||||
|
for _, uniqueInfo := range item.UniqueItems {
|
||||||
|
if uniqueInfo.ID == int(itm.UniqueSetID) {
|
||||||
|
originalCode = uniqueInfo.Code
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, setItemInfo := range item.SetItems {
|
||||||
|
if setItemInfo.ID == int(itm.UniqueSetID) {
|
||||||
|
originalCode = setItemInfo.Code
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if itemCode == eliteCode {
|
||||||
|
if originalCode == normalCode {
|
||||||
|
// Double upgraded: Normal -> Exceptional -> Elite
|
||||||
|
maxReq += 12 // +5 for exceptional, +7 for elite
|
||||||
|
} else if originalCode == exceptionalCode {
|
||||||
|
// Single upgraded: Exceptional -> Elite
|
||||||
|
maxReq += 7
|
||||||
|
}
|
||||||
|
} else if itemCode == exceptionalCode && originalCode == normalCode {
|
||||||
|
// Single upgraded: Normal -> Exceptional
|
||||||
|
maxReq += 5
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check unique/set specific level requirement
|
||||||
|
if itm.Identified {
|
||||||
|
if itm.Quality == item.QualityUnique {
|
||||||
|
for _, uniqueInfo := range item.UniqueItems {
|
||||||
|
if uniqueInfo.ID == int(itm.UniqueSetID) {
|
||||||
|
if uniqueInfo.LevelReq > maxReq {
|
||||||
|
maxReq = uniqueInfo.LevelReq
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // Set item
|
||||||
|
for _, setItemInfo := range item.SetItems {
|
||||||
|
if setItemInfo.ID == int(itm.UniqueSetID) {
|
||||||
|
if setItemInfo.LevelReq > maxReq {
|
||||||
|
maxReq = setItemInfo.LevelReq
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return maxReq
|
||||||
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
fixedPropsRegexp = regexp.MustCompile(`(\[(type|quality|class|name|flag|color|prefix|suffix|levelreq)]\s*(<=|<|>|>=|!=|==)\s*([a-zA-Z0-9]+))`)
|
fixedPropsRegexp = regexp.MustCompile(`(\[(type|quality|class|name|flag|color|prefix|suffix)]\s*(<=|<|>|>=|!=|==)\s*([a-zA-Z0-9]+))`)
|
||||||
statsRegexp = regexp.MustCompile(`\[(.*?)]`)
|
statsRegexp = regexp.MustCompile(`\[(.*?)]`)
|
||||||
maxQtyRegexp = regexp.MustCompile(`(\[maxquantity]\s*(<=|<|>|>=|!=|==)\s*([0-9]+))`)
|
maxQtyRegexp = regexp.MustCompile(`(\[maxquantity]\s*(<=|<|>|>=|!=|==)\s*([0-9]+))`)
|
||||||
)
|
)
|
||||||
@@ -169,8 +169,6 @@ func (r Rule) Evaluate(it data.Item) (RuleResult, error) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case "levelreq":
|
|
||||||
stage1Props["levelreq"] = it.LevelReq
|
|
||||||
case "color":
|
case "color":
|
||||||
// TODO: Not supported yet
|
// TODO: Not supported yet
|
||||||
}
|
}
|
||||||
@@ -238,7 +236,7 @@ func replaceStringPropertiesInStage1(stage1 string) (string, error) {
|
|||||||
replaceWith = strings.ReplaceAll(prop[0], prop[4], fmt.Sprintf("%d", item.GetIDByName(prop[4])))
|
replaceWith = strings.ReplaceAll(prop[0], prop[4], fmt.Sprintf("%d", item.GetIDByName(prop[4])))
|
||||||
case "flag":
|
case "flag":
|
||||||
replaceWith = strings.ReplaceAll(prop[0], prop[4], fmt.Sprintf("%d", 1))
|
replaceWith = strings.ReplaceAll(prop[0], prop[4], fmt.Sprintf("%d", 1))
|
||||||
case "prefix", "suffix", "levelreq":
|
case "prefix", "suffix":
|
||||||
// Handle prefix/suffix IDs and levelreq
|
// Handle prefix/suffix IDs and levelreq
|
||||||
replaceWith = strings.ReplaceAll(prop[0], prop[4], prop[4])
|
replaceWith = strings.ReplaceAll(prop[0], prop[4], prop[4])
|
||||||
case "color":
|
case "color":
|
||||||
|
|||||||
Reference in New Issue
Block a user