Thread Tools Display Modes
02/11/23, 03:02 AM   #1
Matoro342
Join Date: Feb 2023
Posts: 9
How do I get the ItemID of an item I hover over in my inventory?

Hello,

I am a rookie currently attempting to write what I've thus far dubbed 'Style Check', a simple add on that will utilize LibCharacterKnowledge to return a boolean on highlighted weapons/armor in the inventory if its motif/style has been unlocked, then show it in a tooltip.

Here's my plan so far:

1. Use a function to get the ItemID/ItemLink (not sure on the difference) from the currently hovered over item.
2. If it is a weapon or item, (is this just if (ItemID.ItemType == ITEMTYPE_ARMOR or ItemID.ItemType == ITEMTYPE_WEAPON)?) continue.
3. Extract the motif or style page from it. No idea how this is done.
4. Pass this motif/style page to LCK.GetItemKnowledgeForCharacter( item, server, charId ).
5. Append text based on the result of 4 to the end of the tooltip for these items that the motif/style is known or unknown. No idea how to do this either. Nobody seems to comment their code.... not that I would steal

For now, I am stuck on 1. I can't find a function or variable for getting the ItemID/Link of a hovered item.
Any help would be welcome! I'll share whatever crowns your time is worth if I can reach the finish line.

Warm regards and thank you for reading.
  Reply With Quote
02/11/23, 06:20 AM   #2
votan
 
votan's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2014
Posts: 577
Hi Matoro342,

basically you hook the SetItem method of ItemTooltip and you are at the right place already.
This method is called to show the tooltip of an item, including the player's inventory.
You get the itemLink, you can get the itemId from it with GetItemLinkItemId. (and all other information, like style, from it)

Take a look at https://www.esoui.com/downloads/info...eTooltips.html and feel free to use the code to start with.
  Reply With Quote
02/11/23, 12:02 PM   #3
Baertram
Super Moderator
 
Baertram's Avatar
WoWInterface Super Mod
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 4,912
Each inventory row got a dataEntry table with a subtable data where you'll find the slots info like itemId, bagId, slotIndex etc.
You can use the function moc() to get the control below your mouse. Read moc's .dataEntry.data then and either use the bagId and slot Index with API functions like GetItem*(bagId, slot Index).

Or for your usecase do at best like shown by votan as you want to add something to the tooltip. ItemLink's are a string containing much info of the dataEntry.data of the slot too. You can create an itemLink from a bagId & slot Index via GetItemLink(bagId, slotIndex).

Tools like merTorchbug updated or zgoo can be used to inspect the control below the mouse and view its data and subtables too. They visualize you the contents. Use /tbm above the control (inventory row) or /zgoo mouse
  Reply With Quote
02/12/23, 07:41 AM   #4
Matoro342
Join Date: Feb 2023
Posts: 9
Originally Posted by votan View Post
Hi Matoro342,

basically you hook the SetItem method of ItemTooltip and you are at the right place already.
This method is called to show the tooltip of an item, including the player's inventory.
You get the itemLink, you can get the itemId from it with GetItemLinkItemId. (and all other information, like style, from it)

Take a look at https://www.esoui.com/downloads/info...eTooltips.html and feel free to use the code to start with.
I am assuming that the SetItem function is setting what the tooltip displays? Looking at your code, I am flabbergasted how everything runs even though you only run an event manager for startup. But anyways, in your HookBagTips you have
Lua Code:
  1. TooltipHook(ItemTooltip, "SetBagItem", GetItemLink)
which goes to
Lua Code:
  1. local function TooltipHook(tooltipControl, method, linkFunc)
  2.     local origMethod = tooltipControl[method]
  3.  
  4.     tooltipControl[method] = function(self, ...)
  5.         origMethod(self, ...)
  6.         AddRuneInfo(self, GetRuneInfoText(linkFunc(...)))
  7.     end
  8. end
but I'll be honest, I have no idea what that does or why. It looks very clever, easily handling multiple kinds of tooltips, and I'd love to use it since I could then apply to loot or whatever, but yeah, it confuses me.
I've made some progress, using moc() and d() to display at least some info after hovering over items. I still don't exactly know how to edit or access the tooltip, my guess is tooltip functions are accessed through item links, is that correct? I must be dumb because I don't understand if ItemTooltip is an object or a property of one.

