-- AdePet.lua -- Hunter-only addon for the 1.12 client. -- Shows: Pet_Name: Loyalty_Level (Loyalty_Name) -- and, under it, "Pet is hungry" when the pet's happiness drops below Happy (yellow/red). -- Window hides itself at max loyalty (Level 6). -- -- Commands: -- /hungry X set hunger check interval to X seconds (default 15) -- /adepet lock | unlock | reset (alias: /ap) AdePetDB = AdePetDB or {} local LOYALTY_INTERVAL = 1.0 local DEFAULT_HUNGRY_INTERVAL = 15 local MAX_LOYALTY = 6 local LOYALTY_NAMES = { [1] = "Rebellious", [2] = "Unruly", [3] = "Submissive", [4] = "Dependable", [5] = "Faithful", [6] = "Best Friend", } local isHunter = false local isHungry = false local hungerLevel = 3 -- 1 = unhappy (red), 2 = content (yellow), 3 = happy (green) local frame = CreateFrame("Frame", "AdePetFrame", UIParent) frame:SetWidth(150) frame:SetHeight(28) frame:SetPoint("CENTER", UIParent, "CENTER", 0, 200) frame:SetMovable(true) frame:EnableMouse(true) frame:RegisterForDrag("LeftButton") frame:SetClampedToScreen(true) frame:Hide() frame:SetBackdrop({ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", tile = true, tileSize = 16, edgeSize = 12, insets = { left = 3, right = 3, top = 3, bottom = 3 }, }) frame:SetBackdropColor(0, 0, 0, 0.7) local text = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal") text:SetPoint("TOP", frame, "TOP", 0, -8) text:SetJustifyH("CENTER") local hungryText = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") hungryText:SetPoint("TOP", text, "BOTTOM", 0, -3) hungryText:SetJustifyH("CENTER") hungryText:Hide() frame:SetScript("OnDragStart", function() if not AdePetDB.locked then this:StartMoving() end end) frame:SetScript("OnDragStop", function() this:StopMovingOrSizing() local point, _, relPoint, x, y = this:GetPoint() AdePetDB.point = point AdePetDB.relPoint = relPoint AdePetDB.x = x AdePetDB.y = y end) local function GetHungryInterval() return AdePetDB.hungryInterval or DEFAULT_HUNGRY_INTERVAL end -- Fit the window to the visible text lines. local function ResizeToText() local w = text:GetStringWidth() local h1 = text:GetHeight() if not h1 or h1 < 1 then h1 = 12 end local height = 8 + h1 + 8 if hungryText:IsShown() then local w2 = hungryText:GetStringWidth() if w2 > w then w = w2 end local h2 = hungryText:GetHeight() if not h2 or h2 < 1 then h2 = 10 end height = height + h2 + 3 end w = w + 24 if w < 90 then w = 90 end frame:SetWidth(w) frame:SetHeight(height) end -- Reads the pet's happiness. 1 = unhappy, 2 = content, 3 = happy. -- Anything below "happy" is treated as hungry. local function UpdateHunger() if not isHunter or not UnitExists("pet") then isHungry = false return end local happiness = GetPetHappiness() if type(happiness) ~= "number" then happiness = tonumber(happiness) end if happiness and happiness < 3 then isHungry = true hungerLevel = happiness else isHungry = false end end -- Extract numeric loyalty level. Standard API returns a number; some servers -- (e.g. OctoWoW) return text like "(Loyalty Level 1) Rebellious". local function ParseLoyalty(raw) if type(raw) == "number" then return raw elseif type(raw) == "string" then local _, _, digits = string.find(raw, "(%d+)") if digits then return tonumber(digits) end -- fallback: match by rank name local lower = string.lower(raw) for level, name in pairs(LOYALTY_NAMES) do if string.find(lower, string.lower(name), 1, true) then return level end end end return nil end local function UpdateDisplay() if not isHunter then frame:Hide() return end if not UnitExists("pet") then text:SetText("No Pet") hungryText:Hide() ResizeToText() frame:Show() return end local petName = UnitName("pet") or "Pet" local loyaltyLevel = ParseLoyalty(GetPetLoyalty()) if loyaltyLevel and loyaltyLevel >= MAX_LOYALTY then frame:Hide() return end if loyaltyLevel then local loyaltyName = LOYALTY_NAMES[loyaltyLevel] or "Unknown" text:SetText(petName .. ": " .. loyaltyLevel .. " (" .. loyaltyName .. ")") else text:SetText(petName) end if isHungry then hungryText:SetText("Pet is hungry") if hungerLevel == 1 then hungryText:SetTextColor(1, 0.2, 0.2) else hungryText:SetTextColor(1, 0.9, 0.1) end hungryText:Show() else hungryText:Hide() end ResizeToText() frame:Show() end local function CheckHunger() UpdateHunger() UpdateDisplay() end local loyaltyElapsed = 0 local hungerElapsed = 0 frame:SetScript("OnUpdate", function() if not isHunter then return end loyaltyElapsed = loyaltyElapsed + arg1 hungerElapsed = hungerElapsed + arg1 if hungerElapsed >= GetHungryInterval() then hungerElapsed = 0 loyaltyElapsed = 0 CheckHunger() elseif loyaltyElapsed >= LOYALTY_INTERVAL then loyaltyElapsed = 0 UpdateDisplay() end end) frame:RegisterEvent("PLAYER_ENTERING_WORLD") frame:RegisterEvent("UNIT_PET") frame:RegisterEvent("PLAYER_REGEN_ENABLED") -- left combat frame:SetScript("OnEvent", function() if event == "PLAYER_ENTERING_WORLD" then local _, englishClass = UnitClass("player") isHunter = (englishClass == "HUNTER") if not isHunter then frame:Hide() return end if AdePetDB.point then frame:ClearAllPoints() frame:SetPoint(AdePetDB.point, UIParent, AdePetDB.relPoint, AdePetDB.x, AdePetDB.y) end end if not isHunter then return end if event == "UNIT_PET" and arg1 ~= "player" then return end -- Entering world, pet change, or leaving combat: check hunger right away. hungerElapsed = 0 CheckHunger() end) SLASH_ADEPETHUNGRY1 = "/hungry" SlashCmdList["ADEPETHUNGRY"] = function(msg) if not isHunter then DEFAULT_CHAT_FRAME:AddMessage("AdePet: this addon only works for Hunters.") return end local seconds = tonumber(msg) if not seconds or seconds < 1 then DEFAULT_CHAT_FRAME:AddMessage("AdePet: hunger check every " .. GetHungryInterval() .. "s. Usage: /hungry X (X = seconds, minimum 1)") return end AdePetDB.hungryInterval = seconds hungerElapsed = 0 DEFAULT_CHAT_FRAME:AddMessage("AdePet: hunger check interval set to " .. seconds .. "s.") end SLASH_ADEPET1 = "/adepet" SLASH_ADEPET2 = "/ap" SlashCmdList["ADEPET"] = function(msg) msg = string.lower(msg or "") if not isHunter then DEFAULT_CHAT_FRAME:AddMessage("AdePet: this addon only works for Hunters.") return end if msg == "lock" then AdePetDB.locked = true DEFAULT_CHAT_FRAME:AddMessage("AdePet: window locked.") elseif msg == "unlock" then AdePetDB.locked = false DEFAULT_CHAT_FRAME:AddMessage("AdePet: window unlocked (drag to move).") elseif msg == "reset" then AdePetDB.point = nil frame:ClearAllPoints() frame:SetPoint("CENTER", UIParent, "CENTER", 0, 200) DEFAULT_CHAT_FRAME:AddMessage("AdePet: position reset.") else DEFAULT_CHAT_FRAME:AddMessage("AdePet commands: /adepet lock, unlock, reset | /hungry X") end end