vanilla-wow-addons – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 ------------------------------------------------------
2 -- FeedOMatic.lua
3 ------------------------------------------------------
4 FOM_VERSION = "11200.1";
5 ------------------------------------------------------
6  
7 -- TODO: if you don't auto-feed, have an option to make the need to feed more noticeable (e.g., pulsing halo around the pet-happiness icon).
8  
9 -- constants
10 FOM_WARNING_INTERVAL = 10; -- don't warn more than once per this many seconds
11 MAX_QUALITY = 35 * 60 + 1; -- We store a notion of a food's "quality": its best happiness-per-tick multiplied by the pet's level as of when that tick occurred. We use "best" because a pet that's closer to "sated" (maximum happiness) will receive less happiness per tick than he would from the same food if he were hungrier. (So, a food that gives 35 happiness per tick to a level 60 pet is "better" than a food that's worth 35 happiness per tick to a level 30 pet.) Foods whose quality hasn't been observed yet are given this value when sorting, so we can prioritize the discovery of new foods' quality ratings.
12 MAX_KEEPOPEN_SLOTS = 150;
13  
14 -- Configuration
15 FOM_Config_Default = {
16 Enabled = false;
17 Alert = "emote";
18 Level = "content";
19 KeepOpenSlots = 8;
20 AvoidUsefulFood = true;
21 AvoidQuestFood = true;
22 AvoidBonusFood = true;
23 Fallback = false;
24 SaveForCookingLevel = 1;
25 PreferHigherQuality = true;
26 Tooltip = true;
27 };
28 FOM_Config = FOM_Config_Default;
29  
30 -- FOM_Cooking = { };
31 -- Has the following internal structure:
32 -- REALM_PLAYER = {
33 -- FOODNAME = SKILL_DIFFICULTY,
34 -- }
35  
36 -- FOM_QuestFood = { };
37 -- Has the following internal structure:
38 -- REALM_PLAYER = {
39 -- FOODNAME = QUANTITY_REQUIRED,
40 -- }
41  
42 -- FOM_FoodQuality = { };
43 -- Has the following internal structure:
44 -- REALM_PLAYER = {
45 -- PETNAME = {
46 -- FOODNAME = HAPPINESS,
47 -- }
48 -- }
49  
50 -- Variables
51 FOM_State = { };
52 FOM_State.InCombat = false;
53 FOM_State.IsAFK = false;
54 FOM_State.ShouldFeed = false;
55 FOM_LastWarning = 0;
56  
57 FOM_LastFood = nil;
58 FOM_RealmPlayer = nil;
59 FOM_LastPetName = nil;
60  
61 -- Anti-freeze code borrowed from ReagentInfo (in turn, from Quest-I-On):
62 -- keeps WoW from locking up if we try to scan the tradeskill window too fast.
63 FOM_TradeSkillLock = { };
64 FOM_TradeSkillLock.Locked = false;
65 FOM_TradeSkillLock.EventTimer = 0;
66 FOM_TradeSkillLock.EventCooldown = 0;
67 FOM_TradeSkillLock.EventCooldownTime = 1;
68  
69  
70 -- State variable used to track required quantities of quest food when it's in more than one stack
71 FOM_Quantity = { };
72  
73 -- Remember how item IDs map to food names at runtime, but don't bloat long-term memory with it...
74 FOM_FoodIDsToNames = {};
75  
76 function FOM_FeedButton_OnClick()
77 if (arg1 == "RightButton") then
78 if FOM_OptionsFrame:IsVisible() then
79 HideUIPanel(FOM_OptionsFrame);
80 else
81 ShowUIPanel(FOM_OptionsFrame);
82 end
83 else
84 FOM_Feed();
85 end
86 end
87  
88 function FOM_FeedButton_OnEnter()
89 if ( PetFrameHappiness.tooltip ) then
90 GameTooltip:SetOwner(PetFrameHappiness, "ANCHOR_RIGHT");
91 GameTooltip:SetText(PetFrameHappiness.tooltip);
92 if ( PetFrameHappiness.tooltipDamage ) then
93 GameTooltip:AddLine(PetFrameHappiness.tooltipDamage, "", 1, 1, 1);
94 end
95 if ( PetFrameHappiness.tooltipLoyalty ) then
96 GameTooltip:AddLine(PetFrameHappiness.tooltipLoyalty, "", 1, 1, 1);
97 end
98 GameTooltip:Show();
99 end
100 end
101  
102 function FOM_FeedButton_OnLeave()
103 GameTooltip:Hide();
104 end
105  
106 function FOM_OnLoad()
107  
108 -- Register for Events
109 this:RegisterEvent("VARIABLES_LOADED");
110  
111 -- Register Slash Commands
112 SLASH_FEEDOMATIC1 = "/feedomatic";
113 SLASH_FEEDOMATIC2 = "/fom";
114 SLASH_FEEDOMATIC3 = "/feed";
115 SLASH_FEEDOMATIC4 = "/petfeed"; -- Rauen's PetFeed compatibility
116 SLASH_FEEDOMATIC5 = "/pf";
117 SlashCmdList["FEEDOMATIC"] = function(msg)
118 FOM_ChatCommandHandler(msg);
119 end
120  
121 -- hook functions so we can manage per-pet saved food quality data
122 FOM_Original_PetRename = PetRename;
123 PetRename = FOM_PetRename;
124 FOM_Original_PetAbandon = PetAbandon;
125 PetAbandon = FOM_PetAbandon;
126  
127 --GFWUtils.Debug = true;
128  
129 GFWUtils.Print("Fizzwidget Feed-O-Matic "..FOM_VERSION.." initialized!");
130  
131 end
132  
133 function FOM_CheckSetup()
134  
135 _, realClass = UnitClass("player");
136 if (realClass ~= "HUNTER") then return; end
137  
138 if (FOM_RealmPlayer == nil) then
139 FOM_RealmPlayer = GetCVar("realmName") .. "." .. UnitName("player");
140 end
141 local currentPetName = UnitName("pet");
142 if (currentPetName and currentPetName ~= "" and currentPetName ~= UNKNOWNOBJECT) then
143 FOM_LastPetName = currentPetName;
144 end
145  
146 if (FOM_FoodQuality == nil) then
147 FOM_FoodQuality = { };
148 end
149 if (FOM_FoodQuality[FOM_RealmPlayer] == nil) then
150 FOM_FoodQuality[FOM_RealmPlayer] = { };
151 end
152 if (FOM_LastPetName) then
153 if (FOM_FoodQuality[FOM_RealmPlayer][FOM_LastPetName] == nil) then
154 FOM_FoodQuality[FOM_RealmPlayer][FOM_LastPetName] = { };
155 end
156 end
157  
158 end
159  
160 function FOM_Tooltip(frame, name, link, source)
161 if (FOM_Config.Tooltip and name ~= nil and UnitExists("pet")) then
162 FOM_CheckSetup();
163  
164 local itemID = FOM_IDFromLink(link);
165 if (not FOM_IsInDiet(itemID)) then
166 return false;
167 end
168  
169 local color;
170 local absoluteQuality = FOM_FoodQuality[FOM_RealmPlayer][FOM_LastPetName][itemID];
171 if (absoluteQuality == nil) then
172 color = HIGHLIGHT_FONT_COLOR;
173 frame:AddLine(string.format(FOM_QUALITY_UNKNOWN, FOM_LastPetName), color.r, color.g, color.b);
174 return true;
175 else
176 local currentQuality = absoluteQuality / UnitLevel("pet");
177 if (currentQuality < 0) then
178 color = QuestDifficultyColor["trivial"];
179 frame:AddLine(string.format(FOM_QUALITY_UNDER, FOM_LastPetName), color.r, color.g, color.b);
180 return true;
181 elseif (currentQuality == 0) then
182 color = QuestDifficultyColor["trivial"];
183 frame:AddLine(string.format(FOM_QUALITY_MIGHT, FOM_LastPetName), color.r, color.g, color.b);
184 return true;
185 elseif (currentQuality <= 8) then
186 color = QuestDifficultyColor["standard"];
187 frame:AddLine(string.format(FOM_QUALITY_WILL, FOM_LastPetName), color.r, color.g, color.b);
188 return true;
189 elseif (currentQuality <= 17) then
190 color = QuestDifficultyColor["difficult"];
191 frame:AddLine(string.format(FOM_QUALITY_LIKE, FOM_LastPetName), color.r, color.g, color.b);
192 return true;
193 elseif (currentQuality <= 35) then
194 color = QuestDifficultyColor["verydifficult"];
195 frame:AddLine(string.format(FOM_QUALITY_LOVE, FOM_LastPetName), color.r, color.g, color.b);
196 return true;
197 else
198 GFWUtils.DebugLog("Unexpected food quality level "..currentQuality);
199 return false;
200 end
201 end
202 end
203 end
204  
205 function FOM_OnEvent(event, arg1)
206  
207 -- Save Variables
208 if ( event == "VARIABLES_LOADED" ) then
209  
210 _, realClass = UnitClass("player");
211 if (realClass == "HUNTER") then
212 -- monitor status for whether we're able to feed
213 this:RegisterEvent("PET_ATTACK_START");
214 this:RegisterEvent("PET_ATTACK_STOP");
215 -- this:RegisterEvent("CHAT_MSG_SYSTEM");
216  
217 -- check your pet roster when at the stables so we don't bloat SavedVariables
218 this:RegisterEvent("PET_STABLE_SHOW");
219 this:RegisterEvent("PET_STABLE_UPDATE");
220  
221 -- track whether foods are useful for Cooking
222 this:RegisterEvent("TRADE_SKILL_SHOW");
223 this:RegisterEvent("TRADE_SKILL_UPDATE");
224  
225 -- figure out what happens when we try to feed pet (gain happiness, didn't like, etc)
226 this:RegisterEvent("CHAT_MSG_SPELL_TRADESKILLS");
227 this:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS");
228 this:RegisterEvent("UI_ERROR_MESSAGE");
229  
230 -- Events for trying to catch when the pet needs feeding
231 this:RegisterEvent("PET_BAR_SHOWGRID");
232 this:RegisterEvent("PET_BAR_UPDATE");
233 this:RegisterEvent("PET_UI_UPDATE");
234 this:RegisterEvent("UNIT_HAPPINESS");
235  
236 FOM_FeedButton = CreateFrame("Button", "FOM_FeedButton", PetFrameHappiness);
237 FOM_FeedButton:SetAllPoints(PetFrameHappiness);
238 FOM_FeedButton:RegisterForClicks("LeftButtonUp", "RightButtonUp");
239 FOM_FeedButton:SetScript("OnClick", FOM_FeedButton_OnClick);
240 FOM_FeedButton:SetScript("OnEnter", FOM_FeedButton_OnEnter);
241 FOM_FeedButton:SetScript("OnLeave", FOM_FeedButton_OnLeave);
242  
243 table.insert(UISpecialFrames,"FOM_OptionsFrame");
244  
245 if (FOM_Config.Level == "happy") then
246 -- we've redefined the Level option and this setting is no loger available
247 FOM_Config.Level = "content";
248 end
249  
250 if (FOM_Config.Tooltip) then
251 GFWTooltip_AddCallback("GFW_FeedOMatic", FOM_Tooltip);
252 end
253 end
254 return;
255  
256 elseif ( event == "PET_ATTACK_START" ) then
257  
258 -- Set Flag
259 FOM_State.InCombat = true;
260 return;
261  
262 elseif ( event == "PET_ATTACK_STOP" ) then
263  
264 -- Remove Flag
265 FOM_State.InCombat = false;
266  
267 elseif ( event == "CHAT_MSG_SPELL_TRADESKILLS" ) then
268  
269 if (FOM_FEEDPET_LOG_FIRSTPERSON == nil) then
270 FOM_FEEDPET_LOG_FIRSTPERSON = GFWUtils.FormatToPattern(FEEDPET_LOG_FIRSTPERSON);
271 end
272 _, _, foodName = string.find(arg1, FOM_FEEDPET_LOG_FIRSTPERSON);
273 if (foodName and foodName ~= "") then
274 local foodID = GFWTable.KeyOf(FOM_FoodIDsToNames, foodName);
275 if (foodID == nil) then
276 local bag, slot = FOM_FindSpecificFood(foodName);
277 local foodLink = GetContainerItemLink(bag, slot);
278 foodID = FOM_IDFromLink(foodLink);
279 end
280 if (foodID) then
281 FOM_LastFood = GFWUtils.ItemLink(foodID);
282 GFWUtils.DebugLog("Manually fed "..FOM_LastFood);
283 end
284 end
285 return;
286  
287 elseif ( event == "CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS" ) then
288  
289 if (arg1 and FOM_HasFeedEffect()) then
290 if (FOM_POWERGAIN_OTHER == nil and POWERGAINSELFOTHER) then
291 FOM_POWERGAIN_OTHER = GFWUtils.FormatToPattern(POWERGAINSELFOTHER);
292 end
293 if (FOM_POWERGAIN_OTHER == nil and POWERGAIN_OTHER) then
294 FOM_POWERGAIN_OTHER = GFWUtils.FormatToPattern(POWERGAIN_OTHER);
295 end
296 if (FOM_POWERGAIN_OTHER == nil) then
297 GFWUtils.PrintOnce(GFWUtils.Red("Feed-O-Matic Error: ").. "Can't find parse pattern for pet happiness.");
298 return;
299 end
300 _, _, name, amount, powerType = string.find(arg1, FOM_POWERGAIN_OTHER);
301 local happiness;
302 if (name == UnitName("pet") and powerType == HAPPINESS_POINTS) then
303 happiness = tonumber(amount);
304 else
305 return;
306 end
307  
308 if (FOM_LastFood and happiness > 0) then
309 FOM_CheckSetup();
310 local itemID = FOM_IDFromLink(FOM_LastFood);
311 local knownQuality = FOM_FoodQuality[FOM_RealmPlayer][FOM_LastPetName][itemID];
312 local quality = happiness * UnitLevel("pet");
313 FOM_FoodQuality[FOM_RealmPlayer][FOM_LastPetName][itemID] = math.max((knownQuality or 0), quality);
314 FOM_LastFood = nil;
315 end
316 end
317 return;
318  
319 elseif ( event == "UI_ERROR_MESSAGE" ) then
320  
321 if (arg1 and string.find(arg1, SPELL_FAILED_FOOD_LOWLEVEL)) then
322  
323 FOM_CheckSetup();
324  
325 if not (FOM_LastFood == nil) then
326 local itemID = FOM_IDFromLink(FOM_LastFood);
327 FOM_FoodQuality[FOM_RealmPlayer][FOM_LastPetName][itemID] = -1;
328 FOM_LastFood = nil;
329 if ( FOM_Config.Alert == "chat") then
330 GFWUtils.Print(string.format(FOM_FEEDING_EAT_ANOTHER, UnitName("pet")));
331 elseif ( FOM_Config.Alert == "emote") then
332 SendChatMessage(string.format(FOM_FEEDING_FEED_ANOTHER, UnitName("pet")), "EMOTE");
333 end
334 return;
335 end
336  
337 elseif (arg1 and string.find(arg1, SPELL_FAILED_WRONG_PET_FOOD)) then
338  
339 FOM_CheckSetup();
340  
341 if (FOM_LastFood) then
342  
343 if ( FOM_Config.Alert == "chat") then
344 GFWUtils.Print(string.format(FOM_FEEDING_EAT_ANOTHER, UnitName("pet")));
345 elseif ( FOM_Config.Alert == "emote") then
346 SendChatMessage(string.format(FOM_FEEDING_FEED_ANOTHER, UnitName("pet")), "EMOTE");
347 end
348 -- remove from quality tracking
349 local itemID = FOM_IDFromLink(FOM_LastFood);
350 FOM_FoodQuality[FOM_RealmPlayer][FOM_LastPetName][itemID] = nil;
351  
352 -- remove from diet
353 local dietList = {GetPetFoodTypes()};
354 for _, diet in dietList do
355 if ( FOM_RemoveFood(string.lower(diet), itemID) ) then
356 local capDiet = string.upper(string.sub(diet, 1, 1)) .. string.sub(diet, 2); -- print a nicely capitalized version
357 GFWUtils.Print("Removed "..FOM_LastFood.." from "..GFWUtils.Hilite(capDiet).." list.");
358 end
359 end
360 FOM_LastFood = nil;
361 return;
362 end
363 end
364 return;
365  
366 elseif (event == "TRADE_SKILL_SHOW" or event == "TRADE_SKILL_UPDATE") then
367 if (GetTradeSkillLine() ~= nil and GetTradeSkillLine() == FOM_CookingSpellName()) then
368 if (FOM_Config.SaveForCookingLevel >= 0 and FOM_Config.SaveForCookingLevel <= 3) then
369 -- Update Cooking reagents list so we can avoid consuming food we could skillup from.
370 if (FOM_RealmPlayer == nil) then
371 FOM_RealmPlayer = GetCVar("realmName") .. "." .. UnitName("player");
372 end
373 if (FOM_Cooking == nil) then
374 FOM_Cooking = { };
375 end
376 if (FOM_Cooking[FOM_RealmPlayer] == nil) then
377 FOM_Cooking[FOM_RealmPlayer] = { };
378 end
379 if (FOM_Cooking ~= nil and FOM_Cooking[FOM_RealmPlayer] ~= nil and TradeSkillFrame and TradeSkillFrame:IsVisible() and not FOM_TradeSkillLock.Locked) then
380 -- This prevents further update events from being handled if we're already processing one.
381 -- This is done to prevent the game from freezing under certain conditions.
382 FOM_TradeSkillLock.Locked = true;
383  
384 for i=1, GetNumTradeSkills() do
385 local itemName, type, _, _ = GetTradeSkillInfo(i);
386 if (type ~= "header") then
387 for j=1, GetTradeSkillNumReagents(i) do
388 local reagentLink = GetTradeSkillReagentItemLink(i, j);
389 local itemID = FOM_IDFromLink(reagentLink);
390  
391 if (itemID and FOM_IsKnownFood(itemID)) then
392 if (FOM_Cooking[FOM_RealmPlayer][itemID] == nil) then
393 FOM_Cooking[FOM_RealmPlayer][itemID] = FOM_DifficultyToNum(type);
394 else
395 FOM_Cooking[FOM_RealmPlayer][itemID] = max(FOM_Cooking[FOM_RealmPlayer][itemID], FOM_DifficultyToNum(type));
396 end
397 end
398 end
399 end
400 end
401 end
402 end
403 end
404 return;
405  
406 elseif (event == "PET_STABLE_SHOW" or event == "PET_STABLE_UPDATE") then
407  
408 -- clean up the FOM_FoodQuality sub-tables in case we missed you abandoning a pet
409 FOM_CheckSetup();
410 local stabledPetNames = {};
411 for petIndex = 0, 2 do
412 local _, petName, _, _, _ = GetStablePetInfo(petIndex);
413 if (petName) then
414 table.insert(stabledPetNames, petName);
415 end
416 end
417 local orphanedPetNames = {};
418 for savedPetName in FOM_FoodQuality[FOM_RealmPlayer] do
419 if (stabledPetNames == nil) then
420 GFWUtils.DebugLog("stabledPetNames == nil");
421 end
422 if (stabledPetNames ~= nil and GFWTable.IndexOf(stabledPetNames, savedPetName) == 0) then
423 table.insert(orphanedPetNames, savedPetName);
424 end
425 end
426 for _, orphanedPet in orphanedPetNames do
427 FOM_FoodQuality[FOM_RealmPlayer][orphanedPet] = nil;
428 end
429 return;
430  
431 elseif (FOM_Config.Level) then
432 FOM_CheckHappiness();
433 end
434  
435 end
436  
437 -- Update our list of quest objectives so we can avoid consuming food we want to accumulate for a quest.
438 function FOM_ScanQuests()
439 FOM_QuestFood = nil;
440 for questNum=1, GetNumQuestLogEntries() do
441 local QText, level, questTag, isHeader, isCollapsed, isComplete = GetQuestLogTitle(questNum);
442 if (not isHeader) then
443 for objectiveNum=1, GetNumQuestLeaderBoards(questNum) do
444 local text, type, finished = GetQuestLogLeaderBoard(objectiveNum, questNum);
445 if (text ~= nil and strlen(text) > 0) then
446 local _, _, objectiveName, numCurrent, numRequired = string.find(text, "(.*): (%d+)/(%d+)");
447 if (FOM_IsKnownFood(objectiveName)) then
448 if (FOM_QuestFood == nil) then
449 FOM_QuestFood = { };
450 end
451 if (FOM_QuestFood[FOM_RealmPlayer] == nil) then
452 FOM_QuestFood[FOM_RealmPlayer] = { };
453 end
454  
455 if (FOM_QuestFood[FOM_RealmPlayer][objectiveName] == nil) then
456 FOM_QuestFood[FOM_RealmPlayer][objectiveName] = tonumber(numRequired);
457 else
458 FOM_QuestFood[FOM_RealmPlayer][objectiveName] = max(FOM_QuestFood[FOM_RealmPlayer][objectiveName], tonumber(numRequired));
459 end
460 end
461 end
462 end
463 end
464 end
465 end
466  
467 function FOM_DifficultyToNum(level)
468 if (level == "optimal" or level == "orange") then
469 return 3;
470 elseif (level == "medium" or level == "yellow") then
471 return 2;
472 elseif (level == "easy" or level == "green") then
473 return 1;
474 elseif (level == "trivial" or level == "gray" or level == "grey") then
475 return 1;
476 else -- bad input
477 return nil;
478 end
479 end
480  
481 function FOM_OnUpdate(elapsed)
482  
483 _, realClass = UnitClass("player");
484 if (realClass ~= "HUNTER") then return; end
485  
486 -- If it's been more than a second since our last tradeskill update,
487 -- we can allow the event to process again.
488 FOM_TradeSkillLock.EventTimer = FOM_TradeSkillLock.EventTimer + elapsed;
489 if (FOM_TradeSkillLock.Locked) then
490 FOM_TradeSkillLock.EventCooldown = FOM_TradeSkillLock.EventCooldown + elapsed;
491 if (FOM_TradeSkillLock.EventCooldown > FOM_TradeSkillLock.EventCooldownTime) then
492  
493 FOM_TradeSkillLock.EventCooldown = 0;
494 FOM_TradeSkillLock.Locked = false;
495 end
496 end
497  
498 --GFWUtils.Debug = true;
499  
500 if (FOM_State.ShouldFeed and FOM_Config.IconWarning and PetFrameHappiness) then
501 if (PetFrameHappiness:IsVisible() and PetFrameHappiness:GetAlpha() == 1) then
502 FOM_FadeOut();
503 end
504 end
505 end
506  
507 function FOM_FadeOut()
508 local fadeInfo = {};
509 fadeInfo.mode = "OUT";
510 fadeInfo.timeToFade = 0.5;
511 fadeInfo.finishedFunc = FOM_FadeIn;
512 UIFrameFade(PetFrameHappiness, fadeInfo);
513 end
514  
515 --hack since a frame can't have a reference to itself in it
516 function FOM_FadeIn()
517 UIFrameFadeIn(PetFrameHappiness, 0.5);
518 end
519  
520 function FOM_CanFeed()
521 if ( not UnitExists("pet") ) then
522 GFWUtils.DebugLog("Can't feed; pet doesn't exist.");
523 return false;
524 end
525 if ( UnitHealth("pet") <= 0 ) then
526 GFWUtils.DebugLog("Can't feed; pet is dead.");
527 return false;
528 end
529 if ( UnitHealth("player") <= 0 ) then
530 GFWUtils.DebugLog("Can't feed; I'm dead.");
531 return false;
532 end
533 if ( CastingBarFrameStatusBar:IsVisible() ) then
534 GFWUtils.DebugLog("Can't feed; casting a spell / tradeksill.");
535 return false;
536 end
537 if ( UnitOnTaxi("player") ) then
538 GFWUtils.DebugLog("Can't feed; flying.");
539 return false;
540 end
541 if ( FOM_State.InCombat ) or ( PlayerFrame.inCombat ) then
542 GFWUtils.DebugLog("Can't feed; in combat.");
543 return false;
544 end
545 if ( LootFrame:IsVisible() ) then
546 GFWUtils.DebugLog("Shouldn't feed; loot window is open.");
547 return false;
548 end
549  
550  
551 local buff, buffIndex;
552 local dontFeedBuffTextures = {
553 "Interface\\Icons\\Ability_Ambush", -- NE Shadowmeld (maybe not unique buff icon?)
554 "Interface\\Icons\\Ability_Rogue_FeignDeath", -- Feign Death
555 "Interface\\Icons\\INV_Drink_07", -- drinking
556 "Interface\\Icons\\INV_Misc_Fork&Knife", -- eating
557 };
558 local mountTextureSubStrings = {
559 "Ability_Mount",
560 "INV_Misc_Foot_Kodo",
561 };
562 for buffIndex=0, 15 do
563 local buff = GetPlayerBuffTexture(buffIndex);
564 if ( buff ~= nil) then
565 for _, buffTexture in dontFeedBuffTextures do
566 if ( buff == buffTexture ) then
567 GFWUtils.DebugLog("Can't feed; currently, eating, drinking, or feigning death.");
568 return false;
569 end
570 end
571 if ( UnitLevel("player") >= 40 ) then
572 for _, buffTexture in mountTextureSubStrings do
573 if ( string.find(buff, buffTexture) ) then
574 FOMTooltip:SetUnitBuff("player", buffIndex+1);
575 local msg = FOMTooltipTextLeft1:GetText();
576 if (msg ~= nil) then
577 msg = string.lower(msg);
578 for _, mountName in FOM_MOUNT_NAME_SUBSTRINGS do
579 if (string.find(msg, mountName)) then
580 GFWUtils.DebugLog("Can't feed; mounted.");
581 return false;
582 end
583 end
584 end
585 end
586 end
587 end
588 end
589 end
590  
591 return true;
592 end
593  
594 function FOM_ChatCommandHandler(msg)
595  
596 if ( msg == "" ) then
597 if FOM_OptionsFrame:IsVisible() then
598 HideUIPanel(FOM_OptionsFrame);
599 else
600 ShowUIPanel(FOM_OptionsFrame);
601 end
602 return;
603 end
604  
605 -- Check for Pet (we don't really need one for most of our chat commands, but we conveniently use its name.)
606 if ( UnitExists("pet") ) then
607 petName = UnitName("pet");
608 if (GetLocale() ~= "enUS") then
609 if (FOM_LocaleInfo == nil) then
610 FOM_LocaleInfo = {};
611 end
612 FOM_LocaleInfo[UnitCreatureFamily("pet")] = {GetPetFoodTypes()};
613 end
614 else
615 petName = "Your pet";
616 end
617  
618 -- Print Help
619 if ( msg == "help" ) or ( msg == "" ) then
620 GFWUtils.Print("Fizzwidget Feed-O-Matic "..FOM_VERSION..":");
621 GFWUtils.Print("/feedomatic /fom <command>");
622 GFWUtils.Print("- "..GFWUtils.Hilite("help").." - Print this helplist.");
623 GFWUtils.Print("- "..GFWUtils.Hilite("status").." - Check current settings.");
624 GFWUtils.Print("- "..GFWUtils.Hilite("reset").." - Reset to default settings.");
625 GFWUtils.Print("- "..GFWUtils.Hilite("alert chat").." | "..GFWUtils.Hilite("emote").." | "..GFWUtils.Hilite("off").." - Alert via chat window or emote channel when feeding.");
626 GFWUtils.Print("- "..GFWUtils.Hilite("level content").." | "..GFWUtils.Hilite("happy").." | "..GFWUtils.Hilite("off").." - Provide an extra reminder to feed your pet when happiness is below this level.");
627 GFWUtils.Print("- "..GFWUtils.Hilite("saveforcook orange").." | "..GFWUtils.Hilite("yellow").." | "..GFWUtils.Hilite("green").." | "..GFWUtils.Hilite("gray").." | "..GFWUtils.Hilite("off").." - Avoid foods used in cooking recipes (based on their difficulty).");
628 GFWUtils.Print("- "..GFWUtils.Hilite("savequest on").." | "..GFWUtils.Hilite("off").." - Avoid foods you need to collect for a quest.");
629 GFWUtils.Print("- "..GFWUtils.Hilite("savebonus on").." | "..GFWUtils.Hilite("off").." - Avoid foods which have bonus effects.");
630 GFWUtils.Print("- "..GFWUtils.Hilite("fallback on").." | "..GFWUtils.Hilite("off").." - Fall back to foods we'd normally avoid if no other food is available.");
631 GFWUtils.Print("- "..GFWUtils.Hilite("keepopen <number>").." - Set when to prefer smaller stacks of food versus evaluating food based on quality. Specify "..GFWUtils.Hilite("off").." instead of a number to always select foods by quality, or "..GFWUtils.Hilite("max").." to always prefer smaller stacks.");
632 GFWUtils.Print("- "..GFWUtils.Hilite("quality high").." | "..GFWUtils.Hilite("low").." - Set whether to prefer foods that give your pet more happiness faster or less happiness more slowly.");
633 GFWUtils.Print("- "..GFWUtils.Hilite("tooltip on").." | "..GFWUtils.Hilite("off").." - Identifies and rates pet foods in their tooltips.");
634 GFWUtils.Print("- "..GFWUtils.Hilite("feed").." - Feed your pet (automatically finds an appropriate food).");
635 GFWUtils.Print("- "..GFWUtils.Hilite("feed <name>").." - Feed your pet a specific food.");
636 GFWUtils.Print("- "..GFWUtils.Hilite("add <diet> <name>").." - Add food to list.");
637 GFWUtils.Print("- "..GFWUtils.Hilite("remove <diet> <name>").." - Remove food from list.");
638 GFWUtils.Print("- "..GFWUtils.Hilite("show <diet>").." - Show food list.");
639 return;
640 end
641  
642 if ( msg == "version" ) then
643 GFWUtils.Print("Fizzwidget Feed-O-Matic "..FOM_VERSION..":");
644 return;
645 end
646  
647 -- Check Status
648 if ( msg == "status" ) then
649 if (FOM_Config.Level) then
650 GFWUtils.Print("Feed-O-Matic will help remind you to feed your pet when he's "..GFWUtils.Hilite(FOM_Config.Level)..".");
651 else
652 GFWUtils.Print("Feed-O-Matic will "..GFWUtils.Hilite("not").." help remind you when to feed your pet.");
653 end
654  
655 if (FOM_Config.KeepOpenSlots < MAX_KEEPOPEN_SLOTS) then
656  
657 if (FOM_Config.PreferHigherQuality) then
658 GFWUtils.Print("Feed-O-Matic will prefer to use higher quality foods first.");
659 else
660 GFWUtils.Print("Feed-O-Matic will prefer to use lower quality foods first.");
661 end
662  
663 if (FOM_Config.KeepOpenSlots == 0) then
664 GFWUtils.Print("Feed-O-Matic will look first at food quality when determining what to feed to your pet.");
665 else
666 GFWUtils.Print("If fewer than "..GFWUtils.Hilite(FOM_Config.KeepOpenSlots).." spaces are open in your inventory, Feed-O-Matic will prefer smaller stacks of food regardless of quality.");
667 end
668  
669 else
670 GFWUtils.Print("Feed-O-Matic will always prefer smaller stacks of food regardless of quality.");
671 end
672  
673 if (FOM_Config.Alert == "emote") then
674 GFWUtils.Print("You will automatically emote when feeding "..petName..".");
675 elseif (FOM_Config.Alert == "chat") then
676 GFWUtils.Print("Feed-O-Matic will notify you in chat when feeding "..petName..".");
677 else
678 GFWUtils.Print("There will be no alert when feeding "..petName..".");
679 end
680  
681 if (FOM_Config.SaveForCookingLevel >= 0 and FOM_Config.SaveForCookingLevel <= 3) then
682 if (FOM_Config.SaveForCookingLevel == 3) then
683 level = "orange";
684 elseif (FOM_Config.SaveForCookingLevel == 2) then
685 level = "yellow";
686 elseif (FOM_Config.SaveForCookingLevel == 1) then
687 level = "green";
688 elseif (FOM_Config.SaveForCookingLevel == 0) then
689 level = "gray";
690 end
691 GFWUtils.Print("Feed-O-Matic will avoid foods used in "..GFWUtils.Hilite(level).." or higher Cooking recipes.");
692 else
693 GFWUtils.Print("Feed-O-Matic will choose foods without regard to whether they're used in Cooking.");
694 end
695  
696 if (FOM_Config.AvoidQuestFood) then
697 GFWUtils.Print("Feed-O-Matic will avoid foods you need to collect for quests.");
698 else
699 GFWUtils.Print("Feed-O-Matic will choose foods without regard to whether they're needed for quests.");
700 end
701 if (FOM_Config.AvoidBonusFood) then
702 GFWUtils.Print("Feed-O-Matic will avoid foods that have an additional bonus effect when eaten by a player.");
703 else
704 GFWUtils.Print("Feed-O-Matic will choose foods without regard to whether they have bonus effects.");
705 end
706 if (FOM_Config.Fallback) then
707 GFWUtils.Print("Feed-O-Matic will fall back to food it would otherwise avoid if no other food is available.");
708 else
709 GFWUtils.Print("Feed-O-Matic will not feed your pet if the only foods available are foods you'd prefer to avoid feeding.");
710 end
711 if (FOM_Config.Tooltip) then
712 GFWUtils.Print("Adding food quality information to tooltips for foods your current pet can eat.");
713 else
714 GFWUtils.Print("Not adding information to item tooltips.");
715 end
716 return;
717 end
718  
719 -- Reset Variables
720 if ( msg == "reset" ) then
721 FOM_Config = FOM_Config_Default;
722 FOM_Cooking = nil;
723 FOM_FoodQuality = nil;
724 FOM_AddedFoods = nil;
725 FOM_RemovedFoods = nil;
726 FOM_QuestFood = nil;
727 GFWUtils.Print("Feed-O-Matic configuration reset.");
728 FOM_ChatCommandHandler("status");
729 return;
730 end
731  
732 -- Turn automatic feeding On
733 if ( msg == "on" ) then
734 GFWUtils.Print("Automatic feeding is no longer available due to changes in the WoW client as of Patch 1.10.");
735 return;
736 end
737  
738 local _, _, cmd, option = string.find(msg, "(%w+) (%w+)");
739  
740 -- Toggle Alert
741 if ( cmd == "alert" ) then
742  
743 if (option == "emote") then
744 FOM_Config.Alert = "emote";
745 GFWUtils.Print("You will automatically emote when feeding "..petName..".");
746 elseif (option == "chat") then
747 FOM_Config.Alert = "chat";
748 GFWUtils.Print("Feed-O-Matic will notify you in chat when feeding "..petName..".");
749 elseif (option == "off") then
750 FOM_Config.Alert = nil;
751 GFWUtils.Print("There will be no alert when feeding "..petName..".");
752 else
753 GFWUtils.Print("Usage: "..GFWUtils.Hilite("/feedomatic alert chat").." | "..GFWUtils.Hilite("emote").." | "..GFWUtils.Hilite("off"));
754 end
755 return;
756 end
757  
758 -- Set Happiness Level
759 if ( cmd == "level" ) then
760 if ( option == "content" ) then
761 FOM_Config.Level = "content";
762 elseif ( option == "happy" ) then
763 FOM_Config.Level = "happy";
764 elseif ( option == "debug" ) then
765 FOM_Config.Level = "debug";
766 else
767 FOM_Config.Level = nil;
768 end
769 if (FOM_Config.Level) then
770 GFWUtils.Print("Feed-O-Matic will help remind you to feed your pet when he's less than "..GFWUtils.Hilite(FOM_Config.Level)..".");
771 FOM_CheckHappiness();
772 else
773 GFWUtils.Print("Feed-O-Matic will "..GFWUtils.Hilite("not").." help remind you when to feed your pet.");
774 FOM_Status.ShouldFeed = nil;
775 end
776 return;
777 end
778  
779 -- Set Cooking recipe level
780 if ( cmd == "saveforcook" ) then
781 local level = option;
782 if (level ~= nil) then
783 local levelNum = FOM_DifficultyToNum(level);
784 if (levelNum ~= nil) then
785 FOM_Config.SaveForCookingLevel = levelNum;
786 FOM_Config.AvoidUsefulFood = true;
787 GFWUtils.Print("Feed-O-Matic will avoid foods used in "..GFWUtils.Hilite(level).." or higher Cooking recipes. You'll need to open your Cooking window for Feed-O-Matic to cache information about what recipes you know.");
788 return;
789 elseif (level == "off") then
790 FOM_Config.SaveForCookingLevel = 4;
791 if (not FOM_Config.AvoidQuestFood and not FOM_Config.Avoid9) then
792 FOM_Config.AvoidUsefulFood = false;
793 end
794 GFWUtils.Print("Feed-O-Matic will choose foods without regard to whether they're used in Cooking.");
795 return;
796 end
797 end
798 GFWUtils.Print("Usage: "..GFWUtils.Hilite("/feedomatic saveforcook orange").." | "..GFWUtils.Hilite("yellow").." | "..GFWUtils.Hilite("green").." | "..GFWUtils.Hilite("gray").." | "..GFWUtils.Hilite("off"));
799 return;
800 end
801  
802 -- Set avoiding food with bonuses
803 if ( cmd == "savequest" ) then
804 if (option == "on") then
805 FOM_Config.AvoidQuestFood = true;
806 FOM_Config.AvoidUsefulFood = true;
807 FOM_ScanQuests();
808 GFWUtils.Print("Feed-O-Matic will avoid foods you need to collect for quests.");
809 elseif (option == "off") then
810 FOM_Config.AvoidQuestFood = true;
811 if not (FOM_Config.SaveForCookingLevel >= 0 and FOM_Config.SaveForCookingLevel <= 3 and not FOM_Config.AvoidBonusFood) then
812 FOM_Config.AvoidUsefulFood = false;
813 end
814 GFWUtils.Print("Feed-O-Matic will choose foods without regard to whether they're needed for quests.");
815 else
816 GFWUtils.Print("Usage: "..GFWUtils.Hilite("/feedomatic savequest on").." | "..GFWUtils.Hilite("off"));
817 end
818 return;
819 end
820  
821 -- Set avoiding quest-objective food
822 if ( cmd == "savebonus" ) then
823 if (option == "on") then
824 FOM_Config.AvoidBonusFood = true;
825 FOM_Config.AvoidUsefulFood = true;
826 GFWUtils.Print("Feed-O-Matic will avoid foods that have an additional bonus effect when eaten by a player.");
827 elseif (option == "off") then
828 FOM_Config.AvoidBonusFood = true;
829 if not (FOM_Config.SaveForCookingLevel >= 0 and FOM_Config.SaveForCookingLevel <= 3 and not FOM_Config.AvoidQuestFood) then
830 FOM_Config.AvoidUsefulFood = false;
831 end
832 GFWUtils.Print("Feed-O-Matic will choose foods without regard to whether they have bonus effects.");
833 else
834 GFWUtils.Print("Usage: "..GFWUtils.Hilite("/feedomatic savebonus on").." | "..GFWUtils.Hilite("off"));
835 end
836 return;
837 end
838  
839 if ( cmd == "fallback" ) then
840 if (option == "on") then
841 FOM_Config.Fallback = true;
842 GFWUtils.Print("Feed-O-Matic will fall back to food it would otherwise avoid if no other food is available.");
843 elseif (option == "off") then
844 FOM_Config.Fallback = false;
845 GFWUtils.Print("Feed-O-Matic will not feed your pet if the only foods available are foods you'd prefer to avoid feeding.");
846 else
847 GFWUtils.Print("Usage: "..GFWUtils.Hilite("/feedomatic fallback on").." | "..GFWUtils.Hilite("off"));
848 end
849 return;
850 end
851  
852 if ( cmd == "tooltip" ) then
853 if (option == "on") then
854 FOM_Config.Tooltip = true;
855 GFWTooltip_AddCallback("GFW_FeedOMatic", FOM_Tooltip);
856 GFWUtils.Print("Adding food quality information to tooltips for foods your current pet can eat.");
857 elseif (option == "off") then
858 FOM_Config.Tooltip = false;
859 GFWUtils.Print("Not adding information to item tooltips.");
860 else
861 GFWUtils.Print("Usage: "..GFWUtils.Hilite("/feedomatic tooltip on").." | "..GFWUtils.Hilite("off"));
862 end
863 return;
864 end
865  
866 -- Set quality sorting direction
867 if ( cmd == "quality" ) then
868 if (option == "high") then
869 FOM_Config.PreferHigherQuality = true;
870 GFWUtils.Print("Feed-O-Matic will prefer to use higher quality foods first.");
871 elseif (option == "low") then
872 FOM_Config.PreferHigherQuality = false;
873 GFWUtils.Print("Feed-O-Matic will prefer to use lower quality foods first.");
874 else
875 GFWUtils.Print("Usage: "..GFWUtils.Hilite("/feedomatic quality high").." | "..GFWUtils.Hilite("low"));
876 end
877 return;
878 end
879  
880 -- Set inventory management threshold
881 if ( cmd == "keepopen" ) then
882 if (option == "off" or option == "none") then
883 newNum = 0;
884 elseif (option == "max") then
885 newNum = MAX_KEEPOPEN_SLOTS;
886 else
887 newNum = tonumber(option);
888 end
889 if (newNum == nil) then
890 GFWUtils.Print("Usage: "..GFWUtils.Hilite("/feedomatic keepopen <number>"));
891 return;
892 end
893 FOM_Config.KeepOpenSlots = newNum;
894 GFWUtils.Print("Feed-O-Matic will try to keep at least "..GFWUtils.Hilite(FOM_Config.KeepOpenSlots).." spaces open in your inventory when looking for food.");
895 return;
896 end
897  
898 -- Feed Pet
899 local _, _, cmd, foodString = string.find(msg, "(%w+) *(.*)");
900 if ( cmd == "feed" ) then
901 if (foodString == "") then
902 FOM_Feed(nil); -- automatically find a food and feed it
903 else
904 local inputFoods = { };
905 for itemLink in string.gfind(foodString, "%[[%w%s:()\"'-]+%]") do
906 local _, _, foodName = string.find(itemLink, "^%[([%w%s:()\"'-]+)%]$");
907 table.insert(inputFoods, foodName);
908 end
909 if (table.getn(inputFoods) == 0) then
910 table.insert(inputFoods, foodString); -- if no item links, treat whole input line as one food's name
911 end
912  
913 for _, food in inputFoods do
914 FOM_Feed(food);
915 end
916 end
917 return;
918 end
919  
920 local _, _, cmd, diet, foodString = string.find(msg, "(%w+) (%w+) *(.*)");
921 if ( cmd == "add" or cmd == "remove" or cmd == "show" or cmd == "list" ) then
922  
923 diet = string.lower(diet); -- let's be case insensitive
924 if ( FOM_Foods[diet] == nil and diet ~= FOM_DIET_ALL) then
925 local usageString = "Usage: "..GFWUtils.Hilite("/feedomatic "..cmd..FOM_DIET_MEAT).." | "..GFWUtils.Hilite(FOM_DIET_FISH).." | "..GFWUtils.Hilite(FOM_DIET_BREAD).." | "..GFWUtils.Hilite(FOM_DIET_CHEESE).." | "..GFWUtils.Hilite(FOM_DIET_FRUIT).." | "..GFWUtils.Hilite(FOM_DIET_FUNGUS).." | "..GFWUtils.Hilite(FOM_DIET_BONUS)
926 if (cmd ~= "show" and cmd ~= "list") then
927 usageString = usageString.." <item link>.";
928 end
929 GFWUtils.Print(usageString);
930 return;
931 end
932  
933 if (cmd == "show" or cmd == "list") then
934 if ( diet == FOM_DIET_ALL ) then
935 diets = {FOM_DIET_MEAT, FOM_DIET_FISH, FOM_DIET_BREAD, FOM_DIET_CHEESE, FOM_DIET_FRUIT, FOM_DIET_FUNGUS, FOM_DIET_BONUS};
936 else
937 diets = {diet};
938 end
939  
940 for _, aDiet in diets do
941 local capDiet = string.upper(string.sub(aDiet, 1, 1)) .. string.sub(aDiet, 2); -- print a nicely capitalized version
942 GFWUtils.Print("Feed-O-Matic "..GFWUtils.Hilite(capDiet).." List:");
943 local dietFoods = FOM_Foods[aDiet];
944 if (FOM_AddedFoods ~= nil and FOM_AddedFoods[aDiet] ~= nil) then
945 dietFoods = GFWTable.Merge(dietFoods, FOM_AddedFoods[aDiet]);
946 end
947 if (FOM_RemovedFoods ~= nil and FOM_RemovedFoods[aDiet] ~= nil) then
948 dietFoods = GFWTable.Subtract(dietFoods, FOM_RemovedFoods[aDiet]);
949 end
950 table.sort(dietFoods);
951 for _, food in dietFoods do
952 local foodName = GetItemInfo(food);
953 if (foodName) then
954 if (FOM_FoodIDsToNames == nil) then
955 FOM_FoodIDsToNames = {};
956 end
957 FOM_FoodIDsToNames[food] = foodName;
958 GFWUtils.Print(GFWUtils.Hilite(" - ")..foodName);
959 else
960 GFWUtils.Print(GFWUtils.Hilite(" - ").."item id "..food.." (name not available)");
961 end
962 end
963 end
964 return;
965 else
966  
967 local inputFoods = { };
968 for itemLink in string.gfind(foodString, "|c%x+|Hitem:%d+:%d+:%d+:%d+|h%[.-%]|h|r") do
969 table.insert(inputFoods, itemLink);
970 local foodID = FOM_IDFromLink(itemLink);
971 if (foodID) then
972 local foodName = FOM_NameFromLink(itemLink);
973 if (FOM_FoodIDsToNames == nil) then
974 FOM_FoodIDsToNames = {};
975 end
976 FOM_FoodIDsToNames[foodID] = foodName;
977 end
978 end
979 if (table.getn(inputFoods) == 0) then
980 GFWUtils.Print("The "..GFWUtils.Hilite("/fom "..cmd).." command requires an item link; shift-click an item to insert a link.");
981 return;
982 end
983  
984 local capDiet = string.upper(string.sub(diet, 1, 1)) .. string.sub(diet, 2); -- print a nicely capitalized version
985 if ( cmd == "add" ) then
986 for _, food in inputFoods do
987 local foodID = FOM_IDFromLink(food);
988 if ( FOM_AddFood(diet, tonumber(foodID)) ) then
989 GFWUtils.Print("Added "..food.." to "..GFWUtils.Hilite(capDiet).." list.");
990 else
991 GFWUtils.Print(food.." already in "..GFWUtils.Hilite(capDiet).." list.");
992 end
993 end
994 if (FOM_Config.AvoidQuestFood) then
995 FOM_ScanQuests(); -- in case any of the newly added foods are quest objectives
996 end
997 return;
998 elseif (cmd == "remove" ) then
999 for _, food in inputFoods do
1000 local foodID = FOM_IDFromLink(food);
1001 if ( FOM_RemoveFood(diet, tonumber(foodID)) ) then
1002 GFWUtils.Print("Removed "..food.." from "..GFWUtils.Hilite(capDiet).." list.");
1003 else
1004 GFWUtils.Print("Could not find "..food.." in "..GFWUtils.Hilite(capDiet).." list.");
1005 end
1006 end
1007 return;
1008 end
1009 end
1010 end
1011  
1012 -- if we got down to here, we got bad input
1013 FOM_ChatCommandHandler("help");
1014 end
1015  
1016 -- Add a food to a list
1017 function FOM_AddFood(diet, food)
1018  
1019 if (FOM_Foods[diet] == nil) then
1020 GFWUtils.DebugLog("FOM_Foods[diet] == nil");
1021 end
1022 if (FOM_AddedFoods == nil or FOM_AddedFoods[diet] == nil) then
1023 GFWUtils.DebugLog("FOM_AddedFoods == nil or FOM_AddedFoods[diet] == nil");
1024 end
1025 if (FOM_RemovedFoods == nil or FOM_RemovedFoods[diet] == nil) then
1026 GFWUtils.DebugLog("FOM_RemovedFoods == nil or FOM_RemovedFoods[diet] == nil");
1027 end
1028 if ( GFWTable.IndexOf(FOM_Foods[diet], food) == 0 ) then
1029 if (FOM_AddedFoods == nil) then
1030 FOM_AddedFoods = {};
1031 end
1032 if (FOM_AddedFoods[diet] == nil) then
1033 FOM_AddedFoods[diet] = {};
1034 end
1035 if ( GFWTable.IndexOf(FOM_AddedFoods[diet], food) == 0 ) then
1036 table.insert( FOM_AddedFoods[diet], food );
1037 table.sort( FOM_AddedFoods[diet] );
1038 if (FOM_RemovedFoods and FOM_RemovedFoods[diet] and GFWTable.IndexOf(FOM_RemovedFoods[diet], food) ~= 0) then
1039 table.remove( FOM_RemovedFoods[diet], GFWTable.IndexOf(FOM_RemovedFoods[diet], food) );
1040 table.sort( FOM_RemovedFoods[diet] );
1041 end
1042 return true;
1043 else
1044 return false;
1045 end
1046 else
1047 return false;
1048 end
1049  
1050 end
1051  
1052 -- Remove a food from a list
1053 function FOM_RemoveFood(diet, food)
1054  
1055 if (FOM_Foods[diet] == nil) then
1056 GFWUtils.DebugLog("FOM_Foods[diet] == nil");
1057 end
1058 if (FOM_AddedFoods == nil or FOM_AddedFoods[diet] == nil) then
1059 GFWUtils.DebugLog("FOM_AddedFoods == nil or FOM_AddedFoods[diet] == nil");
1060 end
1061 if (FOM_RemovedFoods == nil or FOM_RemovedFoods[diet] == nil) then
1062 GFWUtils.DebugLog("FOM_RemovedFoods == nil or FOM_RemovedFoods[diet] == nil");
1063 end
1064 if ( GFWTable.IndexOf(FOM_Foods[diet], food) ~= 0 ) then
1065 if (FOM_RemovedFoods == nil) then
1066 FOM_RemovedFoods = {};
1067 end
1068 if (FOM_RemovedFoods[diet] == nil) then
1069 FOM_RemovedFoods[diet] = {};
1070 end
1071 if ( GFWTable.IndexOf(FOM_RemovedFoods[diet], food) == 0 ) then
1072 table.insert( FOM_RemovedFoods[diet], food );
1073 table.sort( FOM_RemovedFoods[diet] );
1074 if (FOM_AddedFoods and FOM_AddedFoods[diet] and GFWTable.IndexOf(FOM_AddedFoods[diet], food) ~= 0) then
1075 table.remove( FOM_AddedFoods[diet], GFWTable.IndexOf(FOM_AddedFoods[diet], food) );
1076 table.sort( FOM_AddedFoods[diet] );
1077 end
1078 return true;
1079 else
1080 return false;
1081 end
1082 else
1083 if (FOM_AddedFoods and FOM_AddedFoods[diet] and GFWTable.IndexOf(FOM_AddedFoods[diet], food) ~= 0) then
1084 table.remove( FOM_AddedFoods[diet], GFWTable.IndexOf(FOM_AddedFoods[diet], food) );
1085 table.sort( FOM_AddedFoods[diet] );
1086 return true;
1087 end
1088 return false;
1089 end
1090  
1091 end
1092  
1093 function FOM_IsBGActive()
1094 local bgNum = 1;
1095 local status;
1096 repeat
1097 status = GetBattlefieldStatus(bgNum);
1098 if (status == "active") then
1099 return true;
1100 end
1101 bgNum = bgNum + 1;
1102 until (status == nil)
1103 return false;
1104 end
1105 -- Check Happiness
1106 function FOM_CheckHappiness()
1107  
1108 -- Check for pet
1109 if not ( UnitExists("pet") ) then
1110 FOM_State.ShouldFeed = nil;
1111 return;
1112 end
1113  
1114 -- Get Pet Info
1115 local pet = UnitName("pet");
1116 local happiness, damage, loyalty = GetPetHappiness();
1117  
1118 -- Check No Happiness
1119 if ( happiness == 0 ) or ( happiness == nil ) then return; end
1120  
1121 local level;
1122 if ( FOM_Config.Level == "unhappy" ) then
1123 level = 1;
1124 elseif ( FOM_Config.Level == "content" ) then
1125 level = 2;
1126 elseif ( FOM_Config.Level == "happy" ) then
1127 level = 3;
1128 elseif ( FOM_Config.Level == "debug" ) then
1129 level = 4;
1130 else
1131 level = 0;
1132 end
1133  
1134 -- Check if Need Feeding
1135 if ( happiness < level + 1 ) then
1136 FOM_State.ShouldFeed = true;
1137 if (not FOM_HasFeedEffect() and GetTime() - FOM_LastWarning > FOM_WARNING_INTERVAL) then
1138 if (FOM_Config.TextWarning) then
1139 local msg;
1140 if (level - happiness == 0) then
1141 msg = FOM_PET_HUNGRY;
1142 else
1143 msg = FOM_PET_VERY_HUNGRY;
1144 end
1145 GFWUtils.Print(string.format(msg, pet));
1146 GFWUtils.Note(string.format(msg, pet));
1147 end
1148 FOM_PlayHungrySound();
1149 FOM_LastWarning = GetTime();
1150 end
1151 else
1152 FOM_State.ShouldFeed = nil;
1153 end
1154  
1155 end
1156  
1157 FOM_HungrySounds = {
1158 [BAT] = "Sound\\Creature\\FelBat\\FelBatDeath.wav",
1159 [BEAR] = "Sound\\Creature\\Bear\\mBearDeathA.wav",
1160 [BOAR] = "Sound\\Creature\\Boar\\mWildBoarAggro2.wav",
1161 [CAT] = "Sound\\Creature\\Tiger\\mTigerStand2A.wav",
1162 [CARRION_BIRD] = "Sound\\Creature\\Carrion\\mCarrionWoundCriticalA.wav",
1163 [CRAB] = "Sound\\Creature\\Crab\\CrabDeathA.wav",
1164 [CROCOLISK] = "Sound\\Creature\\Basilisk\\mBasiliskSpellCastA.wav",
1165 [GORILLA] = "Sound\\Creature\\Gorilla\\GorillaDeathA.wav",
1166 [HYENA] = "Sound\\Creature\\Hyena\\HyenaPreAggroA.wav",
1167 [OWL] = "Sound\\Creature\\OWl\\OwlPreAggro.wav",
1168 [RAPTOR] = "Sound\\Creature\\Raptor\\mRaptorWoundCriticalA.wav",
1169 [SCORPID] = "Sound\\Creature\\SilithidWasp\\mSilithidWaspStand2A.wav",
1170 [SPIDER] = "Sound\\Creature\\Tarantula\\mTarantulaFidget2a.wav",
1171 [TALLSTRIDER] = "Sound\\Creature\\TallStrider\\tallStriderPreAggroA.wav",
1172 [TURTLE] = "Sound\\Creature\\SeaTurtle\\SeaTurtleWoundCritA.wav",
1173 [WIND_SERPENT] = "Sound\\Creature\\WindSerpant\\mWindSerpantDeathA.wav",
1174 [WOLF] = "Sound\\Creature\\Wolf\\mWolfFidget2c.wav",
1175 };
1176 function FOM_PlayHungrySound()
1177 if (FOM_Config.AudioWarning) then
1178 local type = UnitCreatureFamily("pet");
1179 local sound = FOM_HungrySounds[type];
1180 if (sound == nil or FOM_Config.AudioWarning == "bell") then
1181 PlaySoundFile("Sound\\Doodad\\BellTollNightElf.wav");
1182 else
1183 PlaySoundFile(sound);
1184 end
1185 end
1186 end
1187  
1188 -- Check Feed Effect
1189 function FOM_HasFeedEffect()
1190  
1191 local i = 1;
1192 local buff;
1193 buff = UnitBuff("pet", i);
1194 while buff do
1195 if ( string.find(buff, "Ability_Hunter_BeastTraining") ) then
1196 return true;
1197 end
1198 i = i + 1;
1199 buff = UnitBuff("pet", i);
1200 end
1201 return false;
1202  
1203 end
1204  
1205 -- Feed Pet
1206 function FOM_Feed(aFood)
1207  
1208 FOM_State.ShouldFeed = false;
1209  
1210 -- Make sure we have a feedable pet
1211 if not (UnitExists("pet")) then
1212 GFWUtils.Note(FOM_ERROR_NO_PET);
1213 return;
1214 end
1215 if (UnitIsDead("pet")) then
1216 GFWUtils.Note(FOM_ERROR_PET_DEAD);
1217 return;
1218 end
1219 if (GetPetFoodTypes() == nil) then
1220 GFWUtils.Note(FOM_ERROR_NO_FEEDABLE_PET);
1221 return;
1222 end
1223  
1224 -- Assign Variable
1225 local pet = UnitName("pet");
1226  
1227 FOM_CheckSetup();
1228 if (FOM_LastPetName == nil or FOM_LastPetName == "") then
1229 GFWUtils.DebugLog("Can't get pet info.");
1230 return;
1231 end
1232  
1233 if (GetLocale() ~= "enUS") then
1234 if (FOM_LocaleInfo == nil) then
1235 FOM_LocaleInfo = {};
1236 end
1237 FOM_LocaleInfo[UnitCreatureFamily("pet")] = {GetPetFoodTypes()};
1238 end
1239  
1240 -- Look for Food
1241 local foodBag, foodItem;
1242 if (aFood ~= nil) then
1243 -- if told to feed a specific food, do so
1244 foodBag, foodItem = FOM_FindSpecificFood(aFood);
1245 if ( foodBag == nil) then
1246 -- No Food Could be Found
1247 GFWUtils.Print(string.format(FOM_ERROR_FOOD_NOT_FOUND, pet, aFood));
1248 return;
1249 end
1250 else
1251 foodBag, foodItem = FOM_NewFindFood();
1252 end
1253  
1254 if ( foodBag == nil) then
1255 -- No Food Could be Found
1256 GFWUtils.Print(string.format(FOM_ERROR_NO_FOOD, pet));
1257 return;
1258 end
1259  
1260 FOM_LastFood = GetContainerItemLink(foodBag, foodItem);
1261  
1262 GFWUtils.DebugLog("Picked "..FOM_LastFood.." (bag "..foodBag..", slot "..foodItem..") for feeding.");
1263 if (FOM_Config.Debug) then
1264 -- don't actually feed anything, just show what we would choose
1265 return;
1266 end
1267  
1268 -- Actually feed the item to the pet
1269 PickupContainerItem(foodBag, foodItem);
1270 if ( CursorHasItem() ) then
1271 DropItemOnUnit("pet");
1272 end
1273 if ( CursorHasItem() ) then
1274 PickupContainerItem(foodBag, foodItem);
1275 else
1276 FOM_State.ShouldFeed = nil;
1277 -- Alert
1278 if ( FOM_Config.Alert == "chat") then
1279 GFWUtils.Print(string.format(FOM_FEEDING_EAT, pet, GFWUtils.Hilite(FOM_LastFood)));
1280 elseif ( FOM_Config.Alert == "emote") then
1281 SendChatMessage(string.format(FOM_FEEDING_FEED, pet, FOM_LastFood).. FOM_RandomEmote(), "EMOTE");
1282 end
1283 end
1284  
1285 end
1286  
1287 function FOM_RandomEmote()
1288  
1289 local randomEmotes = {};
1290 if (UnitSex("pet") == 2) then
1291 randomEmotes = GFWTable.Merge(randomEmotes, FOM_Emotes["male"]);
1292 elseif (UnitSex("pet") == 3) then
1293 randomEmotes = GFWTable.Merge(randomEmotes, FOM_Emotes["female"]);
1294 end
1295  
1296 randomEmotes = GFWTable.Merge(randomEmotes, FOM_Emotes[UnitCreatureFamily("pet")]);
1297 randomEmotes = GFWTable.Merge(randomEmotes, FOM_Emotes[FOM_NameFromLink(FOM_LastFood)]);
1298 randomEmotes = GFWTable.Merge(randomEmotes, FOM_Emotes["any"]);
1299  
1300 return randomEmotes[math.random(table.getn(randomEmotes))];
1301  
1302 end
1303  
1304 function FOM_FindSpecificFood(foodName)
1305 for bagNum = 0, 4 do
1306 if (not FOM_BagIsQuiver(bagNum) ) then
1307 -- skip bags that can't contain food
1308  
1309 local bagSize = GetContainerNumSlots(bagNum);
1310 for itemNum = 1, bagSize do
1311  
1312 itemName = FOM_GetItemName(bagNum, itemNum);
1313 if ( itemName == foodName ) then
1314 return bagNum, itemNum;
1315 end
1316  
1317 end
1318 end
1319 end
1320 return nil;
1321 end
1322  
1323 function FOM_IsTemporaryFood(itemLink)
1324  
1325 local _, _, link = string.find(itemLink, "(item:%d+:%d+:%d+:%d+)");
1326 if (link == nil or link == "") then
1327 return false;
1328 end
1329 FOMTooltip:ClearLines();
1330 FOMTooltip:SetHyperlink(link);
1331 if (FOMTooltipTextLeft2:GetText() == ITEM_CONJURED) then
1332 return true;
1333 else
1334 return false;
1335 end
1336  
1337 end
1338  
1339 function FOM_FlatFoodList()
1340 local foodList = {};
1341 FOM_Quantity = { };
1342 for bagNum = 0, 4 do
1343 if (not FOM_BagIsQuiver(bagNum) ) then
1344 -- skip bags that can't contain food
1345 for itemNum = 1, GetContainerNumSlots(bagNum) do
1346 local itemLink = GetContainerItemLink(bagNum, itemNum);
1347 if (itemLink) then
1348 local itemID = FOM_IDFromLink(itemLink);
1349 local _, itemCount = GetContainerItemInfo(bagNum, itemNum);
1350 if ( FOM_IsInDiet(itemID) ) then
1351 if (FOM_FoodIDsToNames == nil) then
1352 FOM_FoodIDsToNames = {};
1353 end
1354 local name = FOM_NameFromLink(itemLink);
1355 FOM_FoodIDsToNames[itemID] = name;
1356 local isUseful = FOM_IsUsefulFood(itemID, itemCount);
1357 foodQuality = (FOM_FoodQuality[FOM_RealmPlayer][FOM_LastPetName][itemID] or MAX_QUALITY);
1358 if (foodQuality > 0) then
1359 table.insert(foodList, {bag=bagNum, slot=itemNum, link=itemLink, count=itemCount, quality=foodQuality, useful=isUseful, temp=FOM_IsTemporaryFood(itemLink)});
1360 end
1361 end
1362 end
1363 end
1364 end
1365 end
1366 return foodList;
1367 end
1368  
1369 function FOM_NewFindFood()
1370 FlatFoodList = FOM_FlatFoodList();
1371  
1372 table.sort(FlatFoodList, FOM_SortCount); -- small stacks first
1373 if (FOM_NumOpenBagSlots() > FOM_Config.KeepOpenSlots) then
1374 if (FOM_Config.PreferHigherQuality) then
1375 table.sort(FlatFoodList, FOM_SortQualityDescending); -- higher quality first
1376 else
1377 table.sort(FlatFoodList, FOM_SortQualityAscending); -- lower quality first
1378 end
1379 end
1380 table.sort(FlatFoodList, FOM_SortTemporary); -- temporary foods first
1381 if (FOM_Config.AvoidUsefulFood) then
1382 table.sort(FlatFoodList, FOM_SortUseful); -- non-useful foods first
1383 end
1384  
1385 for _, foodInfo in FlatFoodList do
1386 if (foodInfo.useful and FOM_Config.AvoidUsefulFood and not FOM_Config.Fallback) then
1387 GFWUtils.DebugLog("Skipping "..foodInfo.count.."x "..foodInfo.link.."; no falling back to avoided foods.");
1388 else
1389 return foodInfo.bag, foodInfo.slot;
1390 end
1391 end
1392  
1393 return nil;
1394 end
1395  
1396 function FOM_SortTemporary(a, b)
1397 if (a.temp) then
1398 aTemp = 1;
1399 else
1400 aTemp = 0;
1401 end
1402 if (b.temp) then
1403 bTemp = 1;
1404 else
1405 bTemp = 0;
1406 end
1407 return aTemp > bTemp;
1408 end
1409  
1410 function FOM_SortCount(a, b)
1411 return a.count < b.count;
1412 end
1413  
1414 function FOM_SortUseful(a, b)
1415 if (a.useful) then
1416 aUseful = 1;
1417 else
1418 aUseful = 0;
1419 end
1420 if (b.useful) then
1421 bUseful = 1;
1422 else
1423 bUseful = 0;
1424 end
1425 return aUseful < bUseful;
1426 end
1427  
1428 function FOM_SortQualityDescending(a, b)
1429 return a.quality > b.quality;
1430 end
1431  
1432 function FOM_SortQualityAscending(a, b)
1433 return a.quality < b.quality;
1434 end
1435  
1436 function FOM_IsUsefulFood(itemID, quantity)
1437 local foodName = GetItemInfo(itemID);
1438 if (foodName == nil) then
1439 GFWUtils.DebugLog("Can't get info for item ID "..itemID..", assuming it's OK to eat.");
1440 return false;
1441 end
1442 if (FOM_Cooking and FOM_Cooking[FOM_RealmPlayer] and FOM_Cooking[FOM_RealmPlayer][itemID]) then
1443 if (FOM_Cooking[FOM_RealmPlayer][itemID] >= FOM_Config.SaveForCookingLevel) then
1444 GFWUtils.DebugLog("Skipping "..quantity.."x "..foodName.."; is good for cooking.");
1445 return true;
1446 end
1447 end
1448 if (FOM_Config.AvoidQuestFood) then
1449 FOM_ScanQuests();
1450 if (FOM_QuestFood ~= nil and FOM_QuestFood[FOM_RealmPlayer] ~= nil and FOM_QuestFood[FOM_RealmPlayer][foodName]) then
1451 if (FOM_Quantity[foodName] == nil) then
1452 FOM_Quantity[foodName] = quantity;
1453 else
1454 FOM_Quantity[foodName] = FOM_Quantity[foodName] + quantity;
1455 end
1456 if (FOM_Quantity[foodName] > FOM_QuestFood[FOM_RealmPlayer][foodName]) then
1457 GFWUtils.DebugLog("Not skipping "..quantity.."x "..foodName.."; is needed for quest, but we have more than enough.");
1458 return false;
1459 else
1460 GFWUtils.DebugLog("Skipping "..quantity.."x "..foodName.."; is needed for quest.");
1461 return true;
1462 end
1463 end
1464 end
1465 if (FOM_Config.AvoidBonusFood and FOM_IsInDiet(itemID, FOM_DIET_BONUS)) then
1466 GFWUtils.DebugLog("Skipping "..quantity.."x "..foodName.."; has bonus effect when eaten by player.");
1467 return true;
1468 end
1469 --GFWUtils.DebugLog("Not skipping "..quantity.."x "..foodName.."; doesn't have other uses.");
1470 return false;
1471 end
1472  
1473 function FOM_NumOpenBagSlots()
1474 local openSlots = 0;
1475 for bagNum = 0, 4 do
1476 if (not FOM_BagIsQuiver(bagNum) ) then
1477 -- skip bags that can't contain food
1478  
1479 local bagSize = GetContainerNumSlots(bagNum);
1480 for itemNum = 1, bagSize do
1481 if (GetContainerItemInfo(bagNum, itemNum) == nil) then
1482 openSlots = openSlots + 1;
1483 end
1484 end
1485 end
1486 end
1487 return openSlots;
1488 end
1489  
1490 function FOM_IsInDiet(food, dietList)
1491  
1492 if ( dietList == nil ) then
1493 dietList = {GetPetFoodTypes()};
1494 end
1495 if ( dietList == nil ) then
1496 return false;
1497 end
1498 if (type(dietList) ~= "table") then
1499 dietList = {dietList};
1500 end
1501 for _, diet in dietList do
1502 diet = string.lower(diet); -- let's be case insensitive
1503 if (FOM_Foods[diet] == nil) then
1504 GFWUtils.DebugLog("FOM_Foods[diet] == nil");
1505 end
1506 if (FOM_RemovedFoods ~= nil and FOM_RemovedFoods[diet] ~= nil and GFWTable.IndexOf(FOM_RemovedFoods[diet], food) ~= 0) then
1507 return false;
1508 end
1509 if (FOM_AddedFoods ~= nil and FOM_AddedFoods[diet] ~= nil and GFWTable.IndexOf(FOM_AddedFoods[diet], food) ~= 0) then
1510 return true;
1511 end
1512 if (GFWTable.IndexOf(FOM_Foods[diet], food) ~= 0) then
1513 return true;
1514 end
1515 end
1516  
1517 return false;
1518  
1519 end
1520  
1521 function FOM_IsKnownFood(food)
1522 return FOM_IsInDiet(food, {FOM_DIET_MEAT, FOM_DIET_FISH, FOM_DIET_BREAD, FOM_DIET_CHEESE, FOM_DIET_FUNGUS, FOM_DIET_FRUIT});
1523 end
1524  
1525 -- Get Item Name
1526 function FOM_GetItemName(bag, slot)
1527  
1528 local itemLink = GetContainerItemLink(bag, slot);
1529 if (itemLink) then
1530 return FOM_NameFromLink(itemLink);
1531 else
1532 return "";
1533 end
1534 end
1535  
1536 function FOM_PetRename(newName)
1537  
1538 FOM_CheckSetup();
1539  
1540 -- move our saved food quality data to be indexed under the new name
1541 FOM_FoodQuality[FOM_RealmPlayer][newName] = FOM_FoodQuality[FOM_RealmPlayer][FOM_LastPetName];
1542 FOM_FoodQuality[FOM_RealmPlayer][FOM_LastPetName] = nil;
1543  
1544 FOM_Original_PetRename(newName);
1545  
1546 end
1547  
1548 function FOM_PetAbandon()
1549  
1550 FOM_CheckSetup();
1551  
1552 -- delete saved food-quality data for this pet so we don't bloat SavedVariables
1553 FOM_FoodQuality[FOM_RealmPlayer][FOM_LastPetName] = nil;
1554  
1555 FOM_Original_PetAbandon();
1556  
1557 end
1558  
1559 -- The icon for the cooking spell is unique and the same in all languages; use that to determine the localized name.
1560 function FOM_CookingSpellName()
1561 FOM_COOKING_ICON = "Interface\\Icons\\INV_Misc_Food_15";
1562 if (FOM_COOKING_NAME == nil) then
1563 local spellName;
1564 local i = 0;
1565 repeat
1566 i = i + 1;
1567 spellName = GetSpellName(i, BOOKTYPE_SPELL);
1568 if (spellName ~= nil and GetSpellTexture(i, BOOKTYPE_SPELL) == FOM_COOKING_ICON) then
1569 FOM_COOKING_NAME = spellName;
1570 return FOM_COOKING_NAME;
1571 end
1572 until (spellName == nil);
1573 end
1574 return FOM_COOKING_NAME;
1575 end
1576  
1577 function FOM_BagIsQuiver(bagNum)
1578 local invSlotID = ContainerIDToInventoryID(bagNum);
1579 local bagLink = GetInventoryItemLink("player", invSlotID);
1580 if (bagLink == nil) then
1581 return false;
1582 end
1583 local _, _, itemID = string.find(bagLink, "item:(%d+):%d+:%d+:%d+");
1584 if (tonumber(itemID)) then
1585 itemID = tonumber(itemID);
1586 local name, link, rarity, minLevel, type, subType, stackCount, equipLoc = GetItemInfo(itemID);
1587 if (type == "Ammo Pouch" or type == "Quiver" or subType == "Ammo Pouch" or subType == "Quiver") then
1588 return true;
1589 end
1590 if (type == FOM_AMMO_POUCH or type == FOM_QUIVER or subType == FOM_AMMO_POUCH or subType == FOM_QUIVER) then
1591 return true;
1592 end
1593 end
1594 return false;
1595 end
1596  
1597 function FOM_IDFromLink(itemLink)
1598 if (itemLink == nil) then return nil; end
1599 local _, _, itemID = string.find(itemLink, "item:(%d+):%d+:%d+:%d+");
1600 if (tonumber(itemID)) then
1601 return tonumber(itemID);
1602 else
1603 return nil;
1604 end
1605 end
1606  
1607 function FOM_NameFromLink(itemLink)
1608 if (itemLink == nil) then return nil; end
1609 local _, _, name = string.find(itemLink, "%[(.+)%]");
1610 return name;
1611 end
1612  
1613 function FOM_OptionsShow()
1614 FOM_VersionText:SetText("v. "..FOM_VERSION);
1615 FOM_KeepOpenSlots:SetText(FOM_Config.KeepOpenSlots);
1616 for option, text in FOM_OptionsButtonText do
1617 local button = getglobal("FOM_OptionsButton_"..option);
1618 local buttonText = getglobal("FOM_OptionsButton_"..option.."Text");
1619 if (button and buttonText) then
1620 if (FOM_Config[option]) then
1621 button:SetChecked(true);
1622 elseif (option == "SaveForCook_All" and FOM_Config.SaveForCookingLevel <= 0) then
1623 button:SetChecked(true);
1624 elseif (option == "SaveForCook_Green" and FOM_Config.SaveForCookingLevel == 1) then
1625 button:SetChecked(true);
1626 elseif (option == "SaveForCook_Yellow" and FOM_Config.SaveForCookingLevel == 2) then
1627 button:SetChecked(true);
1628 elseif (option == "SaveForCook_Orange" and FOM_Config.SaveForCookingLevel == 3) then
1629 button:SetChecked(true);
1630 elseif (option == "SaveForCook_None" and FOM_Config.SaveForCookingLevel >= 4) then
1631 button:SetChecked(true);
1632 elseif (option == "AudioWarningBell" and FOM_Config.AudioWarning == "bell") then
1633 button:SetChecked(true);
1634 elseif (option == "AlertEmote" and FOM_Config.Alert == "emote") then
1635 button:SetChecked(true);
1636 elseif (option == "AlertChat" and FOM_Config.Alert == "chat") then
1637 button:SetChecked(true);
1638 elseif (option == "AlertNone" and not FOM_Config.Alert) then
1639 button:SetChecked(true);
1640 elseif (option == "LevelContent" and FOM_Config.Level == "content") then
1641 button:SetChecked(true);
1642 elseif (option == "LevelUnhappy" and FOM_Config.Level == "unhappy") then
1643 button:SetChecked(true);
1644 elseif (option == "LevelOff" and not FOM_Config.Level) then
1645 button:SetChecked(true);
1646 else
1647 button:SetChecked(false);
1648 end
1649 buttonText:SetText(text);
1650 end
1651 end
1652 end
1653  
1654 function FOM_OptionsClick()
1655 local button = this:GetName();
1656 local option = string.gsub(button, "FOM_OptionsButton_", "");
1657  
1658 if (option == "SaveForCook_All" and this:GetChecked()) then
1659 FOM_Config.SaveForCookingLevel = 0;
1660 elseif (option == "SaveForCook_Green" and this:GetChecked()) then
1661 FOM_Config.SaveForCookingLevel = 1;
1662 elseif (option == "SaveForCook_Yellow" and this:GetChecked()) then
1663 FOM_Config.SaveForCookingLevel = 2;
1664 elseif (option == "SaveForCook_Orange" and this:GetChecked()) then
1665 FOM_Config.SaveForCookingLevel = 3;
1666 elseif (option == "SaveForCook_None" and this:GetChecked()) then
1667 FOM_Config.SaveForCookingLevel = 4;
1668 elseif (option == "AudioWarningBell") then
1669 if (this:GetChecked()) then
1670 FOM_Config.AudioWarning = "bell";
1671 else
1672 FOM_Config.AudioWarning = 1;
1673 end
1674 elseif (option == "AlertEmote" and this:GetChecked()) then
1675 FOM_Config.Alert = "emote";
1676 elseif (option == "AlertChat" and this:GetChecked()) then
1677 FOM_Config.Alert = "chat";
1678 elseif (option == "AlertNone" and this:GetChecked()) then
1679 FOM_Config.Alert = nil;
1680 elseif (option == "LevelContent" and this:GetChecked()) then
1681 FOM_Config.Level = "content";
1682 elseif (option == "LevelUnhappy" and this:GetChecked()) then
1683 FOM_Config.Level = "unhappy";
1684 elseif (option == "LevelOff" and this:GetChecked()) then
1685 FOM_Config.Level = nil;
1686 else
1687 FOM_Config[option] = this:GetChecked();
1688 end
1689 FOM_OptionsShow();
1690 end
1691  
1692 function FOM_KeepOpenSlots_TextChanged()
1693 FOM_Config.KeepOpenSlots = tonumber(this:GetText()) or 0;
1694 end
1695  
1696