mirror of
https://codeberg.org/Duvelcorp/MetaHunt.git
synced 2026-09-24 00:26:58 +00:00
323 lines
15 KiB
Lua
323 lines
15 KiB
Lua
-- MetaHunt level tracker. All training facts come from MTH_DS_TrainerCatalog
|
|
-- through trainer-spell-planner.lua; this module only detects progression and
|
|
-- presents the resulting facts through chat and animations.
|
|
|
|
local MTH_LT_Frame = nil
|
|
local MTH_LT_PendingPetCheck = false
|
|
|
|
local MTH_LT_HunterLines = {
|
|
[1] = "You can now track beasts. Revolutionary: look for the things you intend to shoot.",
|
|
[2] = "The wilderness remains deeply unimpressed.",
|
|
[3] = "Still mostly leather, arrows, and misplaced confidence.",
|
|
[4] = "You have actual trainer lessons now. Try not to spend all your coin on repairs.",
|
|
[5] = "Your pet is doing its share. Please consider doing yours.",
|
|
[6] = "A hunter's mark: because shouting at the target was not precise enough.",
|
|
[7] = "Every pull is a plan until it becomes cardio.",
|
|
[8] = "Concussive Shot. Distance is now a tactical concept, not an accident.",
|
|
[9] = "Your arrows have begun their long argument with gravity.",
|
|
[10] = "You have a hawk aspect. The bird remains unavailable for comment.",
|
|
[11] = "A fine age for discovering that pets also require paperwork.",
|
|
[12] = "Mend Pet unlocked. Your pet has noticed this was overdue.",
|
|
[13] = "The wilderness has upgraded its complaints department.",
|
|
[14] = "Eagle Eye. Finally, a way to inspect trouble before walking into it.",
|
|
[15] = "You have survived another level through skill, luck, or a pet-shaped shield.",
|
|
[16] = "Traps and sharp things. Subtlety continues to be optional.",
|
|
[17] = "Your pet is still carrying the emotional weight of this partnership.",
|
|
[18] = "Multi-Shot. One target was apparently an unacceptable limitation.",
|
|
[19] = "Soon you may run faster. The enemies will take this personally.",
|
|
[20] = "Congratulations: escape now has a speed setting.",
|
|
[21] = "Fast enough to arrive at the next questionable decision sooner.",
|
|
[22] = "Your trainer has new bills and somehow they are all addressed to you.",
|
|
[23] = "The pet remains employed despite the working conditions.",
|
|
[24] = "Beast Lore. At last: research before violence. Briefly.",
|
|
[25] = "Halfway to better excuses, nowhere near fewer mistakes.",
|
|
[26] = "Rapid Fire. Your bow has entered its impatient phase.",
|
|
[27] = "Things are going well enough to become dangerous.",
|
|
[28] = "Your arrows now contain a measurable amount of intent.",
|
|
[29] = "Prepare for the hunter's most respected tactical maneuver.",
|
|
[30] = "Feign Death. Why win a fight when you can become administrative debris?",
|
|
[31] = "You are alive, which validates absolutely nothing.",
|
|
[32] = "Flare. Stealth has been downgraded to a suggestion.",
|
|
[33] = "The next trap is definitely part of the plan.",
|
|
[34] = "Explosive Trap. Negotiation has left the chat.",
|
|
[35] = "Your pet thinks this is all normal. That is worrying.",
|
|
[36] = "More damage, more maintenance, same heroic disregard for repair bills.",
|
|
[37] = "Keep going. The next disaster is probably already pathing toward you.",
|
|
[38] = "Your toolkit is becoming impressively hard to explain to civilized people.",
|
|
[39] = "One level until armor finally admits you have been taking hits.",
|
|
[40] = "Mail training. Leather got you this far; enemies kept putting holes in it.",
|
|
[41] = "You are now visibly better protected from consequences.",
|
|
[42] = "More Multi-Shot: because collateral damage needed a sequel.",
|
|
[43] = "Your pet has grown used to the sound of avoidable danger.",
|
|
[44] = "The trainer is delighted. Your coin pouch is less enthusiastic.",
|
|
[45] = "You are a seasoned hunter now, which means the mistakes are expensive.",
|
|
[46] = "Nature resistance: proof that the outdoors have been escalating.",
|
|
[47] = "Still alive. Still pointing the dangerous end away from yourself. Usually.",
|
|
[48] = "Your damage has matured into a fully funded public nuisance.",
|
|
[49] = "One more level until the trainer starts charging executive prices.",
|
|
[50] = "Your arrows have tenure now.",
|
|
[51] = "The wilderness would like a word. It has a queue.",
|
|
[52] = "Aimed Shot hits harder, which is your preferred form of diplomacy.",
|
|
[53] = "Your pet remains your most reliable party member. Make of that what you will.",
|
|
[54] = "Explosive Trap again. The floor continues to be a valid target.",
|
|
[55] = "Almost there. Try not to die to something with a tutorial tooltip.",
|
|
[56] = "Aspect of the Viper. Mana problems now have a bird-shaped solution.",
|
|
[57] = "The finish line is visible. So are several elite mobs. Choose carefully.",
|
|
[58] = "The final trainer bills are arriving with alarming confidence.",
|
|
[59] = "One last level. Your pet has begun drafting a victory speech.",
|
|
[60] = "You made it. The wildlife will remember this unfavorably.",
|
|
}
|
|
|
|
local MTH_LT_Priority = {
|
|
["Feign Death"] = 100,
|
|
["Mail"] = 95,
|
|
["Aspect of the Cheetah"] = 90,
|
|
["Rapid Fire"] = 88,
|
|
["Aspect of the Pack"] = 86,
|
|
["Explosive Trap"] = 84,
|
|
["Freezing Trap"] = 82,
|
|
["Flare"] = 80,
|
|
["Eagle Eye"] = 78,
|
|
["Multi-Shot"] = 76,
|
|
["Aimed Shot"] = 74,
|
|
["Aspect of the Viper"] = 72,
|
|
["Trueshot Aura"] = 70,
|
|
["Volley"] = 68,
|
|
["Track Hidden"] = 66,
|
|
}
|
|
|
|
local MTH_LT_PetLines = {
|
|
"has leveled up. It is now statistically better than your last pull.",
|
|
"has leveled up. The food budget has noticed.",
|
|
"has leveled up. Please do not celebrate by pulling three extra mobs.",
|
|
"has leveled up. It remains committed to solving problems with teeth.",
|
|
"has leveled up. The wilderness has filed no objection.",
|
|
"has leveled up. Your dependable colleague is carrying this team again.",
|
|
}
|
|
|
|
local MTH_LT_LoyaltyLines = {
|
|
"has decided you are less terrible than expected.",
|
|
"has upgraded its opinion of you. Keep the food coming.",
|
|
"is learning to trust your decision-making. This may be a mistake.",
|
|
"has accepted the arrangement. The arrangement includes snacks.",
|
|
"now trusts you more. Do not immediately test this with a cliff.",
|
|
}
|
|
|
|
local function MTH_LT_Store()
|
|
if not MTH_CharSavedVariables then MTH_CharSavedVariables = {} end
|
|
if type(MTH_CharSavedVariables.levelTracker) ~= "table" then
|
|
MTH_CharSavedVariables.levelTracker = { petLine = 0, loyaltyLine = 0 }
|
|
end
|
|
return MTH_CharSavedVariables.levelTracker
|
|
end
|
|
|
|
local function MTH_LT_MessageEnabled(key, defaultValue)
|
|
return MTH and type(MTH.IsMessageEnabled) == "function" and MTH:IsMessageEnabled(key, defaultValue)
|
|
end
|
|
|
|
local function MTH_LT_FormatCost(copper)
|
|
local total = tonumber(copper) or 0
|
|
local gold = math.floor(total / 10000)
|
|
local silver = math.floor((total - gold * 10000) / 100)
|
|
local bronze = total - gold * 10000 - silver * 100
|
|
local parts = {}
|
|
if gold > 0 then table.insert(parts, "|cffffd100" .. gold .. "g|r") end
|
|
if silver > 0 or gold > 0 then table.insert(parts, "|cffc7c7cf" .. silver .. "s|r") end
|
|
table.insert(parts, "|cffeda55f" .. bronze .. "c|r")
|
|
return table.concat(parts, " ")
|
|
end
|
|
|
|
local function MTH_LT_NextLine(store, key, lines)
|
|
store[key] = (tonumber(store[key]) or 0) + 1
|
|
if store[key] > table.getn(lines) then store[key] = 1 end
|
|
return lines[store[key]]
|
|
end
|
|
|
|
local function MTH_LT_GetHeadline(plan)
|
|
local best = nil
|
|
local bestPriority = -1
|
|
for _, entry in ipairs(plan.rows or {}) do
|
|
local priority = MTH_LT_Priority[tostring(entry.row and entry.row.name or "")] or 0
|
|
if priority > bestPriority then best, bestPriority = entry, priority end
|
|
end
|
|
return best
|
|
end
|
|
|
|
local function MTH_LT_FormatRows(plan)
|
|
local labels = {}
|
|
for index, entry in ipairs(plan.rows or {}) do
|
|
local row = entry.row or {}
|
|
local label = tostring(row.name or "Unknown")
|
|
if row.rank and row.rank ~= "" then label = label .. " " .. tostring(row.rank) end
|
|
table.insert(labels, label)
|
|
end
|
|
return table.concat(labels, ", ")
|
|
end
|
|
|
|
local function MTH_LT_PrintSpellList(plan)
|
|
local line = ""
|
|
local isFirstLine = true
|
|
for _, entry in ipairs(plan.rows or {}) do
|
|
local row = entry.row or {}
|
|
local label = tostring(row.name or "Unknown")
|
|
if row.rank and row.rank ~= "" then label = label .. " " .. tostring(row.rank) end
|
|
if line == "" then
|
|
line = label
|
|
elseif string.len(line) + string.len(label) + 2 > 92 then
|
|
MTH:Print((isFirstLine and "New spells available: " or "And also: ") .. line)
|
|
isFirstLine = false
|
|
line = label
|
|
else
|
|
line = line .. ", " .. label
|
|
end
|
|
end
|
|
if line ~= "" then MTH:Print((isFirstLine and "New spells available: " or "And also: ") .. line) end
|
|
end
|
|
|
|
local function MTH_LT_AnnounceTraining(kind, level, eventKind, preview)
|
|
if type(MTH_TrainerPlan_BuildLevel) ~= "function" then return end
|
|
local base = MTH_TrainerPlan_BuildLevel(kind, level, { honored = false, includeKnown = preview })
|
|
local honored = MTH_TrainerPlan_BuildLevel(kind, level, { honored = true, includeKnown = preview })
|
|
if base.unlearned.count <= 0 then
|
|
if kind == "hunter" and MTH_LT_MessageEnabled("hunterLevelUp", true) then
|
|
MTH:Print("Congratz! You hit level " .. tostring(level) .. ".")
|
|
end
|
|
if preview then MTH:Print("Level test: no " .. kind .. " trainer spells in the 1.18.1 catalog at level " .. tostring(level) .. ".") end
|
|
return
|
|
end
|
|
local headline = MTH_LT_GetHeadline(base)
|
|
local headlineText = headline and headline.row and tostring(headline.row.name or "") or "New training"
|
|
if headline and headline.row and headline.row.rank and headline.row.rank ~= "" then headlineText = headlineText .. " " .. headline.row.rank end
|
|
local isLevelCap = kind == "hunter" and level == 60
|
|
if isLevelCap then headlineText = "The hunt is yours" end
|
|
if MTH_LT_MessageEnabled(eventKind == "hunter" and "hunterLevelUp" or "petLevelUp", true) then
|
|
if kind == "hunter" then
|
|
MTH:Print("Congratz! You hit level " .. tostring(level) .. ".")
|
|
MTH:Print(MTH_LT_HunterLines[level] or "New training is available.")
|
|
MTH:Print("The spells you can learn will cost you " .. MTH_LT_FormatCost(base.unlearned.cost)
|
|
.. ", but only " .. MTH_LT_FormatCost(honored.unlearned.cost) .. " if you are Honored with the master.")
|
|
MTH_LT_PrintSpellList(base)
|
|
else
|
|
MTH:Print("" .. MTH_LT_FormatRows(base))
|
|
MTH:Print("Trainer cost: Base " .. MTH_LT_FormatCost(base.unlearned.cost) .. " | Honored " .. MTH_LT_FormatCost(honored.unlearned.cost))
|
|
end
|
|
end
|
|
local isMilestone = kind == "hunter" and (level == 10 or level == 20 or level == 30 or level == 40 or level == 50 or level == 60)
|
|
local flag = isMilestone and "level.huntermilestone" or (kind == "hunter" and "level.hunter" or "level.pet")
|
|
if type(MTH_FX_IsEnabled) == "function" and MTH_FX_IsEnabled(flag) and type(MTH_Celebrate) == "function" then
|
|
local subtitle = kind == "hunter" and (MTH_LT_HunterLines[level] or "New training is available.") or "New pet training is available. The trainer wants coin."
|
|
if isMilestone and type(MTH_CelebrateBlackHole) == "function" then
|
|
MTH_CelebrateBlackHole("Level " .. tostring(level) .. " - " .. headlineText, subtitle)
|
|
else
|
|
MTH_Celebrate("Level " .. tostring(level) .. " - " .. headlineText, subtitle, "fanfare", 4.8)
|
|
end
|
|
end
|
|
end
|
|
|
|
local function MTH_LT_HandleHunterLevel(level)
|
|
local store = MTH_LT_Store()
|
|
local previous = tonumber(store.hunterLevel)
|
|
store.hunterLevel = level
|
|
if previous and level > previous then
|
|
MTH_LT_AnnounceTraining("hunter", level, "hunter")
|
|
end
|
|
end
|
|
|
|
local function MTH_LT_GetPetState()
|
|
if type(UnitExists) ~= "function" or not UnitExists("pet") then return nil end
|
|
local level = type(UnitLevel) == "function" and tonumber(UnitLevel("pet")) or nil
|
|
local name = type(UnitName) == "function" and UnitName("pet") or "Your pet"
|
|
if not level or level <= 0 then return nil end
|
|
local loyalty = nil
|
|
local getPetLoyalty = (type(getglobal) == "function" and getglobal("GetPetLoyalty")) or (_G and _G["GetPetLoyalty"])
|
|
if type(getPetLoyalty) == "function" then loyalty = tonumber(getPetLoyalty()) end
|
|
return { key = tostring(name or "pet"), name = tostring(name or "Your pet"), level = level, loyalty = loyalty }
|
|
end
|
|
|
|
local function MTH_LT_HandlePetState()
|
|
MTH_LT_PendingPetCheck = false
|
|
local state = MTH_LT_GetPetState()
|
|
if not state then return end
|
|
local store = MTH_LT_Store()
|
|
local pet = store.pet
|
|
if type(pet) ~= "table" or pet.key ~= state.key then
|
|
store.pet = state
|
|
return
|
|
end
|
|
if state.level > (tonumber(pet.level) or 0) then
|
|
local line = MTH_LT_NextLine(store, "petLine", MTH_LT_PetLines)
|
|
if MTH_LT_MessageEnabled("petLevelUp", true) then MTH:Print(state.name .. " reached level " .. state.level .. ". " .. line) end
|
|
MTH_LT_AnnounceTraining("pet", state.level, "pet")
|
|
end
|
|
if state.loyalty and state.loyalty > (tonumber(pet.loyalty) or 0) then
|
|
local line = MTH_LT_NextLine(store, "loyaltyLine", MTH_LT_LoyaltyLines)
|
|
if state.loyalty == 6 then line = "is your Best Friend. Against all evidence, it trusts you completely." end
|
|
if MTH_LT_MessageEnabled("petLoyaltyUp", true) then MTH:Print(state.name .. " reached Loyalty Level " .. state.loyalty .. ". " .. line) end
|
|
if type(MTH_FX_IsEnabled) == "function" and MTH_FX_IsEnabled("level.loyalty") and type(MTH_Celebrate) == "function" then
|
|
MTH_Celebrate(state.name .. " - Loyalty " .. state.loyalty, line, state.loyalty == 6 and "victory" or "fanfare")
|
|
end
|
|
end
|
|
store.pet = state
|
|
end
|
|
|
|
local function MTH_LT_RequestPetCheck()
|
|
if MTH_LT_PendingPetCheck or not MTH_LT_Frame then return end
|
|
MTH_LT_PendingPetCheck = true
|
|
MTH_LT_Frame.elapsed = 0
|
|
MTH_LT_Frame:SetScript("OnUpdate", function()
|
|
this.elapsed = (this.elapsed or 0) + (arg1 or 0)
|
|
if this.elapsed >= 0.35 then
|
|
this:SetScript("OnUpdate", nil)
|
|
MTH_LT_HandlePetState()
|
|
end
|
|
end)
|
|
end
|
|
|
|
function MTH_LevelTracker_Test(kind, level)
|
|
if kind == "hunter" or kind == "pet" then
|
|
local targetLevel = tonumber(level) or ((kind == "hunter") and (tonumber(UnitLevel("player")) or 1) or 1)
|
|
MTH:Print("Level test: previewing " .. kind .. " trainer spells at level " .. tostring(targetLevel) .. ".")
|
|
MTH_LT_AnnounceTraining(kind, targetLevel, kind, true)
|
|
return true
|
|
end
|
|
if kind == "loyalty" then
|
|
local state = MTH_LT_GetPetState()
|
|
local loyalty = tonumber(level) or (state and state.loyalty) or 1
|
|
local petName = state and state.name or "Your pet"
|
|
local line = loyalty == 6 and "is your Best Friend. Against all evidence, it trusts you completely."
|
|
or MTH_LT_LoyaltyLines[1]
|
|
MTH:Print(petName .. " reached Loyalty Level " .. tostring(loyalty) .. ". " .. line)
|
|
if type(MTH_Celebrate) == "function" then
|
|
MTH_Celebrate(petName .. " - Loyalty " .. tostring(loyalty), line, loyalty == 6 and "victory" or "fanfare")
|
|
end
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
function MTH_LevelTracker_Initialize()
|
|
if MTH_LT_Frame then return end
|
|
MTH_LT_Frame = CreateFrame("Frame", "MTH_LevelTracker")
|
|
MTH_LT_Frame:RegisterEvent("PLAYER_ENTERING_WORLD")
|
|
MTH_LT_Frame:RegisterEvent("PLAYER_LEVEL_UP")
|
|
MTH_LT_Frame:RegisterEvent("UNIT_LEVEL")
|
|
MTH_LT_Frame:RegisterEvent("UNIT_PET")
|
|
MTH_LT_Frame:RegisterEvent("PET_BAR_UPDATE")
|
|
MTH_LT_Frame:SetScript("OnEvent", function()
|
|
if event == "PLAYER_ENTERING_WORLD" then
|
|
local level = type(UnitLevel) == "function" and tonumber(UnitLevel("player")) or nil
|
|
if level then MTH_LT_Store().hunterLevel = level end
|
|
MTH_LT_RequestPetCheck()
|
|
elseif event == "PLAYER_LEVEL_UP" then
|
|
MTH_LT_HandleHunterLevel(tonumber(arg1) or tonumber(UnitLevel("player")) or 1)
|
|
elseif event == "UNIT_LEVEL" and arg1 == "pet" then
|
|
MTH_LT_RequestPetCheck()
|
|
elseif event == "UNIT_PET" and arg1 == "player" then
|
|
MTH_LT_RequestPetCheck()
|
|
elseif event == "PET_BAR_UPDATE" then
|
|
MTH_LT_RequestPetCheck()
|
|
end
|
|
end)
|
|
end
|
|
|
|
MTH_LevelTracker_Initialize() |