vanilla-wow-addons – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 --[[
2 path: /PetFeeder/
3 filename: PetFeeder.lua
4 author: Jeff Parker <jeff3parker@gmail.com>
5 created: Tue, 22 Jan 2005 14:15:00 -0800
6 updated: Tue, 22 Jan 2005 21:39:00 -0800
7  
8 Pet Feeder: a GUI interface allowing you configure happiness level for your pet &
9 drag/drop foods you wish your pet to eat. When the pet happiness drops below
10 the selected threshold will automatically feed your pet.
11 To remove a food from the list, simply click on it.
12 ]]
13  
14  
15 PETFEEDER_ITEM_HEIGHT = 32;
16 PETFEEDER_ITEMS_SHOWN = 7;
17  
18 PETFEEDER_FL_DISLIKED = 0;
19 PETFEEDER_FL_UNKNOWN = 1;
20 PETFEEDER_FL_APPROVED = 2;
21  
22  
23 -- Configuration
24 PeetFeederPlayer_Config = {};
25  
26 UIPanelWindows["PetFeederFrame"] = { area = "left", pushable = 4 };
27 PETFEEDER_TAB_SUBFRAMES = { "PetFeeder_FoodsFrame", "PetFeeder_ApprovedFoodsFrame", "PetFeeder_UnlikedFoodsFrame" };
28  
29 -- Foods Lists
30 PetFeederPlayer_Foods = {};
31 PetFeeder_Foods = {};
32 PetFeeder_BadFoods = {};
33 PetFeeder_QuestItems = {};
34 PetFeeder_PetName = "";
35 local LastPetName = nil;
36 PetFeeder_Pets = {};
37  
38 -- Variables
39 PetFeeder_Var = { };
40  
41 PetFeeder_Var.PetInCombat = false;
42 PetFeeder_Var.PlayerInCombat = false;
43 PetFeeder_Var.PetDead = false;
44 PetFeeder_Var.PlayerDead = false;
45 PetFeeder_Var.TradeOrLoot = false;
46 PetFeeder_Var.Searching = false;
47 PetFeeder_Var.isSitting = false;
48 PetFeeder_Var.sitPosX = -1;
49 PetFeeder_Var.sitPosY = -1;
50 PetFeeder_Var.feedStartTime = 0;
51 PetFeeder_Var.debug = false;
52 PetFeeder_Var.AutoFindFoodTimer = 0;
53 PetFeeder_Var.AutoFindFoodTimeout = 60; -- 60 seconds
54 PetFeeder_Var.LastItemAttempted = nil;
55 PetFeeder_Var.Feed = false;
56 PetFeeder_Var.DialogShowing = false;
57  
58  
59 -- Hooked function variables
60 Pre_SitOrStand = nil;
61 Pre_DoEmote = nil;
62 Pre_PetFeeder_ZMI = nil;
63 Pre_PetFeeder_ZMO = nil;
64  
65 --Pre_Jump = nil; -- blocked by Blizzard in v1.10
66  
67 PetDies_ChatParseInfo = { AddOn = "PetFeeder" };
68  
69 function PetFeeder_PetIsDead(value)
70 PetFeeder_Var.PetDead = value;
71 if ( value == true ) then
72 PFDebugMessage("PF-Died", "PET DIED. <from messages>", "debug");
73 else
74 PFDebugMessage("PF-Died", "PET REVIVED. <from messages>", "debug");
75 end
76 end
77  
78 --[[
79 =============================================================================
80 Debug message output
81 =============================================================================
82 ]]
83 function PFDebugMessage(x,y,z)
84 if ( z == "error" ) then
85 DEFAULT_CHAT_FRAME:AddMessage(format("|cffff0000[%s]: %s|r", x, y))
86 end
87  
88 if ( PetFeeder_Var.debug ) then
89 DEFAULT_CHAT_FRAME:AddMessage(format("|ccfff0000[%s]: %s|r", x, y))
90 end
91 end
92  
93  
94 --[[
95 =============================================================================
96 The loading frame handles getting our AddOn initialized properly
97 =============================================================================
98 ]]
99 function PetFeederLoadingFrame_OnUpdate()
100 if ( PetFeederFrame.loaded ) then
101 PetFeederLoadingFrame:UnregisterEvent("VARIABLES_LOADED");
102 PetFeederLoadingFrame:UnregisterEvent("UNIT_NAME_UPDATE");
103 PetFeederLoadingFrame:Hide();
104 PetFeederLoadingFrame = nil;
105  
106  
107 elseif ( PetFeederLoadingFrame.loadTime + 10 <= GetTime() ) then
108 --PetFeederFrame_LoadData();
109 PetFeederFrame.loaded = true;
110 PetFeederLoadingFrame.loadTime = GetTime();
111 end
112 end
113  
114 function PetFeederLoadingFrame_OnLoad()
115 PetFeederLoadingFrame:RegisterEvent("VARIABLES_LOADED");
116 PetFeederLoadingFrame:RegisterEvent("UNIT_NAME_UPDATE");
117 PetFeederLoadingFrame.init = 0;
118 PetFeederLoadingFrame.loadTime = GetTime();
119  
120 end
121  
122 function PetFeederLoadingFrame_OnEvent(event, arg1)
123 if ( not PetFeederLoadingFrame ) then
124 return;
125 end
126 if ( event == "VARIABLES_LOADED" or event == "UNIT_NAME_UPDATE" ) then
127 PetFeederLoadingFrame.init = PetFeederLoadingFrame.init + 1;
128 end
129  
130  
131  
132 end
133  
134 --[[
135 =============================================================================
136 Initialize data, perform hooks, register for events
137 =============================================================================
138 ]]
139  
140  
141 function PetFeederFrame_LoadData()
142  
143 if ( UnitClass("player") ~= PETFEEDER_HUNTER) then
144 return;
145 end
146  
147 PetFeederFrame_InitConfig();
148  
149 PetFeeder_PetName = UnitName( "pet" );
150 if ( PetFeeder_PetName == "Unknown Entity" ) then
151 PetFeeder_PetName = nil;
152 return
153 end
154 if ( PetFeeder_PetName ~= nil ) then
155 initChatParseforPetDiesEvent();
156 PetDies_ChatParseInfo.template = PetFeeder_PetName.." dies.";
157 PFChatParse_RegisterEvent(PetDies_ChatParseInfo);
158 PFDebugMessage("PF-Register", "registering Pet Died event", "debug");
159 -- Check for old version of foods
160 if ( PetFeederPlayer_Foods[PetFeeder_PetName] and getn(PetFeederPlayer_Foods[PetFeeder_PetName]) > 0) then
161 anItem = PetFeederPlayer_Foods[PetFeeder_PetName][1];
162 if ( not anItem.quality ) then
163 FixOldInventoryData();
164 end
165 end
166  
167 if ( PetFeederPlayer_Foods[PetFeeder_PetName] ) then
168 for i=1, table.getn( PetFeederPlayer_Foods[PetFeeder_PetName] ) do
169 if ( not PetFeederPlayer_Foods[PetFeeder_PetName][i].foodlikedstate ) then
170 PetFeederPlayer_Foods[PetFeeder_PetName][i].foodlikedstate = PETFEEDER_FL_UNKNOWN;
171 return true;
172 end
173 end
174 end
175 end
176  
177  
178  
179 PetFeederFrame.loaded = true;
180 end
181  
182 function PetFeederFrame_InitConfig()
183  
184 PetFeederFrame_SetPlayerConfig("Enabled",1);
185 PetFeederFrame_SetPlayerConfig("BarEnabled",1);
186 PetFeederFrame_SetPlayerConfig("Alert",1);
187 PetFeederFrame_SetPlayerConfig("Level",2);
188 PetFeederFrame_SetPlayerConfig("SortOption",1);
189 PetFeederFrame_SetPlayerConfig("SortOption1",1);
190 PetFeederFrame_SetPlayerConfig("SortOption2",1);
191 PetFeederFrame_SetPlayerConfig("AutoFindFood",1);
192 PetFeederFrame_SetPlayerConfig("SkipBuffFoods",1);
193 PetFeederFrame_SetPlayerConfig("RequireApproval",1);
194 PetFeederFrame_SetPlayerConfig("FeedOnlyApproved",1);
195  
196 end
197 function PetFeederFrame_SetPlayerConfig(ftableitem,defaultvalue)
198  
199 if ( not defaultvalue ) then
200 defaultvalue = 0;
201 end
202  
203 PeetFeederPlayer_Config[ftableitem] = PeetFeederPlayer_Config[ftableitem] or defaultvalue;
204  
205 end
206  
207  
208 function initChatParseforPetDiesEvent()
209 PetDies_ChatParseInfo.event = "CHAT_MSG_COMBAT_FRIENDLY_DEATH";
210 PetDies_ChatParseInfo.func = function(t) PetFeeder_PetIsDead(true); end;
211 PetDies_ChatParseInfo.template = "%s "..PETFEEDER_PET_DIES_MSG;
212 PetDies_ChatParseInfo.english = "Aslok dies."; -- example
213 PetDies_ChatParseInfo.fields = { };
214 end
215 --[[
216 =============================================================================
217 Initialize saves, slash cmd and panels
218 =============================================================================
219 ]]
220 function PetFeederFrame_OnLoad()
221  
222 if ( UnitClass("player") ~= PETFEEDER_HUNTER ) then
223 if ( DEFAULT_CHAT_FRAME ) then
224 DEFAULT_CHAT_FRAME:AddMessage("|cFFFFFF00PetFeeder:|r "..PETFEEDER_SESSION_DISABLED);
225 end
226 return;
227 end
228  
229 PetFeederFrame_LoadData();
230  
231 -- Register for Events
232 this:RegisterEvent("PET_ATTACK_START");
233 this:RegisterEvent("PET_ATTACK_STOP");
234 this:RegisterEvent("UNIT_HAPPINESS");
235 this:RegisterEvent("PLAYER_REGEN_DISABLED");
236 this:RegisterEvent("PLAYER_REGEN_ENABLED");
237 this:RegisterEvent("PLAYER_PET_CHANGED");
238 this:RegisterEvent("PLAYER_ALIVE");
239 this:RegisterEvent("PLAYER_UNGHOST")
240 this:RegisterEvent("PLAYER_DEAD");
241 this:RegisterEvent("TRADE_SHOW");
242 this:RegisterEvent("TRADE_CLOSED");
243 this:RegisterEvent("LOOT_SHOW");
244 this:RegisterEvent("LOOT_CLOSED");
245 this:RegisterEvent("CHAT_MSG_COMBAT_FRIENDLY_DEATH");
246 this:RegisterEvent("PET_BAR_UPDATE"); -- to get the rez pet event
247 this:RegisterEvent("BAG_UPDATE");
248 this:RegisterEvent("UNIT_NAME_UPDATE");
249 this:RegisterEvent("LOCALPLAYER_PET_RENAMED");
250  
251 -- this is player initiated and will help fire the feeding
252 this:RegisterEvent("PLAYER_TARGET_CHANGED");
253  
254 -- Hook functions
255 if ( not Pre_DoEmote ) then
256 Pre_DoEmote = DoEmote;
257 DoEmote = PetFeeder_DoEmote;
258 end
259  
260 if ( not Pre_PetFeeder_ZMI ) then
261 Pre_PetFeeder_ZMI = CameraZoomIn;
262 CameraZoomIn = PetFeeder_ZMI;
263 end
264  
265 if ( not Pre_PetFeeder_ZMO ) then
266 Pre_PetFeeder_ZMO = CameraZoomOut;
267 CameraZoomOut = PetFeeder_ZMO;
268 end
269  
270  
271 local chatParseInfo = { AddOn = "PetFeeder" };
272 chatParseInfo.event = "CHAT_MSG_SPELL_FAILED_LOCALPLAYER";
273 chatParseInfo.func = function(t) PetFeeder_RemoveBadFood(); end;
274 chatParseInfo.template = PETFEEDER_FAILED_TO_FEED;
275 chatParseInfo.english = "You fail to perform Feed Pet: Your pet doesn't like that food.";
276 chatParseInfo.fields = { };
277  
278 if ( not PFChatParse_RegisterEvent ) then
279 PFDebugMessage("PF", "function PFChatParse_RegisterEvent not defined!", "error");
280 end
281  
282 PFChatParse_RegisterEvent(chatParseInfo);
283  
284 local chatParseInfo1 = { AddOn = "PetFeeder" };
285 chatParseInfo1.event = "CHAT_MSG_SPELL_FAILED_LOCALPLAYER";
286 chatParseInfo1.func = function(t) PetFeeder_RemoveBadFood(); end;
287 chatParseInfo1.template = PETFEEDER_FOODTOOLOW;
288 chatParseInfo1.english = "You fail to perform Feed Pet: That food's level is not high enough for your pet.";
289 chatParseInfo1.fields = { };
290 PFChatParse_RegisterEvent(chatParseInfo1);
291  
292 local chatParseInfo2 = { AddOn = "PetFeeder" };
293 chatParseInfo2.event = "CHAT_MSG_SYSTEM";
294 chatParseInfo2.func = function() PetFeeder_DoEmote("SIT"); end;
295 chatParseInfo2.template = PETFEEDER_AFK;
296 chatParseInfo2.english = "You are now AFK: Away from Keyboard";
297 chatParseInfo2.fields = { };
298 PFChatParse_RegisterEvent(chatParseInfo2);
299  
300 if ( DEFAULT_CHAT_FRAME ) then
301 DEFAULT_CHAT_FRAME:AddMessage("Jeff's "..PETFEEDER_TITLE.." AddOn loaded. Use /pf");
302 end
303 UIErrorsFrame:AddMessage(loadMessage, 1.0, 1.0, 0.0, 1.0, UIERRORS_HOLD_TIME);
304  
305 -- Register Slash Commands
306 SLASH_PetFeeder1 = "/PetFeeder";
307 SLASH_PetFeeder2 = "/pf";
308 SlashCmdList["PetFeeder"] = function(msg)
309 PetFeeder_SlashCmd(msg);
310 end
311  
312 -- Tab Handling code
313 PanelTemplates_SetNumTabs(PetFeederFrame, 3);
314 PanelTemplates_SetTab(PetFeederFrame, 1);
315  
316 this.loaded = nil;
317  
318 end
319  
320 --[[
321 =============================================================================
322 Called when PF opens or closes
323 =============================================================================
324 ]]
325 function PetFeederFrame_OnShow()
326 PlaySound("igCharacterInfoOpen");
327 PetFeeder_Update_Frames();
328  
329 end
330  
331 function PetFeederFrame_OnHide()
332 PlaySound("igCharacterInfoClose");
333 end
334  
335 --[[
336 =============================================================================
337 Hooked Functions
338 replaces the original calls with our own and then calls the original. These
339 methods are hooked so we can detect when a player performs a specific action
340 such as sitting, jumping, etc.
341 =============================================================================
342 ]]
343 function PetFeeder_DoEmote(token,...)
344  
345 if ( token == "SIT" or token == "sit") then
346 -- DEFAULT_CHAT_FRAME:AddMessage("emote SIT");
347 PetFeeder_Var.sitPosX, PetFeeder_Var.sitPosY = GetPlayerMapPosition("player");
348 PetFeeder_Var.isSitting = true;
349 end
350 if ( token == "STAND" ) then
351 PetFeeder_Var.isSitting = false;
352 end
353  
354 if ( table.getn(arg) > 0 ) then
355 Pre_DoEmote(token,arg[1]);
356 else
357 Pre_DoEmote(token);
358 end
359  
360 end
361  
362 -- Zoom in mouse wheel hook to call our event handler
363 function PetFeeder_ZMI(arg1)
364 PetFeederFrame_OnEvent("PLAYER_TARGET_CHANGED","pet");
365 Pre_PetFeeder_ZMI(arg1);
366 end
367  
368 -- Zoom out mouse wheel hook to call our event handler
369 function PetFeeder_ZMO(arg1)
370 PetFeederFrame_OnEvent("PLAYER_TARGET_CHANGED","pet");
371 Pre_PetFeeder_ZMO(arg1);
372 end
373  
374  
375 --[[
376 =============================================================================
377 Walked through our list of foods and obtains the ItemCount for each
378 =============================================================================
379 ]]
380 function PetFeeder_UpdateQuantities()
381 PetFeeder_GetQuestItems();
382 for index, value in PetFeederPlayer_Foods[PetFeeder_PetName] do
383 -- update the item count
384 PetFeederPlayer_Foods[PetFeeder_PetName][index].quantity = PetFeeder_GetItemCount( value.name );
385  
386 end
387 end
388  
389  
390 function PetFeeder_GetQuestItems()
391  
392 PetFeeder_QuestItems = nil;
393 PetFeeder_QuestItems = {};
394 local numEntries, numQuests = GetNumQuestLogEntries()
395  
396 for questNum = 1, GetNumQuestLogEntries() do
397 SelectQuestLogEntry(questNum);
398 local questTitle, level, questTag, isHeader, isCollapsed, isComplete = GetQuestLogTitle(questNum);
399 if ( not isHeader ) then
400 for requiredItem = 1, GetNumQuestLeaderBoards(questNum) do
401  
402 local text, type, finished = GetQuestLogLeaderBoard(requiredItem);
403 if ( type == "item" ) then
404 local _, _, itemName, numCurrent, numRequired = string.find(text, "(.*): (%d+)/(%d+)");
405 --DEFAULT_CHAT_FRAME:AddMessage("itemName="..itemName);
406 --DEFAULT_CHAT_FRAME:AddMessage("numRequired="..numRequired);
407 if (PetFeeder_QuestItems[itemName]) then
408 PetFeeder_QuestItems[itemName] = PetFeeder_QuestItems[itemName] + numRequired;
409 else
410 PetFeeder_QuestItems[itemName] = numRequired;
411 end
412 end
413 end
414 end
415  
416 end
417 end
418  
419 function togglePetFeeder(tab)
420 if not ( PetFeeder_HasPet() ) then
421 UIErrorsFrame:AddMessage(PETFEEDER_ESTABLISH_PET, 0.8, 0, 0, 1.0, UIERRORS_HOLD_TIME);
422 return;
423 end
424  
425 if ( not tab ) then
426 if ( PetFeederFrame:IsVisible() ) then
427 HideUIPanel(PetFeederFrame);
428 else
429 ShowUIPanel(PetFeederFrame);
430 local selectedFrame = getglobal(PETFEEDER_TAB_SUBFRAMES[PetFeederFrame.selectedTab]);
431 if ( not selectedFrame:IsVisible() ) then
432 selectedFrame:Show();
433 end
434 end
435 else
436 local subFrame = getglobal(tab);
437 if ( subFrame ) then
438 PanelTemplates_SetTab(PetFeederFrame, subFrame:GetID() );
439 if ( PetFeederFrame:IsVisible() ) then
440 if ( subFrame:IsVisible() ) then
441 HideUIPanel( PetFeederFrame );
442 else
443 PlaySound("igCharacterInfoTab");
444 PetFeederFrame_ShowSubFrame(tab);
445 end
446 else
447 ShowUIPanel( PetFeederFrame );
448 PetFeederFrame_ShowSubFrame(tab);
449 end
450 end
451 end
452  
453  
454 end
455  
456 function PetFeederFrame_ShowSubFrame(frameName)
457 for index, value in PETFEEDER_TAB_SUBFRAMES do
458 if ( value == frameName ) then
459 getglobal(value):Show();
460 else
461 getglobal(value):Hide();
462 end
463 end
464 end
465 ---------------------------------------------------
466 --Show config dialog when slash-command is called--
467 ---------------------------------------------------
468 function PetFeeder_SlashCmd(msg)
469  
470 if ( not PetFeeder_HasPet() ) then
471 UIErrorsFrame:AddMessage(PETFEEDER_ESTABLISH_PET, 0.8, 0, 0, 1.0, UIERRORS_HOLD_TIME);
472 return;
473 end
474  
475 PetFeeder_PetName = UnitName( "pet" );
476  
477 if (msg == "feed" ) then
478 PetFeeder_Feed();
479 elseif ( msg == "clear" ) then
480 PetFeeder_ClearFoods();
481 elseif ( msg == "clearbad" ) then
482 PetFeeder_ClearBadFoods();
483 elseif ( msg == "dump" ) then
484 PetFeeder_DebugDump();
485 elseif ( msg == "toggledebug" ) then
486 PetFeeder_Var.debug = not PetFeeder_Var.debug;
487 if ( PetFeeder_Var.debug ) then
488 DEFAULT_CHAT_FRAME:AddMessage("debug is ON");
489 else
490 DEFAULT_CHAT_FRAME:AddMessage("debug is OFF");
491 end
492 elseif ( msg == "buff" ) then
493 PetFeeder_PlayerBuff();
494 elseif ( msg == "populate" ) then
495 PetFeeder_PopulateFoods();
496 else
497 togglePetFeeder(nil);
498 end
499  
500 end
501  
502 -- Do not localize this
503 function PetFeeder_DebugDump()
504 local i;
505 DEFAULT_CHAT_FRAME:AddMessage("Petname is "..PetFeeder_PetName);
506 DEFAULT_CHAT_FRAME:AddMessage("PetFeeder Foods in the order of consumption");
507 for index, value in PetFeederPlayer_Foods[PetFeeder_PetName] do
508 DEFAULT_CHAT_FRAME:AddMessage(value.name.." "..value.foodlikedstate);
509 end
510 end
511  
512 function PetFeeder_GetID(button)
513 if ( button == nil ) then
514 return 0;
515 end
516  
517 return (button:GetID())
518 end
519  
520 LLLAstEvetnt = nil;
521 local PetRename = false;
522  
523  
524 function PetFeederFrame_OnEvent(event, arg1)
525 --[[if ( LLLAstEvetnt ~= event ) then
526 LLLAstEvetnt = event;
527 DEFAULT_CHAT_FRAME:AddMessage(event);
528 if ( arg1 ) then
529 DEFAULT_CHAT_FRAME:AddMessage("Arg1: "..arg1);
530 end
531 if ( arg2 ) then
532 DEFAULT_CHAT_FRAME:AddMessage("Arg2: "..arg2);
533 end
534  
535 end]]
536  
537 if (not PeetFeederPlayer_Config.Enabled ) then
538 PFDebugMessage("PF", "PF is disabled", "debug");
539 return;
540 end
541  
542 local eventmsg = "event="..event;
543 PFDebugMessage("PF", eventmsg, "debug");
544 if (arg1 ) then
545 eventmsg = "arg1="..arg1;
546 PFDebugMessage("PF", eventmsg, "debug");
547 end
548  
549 if ( event == "PLAYER_PET_CHANGED" ) then
550 PetFeeder_Var.PetInCombat = false;
551 PetFeeder_Var.PetDead = false;
552 PetFeeder_Var.PlayerInCombat = false;
553 PetFeeder_Var.PlayerDead = false;
554 initChatParseforPetDiesEvent();
555 PFChatParse_UnregisterEvent(PetDies_ChatParseInfo);
556 PetDies_chatParseInfo.template = PetFeeder_PetName.." dies.";
557 PFChatParse_RegisterEvent(PetDies_ChatParseInfo);
558 PFDebugMessage("PF-Register", "registering Pet Died event", "debug");
559 return;
560 end
561  
562 if ( event == "PET_ATTACK_START" ) then
563 PetFeeder_Var.PetInCombat = true;
564 PFDebugMessage("PF", "Pet START COMBAT", "debug");
565 return;
566 elseif ( event == "PLAYER_REGEN_DISABLED" ) then
567 PetFeeder_Var.PlayerInCombat = true;
568 return;
569 elseif ( event == "PET_ATTACK_STOP" ) then
570 PFDebugMessage("PF", "Pet EXIT COMBAT", "debug");
571 PetFeeder_Var.PetInCombat = false;
572 elseif ( event == "PLAYER_REGEN_ENABLED" ) then
573 PetFeeder_Var.PlayerInCombat = false;
574 elseif ( event == "PET_BAR_UPDATE" and arg1 == nil) then
575 if ( not PetFeeder_HasPet() ) then
576 return;
577 end
578 PetFeeder_PetName = UnitName("pet");
579 if ( LastPetName ) then
580 LastPetName = nil;
581 else
582 LastPetName = PetFeeder_PetName;
583 end
584 PetFeeder_Var.PetDead = false;
585 PetFeeder_Var.PetInCombat = false; -- Pet could have died during combat and we don't get notified
586 PFDebugMessage("PF-Alive", "Pet is alive <showgrid>", "debug");
587 if ( PeetFeederPlayer_Config.AutoFindFood ) then
588 PetFeeder_PopulateFoods();
589 end
590 PetFeeder_Update_Frames();
591 elseif ( event == "PLAYER_DEAD" ) then
592 PetFeeder_Var.PlayerDead = true;
593 return;
594 elseif ( event == "PLAYER_ALIVE" or event == "PLAYER_UNGHOST" ) then -- no notification of deaths, be sure to clear these
595 PetFeeder_Var.PetInCombat = false;
596 PetFeeder_Var.PlayerInCombat = false;
597 PetFeeder_Var.PlayerDead = false;
598 elseif ( event == "TRADE_SHOW" or event == "LOOT_SHOW") then
599 PetFeeder_Var.TradeOrLoot = true;
600 return;
601 elseif ( event == "TRADE_CLOSED" or event == "LOOT_CLOSED") then
602 PetFeeder_Var.TradeOrLoot = false;
603 return;
604 elseif ( event == "BAG_UPDATE" or event == "UNIT_PET" ) then
605 if ( not PetFeeder_HasPet() ) then
606 return;
607 end
608 if ( PeetFeederPlayer_Config.AutoFindFood ) then
609 PetFeeder_PopulateFoods();
610 end
611 PetFeeder_Update_Frames();
612 elseif ( event == "LOCALPLAYER_PET_RENAMED" ) then
613 PetRename = true;
614 elseif ( event == "UNIT_NAME_UPDATE" ) then
615 if ( arg1 and arg1 == "pet" ) then
616 if ( not PetFeeder_HasPet() ) then
617 return;
618 end
619 if ( PetFeeder_PetName ~= UnitName("pet") ) then
620 --DEFAULT_CHAT_FRAME:AddMessage("UNIT_NAME_UPDATE is running "..UnitName("pet"));
621 if ( PetRename ) then
622 if ( PetFeederPlayer_Foods[PetFeeder_PetName] ) then
623 PetFeederPlayer_Foods[UnitName("pet")] = PetFeederPlayer_Foods[PetFeeder_PetName];
624 end
625 PetRename = false;
626  
627 elseif ( PetFeederPlayer_Foods[PetFeeder_PetName] ) then
628 PetFeederPlayer_Foods[PetFeeder_PetName] = {};
629 LastPetName = UnitName("pet");
630 end
631 PetFeeder_PetName = UnitName("pet");
632  
633 else
634  
635 return;
636 end
637 if ( PeetFeederPlayer_Config.AutoFindFood ) then
638 PetFeeder_PopulateFoods();
639 end
640 PetFeeder_Update_Frames();
641 return;
642 else
643 return;
644 end
645  
646 end
647  
648  
649  
650 -- HACK
651 -- in v1.10 Blizzard changed the DropItemOnUnit( ) method so that it must be player
652 -- click event related. This event identifies such an event.
653 -- There's no reason to even try feeding the pet unless this event has fired otherwise the feed attempt will fail.
654 if ( event == "PLAYER_TARGET_CHANGED" ) then
655 if ( PeetFeederPlayer_Config.Enabled ) then
656 PFDebugMessage("PF", "Attempt to feed", "debug");
657 if ( PetFeeder_CheckHappiness() == false ) then
658 return; -- feeding not necessary
659 end
660 PetFeeder_Feed();
661 end
662 end
663 end
664  
665  
666 function PetFeeder_CanFeed()
667 -- Abort routines
668 if not ( PetFeeder_HasPet() ) then
669 PFDebugMessage("PF-Abort", "cannot find a pet", "debug");
670 PetFeeder_Var.PetInCombat = false; -- Pet could have died during combat and we don't get notified
671 return;
672 end
673 if ( UnitHealth("pet") <= 0 ) then
674 PFDebugMessage("PF-Abort", "Pet Dead", "debug");
675 return false;
676 end
677 if ( UnitHealth("player") <= 0 ) then
678 PFDebugMessage("PF-Abort", "Player Dead", "debug");
679 return false;
680 end
681 if ( CastingBarFrameStatusBar:IsVisible() ) then
682 PFDebugMessage("PF-Abort", "Player Casting Spell", "debug");
683 return false;
684 end
685 if ( UnitOnTaxi("player") ) then
686 PFDebugMessage("PF-Abort", "Player On Taxi", "debug");
687 return false;
688 end
689  
690  
691 if ( PetFeeder_Var.PetInCombat == true or PetFeeder_Var.PlayerInCombat == true ) then
692 PFDebugMessage("PF-Abort", "Can't feed while in combat", "debug");
693 return false;
694 end
695  
696 if ( PetFeeder_HasFeedEffect() ) then
697 PFDebugMessage("PF-Abort", "Pet already has Feed effect", "debug");
698 return false;
699 end
700  
701 -- Extra check to clear sitting flag
702 if ( PetFeeder_Var.isSitting == true) then
703 local posX, posY = GetPlayerMapPosition("player");
704 if ( PetFeeder_Var.sitPosX ~= posX ) then
705 PetFeeder_Var.isSitting = false;
706 elseif (PetFeeder_Var.sitPosY ~= posY ) then
707 PetFeeder_Var.isSitting = false;
708 end
709 end
710  
711 -- Must have Pet from here down
712 if ( not PetFeeder_PetName or PetFeeder_PetName == "" or PetFeeder_PetName == "Unknown Entity" ) then
713 PetFeeder_PetName = UnitName( "pet" );
714 if ( not PetFeeder_PetName or PetFeeder_PetName == "" ) then
715 PFDebugMessage("PF-Critical", "Did not find pet in <event handler>", "debug");
716 return false;
717 end
718 initChatParseforPetDiesEvent();
719 PFChatParse_UnregisterEvent(PetDies_ChatParseInfo);
720 PetDies_ChatParseInfo.template = PetFeeder_PetName.." dies.";
721 PFChatParse_RegisterEvent(PetDies_ChatParseInfo);
722 PFDebugMessage("PF-Register", "registering Pet Died event", "debug");
723 end
724  
725 if ( not PetFeederPlayer_Foods[PetFeeder_PetName] ) then
726 PFDebugMessage("PF", "inserting new pet", "debug");
727 PetFeederPlayer_Foods[PetFeeder_PetName] = {};
728 end
729  
730  
731  
732 -- Is there a debuff on the pet that will break the feeding Buff?
733 if ( PetFeeder_PetDebuff() ) then
734 PFDebugMessage("PF-Abort", "Pet is debuffed", "debug");
735 return false;
736 end
737  
738 -- check for player buffs that might interfere with feeding
739 -- or result in undesired effects (such as stopping feign death or shadowmelding)
740 if ( PetFeeder_PlayerBuff() ) then
741 PFDebugMessage("PF-Abort", "Can't feed with these player buffs", "debug");
742 return false;
743 end
744  
745 return true;
746 end
747  
748  
749 -- Check player buffs
750 -- return true if buff enabled we don't want to break by feeding
751 -- (i.e. FeignDeath or Shadowmeld )
752 function PetFeeder_PlayerBuff()
753 local i = 1;
754 local buff;
755 local unit = "player";
756 buff = UnitBuff(unit,i);
757 while buff do
758 --PetFeederTooltip:SetUnitBuff( unit, i );
759 --DEFAULT_CHAT_FRAME:AddMessage("debug::Player buff::"..i.."="..buff);
760 local debuginfo = "Player buff::"..i.."="..buff;
761 if ( isMounted( unit, i, buff ) ) then
762 PFDebugMessage("PF-Abort", "Player is mounted", "debug");
763 return true;
764 elseif ( string.find(buff, "Ability_Rogue_FeignDeath") ) then
765 PFDebugMessage("PF-Abort", debuginfo, "debug");
766 return true;
767 elseif ( string.find(buff, "Ability_Ambush") ) then -- shadowmeld
768 PFDebugMessage("PF-Abort", debuginfo, "debug");
769 return true;
770 elseif ( string.find(buff, "DemonBreath") ) then -- water breathing
771 PFDebugMessage("PF-Abort", debuginfo, "debug");
772 return true;
773 end
774 i = i + 1;
775 buff = UnitBuff(unit,i);
776 end
777  
778 -- Check for eating or drinking
779 local playerBuffs = {"Interface\\Icons\\INV_Drink_07","Interface\\Icons\\INV_Misc_Fork&Knife"};
780 for i=0, 15 do
781 buff = GetPlayerBuffTexture(i);
782 if ( buff ) then
783 for k,v in playerBuffs do
784 if ( buff == v ) then
785 PFDebugMessage("PF-Abort", buff, "debug");
786 return true;
787 end
788 end
789 end
790 end
791  
792 if ( PetFeeder_Var.TradeOrLoot ) then
793 return true;
794 end
795  
796 return false;
797 end
798  
799 --=============================================================================
800 -- Return information about the pattern
801 --
802 -- pattern pattern to find
803 local function BuffInformation( pattern )
804 if pattern then
805 return string.find( PetFeederTooltipTextLeft2:GetText(), pattern );
806 else
807 return 1;
808 end
809 end
810 --=============================================================================
811  
812 -- Check to see if the player is mounted
813 function isMounted(unit, i, buff )
814 PetFeederTooltip:SetUnitBuff( unit, i );
815 if ( string.find(buff, "_Mount_" ) or string.find(buff,"INV_Misc_Foot_Kodo") ) then
816 local startpos,endpos,buffValue = BuffInformation(" (%d+)%%");
817 if ( buffValue ~= nil ) then
818 buffValue = buffValue + 0;
819 if ( buffValue >=60 ) then
820 return true;
821 end
822 end
823 end
824  
825 return false;
826  
827 end
828  
829 -- Check pet debuffs
830 -- return true if pet has debuff that will break feeding
831 -- (i.e. poisoned )
832 function PetFeeder_PetDebuff()
833 local i = 1;
834 local buff;
835 buff = UnitDebuff("pet", i);
836  
837 while buff do
838 local debuginfo = "Pet debuff::"..i.."="..buff;
839 --PFDebugMessage("PF", debuginfo, "debugbuff");
840  
841 if ( string.find(buff, "Spell_Nature_CorrosiveBreath") ) then
842 return true; -- this comes from a Venom Spitter when it poisons the target
843 end
844 if ( string.find(buff, "Spell_Nature") ) then
845 return true; -- this might be too liberal, but should catch all instances we are searching for
846 end
847 i = i + 1;
848 buff = UnitDebuff("pet", i);
849 end
850 return false;
851  
852 end
853  
854 -- Check Feed Effect
855 function PetFeeder_HasFeedEffect()
856 local i = 1;
857 local buff;
858 buff = UnitBuff("pet", i);
859  
860 while buff do
861 local debuginfo = "Pet buff::"..i.."="..buff;
862 --PFDebugMessage("PF", debuginfo, "debugbuff");
863  
864 if ( string.find(buff, "Ability_Hunter_BeastTraining") ) then
865 return true;
866 end
867 i = i + 1;
868 buff = UnitBuff("pet", i);
869 end
870 return false;
871  
872 end
873  
874 -- Check Happiness
875 function PetFeeder_CheckHappiness()
876  
877 if ( UnitHealth("pet") <= 0 ) then
878 PFDebugMessage("PF-Abort", "Pet Dead", "debug");
879 return false;
880 end
881 if ( UnitHealth("player") <= 0 ) then
882 PFDebugMessage("PF-Abort", "Player Dead", "debug");
883 return false;
884 end
885  
886 -- Get Pet Info
887 --local pet = UnitName("pet");
888 local happiness, damage, loyalty = GetPetHappiness();
889  
890 local level = PeetFeederPlayer_Config.Level + 1;
891  
892 -- Check Happiness
893 if ( happiness == 0 ) or ( happiness == nil ) then
894 PFDebugMessage("PF-Abort", "Unable to determine pet happiness", "debug");
895 return false;
896 end
897  
898 if ( happiness >= level ) then
899 local msg = "Feeding not necessary. Pet happiness is at threshold:"..PETFEEDER_LEVELS_DROPDOWN[happiness-1].name;
900 PFDebugMessage("PF-Abort", msg, "debug");
901 return false;
902 end
903  
904 -- Check if Feeding is needed
905 PFDebugMessage("PF", "pet isn't happy enough", "debug");
906  
907 if not ( PetFeeder_Var.Searching ) then
908 return true;
909 else
910 PFDebugMessage("PF-Abort", "Pet already searching for food", "debug");
911 end
912  
913 return false;
914 end
915  
916 -- Feed Pet
917 function PetFeeder_Feed()
918  
919 if ( not PetFeeder_Var.feedStartTime) then
920 PetFeeder_Var.feedStartTime = GetTime();
921 else
922 local time = GetTime();
923 local timePast = time - PetFeeder_Var.feedStartTime;
924 if ( timePast < 2 ) then
925 return;
926 end
927 end
928  
929  
930  
931 if ( not PetFeeder_CanFeed() ) then return; end
932  
933 -- Check if dragging item
934 if ( CursorHasItem() ) then
935 PFDebugMessage("PF-Abort", "item is on cursor", "debug");
936 return;
937 end
938  
939 -- Make sure PetFeeder_PetName has pet name
940 PetFeeder_PetName = UnitName( "pet" );
941 if ( not PetFeederPlayer_Foods[PetFeeder_PetName] ) then
942 PetFeederPlayer_Foods[PetFeeder_PetName] = {};
943 end
944  
945 PetFeeder_UpdateQuantities();
946 PetFeeder_Var.Searching = true;
947 if ( PeetFeederPlayer_Config.Alert ) then
948 DEFAULT_CHAT_FRAME:AddMessage(PetFeeder_PetName..PETFEEDER_BEGIN_SEARCH);
949 end
950  
951 -- 1. Get first available food from our list with quantity > 0
952 -- 2. Find the m,n location of it in the pack.
953 -- 3. Pick up and eat.
954 local lowestQuantity = 99;
955 local lowestM = 0;
956 local lowestN = 0;
957 for index, value in PetFeederPlayer_Foods[PetFeeder_PetName] do
958 if ( value.quantity > 0 ) then
959  
960 if ( PeetFeederPlayer_Config.RequireApproval and PeetFeederPlayer_Config.RequireApproval == 1 and value.foodlikedstate == PETFEEDER_FL_UNKNOWN ) then
961 PetFeeder_ApproveFoodItem(value.name);
962 PetFeeder_Var.Feed = true;
963  
964 return;
965 end
966 if ( (PeetFeederPlayer_Config.FeedOnlyApproved == 1 and value.foodlikedstate == PETFEEDER_FL_APPROVED) or ( PeetFeederPlayer_Config.FeedOnlyApproved == 0 and value.foodlikedstate > 0 ) )then
967  
968 -- Find lowest instance of the food item
969 for m = 0, 4 do
970 for n = 1, 18 do
971 itemObject = PetFeeder_GetItemObject(m,n);
972 if ( itemObject and itemObject.name == value.name ) then
973 -- Using this itemCount because we need the actual value in the slot
974 local texture, itemCount, locked, quality, readable = GetContainerItemInfo(m,n);
975 if ( itemCount < lowestQuantity ) then
976 --DEFAULT_CHAT_FRAME:AddMessage("lowest M = "..m.." lowestN="..n.." lowestqty="..itemCount);
977 lowestQuantity = itemCount;
978 lowestM = m;
979 lowestN = n;
980 end
981 end
982 end
983 end
984  
985 local msg = "Feed item in bag,slot="..lowestM..","..lowestN.." which is "..value.name;
986 PFDebugMessage("PF", msg, "debug" );
987  
988 PickupContainerItem( lowestM, lowestN );
989  
990 PetFeeder_Var.feedStartTime = GetTime();
991  
992 if ( CursorHasItem() ) then
993 DropItemOnUnit("pet");
994 PetFeeder_Var.LastItemAttempted = value;
995 PFDebugMessage("PF", "Fed item "..value.name, "debug" );
996 end
997 if ( CursorHasItem() ) then
998 PickupContainerItem(lowestM, lowestN);
999 end
1000  
1001 value.quantity = value.quantity - 1;
1002 -- Alert
1003 if ( PeetFeederPlayer_Config.Alert ) then
1004 DEFAULT_CHAT_FRAME:AddMessage(PetFeeder_PetName..PETFEEDER_EATS_A..value.name );
1005 end
1006  
1007 PetFeeder_Var.Searching = false;
1008 return;
1009 end
1010 end
1011 end
1012  
1013 -- No Food Could be Found
1014 PFDebugMessage("PF", "No food could be found to feed the pet", "debug" );
1015 if ( PeetFeederPlayer_Config.Alert ) then
1016 DEFAULT_CHAT_FRAME:AddMessage(PetFeeder_PetName..PETFEEDER_NO_FOOD);
1017 end
1018  
1019 PetFeeder_Var.Searching = false;
1020 end
1021  
1022 function PetFeeder_ApproveFoodItem( lname )
1023  
1024 local _,_,name = string.find(lname, "(.*) %(%d+%)");
1025 if ( not name ) then
1026 name = lname;
1027 end
1028  
1029 StaticPopupDialogs["PetFeeder_ApproveFoodItem"] = {
1030 text = PETFEEDER_APPROVE_FOOD..": "..name,
1031 button1 = PETFEEDER_APPROVE,
1032 button2 = PETFEEDER_DISLIKE,
1033 whileDead = 1,
1034 OnAccept = function()
1035 PetFeeder_AddFood(name, PETFEEDER_FL_APPROVED);
1036 PetFeeder_Var.DialogShowing = false;
1037 PetFeeder_Var.Searching = false;
1038 if ( PetFeeder_Var.Feed == true ) then
1039 PetFeeder_Feed();
1040 end
1041 PetFeeder_Update_Frames();
1042 end,
1043 OnCancel = function()
1044 PetFeeder_AddFood(name, PETFEEDER_FL_DISLIKED);
1045 PetFeeder_Var.DialogShowing = false;
1046 PetFeeder_Var.Searching = false;
1047 if ( PetFeeder_Var.Feed == true ) then
1048 -- PetFeeder_Feed();
1049 end
1050 PetFeeder_Update_Frames();
1051 end,
1052  
1053 timeout = 0
1054 };
1055 PetFeeder_Var.DialogShowing = true;
1056 StaticPopup_Show("PetFeeder_ApproveFoodItem");
1057  
1058 end
1059  
1060 ------------------
1061 -- Threshold Dropdown
1062 ------------------
1063 local function PetFeederFrameDropDown_Initialize()
1064 local info;
1065 for i = 1, getn(PETFEEDER_LEVELS_DROPDOWN), 1 do
1066 info = { };
1067 info.text = PETFEEDER_LEVELS_DROPDOWN[i].name;
1068 info.func = PetFeederFrameDropDownButton_OnClick;
1069 UIDropDownMenu_AddButton(info);
1070 end
1071 end
1072  
1073 function PetFeederFrameDropDown_OnLoad()
1074 UIDropDownMenu_Initialize(PetFeederFrameDropDown, PetFeederFrameDropDown_Initialize);
1075 UIDropDownMenu_SetWidth(80);
1076 UIDropDownMenu_SetButtonWidth(24);
1077 UIDropDownMenu_JustifyText("LEFT", PetFeederFrameDropDown)
1078 end
1079  
1080 function PetFeederFrameDropDownButton_OnClick()
1081 UIDropDownMenu_SetSelectedID(PetFeederFrameDropDown, this:GetID());
1082 PeetFeederPlayer_Config.Level = UIDropDownMenu_GetSelectedID(PetFeederFrameDropDown);
1083 end
1084  
1085  
1086 -- Sorting Algorithms
1087  
1088  
1089 function PetFeeder_SortFoods()
1090  
1091 if ( PetFeederPlayer_Foods[PetFeeder_PetName] == nil ) then
1092 PetFeeder_ClearFoods();
1093 return;
1094 end
1095  
1096 PetFeeder_UpdateQuantities();
1097  
1098 table.sort( PetFeederPlayer_Foods[PetFeeder_PetName], function(a,b) return a.name > b.name end );
1099  
1100  
1101 if ( PeetFeederPlayer_Config.SortOption == 1 ) then
1102 return;
1103 end;
1104  
1105  
1106 table.sort( PetFeederPlayer_Foods[PetFeeder_PetName], PetFeeder_CompareItem );
1107  
1108 end
1109 --[[
1110 =============================================================================
1111 The primary sort compare method. We may call up to to actual sorting methods
1112 depending on the results. The sorting methods return 1, 0, -1 while
1113 this method results true|false;
1114 returns:
1115 =============================================================================
1116 ]]
1117  
1118 function PetFeeder_CompareItem(a,b)
1119  
1120 local result = 0;
1121  
1122 if ( not PeetFeederPlayer_Config.SortOption ) then PeetFeederPlayer_Config.SortOption = 1; end
1123 if ( PETFEEDER_SORTOPTION_DROPDOWN[PeetFeederPlayer_Config.SortOption].func ) then
1124 result = PETFEEDER_SORTOPTION_DROPDOWN[PeetFeederPlayer_Config.SortOption].func(a,b);
1125 end
1126  
1127 if ( not PeetFeederPlayer_Config.SortOption2 ) then PeetFeederPlayer_Config.SortOption2 = 3; end
1128  
1129 if (PETFEEDER_SORTOPTION_DROPDOWN[PeetFeederPlayer_Config.SortOption2].func and result == 0) then
1130 result = PETFEEDER_SORTOPTION_DROPDOWN[PeetFeederPlayer_Config.SortOption2].func(a,b);
1131 end
1132  
1133  
1134 return result > 0;
1135  
1136 end
1137  
1138 function sortQuantityHighLow(a,b)
1139 --table.sort( PetFeeder_Foods[PetFeeder_PetName], function(a,b) return a.quantity > b.quantity end );
1140 if ( a and b ) then
1141 return a.quantity - b.quantity;
1142 else
1143 return 0;
1144 end
1145 end
1146 function sortQuantityLowHigh(a,b)
1147 --table.sort( PetFeeder_Foods[PetFeeder_PetName], function(a,b) return a.quantity < b.quantity end );
1148 if ( a and b ) then
1149 return b.quantity - a.quantity;
1150 else
1151 return 0;
1152 end
1153 end
1154 function sortQualityHighLow(a,b)
1155 --table.sort( PetFeeder_Foods[PetFeeder_PetName], function(a,b) return a.quality > b.quality end );
1156 if ( a and b ) then
1157 return a.quality - b.quality;
1158 else
1159 return 0;
1160 end
1161 end
1162 function sortQualityLowHigh(a,b)
1163 --table.sort( PetFeeder_Foods[PetFeeder_PetName], function(a,b) return a.quality < b.quality end );
1164 if ( a and b ) then
1165 return b.quality - a.quality;
1166 else
1167 return 0;
1168 end
1169 end
1170 function sortAlphabeticallyHighLow(a,b)
1171 --table.sort( PetFeeder_Foods[PetFeeder_PetName], function(a,b) return a.name > b.name end );
1172 if ( a and b ) then
1173 if ( a.name > b.name ) then
1174 return 1;
1175 elseif ( a.name == b.name ) then
1176 return 0;
1177 end
1178 return -1;
1179 end
1180 return 0;
1181 end
1182  
1183 function sortAlphabeticallyLowHigh(a,b)
1184 --table.sort( PetFeeder_Foods[PetFeeder_PetName], function(a,b) return a.name < b.name end );
1185 if ( a and b ) then
1186 if ( a.name < b.name ) then
1187 return 1;
1188 elseif ( a.name == b.name ) then
1189 return 0;
1190 end
1191 return -1;
1192 end
1193 return 0;
1194 end
1195  
1196  
1197 ----------------------------
1198 --PetFeeder Checkbuttons--
1199 -----------------------------
1200 function PetFeeder_PF_Enabled_CheckBt_Update(whatValue)
1201 PeetFeederPlayer_Config.Enabled = whatValue;
1202 PetFeeder_Update_Frames();
1203 end
1204  
1205 function PetFeeder_PF_AutoFindFood_CheckBt_Update(whatValue)
1206 PeetFeederPlayer_Config.AutoFindFood = whatValue;
1207 if ( PeetFeederPlayer_Config.AutoFindFood ) then
1208 PetFeeder_PopulateFoods();
1209 end
1210 PetFeeder_Update_Frames();
1211  
1212 end
1213  
1214 function PetFeeder_PF_Alerts_CheckBt_Update(whatValue)
1215 PeetFeederPlayer_Config.Alert = whatValue;
1216 end
1217  
1218 function PetFeeder_PF_SkipBuffFoods_CheckBt_Update(whatValue)
1219 PeetFeederPlayer_Config.skipBuffFoods = whatValue;
1220 if ( PeetFeederPlayer_Config.AutoFindFood ) then
1221 PetFeeder_PopulateFoods();
1222 end
1223 PetFeeder_Update_Frames();
1224 end
1225  
1226 function PetFeeder_PF_FeedOnlyApproved_CheckBt_Update(whatValue)
1227 PeetFeederPlayer_Config.FeedOnlyApproved = whatValue;
1228 end
1229  
1230 function PetFeeder_PF_RequireApproval_CheckBt_Update(whatValue)
1231 PeetFeederPlayer_Config.RequireApproval = whatValue;
1232 end
1233  
1234 --[[
1235 =============================================================================
1236 Food Management Routines
1237 =============================================================================
1238 ]]
1239  
1240 --[[
1241 =============================================================================
1242 Adds a food item to the Food list or the Bad food list. Checks to ensure
1243 that the food isn't already in the table and checks to ensure we aren't
1244 re-adding food the Pet doesn't like.
1245 params:
1246 - PetFeederPlayer_Foods[PetFeeder_PetName]: list to add the item to.
1247 - value : table object for the item
1248 =============================================================================
1249 ]]
1250  
1251 function PetFeeder_AddFood( value , foodlikedstate )
1252  
1253 -- DEFAULT_CHAT_FRAME:AddMessage(value);
1254 -- Make sure PetFeeder_PetName has real pet name
1255 PetFeeder_PetName = UnitName( "pet" );
1256 if ( not PetFeeder_PetName ) then
1257 return;
1258 end
1259 if ( not PetFeederPlayer_Foods[PetFeeder_PetName] ) then
1260 PetFeederPlayer_Foods[PetFeeder_PetName] = {};
1261 end
1262  
1263 local changeVal = true;
1264 if ( not foodlikedstate ) then
1265 foodlikedstate = PETFEEDER_FL_UNKNOWN;
1266 changeVal = false;
1267 end
1268  
1269 if ( type(value) ~= "table" ) then
1270 local _,_,name = string.find(value, "(.*) %(%d+%)");
1271 if ( not name ) then
1272 name = value;
1273 end
1274 if ( name ) then
1275 for i=1, table.getn( PetFeederPlayer_Foods[PetFeeder_PetName] ) do
1276 if ( PetFeederPlayer_Foods[PetFeeder_PetName][i].name == name ) then
1277 value = PetFeederPlayer_Foods[PetFeeder_PetName][i];
1278 end
1279 end
1280 end
1281  
1282 end
1283  
1284 if ( not value ) then
1285 return;
1286 end
1287  
1288 -- don't add if already in the table
1289 -- just change foodlikedstate state
1290  
1291 PFDebugMessage("PF", "Pet Name: "..PetFeeder_PetName, "debug");
1292 if ( not PetFeederPlayer_Foods[PetFeeder_PetName] ) then
1293 PFDebugMessage("PF", "No table for pet", "debug");
1294 end
1295 PFDebugMessage("PF", "Food State Name: "..foodlikedstate, "debug");
1296 for i=1, table.getn( PetFeederPlayer_Foods[PetFeeder_PetName] ) do
1297 if ( PetFeederPlayer_Foods[PetFeeder_PetName][i].name == value.name ) then
1298 if ( changeVal or not PetFeederPlayer_Foods[PetFeeder_PetName][i].foodlikedstate ) then
1299 PFDebugMessage("PF", "Change Food State Name: "..foodlikedstate, "debug");
1300 PetFeederPlayer_Foods[PetFeeder_PetName][i].foodlikedstate = foodlikedstate;
1301 end
1302 return true;
1303 end
1304 end
1305  
1306  
1307 value.foodlikedstate = foodlikedstate;
1308  
1309 table.insert(PetFeederPlayer_Foods[PetFeeder_PetName], value );
1310  
1311 return true;
1312 end
1313  
1314 function PetFeeder_ClearFoods( foodlikedstate )
1315 if not ( PetFeeder_HasPet() ) then
1316 UIErrorsFrame:AddMessage(PETFEEDER_NEED_PET, 0.8, 0, 0, 1.0, UIERRORS_HOLD_TIME);
1317 return;
1318 end
1319  
1320 PetFeeder_PetName = UnitName( "pet" );
1321 if ( not foodlikedstate ) then
1322 PetFeederPlayer_Foods[PetFeeder_PetName] = {};
1323 else
1324 for i=table.getn( PetFeederPlayer_Foods[PetFeeder_PetName] ), 1,-1 do
1325 if ( PetFeederPlayer_Foods[PetFeeder_PetName][i].foodlikedstate == foodlikedstate ) then
1326 table.remove(PetFeederPlayer_Foods[PetFeeder_PetName],i);
1327 -- PetFeeder_AddFood(PetFeederPlayer_Foods[PetFeeder_PetName][i], PETFEEDER_FL_UNKNOWN);
1328 end
1329 end
1330 end
1331 PetFeeder_Update_Frames();
1332 end
1333  
1334 function PetFeeder_FoodsFrame_UpdateExt( foodlikedstate )
1335  
1336 local frameCoWord;
1337  
1338 if ( not foodlikedstate ) then
1339 foodlikedstate = PETFEEDER_FL_UNKNOWN;
1340 end
1341  
1342 if ( foodlikedstate == PETFEEDER_FL_UNKNOWN ) then
1343 frameCoWord = "";
1344 elseif ( foodlikedstate == PETFEEDER_FL_APPROVED ) then
1345 frameCoWord = "Approved";
1346 else
1347 frameCoWord = "Unliked";
1348 end
1349  
1350 local iItem;
1351  
1352 local numEntries = 0;
1353 for index, value in PetFeederPlayer_Foods[PetFeeder_PetName] do
1354 if ( value.foodlikedstate == foodlikedstate ) then
1355 numEntries = numEntries + 1;
1356 end
1357 end
1358  
1359 --DEFAULT_CHAT_FRAME:AddMessage(frameCoWord.." numEntries "..numEntries);
1360  
1361 local scrollFrame = getglobal("PetFeeder_"..frameCoWord.."FoodsFrameListScrollFrame");
1362 FauxScrollFrame_Update(scrollFrame, numEntries, PETFEEDER_ITEMS_SHOWN, PETFEEDER_ITEM_HEIGHT, nil, nil, nil, nil, nil, PETFEEDER_ITEM_HEIGHT);
1363  
1364 local scrollFrameOffset = FauxScrollFrame_GetOffset(scrollFrame);
1365 --DEFAULT_CHAT_FRAME:AddMessage(" scrollFrameOffset "..scrollFrameOffset);
1366 local realItem = 1;
1367 local realIndex = 0;
1368 local usedButtons = 1;
1369 while usedButtons <= PETFEEDER_ITEMS_SHOWN do
1370 realIndex = realIndex + 1
1371 local buttonItem = getglobal("PetFeeder_"..frameCoWord.."FoodsFrameItem"..usedButtons);
1372 if ( usedButtons > numEntries ) then
1373 buttonItem:Hide();
1374 usedButtons = usedButtons + 1;
1375 else
1376  
1377 iconTexture = getglobal("PetFeeder_"..frameCoWord.."FoodsFrameItem"..usedButtons.."ItemIconTexture");
1378 if ( PetFeederPlayer_Foods[PetFeeder_PetName][realIndex] ) then
1379 local value = PetFeederPlayer_Foods[PetFeeder_PetName][realIndex];
1380  
1381 if ( value.foodlikedstate == foodlikedstate ) then
1382 if ( realItem > scrollFrameOffset ) then
1383 --DEFAULT_CHAT_FRAME:AddMessage(" realIndex "..realIndex.." Name "..value.name);
1384 if ( value.texture ) then
1385 iconTexture:SetTexture( value.texture );
1386 end
1387 local name = value.name.." ("..value.quantity..")";
1388 if ( value.quality ) then
1389 name = name.." - quality: "..value.quality;
1390 end
1391  
1392 buttonItem:SetText(name);
1393 buttonItem:Show();
1394 usedButtons = usedButtons + 1
1395 end
1396 realItem = realItem + 1;
1397  
1398 end
1399 else
1400 usedButtons = usedButtons + 1;
1401 end
1402 end
1403 end
1404 end
1405  
1406 --[[
1407 =============================================================================
1408 This method gets called by the ChatMsg callback functions when it detects
1409 that a pet doesn't like the food we fed it.
1410 - Bad food will be the first one readily available
1411 - Only gets called when a bad food item is detected
1412 - If the user manually feeds, the timer which is set when WE feed, will be off
1413 by more than 2 clicks. We don't want to remove any foods from our list because
1414 we don't know what the pet didn't like.
1415 params:
1416 - t: nil
1417 =============================================================================
1418 ]]
1419 function PetFeeder_RemoveBadFood()
1420  
1421 PetFeeder_UpdateQuantities();
1422  
1423 PFDebugMessage("PF", "Bad food detected "..PetFeeder_Var.LastItemAttempted.name, "debug");
1424  
1425 if ( (GetTime() - PetFeeder_Var.feedStartTime) >= 2 ) then
1426 PFDebugMessage("PF", "Not removing bad food as feed wasn't initiated by PF", "debug");
1427 return;
1428 end
1429 PetFeeder_Var.feedStartTime = 0;
1430 for index, value in PetFeederPlayer_Foods[PetFeeder_PetName] do
1431 if ( value.name == PetFeeder_Var.LastItemAttempted.name ) then
1432 if ( PeetFeederPlayer_Config.Alert ) then
1433 DEFAULT_CHAT_FRAME:AddMessage(PETFEEDER_REMOVE_FOOD..value.name);
1434 end
1435  
1436 PetFeeder_AddFood( value , PETFEEDER_FL_DISLIKED );
1437 break;
1438 end
1439 end
1440  
1441 PetFeeder_Update_Frames();
1442  
1443 end
1444  
1445 --[[
1446 =============================================================================
1447 Gets called when we want to drop an item onto the list. Identifies which
1448 item in bag,slot is being dropped, gets into about that item and then attempts
1449 to add it to the list.
1450 params:
1451 - PetFeederPlayer_Foods[PetFeeder_PetName]: the name of the list to add the item to.
1452 =============================================================================
1453 ]]
1454  
1455 function PetFeeder_Update_Frames()
1456 if ( not UnitName( "pet" ) ) then
1457 return;
1458 end
1459 PetFeeder_SortFoods();
1460 PetFeeder_UnlikedFoodsFrame_Update();
1461 PetFeeder_FoodsFrame_Update();
1462 PetFeeder_ApprovedFoodsFrame_Update();
1463  
1464 end
1465  
1466  
1467 function PetFeeder_DroptheItem( accept , foodlikedstate )
1468  
1469 if CursorHasItem() and PetFeeder_PickedupItem then
1470  
1471 local value = PetFeeder_GetItemObject( PetFeeder_PickedupItem.bag,PetFeeder_PickedupItem.slot );
1472 if ( value ) then
1473 --if ( accept == "any" ) then
1474 -- if ( PetFeederFrame_IsFood( value ) or accept == "any" ) then
1475  
1476 PetFeeder_AddFood( value, foodlikedstate );
1477  
1478 --end
1479 end
1480 ResetCursor();
1481 PetFeeder_TakeItemOffCursor(PetFeeder_PickedupItem.bag,PetFeeder_PickedupItem.slot);
1482 end -- if has item and we know where it came from
1483  
1484 PetFeeder_PickedupItem = nil;
1485  
1486 end
1487  
1488  
1489 --[[
1490 =============================================================================
1491 Returns the item name;
1492 params:
1493 - bag: the bag number of the item
1494 - slot: the slot number of the item
1495 =============================================================================
1496 ]]
1497 function PetFeeder_GetItemName(bag, slot)
1498 --local name,totalCount,quality,texture,linktext = PetFeeder_GetItemInfo(bag,slot);
1499 local value = PetFeeder_GetItemObject( m, n );
1500  
1501 if ( value ) then
1502 return value.name;
1503 end
1504  
1505 return nil;
1506 end
1507  
1508 --[[
1509 =============================================================================
1510 Looks through all bags/slots to find the item and adds up the total quantity
1511 for it.
1512 params:
1513 - itemName: name of the item
1514 =============================================================================
1515 ]]
1516 function PetFeeder_GetItemCount(itemName)
1517 --DEFAULT_CHAT_FRAME:AddMessage("itemName="..itemName);
1518 local totalItemCount = 0;
1519 local itemQuality = 0;
1520 -- calc total number of items
1521 for m = 0, 4 do
1522 for n = 1, 20 do
1523 local curLinkText = GetContainerItemLink(m, n);
1524 local curname;
1525 if curLinkText then
1526 _, _, id,curname = string.find(curLinkText, "^.*:(%d+):%d+:%d+:%d+.*%[(.*)%].*$");
1527  
1528 end
1529 if ( curname == itemName ) then
1530  
1531 texture, itemCount, locked, quality, readable = GetContainerItemInfo(m,n);
1532 itemQuality = quality;
1533 if ( itemCount ) then
1534 totalItemCount = totalItemCount + itemCount;
1535 end
1536 end
1537 end
1538 end
1539  
1540 if ( PetFeeder_QuestItems[itemName] ) then
1541 --DEFAULT_CHAT_FRAME:AddMessage("Quest itemName="..itemName);
1542 local sum = totalItemCount - PetFeeder_QuestItems[itemName];
1543 --DEFAULT_CHAT_FRAME:AddMessage("sum="..sum);
1544 totalItemCount = max(sum,0);
1545 end
1546 return totalItemCount, itemQuality;
1547  
1548 end
1549  
1550 function PetFeeder_GetItemObject(bag,slot)
1551  
1552 local value = { };
1553 local linktext = GetContainerItemLink(bag, slot);
1554 local itemTexture, itemCount, locked, itemQuality, readable = GetContainerItemInfo(bag,slot);
1555 local itemColor, itemID, itemName;
1556 local restores, overTime;
1557  
1558 value.quality = 61;
1559  
1560 -- no sense processing if there isn't an item
1561 if ( not linktext ) then
1562 return nil;
1563 end
1564  
1565 for itemColor, itemID, itemName in string.gfind(linktext, "|c(%x+)|Hitem:(%d+:%d+:%d+:%d+)|h%[(.-)%]|h|r") do
1566 if ( itemColor and itemID and itemName ~= "" ) then
1567 value.name = itemName;
1568 value.color=itemColor;
1569 value.id=itemID;
1570 --DEFAULT_CHAT_FRAME:AddMessage("color="..itemColor.." itemID="..itemID.." name="..itemName.." texture="..itemTexture);
1571 end
1572 end
1573  
1574 if ( not value.id ) then
1575 return nil;
1576 end
1577  
1578 local _, _, _, _, itemType, itemSub = GetItemInfo("item:"..value.id)
1579 --DEFAULT_CHAT_FRAME:AddMessage(value.name.." - "..itemType.." - "..itemSub)
1580 value.type = itemSub;
1581 value.texture = itemTexture;
1582 value.link = linktext;
1583  
1584 -- Look for 'Use: Restores XXXX health over YY seconds'
1585 -- Regex looks for 'Use:', a space, 1 or more characters, a space, 1 or more digits
1586 -- Return the digits as our version of quality
1587 if ( value ) then
1588 PetFeederTooltip:ClearLines();
1589 PetFeederTooltip:SetHyperlink( "item:"..value.id );
1590 --PFDebugMessage("PF", "Parse ITEM="..value.name, "info");
1591 end
1592 local i;
1593  
1594 if ( PetFeederTooltipTextLeft2:GetText() ) then
1595 --PFDebugMessage("PF", "TooltipTextLeft2="..PetFeederTooltipTextLeft2:GetText(), "info");
1596 --for restores in string.gfind(PetFeederTooltipTextLeft2:GetText(), PETFEEDER_RESTORES.." (%d+)") do
1597 for restores in string.gfind(PetFeederTooltipTextLeft2:GetText(), ITEM_SPELL_TRIGGER_ONUSE.." %w+ (%d+)") do
1598 if ( restores ~= "" ) then
1599 value.quality = tonumber(restores);
1600 end
1601 end
1602 end
1603 if ( PetFeederTooltipTextLeft3:GetText() ) then
1604 --PFDebugMessage("PF", "TooltipTextLeft3="..PetFeederTooltipTextLeft3:GetText(), "info");
1605 --for restores in string.gfind(PetFeederTooltipTextLeft3:GetText(), PETFEEDER_RESTORES.." (%d+)") do
1606 for restores in string.gfind(PetFeederTooltipTextLeft3:GetText(), ITEM_SPELL_TRIGGER_ONUSE.." %w+ (%d+)") do
1607 if ( restores ~= "" ) then
1608 value.quality = tonumber(restores);
1609 end
1610 end
1611 end
1612  
1613  
1614 value.attributeBuffs = false;
1615 if ( PetFeederTooltipTextLeft2:GetText() ) then
1616 for i = 1, getn(PETFEEDER_ITEM_ATTRIBUTE_BUFFS), 1 do
1617 for restores in string.gfind(PetFeederTooltipTextLeft2:GetText(), PETFEEDER_ITEM_ATTRIBUTE_BUFFS[i].search ) do
1618 if ( restores ~= "" ) then
1619 value.attributeBuffs = true;
1620 break;
1621 end
1622 end
1623 end
1624 end
1625  
1626 if ( PetFeederTooltipTextLeft3:GetText() and (value.attributeBuffs == false)) then
1627 for i = 1, getn(PETFEEDER_ITEM_ATTRIBUTE_BUFFS), 1 do
1628 for restores in string.gfind(PetFeederTooltipTextLeft3:GetText(), PETFEEDER_ITEM_ATTRIBUTE_BUFFS[i].search ) do
1629 if ( restores ~= "" ) then
1630 value.attributeBuffs = true;
1631 break;
1632 end
1633 end
1634 end
1635 end
1636  
1637  
1638 local totalItemCount = PetFeeder_GetItemCount( name );
1639 value.quantity = totalItemCount;
1640  
1641 -- if ( value.name and value.name == "Mystery Meat" ) then
1642 -- DEFAULT_CHAT_FRAME:AddMessage("object::color="..value.color.." itemID="..value.id.." name="..value.name);
1643 -- DEFAULT_CHAT_FRAME:AddMessage("object::texture="..value.texture.." quality="..value.quality.." link="..value.link);
1644 -- DEFAULT_CHAT_FRAME:AddMessage("object::quantity="..value.quantity);
1645 -- else
1646 -- DEFAULT_CHAT_FRAME:AddMessage("null name in bag="..bag.." slot="..slot);
1647 -- end
1648  
1649 if ( value.name ) then
1650 return value;
1651 end
1652  
1653 return nil;
1654  
1655 end
1656  
1657 function PetFeeder_TakeItemOffCursor(srcBag, srcSlot)
1658 if srcBag == -1 then
1659 PickupInventoryItem(srcSlot);
1660 else
1661 PickupContainerItem(srcBag, srcSlot);
1662 end
1663 end
1664  
1665 --[[
1666 =============================================================================
1667 Algorithm to auto-populate foods into our food list. Uses pattern matching
1668 to find foods based on popular words associated with foods in the game.
1669 Alt Algorithm: uses texture to determine whether an item is a food item or not.
1670 =============================================================================
1671 ]]
1672 function PetFeeder_PopulateFoods()
1673 --DEFAULT_CHAT_FRAME:AddMessage("PetFeeder_PopulateFoods");
1674 if not ( PetFeeder_HasPet() ) then
1675 return;
1676 end
1677  
1678 -- Walk through each inventory item
1679 for m = 0, 4 do
1680 for n = 1, 20 do
1681  
1682 local value = PetFeeder_GetItemObject( m,n );
1683 if ( value ) then
1684 if ( PetFeederFrame_IsFood( value )
1685 and ( (PeetFeederPlayer_Config.skipBuffFoods and value.attributeBuffs == false)
1686 or (not PeetFeederPlayer_Config.skipBuffFoods)) )
1687 then
1688 -- DEFAULT_CHAT_FRAME:AddMessage(value.name);
1689 PetFeeder_AddFood( value );
1690 end
1691 end
1692  
1693 end
1694 end
1695  
1696 end
1697  
1698 --[[
1699 =============================================================================
1700 Determine whether the item is food or not. We try three things to figure this out
1701 1. If the texture contains the word _Food_ or _Misc_Bowl_ we assume its a food item
1702 2. If the texture contains certain woods (ie: Weapon, Arrow) we eliminate it as a choice
1703 3. Everything else goes through our food filter list to see if they contain
1704 keywords for food items.
1705 Even if we mis-identify something as a food item, it will get eliminated from
1706 the pet's diet list as soon as it tries to eat it and the Add_Food routine
1707 will eliminate it for us.
1708 =============================================================================
1709 ]]
1710 function PetFeederFrame_IsFood( item )
1711  
1712 local isGood = false;
1713 --DEFAULT_CHAT_FRAME:AddMessage("texture="..item.texture.." item="..item.name);
1714  
1715 if ( item.type == PETFEEDER_CONSUMABLE or item.type == PETFEEDER_TRADEGOODS or PF_FOM_IsFood(item) ) then
1716 local foodTextures = { "_Food_", "_Misc_", "_Fish_","_Mushroom_" };
1717 local i
1718 for i=1, table.getn( foodTextures ) do
1719 if ( string.find( item.texture, foodTextures[i] ) ) then
1720 isGood = true;
1721 break;
1722 end
1723 end
1724 else
1725 return false;
1726 end
1727  
1728 local notFoodTextures = { "_Gem_", "_ArmorKit_", "_Flower_","_LeatherScrap_","_Bandage_","_MonsterScales_","_Herb_" };
1729 local i
1730 for i=1, table.getn( notFoodTextures ) do
1731 if ( string.find( item.texture, notFoodTextures[i] ) ) then
1732 return false;
1733 end
1734 end
1735 return isGood;
1736  
1737 end
1738  
1739  
1740  
1741 --=============================================================================
1742 -- Return information about the pattern
1743 --
1744 -- pattern pattern to find
1745 local function BuffInformation( pattern )
1746 if pattern then
1747 return string.find( PetFeederTooltipTextLeft2:GetText(), pattern );
1748 else
1749 return 1;
1750 end
1751 end
1752 --=============================================================================
1753  
1754  
1755 -- Called when you click on a Tab
1756 function PetFeederTab_OnClick()
1757 if ( this:GetName() == "PetFeederFrameTab1" ) then
1758 togglePetFeeder("PetFeeder_FoodsFrame");
1759 elseif ( this:GetName() == "PetFeederFrameTab2" ) then
1760 togglePetFeeder("PetFeeder_ApprovedFoodsFrame");
1761 elseif ( this:GetName() == "PetFeederFrameTab3" ) then
1762 togglePetFeeder("PetFeeder_UnlikedFoodsFrame");
1763 end
1764 PlaySound("igCharacterInfoTab");
1765 end
1766  
1767 --[[
1768 =============================================================================
1769 Hooked function that gets called when a user picks up an item
1770 =============================================================================
1771 ]]
1772 local PetFeeder_Save_PickupContainerItem = PickupContainerItem;
1773 PickupContainerItem = function (bag,slot)
1774 PetFeeder_PickedupItem = { };
1775 PetFeeder_PickedupItem.bag = bag;
1776 PetFeeder_PickedupItem.slot = slot;
1777  
1778 return PetFeeder_Save_PickupContainerItem(bag,slot);
1779 end
1780  
1781 --[[
1782 =============================================================================
1783 Hooked function that gets called when a user picks up an item
1784 =============================================================================
1785 ]]
1786 local PetFeeder_Save_PickupInventoryItem = PickupInventoryItem;
1787 PickupInventoryItem = function (slot)
1788 PetFeeder_PickedupItem = { };
1789 PetFeeder_PickedupItem.bag = -1;
1790 PetFeeder_PickedupItem.slot = slot;
1791 return PetFeeder_Save_PickupInventoryItem(slot);
1792 end
1793  
1794 function PetFeederItemButton_OnEnter(lname)
1795  
1796 local _,_,name = string.find(lname, "(.*) %(%d+%)");
1797 if ( not name ) then
1798 name = lname;
1799 end
1800  
1801 local link = nil;
1802  
1803 for index, value in PetFeederPlayer_Foods[PetFeeder_PetName] do
1804 if ( value.name == name ) then
1805 link = "item:"..value.id;
1806 end
1807 end
1808  
1809 if( link ) then
1810 GameTooltip:SetOwner(this,"ANCHOR_RIGHT");
1811 GameTooltip:SetHyperlink(link);
1812 GameTooltip:Show();
1813 end
1814 end
1815  
1816 function PetFeederItemButton_OnLeave()
1817 if( PetFeederFrame.TooltipButton ) then
1818 PetFeederFrame.TooltipButton = nil;
1819 HideUIPanel(PetFeederDisplayTooltip);
1820 end
1821 end
1822  
1823 function FixOldInventoryData()
1824 local itemObject;
1825  
1826 for index, value in PetFeederPlayer_Foods[PetFeeder_PetName] do
1827 for m = 0, 4 do
1828 for n = 1, 18 do
1829 itemObject = PetFeeder_GetItemObject(m,n);
1830 if ( itemObject and itemObject.name == value.name ) then
1831 value = itemObject;
1832 break;
1833 end
1834 end
1835 if ( itemObject and itemObject.name == value.name ) then
1836 break;
1837 end
1838 end
1839 end
1840 end
1841  
1842  
1843 --[[
1844 =============================================================================
1845 Test whether a pet is present or not.
1846 =============================================================================
1847 ]]
1848 function PetFeeder_HasPet()
1849 if ( not UnitExists("pet") ) then
1850 return false;
1851 elseif ( UnitName("pet") == "Unknown Entity" or UnitName("pet") == "Unknown" ) then
1852 return false;
1853 end
1854  
1855 return true;
1856 end
1857  
1858  
1859  
1860 function PetFeeder_IdFromLink(link)
1861 if (link == nil) then return nil; end
1862 local _, _, itemID = string.find(link, "(%d+):%d+:%d+:%d+");
1863 -- DEFAULT_CHAT_FRAME:AddMessage("link ".. link .." to "..itemID);
1864  
1865 if (tonumber(itemID)) then
1866 return tonumber(itemID);
1867 else
1868 return nil;
1869 end
1870 end