├── NPCBotInventory.lua ├── NPCBotInventory.toc └── README.md /NPCBotInventory.lua: -------------------------------------------------------------------------------- 1 | local playerName = UnitName("player") -- Get the current player's name 2 | BotInventoryDB = BotInventoryDB or {} 3 | BotInventoryDB[playerName] = BotInventoryDB[playerName] or {} -- Initialize player-specific storage 4 | local botInventories = botInventories or {} 5 | 6 | local function LoadSavedInventories() 7 | -- Ensure we are loading the current player's bot inventories 8 | if BotInventoryDB[playerName] then 9 | for botName, inventory in pairs(BotInventoryDB[playerName]) do 10 | botInventories[botName] = inventory 11 | print("Loaded inventory for bot:", botName, "for player:", playerName) 12 | end 13 | end 14 | end 15 | 16 | -- create a new frame for the item links 17 | local itemLinkFrame = CreateFrame("Frame", "ItemLinkFrame", UIParent) 18 | itemLinkFrame:SetMovable(true) 19 | itemLinkFrame:EnableMouse(true) 20 | itemLinkFrame:RegisterForDrag("LeftButton") 21 | itemLinkFrame:SetScript("OnDragStart", itemLinkFrame.StartMoving) 22 | itemLinkFrame:SetScript("OnDragStop", itemLinkFrame.StopMovingOrSizing) 23 | itemLinkFrame:SetSize(400, 570) 24 | itemLinkFrame:SetPoint("CENTER") 25 | itemLinkFrame:SetBackdrop({ 26 | bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background", 27 | edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", 28 | tile = true, 29 | tileSize = 16, 30 | edgeSize = 16, 31 | insets = { 32 | left = 4, 33 | right = 4, 34 | top = 4, 35 | bottom = 4 36 | } 37 | }) 38 | itemLinkFrame:SetBackdropColor(0, 0, 0, 1) 39 | 40 | 41 | -- create a fontstring for the title 42 | local title = itemLinkFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal") 43 | title:SetPoint("TOP", itemLinkFrame, "TOP", 0, -10) 44 | title:SetText("") 45 | 46 | itemLinkFrame:Hide() 47 | 48 | -- Create a frame to list bot names 49 | local botListFrame = CreateFrame("Frame", "BotListFrame", UIParent) 50 | botListFrame:SetMovable(true) 51 | botListFrame:EnableMouse(true) 52 | botListFrame:RegisterForDrag("LeftButton") 53 | botListFrame:SetScript("OnDragStart", botListFrame.StartMoving) 54 | botListFrame:SetScript("OnDragStop", botListFrame.StopMovingOrSizing) 55 | botListFrame:SetSize(200, 400) 56 | --botListFrame:SetPoint("CENTER", UIParent, "CENTER", -250, 0) 57 | botListFrame:SetBackdrop({ 58 | bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background", 59 | edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", 60 | tile = true, 61 | tileSize = 16, 62 | edgeSize = 16, 63 | insets = {left = 4, right = 4, top = 4, bottom = 4} 64 | }) 65 | botListFrame:SetBackdropColor(0.1, 0.1, 0.1, 1) 66 | botListFrame:Hide() 67 | 68 | -- Table to store individual frames for each bot 69 | local botFrames = {} 70 | 71 | -- Function to display or update saved inventory for a bot 72 | local function ShowSavedInventory(botName) 73 | -- Create a new frame if it doesn't exist 74 | if not botFrames[botName] then 75 | botFrames[botName] = CreateFrame("Frame", botName.."ItemLinkFrame", UIParent) 76 | local frame = botFrames[botName] 77 | -- Refresh Button 78 | local refreshButton = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate") 79 | refreshButton:SetSize(125, 22) 80 | refreshButton:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -10, 10) 81 | refreshButton:SetText("Query and Refresh") 82 | 83 | refreshButton:SetScript("OnClick", function() 84 | -- First execution 85 | for _, itemLink in ipairs(botInventories[botName]) do 86 | if itemLink then 87 | GameTooltip:SetHyperlink(itemLink) 88 | end 89 | end 90 | ShowSavedInventory(botName) 91 | 92 | -- Second execution (consider adding a delay if necessary) 93 | for _, itemLink in ipairs(botInventories[botName]) do 94 | if itemLink then 95 | GameTooltip:SetHyperlink(itemLink) 96 | end 97 | end 98 | ShowSavedInventory(botName) 99 | end) 100 | frame:SetMovable(true) 101 | frame:EnableMouse(true) 102 | frame:RegisterForDrag("LeftButton") 103 | frame:SetScript("OnDragStart", frame.StartMoving) 104 | frame:SetScript("OnDragStop", frame.StopMovingOrSizing) 105 | frame:SetSize(400, 570) 106 | frame:SetPoint("CENTER") 107 | frame:SetBackdrop({ 108 | bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background", 109 | edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", 110 | tile = true, 111 | tileSize = 16, 112 | edgeSize = 16, 113 | insets = { left = 4, right = 4, top = 4, bottom = 4 } 114 | }) 115 | frame:SetBackdropColor(0, 0, 0, 1) 116 | 117 | local title = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal") 118 | title:SetPoint("TOP", frame, "TOP", 0, -10) 119 | title:SetText(botName.."'s gear") 120 | 121 | frame.buttons = {} 122 | 123 | local closeButton = CreateFrame("Button", nil, frame, "UIPanelCloseButton") 124 | closeButton:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -6, -6) 125 | closeButton:SetScript("OnClick", function() 126 | frame:Hide() 127 | for i = #frame.buttons, 1, -1 do 128 | frame.buttons[i]:Hide() 129 | frame.buttons[i]:SetParent(nil) 130 | table.remove(frame.buttons, i) 131 | end 132 | end) 133 | 134 | frame:Hide() 135 | end 136 | 137 | local frame = botFrames[botName] 138 | 139 | -- Clear existing buttons 140 | for i = #frame.buttons, 1, -1 do 141 | frame.buttons[i]:Hide() 142 | frame.buttons[i] = nil 143 | end 144 | 145 | -- Populate the frame with bot inventory 146 | for i, link in ipairs(botInventories[botName]) do 147 | local _, itemName, _, _, _, _, _, _, _, texture = GetItemInfo(link) 148 | if not texture then 149 | itemName = string.match(link, "%[(.*)%]") 150 | texture = string.match(link, "|T(.-):") 151 | end 152 | 153 | local buttonName = "ItemButton_"..(#frame.buttons + 1) 154 | local itemButton = CreateFrame("Button", buttonName, frame, "ItemButtonTemplate") 155 | itemButton:SetSize(24, 24) 156 | itemButton:SetNormalTexture(texture) 157 | 158 | local normalTexture = itemButton:GetNormalTexture() 159 | if normalTexture then 160 | local textureWidth, textureHeight = normalTexture:GetSize() 161 | local ratio = itemButton:GetWidth() / textureWidth 162 | normalTexture:SetSize(itemButton:GetWidth(), textureHeight * ratio) 163 | end 164 | 165 | itemButton:SetScript("OnEnter", function() 166 | GameTooltip:SetOwner(itemButton, "ANCHOR_RIGHT") 167 | GameTooltip:SetHyperlink(link) 168 | GameTooltip:Show() 169 | end) 170 | itemButton:SetScript("OnLeave", function() 171 | GameTooltip:Hide() 172 | end) 173 | 174 | table.insert(frame.buttons, itemButton) 175 | 176 | if #frame.buttons == 1 then 177 | itemButton:SetPoint("TOPLEFT", frame, "TOPLEFT", 20, -20) 178 | else 179 | itemButton:SetPoint("TOPLEFT", frame.buttons[#frame.buttons - 1], "BOTTOMLEFT", 0, -10) 180 | end 181 | 182 | local itemNameText = itemButton:CreateFontString(nil, "OVERLAY", "GameFontNormal") 183 | itemNameText:SetPoint("LEFT", itemButton, "RIGHT", 10, 0) 184 | itemNameText:SetText(itemName) 185 | end 186 | 187 | frame:Show() 188 | end 189 | 190 | local function UpdateBotList() 191 | print("Updating bot list UI...") -- Debugging line 192 | 193 | -- Clear existing buttons 194 | for _, button in pairs(botListFrame.buttons) do 195 | button:Hide() 196 | end 197 | wipe(botListFrame.buttons) 198 | 199 | -- Create a sorted list of bot names 200 | local sortedBotNames = {} 201 | for botName, _ in pairs(botInventories) do 202 | table.insert(sortedBotNames, botName) 203 | end 204 | table.sort(sortedBotNames) 205 | 206 | -- Create a button for each sorted bot name and calculate the new height 207 | local yOffset = -30 208 | local buttonHeight = 20 209 | local spacing = 5 210 | local numBots = 0 211 | 212 | for _, botName in ipairs(sortedBotNames) do 213 | local botButton = CreateFrame("Button", nil, botListFrame, "GameMenuButtonTemplate") 214 | botButton:SetSize(180, buttonHeight) 215 | botButton:SetPoint("TOP", botListFrame, "TOP", 0, yOffset) 216 | botButton:SetText(botName) 217 | botButton:SetNormalFontObject("GameFontNormal") 218 | botButton:SetHighlightFontObject("GameFontHighlight") 219 | botButton:SetScript("OnClick", function() 220 | ShowSavedInventory(botName) 221 | end) 222 | table.insert(botListFrame.buttons, botButton) 223 | yOffset = yOffset - (buttonHeight + spacing) 224 | numBots = numBots + 1 225 | end 226 | 227 | -- Calculate and set the new height of the frame 228 | local newHeight = (buttonHeight + spacing) * numBots + 70 229 | botListFrame:SetHeight(math.max(100, newHeight)) -- Ensure a minimum height 230 | end 231 | 232 | local playerName = UnitName("player") -- Get the current player's name 233 | 234 | -- Define the confirmation popup dialog at the beginning of your script file 235 | StaticPopupDialogs["CLEAR_ALL_BOTS_CONFIRMATION"] = { 236 | text = "Are you sure you want to clear all bot inventories?", 237 | button1 = "Yes", 238 | button2 = "No", 239 | OnAccept = function() 240 | local playerName = UnitName("player") -- Get the current player's name 241 | if BotInventoryDB[playerName] then 242 | wipe(BotInventoryDB[playerName]) 243 | end 244 | wipe(botInventories) 245 | UpdateBotList() 246 | print("All bot inventories cleared for player:", playerName) 247 | end, 248 | timeout = 0, 249 | whileDead = true, 250 | hideOnEscape = true, 251 | preferredIndex = 3, -- to avoid UI taint issues 252 | } 253 | 254 | -- Add the "Clear All Bots" button 255 | local clearAllButton = CreateFrame("Button", "ClearAllBotsButton", botListFrame, "UIPanelButtonTemplate") 256 | clearAllButton:SetSize(160, 30) 257 | clearAllButton:SetPoint("BOTTOM", botListFrame, "BOTTOM", 0, 10) 258 | clearAllButton:SetText("Clear All Bots") 259 | clearAllButton:SetScript("OnClick", function() 260 | StaticPopup_Show("CLEAR_ALL_BOTS_CONFIRMATION") 261 | end) 262 | 263 | botListFrame.buttons = {} 264 | 265 | local lastCallTime = GetTime() 266 | local playerName = UnitName("player") -- Get the current player's name 267 | 268 | local function OnChatMessage(self, event, message, sender, ...) 269 | if (event == "CHAT_MSG_MONSTER_WHISPER") then 270 | local currentTime = GetTime() 271 | local isNewBot = false 272 | 273 | if (currentTime - lastCallTime) >= 2 then 274 | if not botInventories[sender] then 275 | isNewBot = true 276 | botInventories[sender] = {} -- Initialize inventory for the new bot 277 | end 278 | 279 | for i = #itemLinkFrame.buttons, 1, -1 do 280 | itemLinkFrame.buttons[i]:Hide() 281 | itemLinkFrame.buttons[i] = nil 282 | end 283 | title:SetText(sender.."'s gear") 284 | 285 | -- Initialize inventory for the sender 286 | botInventories[sender] = {} 287 | end 288 | 289 | local link = string.match(message, "|H(.*)|h%[(.*)%]|h") 290 | if (link) then 291 | -- Ensure the sender's inventory is initialized 292 | botInventories[sender] = botInventories[sender] or {} 293 | table.insert(botInventories[sender], link) 294 | BotInventoryDB[playerName] = BotInventoryDB[playerName] or {} 295 | BotInventoryDB[playerName][sender] = botInventories[sender] -- Store in player-specific section 296 | 297 | 298 | local _, itemName, quality, _, _, _, _, _, _, texture = GetItemInfo(link) 299 | if not texture then 300 | itemName = string.match(message, "%[(.*)%]") 301 | local colorCode = string.match(message, "|c%x%x%x%x%x%x%x%x") 302 | if colorCode then 303 | itemName = colorCode .. "[" .. itemName .. "]" .. "|r" 304 | end 305 | texture = string.match(message, "|T(.-):") 306 | end 307 | 308 | local buttonName = "ItemButton_"..(#itemLinkFrame.buttons + 1) 309 | local itemButton = CreateFrame("Button", buttonName, itemLinkFrame, "ItemButtonTemplate") 310 | itemButton:SetSize(24, 24) 311 | itemButton:SetNormalTexture(texture) 312 | local normalTexture = itemButton:GetNormalTexture() 313 | if normalTexture then 314 | local textureWidth, textureHeight = normalTexture:GetSize() 315 | local ratio = itemButton:GetWidth() / textureWidth 316 | normalTexture:SetSize(itemButton:GetWidth(), textureHeight * ratio) 317 | end 318 | 319 | itemButton:SetScript("OnEnter", function() 320 | GameTooltip:SetOwner(itemButton, "ANCHOR_RIGHT") 321 | GameTooltip:SetHyperlink(link) 322 | GameTooltip:Show() 323 | end) 324 | itemButton:SetScript("OnLeave", function() 325 | GameTooltip:Hide() 326 | end) 327 | 328 | table.insert(itemLinkFrame.buttons, itemButton) 329 | 330 | if #itemLinkFrame.buttons == 1 then 331 | itemButton:SetPoint("TOPLEFT", itemLinkFrame, "TOPLEFT", 20, -20) 332 | else 333 | itemButton:SetPoint("TOPLEFT", itemLinkFrame.buttons[#itemLinkFrame.buttons-1], "BOTTOMLEFT", 0, -10) 334 | end 335 | 336 | local itemNameText = itemButton:CreateFontString(nil, "OVERLAY", "GameFontNormal") 337 | itemNameText:SetPoint("LEFT", itemButton, "RIGHT", 10, 0) 338 | itemNameText:SetText(itemName) 339 | 340 | if not itemLinkFrame:IsShown() then 341 | title:SetText(sender.."'s gear") 342 | itemLinkFrame:Show() 343 | end 344 | end 345 | 346 | lastCallTime = GetTime() 347 | 348 | if botListFrame:IsShown() and isNewBot then 349 | UpdateBotList() 350 | end 351 | end 352 | end 353 | 354 | 355 | -- register the OnChatMessage function for the CHAT_MSG_MONSTER_WHISPER event 356 | itemLinkFrame:SetScript("OnEvent", OnChatMessage) 357 | itemLinkFrame:RegisterEvent("CHAT_MSG_MONSTER_WHISPER") 358 | 359 | -- initialize the buttons table 360 | itemLinkFrame.buttons = {} 361 | 362 | -- create a button to close the itemLinkFrame window 363 | local closeButton = CreateFrame("Button", nil, itemLinkFrame, "UIPanelCloseButton") 364 | closeButton:SetPoint("TOPRIGHT", itemLinkFrame, "TOPRIGHT", -6, -6) 365 | closeButton:SetScript("OnClick", function() 366 | itemLinkFrame:Hide() 367 | for i = #itemLinkFrame.buttons, 1, -1 do 368 | itemLinkFrame.buttons[i]:Hide() 369 | itemLinkFrame.buttons[i]:SetParent(nil) 370 | table.remove(itemLinkFrame.buttons, i) 371 | end 372 | end) 373 | 374 | -- Registering the slash command 375 | SLASH_SHOWINVENTORY1 = '/showinventory' 376 | 377 | -- Slash command handler 378 | SlashCmdList["SHOWINVENTORY"] = function(msg) 379 | local botName = msg:trim() -- Extract the bot name from the command argument 380 | if botName == "" then 381 | botName = "McKenzie" -- Default to "McKenzie" if no name is provided 382 | end 383 | ShowSavedInventory(botName) 384 | end 385 | 386 | 387 | local botListTitle = botListFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal") 388 | botListTitle:SetPoint("TOP", botListFrame, "TOP", 0, -10) 389 | botListTitle:SetText("Bot Inventory List") 390 | 391 | -- Slash command to toggle bot list frame 392 | SLASH_TOGGLEBOTLIST1 = '/togglebotlist' 393 | SlashCmdList["TOGGLEBOTLIST"] = function(msg) 394 | if botListFrame:IsShown() then 395 | botListFrame:Hide() 396 | else 397 | UpdateBotList() 398 | botListFrame:Show() 399 | end 400 | end 401 | 402 | local toggleButton = CreateFrame("Button", "BotListToggleButton", UIParent, "UIPanelButtonTemplate") 403 | toggleButton:SetSize(120, 30) 404 | toggleButton:SetPoint("CENTER", UIParent, "CENTER", 0, -300) -- Adjust this position as needed 405 | toggleButton:SetText("Bot Inventory List") 406 | toggleButton:SetMovable(true) 407 | toggleButton:EnableMouse(true) 408 | toggleButton:RegisterForDrag("LeftButton") 409 | 410 | toggleButton:SetScript("OnDragStart", toggleButton.StartMoving) 411 | toggleButton:SetScript("OnDragStop", function(self) 412 | self:StopMovingOrSizing() 413 | -- Reposition botListFrame relative to the new position of toggleButton 414 | if botListFrame:IsShown() then 415 | botListFrame:ClearAllPoints() 416 | botListFrame:SetPoint("TOP", self, "BOTTOM", 0, -10) 417 | end 418 | end) 419 | 420 | -- Toggle the visibility of the botListFrame 421 | toggleButton:SetScript("OnClick", function() 422 | if botListFrame:IsShown() then 423 | botListFrame:Hide() 424 | else 425 | UpdateBotList() 426 | botListFrame:Show() 427 | end 428 | end) 429 | 430 | -- Position the botListFrame to drop down from the toggleButton 431 | botListFrame:ClearAllPoints() 432 | botListFrame:SetPoint("TOP", toggleButton, "BOTTOM", 0, -10) 433 | 434 | local eventFrame = CreateFrame("Frame") 435 | eventFrame:RegisterEvent("ADDON_LOADED") 436 | eventFrame:SetScript("OnEvent", function(self, event, addonName) 437 | if addonName == "NPCBotInventory" then 438 | LoadSavedInventories() 439 | UpdateBotList() 440 | botListFrame:Show() 441 | end 442 | end) 443 | -------------------------------------------------------------------------------- /NPCBotInventory.toc: -------------------------------------------------------------------------------- 1 | ## Interface: 30300 2 | ## Title: NPCBotInventory 3 | ## Author: Twixality 4 | ## Version: 1.2 5 | ## SavedVariables: BotInventoryDB 6 | 7 | NPCBotInventory.lua 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NPCBot Inventory 2 | ![WoWScrnShot_031223_020956](https://user-images.githubusercontent.com/50698894/224517170-1b61be47-9b9d-43c6-8267-1eb0d972d4b3.jpg) 3 | 4 | World of Warcraft 3.3.5 addon for use with NPCBots that displays bot's equipped items in a window. 5 | 6 | This addon works by scanning for items linked in chat by bots and parsing them into a new window. 7 | 8 | As usual with addons, unpack in Interface/Addons 9 | 10 | Usage: Login and ask a bot to show it's currently equipped items (Manage Equipment - Show me your inventory) 11 | 12 | --------------------------------------------------------------------------------