Index: addresses.lua =================================================================== --- addresses.lua (revision 476) +++ addresses.lua (working copy) @@ -46,4 +46,32 @@ staticbase_macro = 0x9FEE3C, staticpattern_char = 0x63B024, staticpattern_macro = 0x7440B5, + -- Start of new memory tables addresses and offsets + staticInventory = 0x9B8948, + staticEquipBase = 0x9ABABC, + tablesBase = 0x9CC224, + tablesBaseOffset = 0x28, + tableStartPtrOffset = 0x124, + tableDataStartPtrOffset = 0x28, + idOffset = 0xC, + qualityBaseOffset = 0x40, + qualityTierOffset = 0x16, + amountOffset = 0x10, + itemInfoOffset = 0x10, + skillsBase = 0x9C58E0, + idCardNPCOffset = 0x364, + qualityBaseOffset = 0x40, + qualityTierOffset = 0x16, + itemCountOffset = 0x10, + durabilityOffset = 0x18, + valueOffset = 0x34, + nameOffset = 0xC, + inUseOffset = 0x1C, + maxStackOffset = 0x1C, + boundStatusOffset = 0x40, + requiredLevelOffset = 0x58, + typeOffset = 0x78, -- Not quite sure about this one but seems to fit, 2 is for consumables + realItemIdOffset = 0x98, + coolDownOffset = 0xE8, + moneyPtr = 0x9BB91C, } Index: classes/EquipItem.lua =================================================================== --- classes/EquipItem.lua (revision 0) +++ classes/EquipItem.lua (revision 0) @@ -0,0 +1,126 @@ +local proc = getProc(); + +CEquipItem = class( + function( self, slot ) + self.Address = addresses.staticEquipBase + ( ( slot - 1 ) * 68 ); + self.BaseItemAddress = nil; + self.Empty = true; + self.Id = 0; + self.Slot = slot; + self.Name = ""; + self.ItemCount = 0; -- I'll keep this for consumables like arrows + self.Color = "ffffff"; + self.ItemLink = "|Hitem:33BF1|h|cff0000ff[Empty]|r|h"; + self.Durability = 0; + self.MaxDurabilty = 0; + self.Quality = 0; -- 0 = white / 1 = green / 2 = blue / 3 = purple / 4 = orange / 5 = gold + self.Value = 0; + self.Worth = 0; + self.Bound = false; -- 1 = no, 2 = bound + self.RequiredLvl = 0; + self.MaxStack = 0; + + if ( self.Address ~= nil and self.Address ~= 0 ) then + self:update(); + end; + end +); + +function CEquipItem:update() + local oldId = self.Id; + self.Id = memoryReadInt( proc, self.Address ); + -- printf( "Address: %X\ID: %d\n", self.Address, self.Id ); + + if self.Id ~= oldId and self.Id ~= 0 then + local nameAddress; + self.BaseItemAddress = GetItemAddress( self.Id ); + -- printf( "Base item address: %X\tID: %d\n", self.BaseItemAddress, self.Id ); + self.Name = ""; + self.Empty = false; + self.ItemCount = memoryReadInt( proc, self.Address + addresses.itemCountOffset ); + self.Durability = memoryReadInt( proc, self.Address + addresses.durabilityOffset ); + if ( self.Durability > 0 ) then + self.Durability = self.Durability / 100; + end; + self.InUse = memoryReadInt( proc, self.Address + addresses.inUseOffset ) ~= 0; + self.BoundStatus = memoryReadInt( proc, self.Address + addresses.boundStatusOffset ); + local plusQuality = memoryReadByte( proc, self.Address + addresses.qualityTierOffset ); + local quality, tier = math.modf ( plusQuality / 16 ); + tier = tier * 16; + -- printf( "Quality: %X\tTier: %X\n", quality, tier ); + if ( quality > 0 ) then + self.Quality = self.Quality + ( quality / 2 ); + end; + self.Color = ITEMCOLOR[ self.Quality + 1 ]; + + self.ItemLink = string.format( "|Hitem:%x|h|c%x[%s]|r|h", self.Id, self.Color or 0xffffffff, self.Name ); + + if ( self.BaseItemAddress ~= nil and self.BaseItemAddress ~= 0 ) then + nameAddress = memoryReadInt( proc, self.BaseItemAddress + addresses.nameOffset ); + if( nameAddress == nil or nameAddress == 0 ) then + tmp = nil; + else + tmp = memoryReadString(proc, nameAddress); + end; + + if tmp ~= nil then + self.Name = self.Name .. tmp; + else + self.Name = ""; + end; + + self.Value = memoryReadInt( proc, self.BaseItemAddress + addresses.valueOffset ); + if ( self.Value > 0 ) then + self.Worth = self.Value / 10; + end; + self.RequiredLvl = memoryReadInt( proc, self.BaseItemAddress + addresses.requiredLevelOffset ); + self.MaxStack = memoryReadInt( proc, self.BaseItemAddress + addresses.maxStackOffset ); + self.Quality = memoryReadInt( proc, self.BaseItemAddress + addresses.qualityBaseOffset ); + else + self.Name = ""; + end; + elseif ( self.Id == 0 ) then + self.Empty = true; + self.Id = 0; + self.Name = ""; + self.ItemCount = 0; + self.Color = "ffffff"; + self.ItemLink = "|Hitem:33BF1|h|cff0000ff[Empty]|r|h"; + self.Durability = 0; + self.Quality = 0; -- 0 = white / 1 = green / 2 = blue / 3 = purple / 4 = orange / 5 = gold + self.Value = 0; + self.Worth = 0; + self.RequiredLvl = 0; + self.Bound = false; + else + -- if id is not 0 and hasn't changed we only update these values + self.ItemCount = memoryReadInt( proc, self.Address + addresses.itemCountOffset ); + self.Durability = memoryReadInt( proc, self.Address + addresses.durabilityOffset ); + if ( self.Durability > 0 ) then + self.Durability = self.Durability / 100; + end; + self.InUse = memoryReadInt( proc, self.Address + addresses.inUseOffset ) ~= 0; + end; + + if( settings.profile.options.DEBUG_INV ) then + if ( self.Empty ) then + printf( "Slot: %d .\n", self.Slot ); + else + local _color = cli.white; + printf( "Slot: %d\tcontains: %d\t (%d) ", self.Slot, self.ItemCount, self.Id ); + if ( self.Quality == 1 ) then + _color = cli.lightgreen; + elseif ( self.Quality == 2 ) then + _color = cli.blue; + elseif ( self.Quality == 3 ) then + _color = cli.purple; + elseif ( self.Quality == 4 ) then + _color = cli.yellow; + elseif ( self.Quality == 5 ) then + _color = cli.forestgreen; + end; + cprintf( _color, "[%s]", self.Name ); + printf( "\tDura: %d\n", self.Durability ); + end; + end; +end \ No newline at end of file Index: classes/inventory.lua =================================================================== --- classes/inventory.lua (revision 476) +++ classes/inventory.lua (working copy) @@ -1,75 +1,114 @@ +include("MemoryTable.lua"); include("item.lua"); +include("EquipItem.lua"); +local proc = getProc(); CInventory = class( function (self) - self.BagSlot = {} + local _bagId = 61; + self.BagSlot = {}; + self.EquipSlots = {}; + self.Money = memoryReadInt( proc, addresses.moneyPtr ); + + if( settings.profile.options.DEBUG_INV ) then + printf( "We gonna update: %d slots.\n", settings.profile.options.INV_MAX_SLOTS ); + end; + + local timeStart = getTime(); + for slotNumber = 1, settings.profile.options.INV_MAX_SLOTS, 1 do - self.BagSlot[slotNumber] = CItem(slotNumber); + self.BagSlot[slotNumber] = CItem( _bagId ); + _bagId = _bagId + 1; end - self.NextItemToUpdate = 1; + if( settings.profile.options.DEBUG_INV ) then + printf( "Inventory update took: %d\n", deltaTime( getTime(), timeStart ) ); + end; + for slotNumber = 1, 22, 1 do + self.EquipSlots[slotNumber] = CEquipItem( slotNumber ); + end + + self.NextItemToUpdate = 1; end -) +); +function CInventory:update() +-- if( settings.profile.options.DEBUG_INV ) then +-- printf( "We gonna update: %d slots.\n", settings.profile.options.INV_MAX_SLOTS ); +-- end; -function CInventory:getAmmunitionCount() - local count = RoMScript("GetInventoryItemCount('player', 9);"); - if count == nil then - count = 0; + local timeStart = getTime(); + + self.Money = memoryReadInt( proc, addresses.moneyPtr ); + + for slotNumber = 1, settings.profile.options.INV_MAX_SLOTS, 1 do + self.BagSlot[slotNumber]:update(); end - return count; -end - --- return is true or false. false if there was no ammunition in the bag, type is "thrown" or "arrow" -function CInventory:reloadAmmunition(type) - item = self:bestAvailableConsumable(type); - -- if theres no ammunition, open a ammunition bag - if not item then - if type == "arrow" then - openItem = self:bestAvailableConsumable("arrow_quiver"); - elseif type == "thrown" then - openItem = self:bestAvailableConsumable("thrown_bag"); - end - - if not openItem then - return false; - end +-- if( settings.profile.options.DEBUG_INV ) then + printf( "Inventory update took: %d\n", deltaTime( getTime(), timeStart ) ); + printf( "You have: %d gold.\n", self.Money ); +-- end; +end; - local unused,unused,checkItemName = RoMScript("GetBagItemInfo(" .. openItem.SlotNumber .. ")"); - yrest(200); - self:update(); - item = self:bestAvailableConsumable("arrow"); - if( item and checkItemName ~= item.Name ) then - cprintf(cli.yellow, language[18], tostring(checkItemName), tostring(item.Name)); - openItem:update(); - else - openItem:use(); - end - - -- after opening, update the inventory (this takes about 10 sec) - self:update(); - - item = self:bestAvailableConsumable(type); +function CInventory:updateEquipment() +-- if( settings.profile.options.DEBUG_INV ) then +-- printf( "We gonna update: %d slots.\n", settings.profile.options.INV_MAX_SLOTS ); +-- end; + + local timeStart = getTime(); + + for slotNumber = 1, settings.profile.options.INV_MAX_SLOTS, 1 do + self.EquipSlots[slotNumber]:update(); end + +-- if( settings.profile.options.DEBUG_INV ) then + printf( "Equipment update took: %d\n", deltaTime( getTime(), timeStart ) ); +-- end; +end; + +-- Here for compatibility reasons +function CInventory:getItemCount(itemId) + if(itemId == nil) then + cprintf(cli.yellow, "Inventory:getItemCount with itemId=nil, please (do not) inform the developers.\n" ); + return 0; + end + + return self:itemTotalCount( itemId ); +end; + +-- No longer uses cached information, it updates before checking +function CInventory:itemTotalCount(itemNameOrId) + self:update(); - if item then - -- use it - local unused,unused,checkItemName = RoMScript("GetBagItemInfo(" .. item.SlotNumber .. ")"); - if( checkItemName ~= item.Name ) then - cprintf(cli.yellow, language[18], tostring(checkItemName), tostring(item.Name)); - item:update(); - else + totalCount = 0; + for slot,item in pairs(self.BagSlot) do + if item.Id == itemNameOrId or item.Name == itemNameOrId then + totalCount = totalCount + item.ItemCount; + end; + end; + + return totalCount; +end; + +function CInventory:useItem(itemNameOrId) + self:update(); + + for slot,item in pairs( self.BagSlot ) do + if item.Id == itemNameOrId or item.Name == itemNameOrId then item:use(); - end - end -end + return true, item.Id, item.Name; + end; + end; + + return false; +end; -function CInventory:isEquipped(__space) +function CInventory:isEquipped( __space ) -- return true if equipped is equipped at slot and has durability > 0 - local slot = 11;-- Automatically set slot to 16/MainHand + local slot = 16;-- Automatically set slot to 16/MainHand _space = string.lower(__space); if ( type(_space) ~= "string" ) then @@ -118,62 +157,46 @@ slot = 20; -- first slot under necklace next to shoulder elseif (_space == "talisman3") then slot = 21; -- first slot under talisman2 next to gloves - end + elseif (_space == "wings") then + slot = 22; + end; - local durability, durabilityMax, itemName = RoMScript("GetInventoryItemDurable('player',"..slot..");"); - - -- prevent aritmetic on a nil value if RoMScript failed/wrong values come back - if( type(durability) ~= "number" or - type(durabilityMax) ~= "number" or - durabilityMax == 0 or - type(itemName) ~= "string" ) then - return false; - end - - local realDurability = tonumber(durability)/tonumber(durabilityMax)*100; + self.EquipSlots[ slot ]:update(); - if( type(realDurability) ~= "number" or - realDurability < 0 ) then + if( self.EquipSlots[ slot ].Empty ) then return false; - end + end; - return true; + local realDurability = self.EquipSlots[ slot ].Durability / self.EquipSlots[ slot ].MaxDurabilty * 100; -end + if( realDurability <= 0 ) then + return false; + end; + + return true; +end; -function CInventory:getDurability(_slot) --- return item durability for a given slot in percent from 0 - 100 +function CInventory:getDurability( _slot ) + -- return item durability for a given slot in percent from 0 - 100 - if( not _slot) then _slot = 15; end -- 15=MainHand | 16=OffHand | 10=Ranged - - local durability, durabilityMax = RoMScript("GetInventoryItemDurable('player',".._slot..");"); - - -- prevent aritmetic on a nil value if RoMScript failed/wrong values come back - if( type(durability) ~= "number" or - type(durabilityMax) ~= "number" - or durabilityMax == 0) then - return 100; - end - - return tonumber(durability)/tonumber(durabilityMax)*100; + if( not _slot) then _slot = 16; end -- 16=MainHand | 17=OffHand | 11=Ranged -end + self.EquipSlots[ _slot ]:update(); + + return self.EquipSlots[ _slot ].Durability / self.EquipSlots[ _slot ].MaxDurabilty * 100; +end; - - function CInventory:getMainHandDurability() --- return values between 0 - 1 for combatibility reasons + -- return values between 0 - 1 for compatibility reasons + return inventory:getDurability( 16 ) / 100; -- 16=Main Hand +end; - return inventory:getDurability(15) / 100; -- 15=Main Hand - -end - -- Make a full update -- or update slot 1 to _maxslot -function CInventory:update(_maxslot) +function CInventory:update( _maxslot ) if( not _maxslot ) then _maxslot = settings.profile.options.INV_MAX_SLOTS; end; - printf(language[1000], _maxslot); -- Updating + -- printf(language[1000], _maxslot); -- Updating keyboardSetDelay(0); for slotNumber = 1, _maxslot, 1 do @@ -185,14 +208,12 @@ printf("\n"); keyboardSetDelay(50); - player.InventoryDoUpdate = false; -- set back update trigger - player.InventoryLastUpdate = os.time(); -- remember update time + -- player.InventoryDoUpdate = false; -- set back update trigger + -- player.InventoryLastUpdate = os.time(); -- remember update time - --cprintf(cli.green, language[1002], settings.profile.options.INV_UPDATE_INTERVAL ); -- inventory update not later then - -end + --cprintf(cli.green, language[1002], settings.profile.options.INV_UPDATE_INTERVAL ); -- inventory update not later then +end; - -- update x slots until given time in ms is gone function CInventory:updateSlotsByTime(_ms) local start_update = getTime(); @@ -229,44 +250,11 @@ self.NextItemToUpdate = self.NextItemToUpdate + 1; if (self.NextItemToUpdate > settings.profile.options.INV_MAX_SLOTS) then self.NextItemToUpdate = 1; - end + end; - end - -end + end; +end; --- uses romscript, its -function CInventory:getItemCount(itemId) - if(itemId == nil) then - cprintf(cli.yellow, "Inventory:getItemCount with itemId=nil, please (do not) inform the developers.\n" ); - return 0; - end - - itemCount = RoMScript("GetBagItemCount("..itemId..")"); - return tonumber(itemCount); -end - --- uses pre existing information -function CInventory:itemTotalCount(itemNameOrId) - totalCount = 0; - for slot,item in pairs(self.BagSlot) do - if item.Id == itemNameOrId or item.Name == itemNameOrId then - totalCount = totalCount+item.ItemCount; - end - end - return totalCount; -end - -function CInventory:useItem(itemNameOrId) - for slot,item in pairs(self.BagSlot) do - if item.Id == itemNameOrId or item.Name == itemNameOrId then - item:use(); - return true, item.Id, item.Name; - end - end - return false -end - -- Returns item name or false, takes in type, example: "healing" or "mana" or "arrow" or "thrown" function CInventory:bestAvailableConsumable(type) local bestLevel = 0; -- required player level of a potion Index: classes/item.lua =================================================================== --- classes/item.lua (revision 476) +++ classes/item.lua (working copy) @@ -1,4 +1,4 @@ --- A little class +local proc = getProc(); -- Tooltip parser keywords ITEM_TOOLTIP_DURABILITY = { @@ -22,44 +22,75 @@ GOLD = tonumber("0xFFA37D50"), }; +-- making a new one because i dont know if the other is used elsewhere +ITEMQUALITYCOLOR = { + tonumber("0xFFFFFFFF"), + tonumber("0xFF00FF00"), + tonumber("0xFF0072BC"), + tonumber("0xFFA864A8"), + tonumber("0xFFF68E56"), + tonumber("0xFFA37D50"), + 0, + 0, + tonumber("0xFFA864A8"), +}; + CItem = class( - function(self,slotNumber) + function( self, bagId ) + self.Address = addresses.staticInventory + ( ( bagId - 61 ) * 68 ); + self.BaseItemAddress = nil; + self.Empty = true; self.Id = 0; - self.BagId = 0; - self.Name = ""; + self.BagId = bagId; + self.Name = ""; self.ItemCount = 0; self.Color = "ffffff"; - self.SlotNumber = slotNumber; + self.SlotNumber = -1; -- No idea how to get this one, i think is not used, at least not in inventory... self.Icon = ""; self.ItemLink = "|Hitem:33BF1|h|cff0000ff[Empty]|r|h"; + self.Durability = 0; + self.Quality = 0; -- 0 = white / 1 = green / 2 = blue / 3 = purple / 4 = orange / 5 = gold + self.Value = 0; + self.Worth = 0; + self.InUse = false; + self.BoundStatus = 1; -- 0 = pick, 1 = no, 2 = bound 3 = equip + self.RequiredLvl = 0; + self.CoolDownTime = 0; + self.LastTimeUsed = 0; + self.MaxStack = 0; + self.ObjType = 0; + + if ( self.Address ~= nil and self.Address ~= 0 ) then + self:update(); + end; end -) +); function CItem:use() - - -- TODO: because client is to slow to notice the use in time, we reduce it by hand - -- after we use it / we will have to check that if we also use other things - -- that are not consumable like mounts, armor + local canUse = true; self:update(); - -- TODO: avoid some unclear bug / should be solved if we really clear empty slots - -- or if we update fast enough? - if( self.BagId == nil ) then - cprintf(cli.yellow, "Empty BagId, that should not happen!\n" ); - return 0; - end + -- If the item can't be used now we should be able to set a timer or something like that to recall this function and check again... + if not self.InUse then + if ( self.CoolDownTime > 0 and ( deltaTime( getTime(), self.LastTimeUsed ) / 1000 ) < self.CoolDownTime ) then -- Item is on CoolDown we can't use it + canUse = false; + end; + else -- Item is in use, locked, we can't use it + canUse = false; + end; + + if ( canUse ) then + RoMScript("UseBagItem("..self.BagId..");"); + self.LastTimeUsed = getTime(); + end; - RoMScript("UseBagItem("..self.BagId..");"); + self:update(); - if (database.consumables[self.Id]) then -- is in consumable database? / could be reduced - self.ItemCount = self.ItemCount - 1; + if ( settings.profile.options.DEBUG_INV ) then + cprintf( cli.lightblue, "DEBUG - Use Item BagId: #%s ItemCount: %s\n", self.BagId, self.ItemCount ); -- Open/eqipt item: end; - if( settings.profile.options.DEBUG_INV) then - cprintf(cli.lightblue, "DEBUG - Use Item BagId: #%s ItemCount: %s\n", self.BagId, self.ItemCount ); -- Open/eqipt item: - end; - return self.ItemCount; end @@ -76,7 +107,132 @@ end function CItem:update() + local nameAddress; + local oldId = self.Id; + self.Id = memoryReadInt( proc, self.Address ) or 0; + + if ( self.Id ~= nil and self.Id ~= oldId and self.Id ~= 0 ) then + self.BaseItemAddress = GetItemAddress( self.Id ); + if ( self.BaseItemAddress == nil or self.BaseItemAddress == 0 ) then + cprintf( cli.yellow, "Wrong value returned in update of item id: %d\n", self.Id ); + return; + end; + + self.Name = ""; + self.Empty = false; + self.ItemCount = memoryReadInt( proc, self.Address + addresses.itemCountOffset ); + self.Durability = memoryReadInt( proc, self.Address + addresses.durabilityOffset ); + if ( self.Durability > 0 ) then + self.Durability = self.Durability / 100; + end; + self.Value = memoryReadInt( proc, self.BaseItemAddress + addresses.valueOffset ); + if ( self.Value > 0 ) then + self.Worth = self.Value / 10; + end; + self.InUse = memoryReadInt( proc, self.Address + addresses.inUseOffset ) ~= 0; + self.BoundStatus = memoryReadInt( proc, self.Address + addresses.boundStatusOffset ); + self.RequiredLvl = memoryReadInt( proc, self.BaseItemAddress + addresses.requiredLevelOffset ); + self.MaxStack = memoryReadInt( proc, self.BaseItemAddress + addresses.maxStackOffset ); + self.ObjType = memoryReadInt( proc, self.BaseItemAddress + addresses.typeOffset ); + + if ( self.ObjType == 2 ) then -- Consumables, lets try to get CD time + local skillItemId = memoryReadInt( proc, self.BaseItemAddress + addresses.realItemIdOffset ); + if ( skillItemId ~= nil and skillItemId ~= 0 ) then + local skillItemAddress = GetItemAddress( skillItemId ); + if ( skillItemAddress ~= nil and skillItemAddress ~= 0 ) then + self.CoolDownTime = memoryReadInt( proc, skillItemAddress + addresses.coolDownOffset ); + end; + end; + -- cprintf( cli.yellow, "Cool down for consumable: %d\n", self.CoolDownTime ); + end; + + -- Special case for cards + if ( self.Id >= 770000 and self.Id <= 771000 ) then + -- We need to get info from NPC... + tmp = memoryReadInt( proc, self.BaseItemAddress + addresses.idCardNPCOffset ); + npcInfoAddress = GetItemAddress( tmp ); + nameAddress = memoryReadInt( proc, npcInfoAddress + addresses.nameOffset ); + self.Name = "Card - "; -- We should add a string so we can localize this + else + nameAddress = memoryReadInt( proc, self.BaseItemAddress + addresses.nameOffset ); + end; + if( nameAddress == nil or nameAddress == 0 ) then + tmp = nil; + else + tmp = memoryReadString(proc, nameAddress); + end; + + if tmp ~= nil then + self.Name = self.Name .. tmp; + else + self.Name = ""; + end; + + self.Quality = memoryReadInt( proc, self.BaseItemAddress + addresses.qualityBaseOffset ); + local plusQuality = memoryReadByte( proc, self.Address + addresses.qualityTierOffset ); + local quality, tier = math.modf ( plusQuality / 16 ); + -- tier = tier * 16; -- Tier not really used yet... + if ( quality > 0 ) then + self.Quality = self.Quality + ( quality / 2 ); + end; + + -- Assign color based on quality + self.Color = ITEMQUALITYCOLOR[ self.Quality + 1 ]; + + -- Build an usable ItemLink + self.ItemLink = string.format( "|Hitem:%x|h|c%x[%s]|r|h", self.Id, self.Color, self.Name ); + elseif ( self.Id == 0 ) then + self.Empty = true; + self.Id = 0; + self.Name = ""; + self.ItemCount = 0; + self.Color = "ffffff"; + self.SlotNumber = -1; + self.Icon = ""; + self.ItemLink = "|Hitem:33BF1|h|cff0000ff[Empty]|r|h"; + self.Durability = 0; + self.Quality = 0; -- 0 = white / 1 = green / 2 = blue / 3 = purple / 4 = orange / 5 = gold + self.Value = 0; + self.Worth = 0; + self.InUse = false; + self.RequiredLvl = 0; + else + -- if id is not 0 and hasn't changed we only update these values + self.ItemCount = memoryReadInt( proc, self.Address + addresses.itemCountOffset ); + self.Durability = memoryReadInt( proc, self.Address + addresses.durabilityOffset ); + if ( self.Durability > 0 ) then + self.Durability = self.Durability / 100; + end; + self.InUse = memoryReadInt( proc, self.Address + addresses.inUseOffset ) ~= 0; + self.BoundStatus = memoryReadInt( proc, self.BaseItemAddress + addresses.boundStatusOffset ); + end; + + if( settings.profile.options.DEBUG_INV ) then + if ( self.Empty ) then + printf( "BagID: %d is .\n", self.BagId ); + else + local _color = cli.white; + printf( "BagID: %d\tcontains: %d\t (%d) ", self.BagId, self.ItemCount, self.Id ); + if ( self.Quality == 1 ) then + _color = cli.lightgreen; + end; + if ( self.Quality == 2 ) then + _color = cli.blue; + end; + if ( self.Quality == 3 ) then + _color = cli.purple; + end; + if ( self.Quality == 4 ) then + _color = cli.yellow; + end; + if ( self.Quality == 5 ) then + _color = cli.forestgreen; + end; + cprintf( _color, "[%s]\n", self.Name ); + end; + end; +--[[ -- local old_BagId = self.BagId; -- remember bagId before update local itemLink, bagId, icon, name, itemCount = RoMScript("GetBagItemLink(GetBagItemInfo("..self.SlotNumber..")),GetBagItemInfo("..self.SlotNumber..")"); local id, color; @@ -125,7 +281,7 @@ cprintf(cli.lightblue, "%s\n", msg); -- Open/eqipt item: end; - +]]-- end -- Parse from |Hitem:33BF1|h|cff0000ff[eeppine ase]|r|h Index: classes/MemoryTable.lua =================================================================== --- classes/MemoryTable.lua (revision 0) +++ classes/MemoryTable.lua (revision 0) @@ -0,0 +1,358 @@ + include(".../addresses.lua"); + include(".../functions.lua"); + +local tablePointer; +local endTablePointer; +local itemSize = 32; +local proc = getProc(); +local tables = {}; + +-- Internal debuging use only... +local debugTableIndexes = false; +local debugTableRanges = false; + +CTRange = class( + function(self, _start, _end, startAddress) + self.Start = _start; + self.End = _end; + self.StartAddress = startAddress; + end +); + + +CTDef = class( + function (self, ptr) + self.Address = ptr; + self.EnAddress = 0; + self.StartId = 0; + self.EndId = 0; + self.Name = ""; + self.Ranges = {}; + + if( self.Address ~= nil and self.Address ~= 0 ) then self:Update(); end; + end +); + +function CTDef:Update() + self.StartId = memoryReadInt(proc, self.Address + addresses.idOffset ); + if ( self.StartId > 800000 ) then -- Special case for one table that starts 32 bytes before... + self.Address = self.Address - 32; + self.StartId = memoryReadInt(proc, self.Address + addresses.idOffset ); + end; + self.EndId = 0; + local lastId = self.StartId; + local currId; + local lastStartId = self.StartId; + local lastStartDir = self.Address; + local currItemDir = self.Address; + local lastItemDir = self.Address; + + if ( debugTableIndexes ) then + printf("Table starts with id: %d\t\t Dir: %X\n", self.StartId, self.Address); + end; + + while ( lastId ~= nil and lastId ~= 0 ) do + currItemDir = currItemDir - itemSize; -- We move itemSize bytes up to go to next one + currId = memoryReadInt(proc, currItemDir + addresses.idOffset ); -- 12 bytes offset id object + + if ( currId == nil or currId == 0 or ( ( currId > ( lastId + 3 ) ) or ( currId < ( lastId - 3 ) ) ) ) then + -- Fiors we add the recently found range if its needed... + local found = false; + for _, _table in ipairs(tables) do + if ( lastStartId >= _table.StartId and lastId <= _table.EndId ) then + found = true; + break; + end; + end; + for _, _range in ipairs(self.Ranges) do + if ( lastStartId >= _range.Start and lastId <= _range.End ) then + found = true; + break; + end; + end; + + if ( (lastId and not self.EndId) or self.EndId < lastId ) then + self.EndId = lastId; + end; + + if ( found == false ) then + -- We dind't find any more ids in range, add this one to the table + table.insert(self.Ranges, CTRange(lastStartId, lastId, lastStartDir)); + if ( debugTableRanges ) then + cprintf( cli.yellow, "Adding range. Start: %d\tEnd: %d\tAddress: %X\tTable#: %d\n", lastStartId, lastId, lastStartDir, #tables ); + end; + end; + + currItemDir = GetNextTableAddress( lastItemDir ); + + if ( currItemDir ~= nil ) then + currId = memoryReadInt(proc, currItemDir + addresses.idOffset ); -- 12 bytes offset object id + if ( currId == nil or currId == 0 or ( ( currId > ( lastId + 3 ) ) or ( currId < ( lastId - 3 ) ) ) ) then + -- no more ids for current table + break; + else + self.EndId = currId; + lastStartId = currId; + lastStartDir = currItemDir; + end; + else + break; + end; + end; + + if ( currId and currItemDir and self.StartId > currId ) then + lastStartId = currId; + lastStartDir = currItemDir; + self.StartId = currId; + self.Address = currItemDir; + end; + + lastId = currId; + lastItemDir = currItemDir; + end; +end; + +function GetTablesPointers() + local tablePointerDir = memoryReadIntPtr( proc, addresses.tablesBase, addresses.tablesBaseOffset ); + tablePointer = tablePointerDir; + endTablePointer = memoryReadInt(proc, tablePointerDir + 0x4); + -- cprintf(cli.yellow, "Tables dir: %x \t Final: %X\n\n\n", tablePointer, endTablePointer); +end; + +function GetNextTableAddress( ptr ) + local threshold = 25; -- We look back a maximum of 25 items to check if the table continues + local _address; + local lastId = memoryReadInt( proc, ptr + addresses.idOffset ); -- 12 bytes offset id + local found = true; + local tmpID; + + local function IdIsInRange( newId, _threshold ) + if ( newId == nil ) then + return false; + end; + if ( _threshold == nil ) then + _threshold = threshold; + end; + if ( newId > lastId and newId < ( lastId + threshold ) ) then + return true; + end; + + return false; + end; + + local function CheckAddress( addressToCheck ) + local tmp = memoryReadInt( proc, addressToCheck + 0x4 ); + + tmpOffset = memoryReadInt( proc, tmp ); + tmpOffset4 = memoryReadInt( proc, tmp + 0x4 ); + tmpID = memoryReadInt( proc, tmp + addresses.idOffset ); + + if debugTableIndexes then + cprintf( cli.green, "Readed from %X\t at 0x4 %X\tOriginal pointer: %X\n", addressToCheck, tmp, ptr ); + if tmpOffset ~= addressToCheck and tmpOffset4 ~= addressToCheck then + printf( cli.red, "Offset at 0x0 points to: %X\tOffset at 0x4 points to: %X\n", tmpOffset or 0, tmpOffset4 or 0 ); + end; + end; + + if ( tmp ~= nil and ( tmp ~= addressToCheck and tmp ~= ptr ) and ( tmpOffset == addressToCheck or tmpOffset4 == addressToCheck ) and IdIsInRange( tmpID ) ) then + if debugTableIndexes then + cprintf( cli.lightblue, "Returning: %X\n", tmp ); + end; + return tmp; + else + tmp = memoryReadInt( proc, addressToCheck + 0x8 ); + + tmpOffset = memoryReadInt( proc, tmp ); + tmpOffset4 = memoryReadInt( proc, tmp + 0x4 ); + tmpID = memoryReadInt( proc, tmp + addresses.idOffset ); + + if debugTableIndexes then + cprintf( cli.green, "Readed at %X\t in 0x8 %X\tID: %d\n", addressToCheck, tmp, tmpID or 0 ); + if tmpOffset ~= addressToCheck and tmpOffset4 ~= addressToCheck then + printf( cli.red, "Offset at 0x0 points to: %X\tOffset at 0x4 points to: %X\n", tmpOffset or 0, tmpOffset4 or 0 ); + end; + end; + + if ( tmp ~= nil and ( tmp ~= addressToCheck and tmp ~= ptr ) and ( tmpOffset == addressToCheck or tmpOffset4 == addressToCheck ) and IdIsInRange( tmpID ) ) then + if debugTableIndexes then + cprintf( cli.lightblue, "Returning: %X\n", tmp ); + end; + return tmp; + end + end; + + if debugTableIndexes then + cprintf( cli.turquoise, "Returning NIL\n" ); + end; + return nil; + end; + + _address = CheckAddress( ptr ); + + if _address == nil then -- Lets try to find an addres backwards + found = false; + for i = 1, threshold do + _address = CheckAddress( ( ptr + ( i * itemSize ) ) ); + if _address ~= nil then + found = true; + break; + end; -- found a match + end; + end + + --[[ + -- Here offsets seem to vary, in some tables you get the next dir in 0x4 and in others in 0x8, should be a pattern but didn't find it yet... + _address = memoryReadInt( proc, ptr + 0x4 ); + tmpID = memoryReadInt( proc, _address + addresses.idOffset ); -- 12 bytes offset id + + if _address == nil or ( memoryReadInt( proc, _address + 0x4 ) ~= ptr and memoryReadInt( proc, _address ) ~= ptr ) then + _address = memoryReadInt( proc, ptr + 0x8 ); + if _address == nil or ( memoryReadInt( proc, _address + 0x4 ) ~= ptr and memoryReadInt( proc, _address ) ~= ptr ) then + if debugTableIndexes then + print("Fail 1\n"); + end; + found = false; + for i = 1, 10 do -- 10 lines should be enough... + _address = memoryReadInt( proc, ( ptr + ( i * itemSize ) ) + 0x4 ); -- we go back one item to see if it fits the id we are looking for + tmpID = memoryReadInt( proc, _address + addresses.idOffset ); + if debugTableIndexes then + printf("Readed 1: %d\n", tmpID or 0); + end + if ( tmpID == lastId + 1 and _address ~= ptr ) then + -- We found it, we can exit and return the address. + found = true; + if debugTableIndexes then + print("Found by brute force.\n"); + end; + break; + end; + end; + if not found and debugTableIndexes then + print("Fail 2\n"); + end; + end; + end + ]]-- + + if found then -- we found the address now check if id is in the right range + tmpID = memoryReadInt( proc, _address + addresses.idOffset ); -- 12 bytes id offset + + if ( tmpID ~= ( lastId + 1 ) ) then + if debugTableIndexes then + print("Falla 3\n"); + printf("\rTenemos ID: %d\tEn dir: %X\n", lastId or 0, _address ); + end; + found = false; + for i = 1, threshold do -- 10 lines should be enough... + _address = _address + itemSize; -- we go back one item to see if it fits the id we are looking for + tmpID = memoryReadInt( proc, _address + addresses.idOffset ); -- 12 bytes offset del id + if debugTableIndexes then + printf("\rReaded 2: %d\n", tmpID or 0 ); + end; + if ( tmpID == ( lastId + 1 ) ) then + -- We found it, we can exit and return the address. + found = true; + if debugTableIndexes then + print("Found by brute force 2\n"); + end; + return _address; + end; + end; + end; + end; + + if not found then + _address = nil; + end; + + if debugTableIndexes then + cprintf( cli.red, "Received: %X\tReturning: %X\n" ,ptr, _address or 0 ); + end; + return _address; +end; + +function GetTableForID( id ) + + for _, _table in ipairs( tables ) do + if ( id >= _table.StartId and id <= _table.EndId ) then + return _table; + end; + end; + + printf( "Table not found for ID: %d\n", id ); + return nil; +end; + +function GetItemAddress( id ) + local _table = GetTableForID( id ); + local _address; + if _table ~= nil then + for _, _range in ipairs( _table.Ranges ) do + if ( id >= _range.Start and id <= _range.End ) then + tmp = id - _range.Start; + -- We substract 32 bytes (itemSize) multiplied by the the number that is the difference between the id we get and the range start + _address = _range.StartAddress - ( tmp * 32 ); + -- We check if this is the right one, there are mixed ids, don't know why i think is just instantiation of tables problem... + local tmpAddress = memoryReadIntPtr(proc, _address + 0x10, 0x8); + if ( id ~= memoryReadInt( proc, tmpAddress ) ) then + -- We search one after... + _address = _range.StartAddress - ( ( tmp - 1 ) * 32 ); + tmpAddress = memoryReadIntPtr(proc, _address + 0x10, 0x8); + if ( id ~= memoryReadInt( proc, tmpAddress ) ) then + -- We search one before... + _address = _range.StartAddress - ( ( tmp + 1 ) * 32 ); + tmpAddress = memoryReadIntPtr(proc, _address + 0x10, 0x8); + if ( id ~= memoryReadInt( proc, tmpAddress ) ) then + -- Couldn't find it, we give up... + _address = nil; + end; + end; + end; + end; + end; + end; + if ( _address ~= nil ) then + _address = memoryReadIntPtr( proc, _address + 0x10, 0x8 ); + end + return _address; +end; + +function LoadTables() + GetTablesPointers(); + + local realTablePointer = memoryReadInt(proc, tablePointer); + local punteroTablaDatos; + + if( not settings.profile.options.DEBUG_INV ) then + cprintf( cli.yellow, "Loading items tables.\n" ); + end; + + local i = 0; + while ( i < 28 ) do + local name = memoryReadString( proc, realTablePointer + 38 ); -- This isn't really necessary but is here for debuging purposes... + + if debugTableIndexes or debugTableRanges then + printf("Name: %s\n", name); + end; + + if( not settings.profile.options.DEBUG_INV ) then + displayProgressBar( ( i + 1 ) / 28 * 100, 50); + end; + + local dataPointerTemporal = memoryReadIntPtr( proc, realTablePointer, addresses.tableStartPtrOffset ); + if dataPointerTemporal ~= nil then + local dataPointer = memoryReadInt( proc, dataPointerTemporal + addresses.tableDataStartPtrOffset ); + -- We move up 32 bytes from the name line + dataPointer = dataPointer - itemSize; + local primerId = memoryReadInt( proc, dataPointer + addresses.idOffset ); -- 12 bytes offset del id de objeto + local _table = CTDef(dataPointer); + _table.Name = name; + table.insert( tables, _table); + end; + i = i + 1; + realTablePointer = memoryReadInt( proc, tablePointer + ( i * 4 ) ); + end; + print( "\n" ); +end; + +LoadTables(); \ No newline at end of file Index: classes/player.lua =================================================================== --- classes/player.lua (revision 476) +++ classes/player.lua (working copy) @@ -700,7 +700,10 @@ if( item ) then -- yrest(settings.profile.options.SKILL_USE_PRIOR); -- potions can be drunk before cast/skill is finished if self.Casting then self:waitTillCastingEnds() end -- wait if still casting minus undercut - local unused,unused,checkItemName = RoMScript("GetBagItemInfo(" .. item.SlotNumber .. ")"); + -- local unused,unused,checkItemName = RoMScript("GetBagItemInfo(" .. item.SlotNumber .. ")"); + -- I think this check here is useless now + local checkItemName = item.Name; + item:update(); if( checkItemName ~= item.Name ) then cprintf(cli.yellow, language[18], tostring(checkItemName), tostring(item.Name)); item:update(); @@ -1186,7 +1189,9 @@ inventory:updateSlotsByTime(settings.profile.options.LOOT_TIME + dist*15); end - looten(); + if target.Lootable then + looten(); + end; -- check for loot problems to give a noob mesassage self:update(); @@ -1199,7 +1204,7 @@ cprintf(cli.green, language[100]); -- We didn't move to the loot!? -- second loot try? - if( type(settings.profile.options.LOOT_AGAIN) == "number" and settings.profile.options.LOOT_AGAIN > 0 ) then + if( type(settings.profile.options.LOOT_AGAIN) == "number" and settings.profile.options.LOOT_AGAIN > 0 and target.Lootable ) then yrest(settings.profile.options.LOOT_AGAIN); looten(); -- try it again end