mirror of
https://codeberg.org/Duvelcorp/MetaHunt.git
synced 2026-10-07 23:10:00 +00:00
v1.0.6
This commit is contained in:
+1
-1
@@ -1,5 +1,5 @@
|
||||
MTH_CONST = MTH_CONST or {}
|
||||
MTH_CONST.version = MTH_CONST.version or "1.0.5"
|
||||
MTH_CONST.version = MTH_CONST.version or "1.0.6"
|
||||
|
||||
MTH_CONST.WEAPON_TYPES = {
|
||||
BOWS = "Bows",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
MTH = MTH or {
|
||||
version = "1.0.5",
|
||||
version = "1.0.6",
|
||||
name = "MetaHunt",
|
||||
modules = {},
|
||||
config = {},
|
||||
@@ -16,6 +16,7 @@ local MTH_MESSAGE_DEFAULTS = {
|
||||
spellbookScan = false,
|
||||
petRanAway = true,
|
||||
mapMarkers = true,
|
||||
stableScan = true,
|
||||
}
|
||||
|
||||
local function MTH_ClassGateTrace(_step, _detail)
|
||||
|
||||
+407
-39
@@ -4,7 +4,6 @@ end
|
||||
|
||||
local MTH_PETS_SCHEMA_VERSION = 2
|
||||
local MTH_PETS_CORE_HOOK_BOUNDARY_KEY = "core-pet-rename-hook"
|
||||
local MTH_PETS_TRACE_RUNAWAY = false
|
||||
MTH_PETS_TRACE_CONSISTENCY = false
|
||||
|
||||
local MTH_StableFrame = nil
|
||||
@@ -17,7 +16,6 @@ local MTH_PETS_LiveStateSeq = 0
|
||||
local MTH_PETS_LiveStateSubscribers = {}
|
||||
local MTH_PETS_LiveStateEventName = "MTH_PET_LIVE_STATE_CHANGED"
|
||||
local MTH_PETS_EventThrottle = {}
|
||||
local MTH_PETS_TRACE_TAME = false
|
||||
|
||||
MTH_PETS_CoreOriginal_PetRename = MTH_PETS_CoreOriginal_PetRename or nil
|
||||
|
||||
@@ -390,6 +388,17 @@ local function MTH_PETS_NormalizeSystemMessage(rawMessage)
|
||||
return message
|
||||
end
|
||||
|
||||
local function MTH_PETS_NormalizeSystemMessageKey(rawMessage)
|
||||
local message = MTH_PETS_NormalizeSystemMessage(rawMessage)
|
||||
message = string.lower(tostring(message or ""))
|
||||
message = string.gsub(message, "%%s", " ")
|
||||
message = string.gsub(message, "[^%w%s]", " ")
|
||||
message = string.gsub(message, "%s+", " ")
|
||||
message = string.gsub(message, "^%s+", "")
|
||||
message = string.gsub(message, "%s+$", "")
|
||||
return message
|
||||
end
|
||||
|
||||
local function MTH_PETS_IsRunawaySystemMessage(rawMessage)
|
||||
local message = MTH_PETS_NormalizeSystemMessage(rawMessage)
|
||||
if message == "" then
|
||||
@@ -397,8 +406,20 @@ local function MTH_PETS_IsRunawaySystemMessage(rawMessage)
|
||||
end
|
||||
|
||||
local lostPetMessage = _G and _G["PETTAME_LOSTPET"]
|
||||
if type(lostPetMessage) == "string" and lostPetMessage ~= "" and message == lostPetMessage then
|
||||
return true
|
||||
if type(lostPetMessage) == "string" and lostPetMessage ~= "" then
|
||||
if message == lostPetMessage then
|
||||
return true
|
||||
end
|
||||
local messageKey = MTH_PETS_NormalizeSystemMessageKey(message)
|
||||
local lostKey = MTH_PETS_NormalizeSystemMessageKey(lostPetMessage)
|
||||
if messageKey ~= "" and lostKey ~= "" then
|
||||
if messageKey == lostKey then
|
||||
return true
|
||||
end
|
||||
if string.find(messageKey, lostKey, 1, true) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local lower = string.lower(message)
|
||||
@@ -406,14 +427,12 @@ local function MTH_PETS_IsRunawaySystemMessage(rawMessage)
|
||||
if string.find(lower, "pet ran away", 1, true) then return true end
|
||||
if string.find(lower, "pet has fled", 1, true) then return true end
|
||||
if string.find(lower, "pet fled", 1, true) then return true end
|
||||
if string.find(lower, "pet has left", 1, true) then return true end
|
||||
if string.find(lower, "pet left", 1, true) then return true end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local function MTH_PETS_TraceRunawayEvent(evt, rawMessage, matched)
|
||||
return
|
||||
end
|
||||
|
||||
local function MTH_PETS_ParseCreatureIdFromGuid(guid)
|
||||
local guidText = tostring(guid or "")
|
||||
if guidText == "" then
|
||||
@@ -717,6 +736,38 @@ local function MTH_PETS_GetPendingTameBeastId(snapshot)
|
||||
return nil
|
||||
end
|
||||
|
||||
local function MTH_PETS_ResolveTameBeastIdForRow(row, snapshot)
|
||||
if type(row) ~= "table" then
|
||||
return nil
|
||||
end
|
||||
|
||||
local pendingResolved = MTH_PETS_GetPendingTameBeastId(snapshot)
|
||||
if pendingResolved and pendingResolved > 0 then
|
||||
return pendingResolved
|
||||
end
|
||||
|
||||
local fromSnapshot = snapshot and tonumber(snapshot.beastId) or nil
|
||||
if fromSnapshot and fromSnapshot > 0 then
|
||||
return fromSnapshot
|
||||
end
|
||||
|
||||
local fromRow = tonumber(row.beastId)
|
||||
if fromRow and fromRow > 0 then
|
||||
return fromRow
|
||||
end
|
||||
|
||||
local lookup = MTH_PETS_FindBeastIdByDataset(
|
||||
tostring((snapshot and snapshot.name) or row.name or ""),
|
||||
tostring((snapshot and snapshot.family) or row.family or ""),
|
||||
tonumber((snapshot and snapshot.level) or row.level)
|
||||
)
|
||||
if lookup and lookup > 0 then
|
||||
return lookup
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
local function MTH_PETS_MakeSignature(name, family, level)
|
||||
local cleanName = MTH_PETS_SafeLower(MTH_PETS_NormalizeText(name))
|
||||
local cleanFamily = MTH_PETS_SafeLower(MTH_PETS_NormalizeText(family))
|
||||
@@ -724,6 +775,114 @@ local function MTH_PETS_MakeSignature(name, family, level)
|
||||
return cleanName .. "|" .. cleanFamily .. "|" .. tostring(numericLevel)
|
||||
end
|
||||
|
||||
local function MTH_PETS_RowHasTameRecord(row)
|
||||
if type(row) ~= "table" then
|
||||
return false
|
||||
end
|
||||
if row.tameRecorded == true then
|
||||
return true
|
||||
end
|
||||
if tonumber(row.tamedAt) and tonumber(row.tamedAt) > 0 then
|
||||
return true
|
||||
end
|
||||
if tonumber(row.tameBeastId) and tonumber(row.tameBeastId) > 0 then
|
||||
return true
|
||||
end
|
||||
if type(row.tameZone) == "string" and row.tameZone ~= "" then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function MTH_PETS_BackfillTameMetadataFromEvents(row)
|
||||
if type(row) ~= "table" then
|
||||
return false
|
||||
end
|
||||
if MTH_PETS_RowHasTameRecord(row) then
|
||||
return false
|
||||
end
|
||||
if type(row.events) ~= "table" then
|
||||
return false
|
||||
end
|
||||
|
||||
local bestEvent = nil
|
||||
local stableFirstSeenAt = tonumber(row.stableFirstSeenAt) or tonumber(row.stabledAt) or 0
|
||||
for i = 1, table.getn(row.events) do
|
||||
local ev = row.events[i]
|
||||
if type(ev) == "table" and tostring(ev.type or "") == "pet-acquired" then
|
||||
local evAt = tonumber(ev.at) or 0
|
||||
local timelineOk = true
|
||||
if stableFirstSeenAt > 0 and evAt > 0 and evAt > stableFirstSeenAt then
|
||||
-- If we only saw this pet as stabled before the acquire event, it was likely a call-out, not a tame.
|
||||
timelineOk = false
|
||||
end
|
||||
if timelineOk then
|
||||
if not bestEvent then
|
||||
bestEvent = ev
|
||||
else
|
||||
local bestAt = tonumber(bestEvent.at) or 0
|
||||
if bestAt <= 0 or (evAt > 0 and evAt < bestAt) then
|
||||
bestEvent = ev
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if type(bestEvent) ~= "table" then
|
||||
return false
|
||||
end
|
||||
|
||||
local context = type(bestEvent.context) == "table" and bestEvent.context or nil
|
||||
local changed = false
|
||||
|
||||
if row.tamedAt == nil or tonumber(row.tamedAt) == nil or tonumber(row.tamedAt) <= 0 then
|
||||
local candidateAt = tonumber(bestEvent.at) or (context and tonumber(context.timestamp) or nil) or tonumber(row.createdAt)
|
||||
if candidateAt and candidateAt > 0 then
|
||||
row.tamedAt = candidateAt
|
||||
changed = true
|
||||
end
|
||||
end
|
||||
|
||||
if context then
|
||||
if row.tameHunterLevel == nil and context.hunterLevel ~= nil then
|
||||
row.tameHunterLevel = context.hunterLevel
|
||||
changed = true
|
||||
end
|
||||
if (row.tameZone == nil or row.tameZone == "") and context.zone ~= nil and tostring(context.zone) ~= "" then
|
||||
row.tameZone = context.zone
|
||||
changed = true
|
||||
end
|
||||
if (row.tameSubZone == nil or row.tameSubZone == "") and context.subZone ~= nil and tostring(context.subZone) ~= "" then
|
||||
row.tameSubZone = context.subZone
|
||||
changed = true
|
||||
end
|
||||
if row.tameX == nil and context.x ~= nil then
|
||||
row.tameX = context.x
|
||||
changed = true
|
||||
end
|
||||
if row.tameY == nil and context.y ~= nil then
|
||||
row.tameY = context.y
|
||||
changed = true
|
||||
end
|
||||
end
|
||||
|
||||
if (row.tameBeastId == nil or tonumber(row.tameBeastId) == nil) and row.beastId ~= nil then
|
||||
local beastId = tonumber(row.beastId)
|
||||
if beastId and beastId > 0 then
|
||||
row.tameBeastId = beastId
|
||||
changed = true
|
||||
end
|
||||
end
|
||||
|
||||
if changed then
|
||||
row.tameRecorded = true
|
||||
row.lastUpdated = time()
|
||||
end
|
||||
|
||||
return changed
|
||||
end
|
||||
|
||||
local function MTH_PETS_EnsurePetStoreSchema(pets)
|
||||
if type(pets.petStore) ~= "table" then
|
||||
pets.petStore = {}
|
||||
@@ -767,6 +926,7 @@ local function MTH_PETS_EnsurePetStoreSchema(pets)
|
||||
end
|
||||
row.stableInfo.loyalty = nil
|
||||
end
|
||||
MTH_PETS_BackfillTameMetadataFromEvents(row)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -919,6 +1079,9 @@ local function MTH_PETS_EnsureSchema(pets)
|
||||
if pets.updatedAt == nil then
|
||||
pets.updatedAt = 0
|
||||
end
|
||||
if pets.createdAt == nil or tonumber(pets.createdAt) == nil or tonumber(pets.createdAt) <= 0 then
|
||||
pets.createdAt = now
|
||||
end
|
||||
if pets.currentPetId == nil then
|
||||
local cpId = (type(pets.currentPet) == "table") and pets.currentPet.id or nil
|
||||
pets.currentPetId = MTH_PETS_NormalizePetId(cpId)
|
||||
@@ -1244,8 +1407,11 @@ local function MTH_PETS_ApplySnapshotToRow(row, snapshot, source, context)
|
||||
row.guid = snapshot.guid or row.guid
|
||||
row.beastId = snapshot.beastId or row.beastId
|
||||
local hasPendingTame = type(MTH_PETS_LastTameAttempt) == "table"
|
||||
if hasPendingTame and snapshot.beastId and (row.tameBeastId == nil or tonumber(row.tameBeastId) == nil) then
|
||||
row.tameBeastId = snapshot.beastId
|
||||
if hasPendingTame and (row.tameBeastId == nil or tonumber(row.tameBeastId) == nil) then
|
||||
local resolvedTameBeastId = MTH_PETS_ResolveTameBeastIdForRow(row, snapshot)
|
||||
if resolvedTameBeastId and resolvedTameBeastId > 0 then
|
||||
row.tameBeastId = resolvedTameBeastId
|
||||
end
|
||||
end
|
||||
if hasPendingTame and (source == "unit-pet-acquire" or source == "refresh-current-pet") and type(context) == "table" then
|
||||
row.tameRecorded = true
|
||||
@@ -1294,8 +1460,11 @@ local function MTH_PETS_ApplySnapshotToRow(row, snapshot, source, context)
|
||||
row.tameSubZone = row.tameSubZone or context.subZone
|
||||
row.tameX = row.tameX or context.x
|
||||
row.tameY = row.tameY or context.y
|
||||
if snapshot.beastId and tonumber(row.tameBeastId) == nil then
|
||||
row.tameBeastId = snapshot.beastId
|
||||
if tonumber(row.tameBeastId) == nil then
|
||||
local resolvedTameBeastId = MTH_PETS_ResolveTameBeastIdForRow(row, snapshot)
|
||||
if resolvedTameBeastId and resolvedTameBeastId > 0 then
|
||||
row.tameBeastId = resolvedTameBeastId
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1950,6 +2119,7 @@ function MTH_PETS_RefreshCurrentPet()
|
||||
|
||||
local cp = pets.currentPet
|
||||
local previousCurrentId = cp and cp.id or nil
|
||||
local hadPetBeforeRefresh = MTH_ST_LastUnitPetHadPet and true or false
|
||||
local now = time()
|
||||
local snapshot = MTH_PETS_MakeSnapshotFromLivePet()
|
||||
if pets.currentPetSuppressed == true and pets.currentPetSuppressedAwaitNoLive == true then
|
||||
@@ -1993,6 +2163,7 @@ function MTH_PETS_RefreshCurrentPet()
|
||||
MTH_PETS_SetCurrentPetId(pets, keepCurrentId)
|
||||
MTH_PETS_LogConsistency("RefreshCurrentPet no-live result current=" .. MTH_PETS_FormatCurrentConsistency(cp)
|
||||
.. " activeCurrentId=" .. tostring(petStore and petStore.activeCurrentId or nil))
|
||||
MTH_ST_LastUnitPetHadPet = false
|
||||
pets.updatedAt = now
|
||||
return
|
||||
end
|
||||
@@ -2029,11 +2200,54 @@ function MTH_PETS_RefreshCurrentPet()
|
||||
if cp.id and cp.id ~= previousCurrentId then
|
||||
MTH_PETS_RequestPetSpellScan("refresh-current-change")
|
||||
end
|
||||
|
||||
local row = MTH_PETS_GetPetById(pets, petId)
|
||||
if type(row) == "table" then
|
||||
if type(row.events) ~= "table" then
|
||||
row.events = {}
|
||||
end
|
||||
|
||||
local eventType = "pet-updated"
|
||||
if created and (not hadPetBeforeRefresh) then
|
||||
eventType = "pet-acquired"
|
||||
end
|
||||
|
||||
local eventContext = MTH_PETS_CaptureContext()
|
||||
table.insert(row.events, {
|
||||
type = eventType,
|
||||
source = "refresh-current-pet",
|
||||
at = now,
|
||||
context = eventContext,
|
||||
})
|
||||
|
||||
if eventType == "pet-acquired" then
|
||||
local hasTameRecord = (row.tameRecorded == true)
|
||||
or (tonumber(row.tamedAt) and tonumber(row.tamedAt) > 0)
|
||||
or (type(row.tameZone) == "string" and row.tameZone ~= "")
|
||||
if not hasTameRecord and type(eventContext) == "table" then
|
||||
row.tameRecorded = true
|
||||
row.tamedAt = row.tamedAt or eventContext.timestamp or now
|
||||
row.tameHunterLevel = row.tameHunterLevel or eventContext.hunterLevel
|
||||
row.tameZone = row.tameZone or eventContext.zone
|
||||
row.tameSubZone = row.tameSubZone or eventContext.subZone
|
||||
row.tameX = row.tameX or eventContext.x
|
||||
row.tameY = row.tameY or eventContext.y
|
||||
if tonumber(row.tameBeastId) == nil then
|
||||
local resolvedTameBeastId = MTH_PETS_ResolveTameBeastIdForRow(row, snapshot)
|
||||
if resolvedTameBeastId and resolvedTameBeastId > 0 then
|
||||
row.tameBeastId = resolvedTameBeastId
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if hadPendingTame and cp.id and cp.id ~= previousCurrentId then
|
||||
MTH_PETS_LogTame("RefreshCurrentPet acquire/change completed; clearing pending tame attempt")
|
||||
MTH_PETS_LastTameAttempt = nil
|
||||
end
|
||||
MTH_PETS_LogConsistency("RefreshCurrentPet live result current=" .. MTH_PETS_FormatCurrentConsistency(cp))
|
||||
MTH_ST_LastUnitPetHadPet = true
|
||||
pets.updatedAt = now
|
||||
end
|
||||
|
||||
@@ -2300,6 +2514,7 @@ function MTH_ST_Scan(reason)
|
||||
local slotCount = tonumber(GetNumStableSlots()) or 0
|
||||
local store = MTH_ST_GetStore()
|
||||
local petsRoot = MTH_PETS_GetRootStore()
|
||||
MTH_PETS_RefreshCurrentPet()
|
||||
local scanContext = MTH_PETS_CaptureContext()
|
||||
local scanStableMasterName = MTH_PETS_GetStableMasterName()
|
||||
store.lastScan = time()
|
||||
@@ -2331,6 +2546,28 @@ function MTH_ST_Scan(reason)
|
||||
}
|
||||
end
|
||||
|
||||
local c1, c2, c3, c4, c5, c6, c7, c8 = GetStablePetInfo(0)
|
||||
local currentPetId = (type(petsRoot) == "table" and type(petsRoot.currentPet) == "table") and petsRoot.currentPet.id or nil
|
||||
if currentPetId and type(petsRoot.petStore) == "table" and type(petsRoot.petStore.activeById) == "table" then
|
||||
local currentRow = petsRoot.petStore.activeById[currentPetId]
|
||||
if type(currentRow) == "table" then
|
||||
local currentIcon = tostring(c1 or "")
|
||||
if currentIcon ~= "" then
|
||||
currentRow.icon = currentIcon
|
||||
currentRow.lastUpdated = time()
|
||||
end
|
||||
end
|
||||
end
|
||||
store.current = {
|
||||
petId = currentPetId,
|
||||
icon = c1,
|
||||
name = c2,
|
||||
level = c3,
|
||||
family = c4,
|
||||
loyalty = c5,
|
||||
raw = { c1, c2, c3, c4, c5, c6, c7, c8 },
|
||||
}
|
||||
|
||||
MTH_PETS_MarkStableVisited(petsRoot, tostring(reason or "stable-scan"))
|
||||
|
||||
MTH_PETS_RefreshCurrentPet()
|
||||
@@ -2541,6 +2778,54 @@ local function MTH_ST_DebugDumpLine(line)
|
||||
end
|
||||
end
|
||||
|
||||
local MTH_PETS_DebugBaselineSnapshot = nil
|
||||
|
||||
local function MTH_ST_DebugCloneValue(value, seen)
|
||||
if type(value) ~= "table" then
|
||||
return value
|
||||
end
|
||||
seen = seen or {}
|
||||
if seen[value] then
|
||||
return seen[value]
|
||||
end
|
||||
local clone = {}
|
||||
seen[value] = clone
|
||||
for key, child in pairs(value) do
|
||||
clone[MTH_ST_DebugCloneValue(key, seen)] = MTH_ST_DebugCloneValue(child, seen)
|
||||
end
|
||||
return clone
|
||||
end
|
||||
|
||||
local function MTH_PETS_CaptureDebugSnapshot(targetPetId)
|
||||
local pets = MTH_PETS_GetRootStore()
|
||||
if type(pets) ~= "table" then
|
||||
return nil, "pets datastore unavailable"
|
||||
end
|
||||
|
||||
MTH_PETS_RefreshCurrentPet()
|
||||
|
||||
local cp = (type(pets.currentPet) == "table") and pets.currentPet or nil
|
||||
local petId = targetPetId or (cp and cp.id) or pets.currentPetId
|
||||
if petId == nil or tostring(petId) == "" then
|
||||
return nil, "no current pet id"
|
||||
end
|
||||
|
||||
local row = MTH_PETS_GetPetById(pets, petId)
|
||||
if type(row) ~= "table" then
|
||||
return nil, "active row missing for pet id=" .. tostring(petId)
|
||||
end
|
||||
|
||||
local snapshot = {
|
||||
capturedAt = time(),
|
||||
petId = tostring(petId),
|
||||
currentPetId = pets.currentPetId,
|
||||
currentPet = MTH_ST_DebugCloneValue(cp or {}),
|
||||
row = MTH_ST_DebugCloneValue(row),
|
||||
stableScan = MTH_ST_DebugCloneValue(pets.stableScan or {}),
|
||||
}
|
||||
return snapshot, nil
|
||||
end
|
||||
|
||||
local function MTH_ST_DebugSortKeys(tbl)
|
||||
local keys = {}
|
||||
for k in pairs(tbl or {}) do
|
||||
@@ -2770,6 +3055,64 @@ function MTH_CommandPetsDump()
|
||||
end
|
||||
end
|
||||
|
||||
function MTH_CommandPetsSnap()
|
||||
local snapshot, err = MTH_PETS_CaptureDebugSnapshot(nil)
|
||||
if not snapshot then
|
||||
MTH:Print("Pet snapshot failed: " .. tostring(err or "unknown"))
|
||||
return false
|
||||
end
|
||||
MTH_PETS_DebugBaselineSnapshot = snapshot
|
||||
MTH:Print("Pet snapshot saved for id=" .. tostring(snapshot.petId) .. ". Run /mth petsdiff after reproducing the issue.")
|
||||
MTH_ST_DebugDumpLine("[PETSNAP] BASELINE BEGIN")
|
||||
MTH_ST_DebugDumpValue("[PETSNAP].baseline", snapshot, 0, 5, {})
|
||||
MTH_ST_DebugDumpLine("[PETSNAP] BASELINE END")
|
||||
return true
|
||||
end
|
||||
|
||||
function MTH_CommandPetsDiff()
|
||||
if type(MTH_PETS_DebugBaselineSnapshot) ~= "table" then
|
||||
MTH:Print("No pet snapshot baseline found. Run /mth petssnap first.")
|
||||
return false
|
||||
end
|
||||
|
||||
local baseline = MTH_PETS_DebugBaselineSnapshot
|
||||
local current, err = MTH_PETS_CaptureDebugSnapshot(baseline.petId)
|
||||
if not current then
|
||||
MTH:Print("Pet snapshot compare failed: " .. tostring(err or "unknown"))
|
||||
return false
|
||||
end
|
||||
|
||||
MTH:Print("Pet snapshot compare for id=" .. tostring(current.petId) .. ".")
|
||||
MTH_ST_DebugDumpLine("[PETSNAP] BEFORE BEGIN")
|
||||
MTH_ST_DebugDumpValue("[PETSNAP].before", baseline, 0, 5, {})
|
||||
MTH_ST_DebugDumpLine("[PETSNAP] BEFORE END")
|
||||
MTH_ST_DebugDumpLine("[PETSNAP] AFTER BEGIN")
|
||||
MTH_ST_DebugDumpValue("[PETSNAP].after", current, 0, 5, {})
|
||||
MTH_ST_DebugDumpLine("[PETSNAP] AFTER END")
|
||||
|
||||
local diffKeys = {
|
||||
"name", "family", "level", "beastId", "icon",
|
||||
"tameRecorded", "tamedAt", "tameZone", "tameSubZone", "tameX", "tameY", "tameBeastId",
|
||||
"stableSlot", "stabledAt", "stableFirstSeenAt", "lastUnstabledAt", "lastSource", "lastUpdated",
|
||||
}
|
||||
local diffCount = 0
|
||||
for i = 1, table.getn(diffKeys) do
|
||||
local key = diffKeys[i]
|
||||
local beforeValue = baseline.row and baseline.row[key] or nil
|
||||
local afterValue = current.row and current.row[key] or nil
|
||||
if tostring(beforeValue) ~= tostring(afterValue) then
|
||||
diffCount = diffCount + 1
|
||||
MTH_ST_DebugDumpLine("[PETSNAP] DIFF row." .. tostring(key) .. ": " .. tostring(beforeValue) .. " -> " .. tostring(afterValue))
|
||||
end
|
||||
end
|
||||
if diffCount <= 0 then
|
||||
MTH_ST_DebugDumpLine("[PETSNAP] DIFF none")
|
||||
end
|
||||
|
||||
MTH_PETS_DebugBaselineSnapshot = current
|
||||
return true
|
||||
end
|
||||
|
||||
function MTH_CommandStableScan()
|
||||
if UnitClass then
|
||||
local _, classToken = UnitClass("player")
|
||||
@@ -2790,9 +3133,10 @@ function MTH_CommandStableScan()
|
||||
MTH:Print("Stable scan captured " .. tostring(slotCount) .. " slot(s).")
|
||||
end
|
||||
|
||||
local function MTH_ST_OnEvent(_, evt, eventArg1)
|
||||
local function MTH_ST_OnEvent(_, evt, eventArg1, eventArg2)
|
||||
evt = evt or event
|
||||
eventArg1 = eventArg1 or arg1
|
||||
eventArg2 = eventArg2 or arg2
|
||||
if not evt then
|
||||
return
|
||||
end
|
||||
@@ -2805,41 +3149,39 @@ local function MTH_ST_OnEvent(_, evt, eventArg1)
|
||||
return
|
||||
end
|
||||
|
||||
if evt == "SPELLCAST_CHANNEL_START" then
|
||||
MTH_PETS_RecordTameAttempt(evt, eventArg1)
|
||||
local isUnitSpellcast = (evt == "UNIT_SPELLCAST_START" or evt == "UNIT_SPELLCAST_STOP"
|
||||
or evt == "UNIT_SPELLCAST_FAILED" or evt == "UNIT_SPELLCAST_INTERRUPTED"
|
||||
or evt == "UNIT_SPELLCAST_CHANNEL_START" or evt == "UNIT_SPELLCAST_CHANNEL_STOP")
|
||||
local castSpellName = eventArg1
|
||||
if isUnitSpellcast then
|
||||
if eventArg1 ~= "player" then
|
||||
return
|
||||
end
|
||||
castSpellName = eventArg2
|
||||
end
|
||||
|
||||
if evt == "SPELLCAST_START" or evt == "SPELLCAST_CHANNEL_START"
|
||||
or evt == "UNIT_SPELLCAST_START" or evt == "UNIT_SPELLCAST_CHANNEL_START" then
|
||||
MTH_PETS_RecordTameAttempt(evt, castSpellName)
|
||||
return
|
||||
end
|
||||
|
||||
if evt == "SPELLCAST_STOP" or evt == "SPELLCAST_CHANNEL_STOP" or evt == "SPELLCAST_FAILED" or evt == "SPELLCAST_INTERRUPTED" then
|
||||
if MTH_PETS_TRACE_TAME then
|
||||
MTH_PETS_LogTame("Spell terminal evt=" .. tostring(evt) .. " spell='" .. tostring(eventArg1 or "") .. "' pending=" .. tostring(type(MTH_PETS_LastTameAttempt) == "table"))
|
||||
end
|
||||
local terminalIsTame = MTH_PETS_IsTameBeastSpellName(eventArg1)
|
||||
if evt == "SPELLCAST_STOP" or evt == "SPELLCAST_CHANNEL_STOP" or evt == "SPELLCAST_FAILED" or evt == "SPELLCAST_INTERRUPTED"
|
||||
or evt == "UNIT_SPELLCAST_STOP" or evt == "UNIT_SPELLCAST_CHANNEL_STOP"
|
||||
or evt == "UNIT_SPELLCAST_FAILED" or evt == "UNIT_SPELLCAST_INTERRUPTED" then
|
||||
local terminalIsTame = MTH_PETS_IsTameBeastSpellName(castSpellName)
|
||||
if not terminalIsTame and type(MTH_PETS_LastTameAttempt) == "table" then
|
||||
terminalIsTame = true
|
||||
if MTH_PETS_TRACE_TAME then
|
||||
MTH_PETS_LogTame("Treating terminal event as tame because pending attempt exists")
|
||||
end
|
||||
end
|
||||
if not terminalIsTame then
|
||||
local fallbackName, fallbackSource = MTH_PETS_GetCurrentPlayerCastOrChannelName()
|
||||
if fallbackName and MTH_PETS_IsTameBeastSpellName(fallbackName) then
|
||||
terminalIsTame = true
|
||||
if MTH_PETS_TRACE_TAME then
|
||||
MTH_PETS_LogTame("Resolved terminal spell via " .. tostring(fallbackSource) .. " => '" .. tostring(fallbackName) .. "'")
|
||||
end
|
||||
end
|
||||
end
|
||||
if terminalIsTame then
|
||||
if evt == "SPELLCAST_FAILED" or evt == "SPELLCAST_INTERRUPTED" then
|
||||
if MTH_PETS_TRACE_TAME then
|
||||
MTH_PETS_LogTame("Tame ended with failure/interruption; clearing pending attempt")
|
||||
end
|
||||
MTH_PETS_LastTameAttempt = nil
|
||||
elseif evt == "SPELLCAST_CHANNEL_STOP" or evt == "SPELLCAST_STOP" then
|
||||
if MTH_PETS_TRACE_TAME then
|
||||
MTH_PETS_LogTame("Tame channel ended; awaiting UNIT_PET to confirm acquire")
|
||||
end
|
||||
end
|
||||
end
|
||||
return
|
||||
@@ -2884,9 +3226,10 @@ local function MTH_ST_OnEvent(_, evt, eventArg1)
|
||||
return
|
||||
end
|
||||
|
||||
if evt == "CHAT_MSG_SYSTEM" or evt == "UI_ERROR_MESSAGE" then
|
||||
if evt == "CHAT_MSG_SYSTEM" or evt == "UI_ERROR_MESSAGE"
|
||||
or evt == "CHAT_MSG_SPELL_PET_INFO" or evt == "CHAT_MSG_SPELL_PET_DAMAGE"
|
||||
or evt == "CHAT_MSG_COMBAT_PET_HITS" or evt == "CHAT_MSG_COMBAT_PET_MISSES" then
|
||||
local matchedRunaway = MTH_PETS_IsRunawaySystemMessage(eventArg1)
|
||||
MTH_PETS_TraceRunawayEvent(evt, eventArg1, matchedRunaway)
|
||||
if matchedRunaway then
|
||||
MTH_PETS_RecordPetRunaway(evt, eventArg1)
|
||||
MTH_PETS_RefreshCurrentPet()
|
||||
@@ -2896,7 +3239,18 @@ local function MTH_ST_OnEvent(_, evt, eventArg1)
|
||||
end
|
||||
|
||||
if evt == "PET_STABLE_SHOW" then
|
||||
MTH_ST_RunScanThrottled(evt, 1)
|
||||
local scanned = MTH_ST_RunScanThrottled(evt, 1)
|
||||
if scanned and MTH and MTH.Print then
|
||||
local shouldPrint = true
|
||||
if MTH.IsMessageEnabled then
|
||||
shouldPrint = MTH:IsMessageEnabled("stableScan", true)
|
||||
end
|
||||
if shouldPrint then
|
||||
local store = MTH_ST_GetStore()
|
||||
local slotCount = tonumber(store and store.slotCount) or 0
|
||||
MTH:Print("Stable scan complete: " .. tostring(slotCount) .. " slot(s).")
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
@@ -2925,16 +3279,28 @@ function MTH_ST_InitService()
|
||||
|
||||
MTH_StableFrame = CreateFrame("Frame", "MTHStableScanFrame")
|
||||
MTH_StableFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
MTH_StableFrame:RegisterEvent("SPELLCAST_START")
|
||||
MTH_StableFrame:RegisterEvent("SPELLCAST_STOP")
|
||||
MTH_StableFrame:RegisterEvent("SPELLCAST_CHANNEL_START")
|
||||
MTH_StableFrame:RegisterEvent("SPELLCAST_CHANNEL_STOP")
|
||||
MTH_StableFrame:RegisterEvent("SPELLCAST_FAILED")
|
||||
MTH_StableFrame:RegisterEvent("SPELLCAST_INTERRUPTED")
|
||||
MTH_StableFrame:RegisterEvent("UNIT_SPELLCAST_START")
|
||||
MTH_StableFrame:RegisterEvent("UNIT_SPELLCAST_STOP")
|
||||
MTH_StableFrame:RegisterEvent("UNIT_SPELLCAST_CHANNEL_START")
|
||||
MTH_StableFrame:RegisterEvent("UNIT_SPELLCAST_CHANNEL_STOP")
|
||||
MTH_StableFrame:RegisterEvent("UNIT_SPELLCAST_FAILED")
|
||||
MTH_StableFrame:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED")
|
||||
MTH_StableFrame:RegisterEvent("UNIT_PET")
|
||||
MTH_StableFrame:RegisterEvent("PET_BAR_UPDATE")
|
||||
MTH_StableFrame:RegisterEvent("UNIT_HAPPINESS")
|
||||
MTH_StableFrame:RegisterEvent("CHAT_MSG_COMBAT_XP_GAIN")
|
||||
MTH_StableFrame:RegisterEvent("PLAYER_XP_UPDATE")
|
||||
MTH_StableFrame:RegisterEvent("CHAT_MSG_SYSTEM")
|
||||
MTH_StableFrame:RegisterEvent("CHAT_MSG_SPELL_PET_INFO")
|
||||
MTH_StableFrame:RegisterEvent("CHAT_MSG_SPELL_PET_DAMAGE")
|
||||
MTH_StableFrame:RegisterEvent("CHAT_MSG_COMBAT_PET_HITS")
|
||||
MTH_StableFrame:RegisterEvent("CHAT_MSG_COMBAT_PET_MISSES")
|
||||
MTH_StableFrame:RegisterEvent("UI_ERROR_MESSAGE")
|
||||
MTH_StableFrame:RegisterEvent("PET_STABLE_SHOW")
|
||||
MTH_StableFrame:RegisterEvent("PET_STABLE_UPDATE")
|
||||
@@ -2960,15 +3326,17 @@ function MTH_ST_InitBootstrap()
|
||||
if not frame then
|
||||
return
|
||||
end
|
||||
frame:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
frame:RegisterEvent("PET_STABLE_SHOW")
|
||||
frame:RegisterEvent("PET_STABLE_UPDATE")
|
||||
frame:SetScript("OnEvent", function(self, evt)
|
||||
evt = evt or event
|
||||
if evt ~= "PET_STABLE_SHOW" then
|
||||
if evt ~= "PLAYER_ENTERING_WORLD" and evt ~= "PET_STABLE_SHOW" and evt ~= "PET_STABLE_UPDATE" then
|
||||
return
|
||||
end
|
||||
MTH_ST_InitService()
|
||||
if type(MTH_ST_Scan) == "function" then
|
||||
MTH_ST_Scan("bootstrap:PET_STABLE_SHOW")
|
||||
if (evt == "PET_STABLE_SHOW" or evt == "PET_STABLE_UPDATE") and type(MTH_ST_Scan) == "function" then
|
||||
MTH_ST_Scan("bootstrap:" .. tostring(evt))
|
||||
end
|
||||
if self and self.UnregisterAllEvents then
|
||||
self:UnregisterAllEvents()
|
||||
|
||||
@@ -284,12 +284,37 @@ function SlashCmdList.MTH(msg, editbox)
|
||||
local lowerMsg = string.lower(msg)
|
||||
if msg == "" then
|
||||
MTH:Print("Available: /mth options, /mth book")
|
||||
MTH:Print("Debug: /mth petsstate, /mth petsdump, /mth petssnap, /mth petsdiff")
|
||||
elseif lowerMsg == "options" then
|
||||
MTH_CommandOptions()
|
||||
elseif lowerMsg == "book" or lowerMsg == "hunterbook" then
|
||||
MTH_CommandBook()
|
||||
elseif lowerMsg == "peers" or lowerMsg == "who" then
|
||||
MTH_CommandPeers()
|
||||
elseif lowerMsg == "petsstate" then
|
||||
if type(MTH_CommandPetsState) == "function" then
|
||||
MTH_CommandPetsState()
|
||||
else
|
||||
MTH:Print("Pets state command is not available yet")
|
||||
end
|
||||
elseif lowerMsg == "petsdump" then
|
||||
if type(MTH_CommandPetsDump) == "function" then
|
||||
MTH_CommandPetsDump()
|
||||
else
|
||||
MTH:Print("Pets dump command is not available yet")
|
||||
end
|
||||
elseif lowerMsg == "petssnap" then
|
||||
if type(MTH_CommandPetsSnap) == "function" then
|
||||
MTH_CommandPetsSnap()
|
||||
else
|
||||
MTH:Print("Pets snapshot command is not available yet")
|
||||
end
|
||||
elseif lowerMsg == "petsdiff" then
|
||||
if type(MTH_CommandPetsDiff) == "function" then
|
||||
MTH_CommandPetsDiff()
|
||||
else
|
||||
MTH:Print("Pets diff command is not available yet")
|
||||
end
|
||||
elseif lowerMsg == "err" then
|
||||
if MTH_DebugFrame and type(MTH_DebugFrame.Toggle) == "function" then
|
||||
MTH_DebugFrame:Toggle()
|
||||
@@ -299,6 +324,7 @@ function SlashCmdList.MTH(msg, editbox)
|
||||
else
|
||||
MTH:Print("Unknown command: " .. tostring(msg))
|
||||
MTH:Print("Available: /mth options, /mth book")
|
||||
MTH:Print("Debug: /mth petsstate, /mth petsdump, /mth petssnap, /mth petsdiff")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ MTH_HUNTERBOOK_TABS.families = {
|
||||
{ x = 10, width = 106, align = "LEFT" },
|
||||
{ x = 122, width = 52, align = "LEFT" },
|
||||
{ x = 176, width = 52, align = "LEFT" },
|
||||
{ x = 232, width = 292, align = "LEFT" },
|
||||
{ x = 460, width = 184, align = "LEFT" },
|
||||
{ x = 232, width = 364, align = "LEFT" },
|
||||
{ x = 532, width = 112, align = "LEFT" },
|
||||
},
|
||||
}
|
||||
|
||||
@@ -27,6 +27,11 @@ local function MTH_BOOKTAB_FamiliesTrim(value)
|
||||
return text
|
||||
end
|
||||
|
||||
local function MTH_BOOKTAB_ShouldDisplayAllDiet(familyName)
|
||||
local token = MTH_BOOKTAB_FamiliesSafeLower(MTH_BOOKTAB_FamiliesTrim(familyName))
|
||||
return token == "bears" or token == "boars"
|
||||
end
|
||||
|
||||
local function MTH_BOOKTAB_FindAbilityBundle(abilityName)
|
||||
if not (MTH_DS_PetSpells and type(MTH_DS_PetSpells.byAbility) == "table") then
|
||||
return nil
|
||||
@@ -95,25 +100,49 @@ function MTH_BOOKTAB_BuildFamiliesRows()
|
||||
if token ~= "" and not seen[token] then
|
||||
seen[token] = true
|
||||
local spellRows = (type(bundle) == "table" and type(bundle.spells) == "table") and bundle.spells or {}
|
||||
local firstAnySpell = nil
|
||||
local firstBeastSpell = nil
|
||||
local rankMin = nil
|
||||
local rankMax = nil
|
||||
local rankMap = {}
|
||||
local beastRankMin = nil
|
||||
local beastRankMax = nil
|
||||
local beastRankMap = {}
|
||||
local anyRankMin = nil
|
||||
local anyRankMax = nil
|
||||
local anyRankMap = {}
|
||||
for s = 1, table.getn(spellRows) do
|
||||
local spell = spellRows[s]
|
||||
if type(spell) == "table" and MTH_BOOKTAB_FamiliesSafeLower(spell.learnMethod or "beast") ~= "trainer" then
|
||||
if not firstBeastSpell then
|
||||
firstBeastSpell = spell
|
||||
if type(spell) == "table" then
|
||||
if not firstAnySpell then
|
||||
firstAnySpell = spell
|
||||
end
|
||||
local rank = tonumber(spell.rankNumber)
|
||||
if rank and rank > 0 then
|
||||
rankMap[rank] = true
|
||||
if not rankMin or rank < rankMin then rankMin = rank end
|
||||
if not rankMax or rank > rankMax then rankMax = rank end
|
||||
anyRankMap[rank] = true
|
||||
if not anyRankMin or rank < anyRankMin then anyRankMin = rank end
|
||||
if not anyRankMax or rank > anyRankMax then anyRankMax = rank end
|
||||
end
|
||||
if MTH_BOOKTAB_FamiliesSafeLower(spell.learnMethod or "beast") ~= "trainer" then
|
||||
if not firstBeastSpell then
|
||||
firstBeastSpell = spell
|
||||
end
|
||||
if rank and rank > 0 then
|
||||
beastRankMap[rank] = true
|
||||
if not beastRankMin or rank < beastRankMin then beastRankMin = rank end
|
||||
if not beastRankMax or rank > beastRankMax then beastRankMax = rank end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local displaySpell = firstBeastSpell or firstAnySpell
|
||||
local rankMap = beastRankMap
|
||||
local rankMin = beastRankMin
|
||||
local rankMax = beastRankMax
|
||||
if not firstBeastSpell then
|
||||
rankMap = anyRankMap
|
||||
rankMin = anyRankMin
|
||||
rankMax = anyRankMax
|
||||
end
|
||||
|
||||
local rankCount = 0
|
||||
for _ in pairs(rankMap) do
|
||||
rankCount = rankCount + 1
|
||||
@@ -123,8 +152,8 @@ function MTH_BOOKTAB_BuildFamiliesRows()
|
||||
name = canonicalMap[token] or canonical,
|
||||
token = token,
|
||||
isUnique = (abilityCounts[token] or 0) == 1,
|
||||
icon = firstBeastSpell and firstBeastSpell.icon or nil,
|
||||
description = firstBeastSpell and firstBeastSpell.description or "",
|
||||
icon = displaySpell and displaySpell.icon or nil,
|
||||
description = displaySpell and displaySpell.description or "",
|
||||
rankMin = rankMin,
|
||||
rankMax = rankMax,
|
||||
rankCount = rankCount,
|
||||
@@ -141,17 +170,23 @@ function MTH_BOOKTAB_BuildFamiliesRows()
|
||||
return MTH_BOOKTAB_FamiliesSafeLower(a.name) < MTH_BOOKTAB_FamiliesSafeLower(b.name)
|
||||
end)
|
||||
|
||||
local dietItems = {}
|
||||
if type(familyRow.food) == "table" then
|
||||
for i = 1, table.getn(familyRow.food) do
|
||||
local food = MTH_BOOKTAB_FamiliesTrim(familyRow.food[i])
|
||||
if food ~= "" then
|
||||
table.insert(dietItems, string.upper(string.sub(food, 1, 1)) .. string.sub(food, 2))
|
||||
local dietText = ""
|
||||
if MTH_BOOKTAB_ShouldDisplayAllDiet(familyName) then
|
||||
dietText = "ALL"
|
||||
else
|
||||
local dietItems = {}
|
||||
if type(familyRow.food) == "table" then
|
||||
for i = 1, table.getn(familyRow.food) do
|
||||
local food = MTH_BOOKTAB_FamiliesTrim(familyRow.food[i])
|
||||
if food ~= "" then
|
||||
table.insert(dietItems, string.upper(string.sub(food, 1, 1)) .. string.sub(food, 2))
|
||||
end
|
||||
end
|
||||
table.sort(dietItems, function(a, b)
|
||||
return MTH_BOOKTAB_FamiliesSafeLower(a) < MTH_BOOKTAB_FamiliesSafeLower(b)
|
||||
end)
|
||||
end
|
||||
table.sort(dietItems, function(a, b)
|
||||
return MTH_BOOKTAB_FamiliesSafeLower(a) < MTH_BOOKTAB_FamiliesSafeLower(b)
|
||||
end)
|
||||
dietText = table.concat(dietItems, ", ")
|
||||
end
|
||||
|
||||
table.insert(results, {
|
||||
@@ -159,7 +194,7 @@ function MTH_BOOKTAB_BuildFamiliesRows()
|
||||
named = tonumber(familyRow.named) or 0,
|
||||
coords = tonumber(familyRow.coords) or 0,
|
||||
abilities = abilities,
|
||||
dietText = table.concat(dietItems, ", "),
|
||||
dietText = dietText,
|
||||
})
|
||||
end
|
||||
end
|
||||
@@ -238,7 +273,7 @@ function MTH_BOOKTAB_EnsureFamiliesUI()
|
||||
ui.headerAbilities:SetText("Abilities")
|
||||
|
||||
ui.headerDiet = ui.frame:CreateFontString(nil, "ARTWORK", "GameFontNormalSmall")
|
||||
ui.headerDiet:SetPoint("TOPLEFT", ui.frame, "TOPLEFT", 460, -2)
|
||||
ui.headerDiet:SetPoint("TOPLEFT", ui.frame, "TOPLEFT", 532, -2)
|
||||
ui.headerDiet:SetTextColor(1.00, 0.82, 0.00)
|
||||
ui.headerDiet:SetText("Diet")
|
||||
|
||||
@@ -270,8 +305,8 @@ function MTH_BOOKTAB_EnsureFamiliesUI()
|
||||
row.coords:SetJustifyH("LEFT")
|
||||
|
||||
row.diet = row:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
|
||||
row.diet:SetPoint("LEFT", row, "LEFT", 460, 0)
|
||||
row.diet:SetWidth(184)
|
||||
row.diet:SetPoint("LEFT", row, "LEFT", 532, 0)
|
||||
row.diet:SetWidth(112)
|
||||
row.diet:SetJustifyH("LEFT")
|
||||
|
||||
row.abilityButtons = {}
|
||||
@@ -363,6 +398,7 @@ function MTH_BOOKTAB_RenderFamiliesList()
|
||||
rowFrame.diet:SetText(tostring(row.dietText or "-"))
|
||||
|
||||
local offsetX = 232
|
||||
local abilityMaxRight = 526
|
||||
for b = 1, table.getn(rowFrame.abilityButtons) do
|
||||
local button = rowFrame.abilityButtons[b]
|
||||
local ability = row.abilities and row.abilities[b] or nil
|
||||
@@ -375,17 +411,23 @@ function MTH_BOOKTAB_RenderFamiliesList()
|
||||
button.text:SetText(nameText)
|
||||
local textW = button.text:GetStringWidth() or 40
|
||||
if textW < 24 then textW = 24 end
|
||||
button:SetWidth(14 + textW)
|
||||
button:ClearAllPoints()
|
||||
button:SetPoint("LEFT", rowFrame, "LEFT", offsetX, 0)
|
||||
local iconPath = ability.icon and MTH_BOOK_ResolveIconPath and MTH_BOOK_ResolveIconPath(ability.icon) or nil
|
||||
if iconPath then
|
||||
button.icon:SetTexture(iconPath)
|
||||
local buttonWidth = 14 + textW
|
||||
if (offsetX + buttonWidth) > abilityMaxRight then
|
||||
button.entry = nil
|
||||
button:Hide()
|
||||
else
|
||||
button.icon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
|
||||
button:SetWidth(buttonWidth)
|
||||
button:ClearAllPoints()
|
||||
button:SetPoint("LEFT", rowFrame, "LEFT", offsetX, 0)
|
||||
local iconPath = ability.icon and MTH_BOOK_ResolveIconPath and MTH_BOOK_ResolveIconPath(ability.icon) or nil
|
||||
if iconPath then
|
||||
button.icon:SetTexture(iconPath)
|
||||
else
|
||||
button.icon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
|
||||
end
|
||||
button:Show()
|
||||
offsetX = offsetX + button:GetWidth() + 6
|
||||
end
|
||||
button:Show()
|
||||
offsetX = offsetX + button:GetWidth() + 6
|
||||
else
|
||||
button.entry = nil
|
||||
button:Hide()
|
||||
|
||||
+2
-2
@@ -1002,9 +1002,9 @@ end
|
||||
local function MTH_BOOK_ParseProjectileDPSFromText(text)
|
||||
if type(text) ~= "string" or text == "" then return nil end
|
||||
local lowered = string.lower(text)
|
||||
local raw = string.match(lowered, "adds%s+([%d]+[%.,]?[%d]*)%s+damage%s+per%s+seconds?")
|
||||
local _, _, raw = string.find(lowered, "adds%s+([%d]+[%.,]?[%d]*)%s+damage%s+per%s+seconds?")
|
||||
if not raw then
|
||||
raw = string.match(lowered, "([%d]+[%.,]?[%d]*)%s+damage%s+per%s+seconds?")
|
||||
_, _, raw = string.find(lowered, "([%d]+[%.,]?[%d]*)%s+damage%s+per%s+seconds?")
|
||||
end
|
||||
if not raw then return nil end
|
||||
local normalized = string.gsub(raw, ",", ".")
|
||||
|
||||
@@ -4,6 +4,7 @@ MTH.VersionCheck = MTH.VersionCheck or {}
|
||||
local VC = MTH.VersionCheck
|
||||
VC.abbrev = "MTH"
|
||||
VC.channelName = "LFT"
|
||||
VC.updateUrl = "https://github.com/DuvelCorp/MetaHunt"
|
||||
VC.nextPublishAt = nil
|
||||
VC.joinAt = nil
|
||||
VC.notified = false
|
||||
@@ -290,7 +291,12 @@ function VC:HandleRemoteMessage(message, author, channelLabel)
|
||||
self.notified = true
|
||||
self.nextPublishAt = nil
|
||||
if MTH and type(MTH.Print) == "function" then
|
||||
MTH:Print("A new version is available !")
|
||||
local localVersionText = tostring(self:GetLocalVersionString() or "?")
|
||||
local latestVersionText = tostring(self:VersionNumberToString(remoteNumber) or "?")
|
||||
MTH:Print("A new version is available!")
|
||||
MTH:Print("YOU SHOULD UPGRADE ! Your version : " .. localVersionText
|
||||
.. " - Latest version " .. latestVersionText
|
||||
.. " --> " .. tostring(self.updateUrl or ""))
|
||||
end
|
||||
|
||||
if VC.frame then
|
||||
|
||||
Reference in New Issue
Block a user