Originally Posted by Baertram View Post
Each inventory row got a dataEntry table with a subtable data where you'll find the slots info like itemId, bagId, slotIndex etc.
You can use the function moc() to get the control below your mouse. Read moc's .dataEntry.data then and either use the bagId and slot Index with API functions like GetItem*(bagId, slot Index).

Or for your usecase do at best like shown by votan as you want to add something to the tooltip. ItemLink's are a string containing much info of the dataEntry.data of the slot too. You can create an itemLink from a bagId & slot Index via GetItemLink(bagId, slotIndex).

Tools like merTorchbug updated or zgoo can be used to inspect the control below the mouse and view its data and subtables too. They visualize you the contents. Use /tbm above the control (inventory row) or /zgoo mouse
I have been able to get item info out of the hovered over items, and your advice here with the dataEntry.data which seems to appear nowhere I found in the API helped me crack that. I still don't know what to do about tooltips though.
  Reply With Quote
02/12/23, 08:58 AM   #5
Baertram
Super Moderator
 
Baertram's Avatar
WoWInterface Super Mod
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 4,912
ItemTooltip is a control which shows multiple lines of information about items.
It is defined via XMl:

Code:
 <TopLevelControl name="ItemTooltipTopLevel" inherits="TooltipTopLevel">
            <Controls>
                <Tooltip name="ItemTooltip" inherits="ZO_ItemIconTooltip">
                    <OnHide>
                        ComparativeTooltip1:SetHidden(true)
                        ComparativeTooltip2:SetHidden(true)
                    </OnHide>
                </Tooltip>
            </Controls>
        </TopLevelControl>
-> inherits="ZO_ItemIconTooltip"means there does exist another XML control ZO_ItemIconTooltip which was defined as virtual="true" and which builds the base of this control ItemTooltip too. If you search the ESOUI sources for ZO_ItemTooltip you'll find it
<code> <Tooltip name="ZO_ItemIconTooltip" inherits="ItemTooltipBase" virtual="true"></code>
and this inherits from ZO_BaseTooltip again.



The base information is added via functions like he one Votan mentioned, SetBagItem

There also exist others e.g. these which set a quest reward the tooltip as you taln to a quest turn in NPC and move the mouse above the reward item:
Lua Code:
  1. InitializeTooltip(ItemTooltip)
  2.             ItemTooltip:SetQuestReward(control.index)

Here is an example how SetBagitem works, using the bagId (BAG_BACKPACK which is the player inventory e.g., or BAG_BANK, BAG_VIRTUAL for craftbag etc.) and slotIndex (the index of the item in that bagId):
https://github.com/esoui/esoui/blob/...slot.lua#L2128

Lua Code:
  1. local data = ZO_Inventory_GetSlotDataForInventoryControl(inventorySlot)
  2.             if data then
  3.                 local bag, index = ZO_Inventory_GetBagAndIndex(inventorySlot)
  4.                 ItemTooltip:SetBagItem(bag, index)
  5.             end

It reads the dataEntry.data of inventorySlot and checks for the bagId and slotIndex, then sets the tooltip base info via ItemTooltip:SetBagItem.


Votans function is a so called "manual post hook" of that function SetBagItem.
It will save the original function to a local variable
local origMethod = tooltipControl[method]
-->tooltipControl[method] = ItemTooltip["SetBagItem"] or within another notation ItemTooltip.SetBagItem
And then it redefines that method:

tooltipControl[method] = function(self, ...)

In there it calls the original function first:
origMethod(self, ...)

And then it calls the own Votan function AddRuneInfo
AddRuneInfo(self, GetRuneInfoText(linkFunc(...)))
after the original one was called.
-> This function most probably adds some extra text or whatever to the tooltip so check what it does in Votan's code

Basically you can do that using ZOs function SecurePostHook too:

Lua Code:
  1. SecurePostHook(ItemTooltip, "SetBagItem", function(bagId, slotIndex)
  2.  --Do your stuff here to add extra info to the tooltip control ItemTooltip after he SetBagItem function was called.
  3. -- e.g. use a function like ItemTooltip:AddLine if this exists to add extra data
  4.     ItemTooltip:AddLine("Test Text", "ZoFontWinH4", ZO_TOOLTIP_DEFAULT_COLOR:UnpackRGB()) --ZoFontWinH4 is the font, the last parameter is the color
  5. end)

Last edited by Baertram : 02/12/23 at 09:04 AM.
  Reply With Quote
02/12/23, 02:33 PM   #6
votan
 
votan's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2014
Posts: 577
Yeah, I real clever tricky thing I have learnd from @Garkin.

You could start with:
Lua Code:
  1. local function TooltipHook(tooltipControl, method, linkFunc)
  2.         local origMethod = tooltipControl[method]
  3.      
  4.         tooltipControl[method] = function(self, ...)
  5.             origMethod(self, ...)
  6.             d(linkFunc(...))
  7.         end
  8.     end
As you can see in my RuneTooltip code, each tooltip method is hooked given the corresponding function to convert the given parameters to an itemLink. To understand that, you have to look at the method and the corresponding function signatures within the documentation:
https://github.com/esoui/esoui/blob/...umentation.txt
  Reply With Quote
02/13/23, 12:06 AM   #7
Matoro342
Join Date: Feb 2023
Posts: 9
Ok, I'll see if I understand this correctly:

Lua Code:
  1. local function TooltipHook(tooltipControl, method, linkFunc)
  2.     local origMethod = tooltipControl[method] -- saving the original method
  3.  
  4.     tooltipControl[method] = function(self, ...) -- redefining the method for the tooltipControl object
  5.         origMethod(self, ...) -- do whatever it was supposed to before
  6.         AddRuneInfo(self, GetRuneInfoText(linkFunc(...))) -- do additional stuff using the function for the item link
  7.     end
  8. end

Am I correct in assuming this only needs to be called once because it just overwrites the original function and it then doesn't require a hook every time it's called? I am somewhat confused as HookBagTips() passes in ItemTooltip to the tooltipControl, I think at first I thought it had to be a defined variable pulled from the game, but this is just actually generally letting us rewrite the functions for any ItemTooltip? I apologize for being a noob with LUA.

With that method, do I still need to use something like ZO_PreHook or an event manager per tooltip? I would guess it only needs to run once. I will try it with SecurePostHook and see where that gets me. Thanks so much!
  Reply With Quote
02/13/23, 01:56 AM   #8
Matoro342
Join Date: Feb 2023
Posts: 9
Here's what I have so far which miraculously solves most of the problems. It is genius that you can just write the name of the function as it would otherwise exist in the code and redefine it. My only issue is the style return from an item link is just a name or number. It's clearly possible from the CharacterKnowledge addon an many others to determine if you have, for example, the nord boots motif, but I am not sure it's possible to do the reverse and go from having nord boots to seeing if you have that motif unlocked. There are a few issues: some motif books just unlock everything at once, which would make those impossible. Clearly, something in the outfit styles collection is already tracking basically everything individually, which I want to access, but don't know how.

Lua Code:
  1. TestAddon = {} -- Initialize addon object
  2. TestAddon.name = "TestAddon" -- Give addon object a reference name
  3.  
  4.  
  5. local function TooltipHook(tooltipControl, method, linkFunc)
  6.     local origMethod = tooltipControl[method] -- Saves the original method (ex. ItemTooltip[SetBagItem])
  7.    
  8.     tooltipControl[method] = function(self, ...) -- We are now going to rewrite the original method
  9.         origMethod(self, ...) -- Let it do what it originally did
  10.         if (GetItemLinkItemType(linkFunc(...)) == ITEMTYPE_ARMOR) or (GetItemLinkItemType(linkFunc(...)) == ITEMTYPE_WEAPON) then -- Check if item is armor or a weapon (visual equipment with styles)
  11.             local style = GetItemLinkItemStyle(linkFunc(...)) -- Get the item style
  12.             self:AddVerticalPadding(20) -- Add some space away from the rest of the tooltip
  13.             self:AddLine(GetItemStyleName(style)) -- Write the style name
  14.         end
  15.     end
  16. end
  17.  
  18. local function HookBagTips() -- We are going to hook functions into the itemtooltips for most kinds that we want to see.
  19.     TooltipHook(ItemTooltip, "SetBagItem", GetItemLink) -- Inventory bags
  20.     TooltipHook(ItemTooltip, "SetTradeItem", GetTradeItemLink) -- Trade screens
  21.     TooltipHook(ItemTooltip, "SetBuybackItem", GetBuybackItemLink)
  22.     TooltipHook(ItemTooltip, "SetStoreItem", GetStoreItemLink) -- Stores, etc.
  23.     TooltipHook(ItemTooltip, "SetAttachedMailItem", GetAttachedItemLink)
  24.     TooltipHook(ItemTooltip, "SetLootItem", GetLootItemLink) -- Loot, you get the idea
  25.     TooltipHook(ItemTooltip, "SetTradingHouseItem", GetTradingHouseSearchResultItemLink)
  26.     TooltipHook(ItemTooltip, "SetTradingHouseListing", GetTradingHouseListingItemLink)
  27.     TooltipHook(ItemTooltip, "SetLink", ReturnItemLink)
  28.  
  29.     TooltipHook(PopupTooltip, "SetLink", ReturnItemLink)
  30. end
  31.  
  32. local function OnAddOnLoaded(event, name)
  33.     if name ~= TestAddon.name then return end -- If it's not our addon loaded, don't run this. Would get errors.
  34.  
  35.     HookBagTips();
  36.     EVENT_MANAGER:UnregisterForEvent(TestAddon.name, event) -- We no longer want this to run as the game loads addons. It only needs to run once.
  37. end
  38.  
  39. EVENT_MANAGER:RegisterForEvent(TestAddon.name, EVENT_ADD_ON_LOADED, OnAddOnLoaded) -- As the game loads, the event manager registers our addon for an event. It takes the name of the addon, and upon the event of loading the addon, it runs the function "OnAddOnLoaded".)
  Reply With Quote
02/13/23, 06:23 AM   #9
Baertram
Super Moderator
 
Baertram's Avatar
WoWInterface Super Mod
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 4,912
I see you have understood it

You can simply these kind of "if ..." code:
Code:
if (GetItemLinkItemType(linkFunc(...)) == ITEMTYPE_ARMOR) or (GetItemLinkItemType(linkFunc(...)) == ITEMTYPE_WEAPON) then -- Check if item is armor or a weapon (visual equipment with styles)
Build a local lookup table with the key = allowed itemTypes and value = boolean true, and then just check for if lookupTable[itemType] then
Lua Code:
  1. local allowedItemtypes = {
  2.  [ITEMTYPE_ARMOR] = true,
  3.  [ITEMTYPE_WEAPON] = true  
  4. }
  5.  
  6. if (allowedItemtypes[GetItemLinkItemType(linkFunc(...))] then -- Check if item is armor or a weapon (visual equipment with styles)
  7. ...
  8. end


And if you need linkFunc(...) more than once define a local like
local itemLink = linkFunc(...)
and then reuse itemLink instead of calling the function again and again and ...


For your other questions:
I never worked with the styles and motifs but there exist several API functions where you pass in an itemLink or bagId, slotIndex and you will get the needed info in return.
I guess IsItemLinkBookKnown(itemLink) could help you here for example


Search the API txt documentation file for "known" and you should find several functions that may help. Not sure if the IsItemLinkBookKnown also works on normal style books without motif pages, I hope so.

Last edited by Baertram : 02/13/23 at 06:26 AM.
  Reply With Quote
02/14/23, 07:18 PM   #10
Matoro342
Join Date: Feb 2023
Posts: 9
Thank you, I've implemented those changes to clean up the code.

I've tried IsItemLinkBookKnown(itemLink) but it returns errors, I assume it only works on books or style pages.

In CharacterKnowledge Internal.lua, they use:

Lua Code:
  1. Internal.KnowFunctions = {
  2.     [Internal.CATEGORY_RECIPE] = IsItemLinkRecipeKnown,
  3.     [Internal.CATEGORY_PLAN] = IsItemLinkRecipeKnown,
  4.     [Internal.CATEGORY_MOTIF] = IsItemLinkBookKnown,
  5. }

And their stated use case is specifically limited to just those items. I will keep looking though as time allows through the API for potential solutions. Really appreciate your continued support.
  Reply With Quote
02/15/23, 03:56 AM   #11
Baertram
Super Moderator
 
Baertram's Avatar
WoWInterface Super Mod
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 4,912
You can get the styleId from the itemLink

Code:
* GetItemLinkInfo(*string* _itemLink_)
** _Returns:_ *string* _icon_, *integer* _sellPrice_, *bool* _meetsUsageRequirement_, *[EquipType|#EquipType]* _equipType_, *integer* _itemStyleId_

--or via
GetItemLinkItemStyle(itemLink)

Code:
* IsSmithingStyleKnown(*integer* _itemStyleId_, *luaindex* _patternIndex_)
** _Returns:_ *bool* _known_
I think the _patternIndex_ is the itemType then, like hands, head, etc. so maybe it's the same as EquipType, but I doubt it.
I guess you need to map between the 2 somehow: EquipType -> itemStylePatternIndex

I never used those functions so far. Maybe spy other addon's code, like CraftStore.

Last edited by Baertram : 02/15/23 at 04:57 AM.
  Reply With Quote
02/16/23, 03:05 AM   #12
Matoro342
Join Date: Feb 2023
Posts: 9
The IsSmithingStyleKnown function does work with just one style argument, which is odd to me, but I checked out CraftStore per your suggestion and they use it like that. It definitely works, but I suppose I should've said I was more interested in the outfit system to begin with.

I would guess most people choose to use outfit stations to change their appearance, especially since it applies to outliers like crown store and event appearances. I have a general plan so far.

I want to use:
Lua Code:
  1. * GetCollectibleId(*luaindex* _topLevelIndex_, *luaindex:nilable* _categoryIndex_, *luaindex* _collectibleIndex_)
  2. ** _Returns:_ *integer* _collectibleId_

But the only useful piece of information I have so far from an itemLink is the outfitStyleId:
Lua Code:
  1. local outfitStyleId = GetItemLinkOutfitStyleId(itemLink)

Using your Torchlight plugin which is awesome, I can see data about each outfit collection item. I haven't found anything too useful yet, but it's given me some ideas.

There is this function:
Lua Code:
  1. * GetOutfitStyleFreeConversionCollectibleId(*integer* _outfitStyleId_)
  2. ** _Returns:_ *integer:nilable* _freeConversionCollectibleId_
I tried using it but it seems to return nil when fed my outfitStyleIds.

I tried:
Lua Code:
  1. * GetCollectibleIdFromLink(*string* _link_)
  2. ** _Returns:_ *integer:nilable* _collectibleId_
But it simply returns errors with my itemLinks.

I am looking for a function that can give me an outfitStyleId from a collectibleId or its referenceId, at least then I could think about a really ugly iterative method where I go through each relevant collectible, store its outfitStyleId and collectibleId, and use those to check, but I keep hitting dead ends. There's more I've tried here that I haven't mentioned. I'll keep trying, I'm pretty sure it must be possible.
  Reply With Quote
02/16/23, 04:21 AM   #13
Baertram
Super Moderator
 
Baertram's Avatar
WoWInterface Super Mod
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 4,912
Checking the ESOUI source code GetCollectibleFromLInk only works for linkTypes == LINK_TYPE_COLLECTIBLE
You can get the linkType by using
Code:
local linkType = GetLinkType(itemLink)
You can find this by searching for e.g. LayoutCollectibleFromLink (which is used in tooltips).

I'm not sure what you try to add to which tooltips and I never workd with the outfitd do far so I'm afraid I cannot furthr help you there atm.
But I guess those outfit link functions etc. only work at the collections -> outfit or at the outfit station item tooltips, and not for any normal items in your inventory/bank/etc.
  Reply With Quote
02/17/23, 03:02 AM   #14
Matoro342
Join Date: Feb 2023
Posts: 9
Here's something I've tried. Not sure if it exposes a bug in the API?

Lua Code:
  1. local itemStyleId = GetOutfitStyleItemStyleId(outfitStyleId)
  2. self:AddLine("itemStyleId " .. itemStyleId) -- Always 0???
  3. self:AddLine(collectibleName .. " red glo 1")
  4. --local outfitStyleName = GetOutfitStyleNameById(outfitStyleId)
  5. self:AddLine(outfitStyleName)
  6. local collectibleItemStyleId = GetOutfitStyleItemStyleId(GetCollectibleReferenceId(3654))
  7. -- Redguard Gloves 1 collectibleId used here for testing. This is how Zenimax does it themselves, "self.outfitStyleItemStyleId = GetOutfitStyleItemStyleId(self.referenceId)" in collectibledatamanager.lua
  8. local match = ""
  9. if itemStyleId == collectibleItemStyleId then
  10.     match = "Yes" -- This is what it always returns. Both are always zero. Why? Idk.
  11. else match = "Nope lol" end
  12. self:AddLine(match)

I would have though that CollectibleData.outfitStyleItemStyleId would have some use not being zero all the time. But since outfits don't interact with item data, what is the use? Where is the actual collectible information coming from that tells it what outfitStyleId to use? I am flabbergasted.

At this point I'm about to try comparing the icon paths and matching them that way. I am stumped!

By the way, does anyone know where to post to request features for the API? The official ESO forums doesn't seem to have a specific category. I am a simple human, I just want GetCollectibleOutfitStyleId().
  Reply With Quote

ESOUI » Developer Discussions » Lua/XML Help » How do I get the ItemID of an item I hover over in my inventory?

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off