mirror of
https://github.com/Blaststar/Questie-Octo-Vanilla.git
synced 2026-10-19 20:00:49 +00:00
Quest tooltip fixes and addition of theme switch
This commit is contained in:
@@ -0,0 +1 @@
|
||||
* -text
|
||||
@@ -0,0 +1,160 @@
|
||||
QuestieOcto.API = QuestieOcto.API or {}
|
||||
local A = QuestieOcto.API
|
||||
|
||||
A.valid = false
|
||||
A.missing = {}
|
||||
A.optional = {}
|
||||
|
||||
local function Has(tableValue, functionName)
|
||||
return tableValue and type(tableValue[functionName])=="function"
|
||||
end
|
||||
|
||||
function A:Validate()
|
||||
self.missing = {}
|
||||
|
||||
local required = {
|
||||
{ "C_QuestLog.GetQuestIDForLogIndex", C_QuestLog, "GetQuestIDForLogIndex" },
|
||||
{ "C_QuestLog.GetLogIndexForQuestID", C_QuestLog, "GetLogIndexForQuestID" },
|
||||
{ "C_QuestLog.IsOnQuest", C_QuestLog, "IsOnQuest" },
|
||||
{ "C_Map.GetBestMapForUnit", C_Map, "GetBestMapForUnit" },
|
||||
{ "C_GossipInfo.GetAvailableQuests", C_GossipInfo, "GetAvailableQuests" },
|
||||
{ "C_CreatureInfo.GetCreatureID", C_CreatureInfo, "GetCreatureID" },
|
||||
{ "C_GameObjectInfo.GetGameObjectInfoByID", C_GameObjectInfo, "GetGameObjectInfoByID" },
|
||||
{ "C_Item.GetItemNameByID", C_Item, "GetItemNameByID" },
|
||||
}
|
||||
|
||||
for _,req in pairs(required) do
|
||||
if not Has(req[2],req[3]) then table.insert(self.missing,req[1]) end
|
||||
end
|
||||
|
||||
self.valid = table.getn(self.missing)==0
|
||||
|
||||
self.optional = {
|
||||
coroutines = coroutine and type(coroutine.create)=="function",
|
||||
hooksecurefunc = type(hooksecurefunc)=="function",
|
||||
tooltipUnit = GameTooltip and type(GameTooltip.GetUnitGUID)=="function",
|
||||
tooltipObject = GameTooltip and type(GameTooltip.GetGameObject)=="function",
|
||||
tooltipItem = GameTooltip and type(GameTooltip.GetItem)=="function",
|
||||
gossipActive = Has(C_GossipInfo,"GetActiveQuests"),
|
||||
questDetails = Has(C_QuestLog,"GetQuestDetails"),
|
||||
questObjectives = Has(C_QuestLog,"GetQuestObjectives"),
|
||||
questsCompleted = type(GetQuestsCompleted)=="function" or Has(C_QuestLog,"GetQuestsCompleted"),
|
||||
queryQuestsCompleted = type(QueryQuestsCompleted)=="function",
|
||||
questFlaggedCompleted = type(IsQuestFlaggedCompleted)=="function" or Has(C_QuestLog,"IsQuestFlaggedCompleted"),
|
||||
mapWorldSize = Has(C_Map,"GetMapWorldSize"),
|
||||
}
|
||||
|
||||
return self.valid
|
||||
end
|
||||
|
||||
function A:GetQuestIDForLogIndex(index)
|
||||
if not self.valid then return nil end
|
||||
return C_QuestLog.GetQuestIDForLogIndex(index)
|
||||
end
|
||||
|
||||
-- Questie-facing normalized quest-log info.
|
||||
--
|
||||
-- Questie 5.2.3/6.0.0 and Questie 3.3.5 all consume the normalized fields
|
||||
-- title, level, tag, isHeader, isCollapsed, isComplete, frequency, questID.
|
||||
--
|
||||
-- The raw client signature differs by expansion. For our actual target
|
||||
-- Interface 11200, the supplied pfQuest Vanilla compatibility layer confirms:
|
||||
-- title, level, tag, isHeader, isCollapsed, isComplete = GetQuestLogTitle(index)
|
||||
-- There is NO suggestedGroup return on Vanilla 1.12.
|
||||
--
|
||||
-- Questie 3.3.5's raw suggestedGroup handling is a WotLK-era compatibility
|
||||
-- detail, so applying it directly to Turtle 11200 shifts completion by one
|
||||
-- field and makes completed quests look incomplete.
|
||||
function A:GetQuestLogInfo(index)
|
||||
if not GetQuestLogTitle then return nil end
|
||||
|
||||
local _,_,_,client=GetBuildInfo()
|
||||
client=tonumber(client) or 11200
|
||||
|
||||
local title,level,tag,isHeader,isCollapsed,isComplete,isDaily,rawQuestID
|
||||
|
||||
if client<=11200 then
|
||||
title,level,tag,isHeader,isCollapsed,isComplete=GetQuestLogTitle(index)
|
||||
else
|
||||
local suggestedGroup
|
||||
title,level,tag,suggestedGroup,isHeader,isCollapsed,isComplete,isDaily,rawQuestID=GetQuestLogTitle(index)
|
||||
end
|
||||
|
||||
local questID=self:GetQuestIDForLogIndex(index) or tonumber(rawQuestID)
|
||||
|
||||
return {
|
||||
title=title,
|
||||
level=level,
|
||||
tag=tag,
|
||||
isHeader=isHeader and true or false,
|
||||
isCollapsed=isCollapsed and true or false,
|
||||
isComplete=isComplete,
|
||||
isDaily=isDaily,
|
||||
questID=questID
|
||||
}
|
||||
end
|
||||
|
||||
function A:GetLogIndexForQuestID(questID)
|
||||
if not self.valid then return nil end
|
||||
return C_QuestLog.GetLogIndexForQuestID(questID)
|
||||
end
|
||||
|
||||
function A:IsOnQuest(questID)
|
||||
if not self.valid then return false end
|
||||
return C_QuestLog.IsOnQuest(questID) and true or false
|
||||
end
|
||||
|
||||
function A:GetBestMapForPlayer()
|
||||
if not self.valid then return nil end
|
||||
return C_Map.GetBestMapForUnit("player")
|
||||
end
|
||||
|
||||
|
||||
function A:GetQuestObjectives(questID,questLogIndex)
|
||||
if C_QuestLog and type(C_QuestLog.GetQuestObjectives)=="function" then
|
||||
-- Questie 3.3.5's Vanilla compatibility implementation accepts the log
|
||||
-- index as a second argument; modern-style implementations ignore extras.
|
||||
return C_QuestLog.GetQuestObjectives(questID,questLogIndex)
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
function A:QueryQuestsCompleted()
|
||||
if type(QueryQuestsCompleted)~="function" then return false end
|
||||
local ok=pcall(QueryQuestsCompleted)
|
||||
return ok and true or false
|
||||
end
|
||||
|
||||
function A:GetQuestsCompleted()
|
||||
if type(GetQuestsCompleted)=="function" then
|
||||
local ok,result=pcall(GetQuestsCompleted)
|
||||
if ok and type(result)=="table" then return result end
|
||||
|
||||
-- Some compatibility layers use the older "fill table" form.
|
||||
local target={}
|
||||
ok=pcall(GetQuestsCompleted,target)
|
||||
if ok and next(target) then return target end
|
||||
end
|
||||
|
||||
if C_QuestLog and type(C_QuestLog.GetQuestsCompleted)=="function" then
|
||||
local ok,result=pcall(C_QuestLog.GetQuestsCompleted)
|
||||
if ok and type(result)=="table" then return result end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
function A:IsQuestFlaggedCompleted(questID)
|
||||
if type(IsQuestFlaggedCompleted)=="function" then
|
||||
local ok,result=pcall(IsQuestFlaggedCompleted,questID)
|
||||
if ok then return result and true or false end
|
||||
end
|
||||
|
||||
if C_QuestLog and type(C_QuestLog.IsQuestFlaggedCompleted)=="function" then
|
||||
local ok,result=pcall(C_QuestLog.IsQuestFlaggedCompleted,questID)
|
||||
if ok then return result and true or false end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
+374
@@ -0,0 +1,374 @@
|
||||
SLASH_QUESTIEOCTO1="/qo"
|
||||
SLASH_QUESTIEOCTO2="/questieocto"
|
||||
|
||||
local function Bool(v)
|
||||
return v and "true" or "false"
|
||||
end
|
||||
|
||||
SlashCmdList["QUESTIEOCTO"]=function(msg)
|
||||
msg=string.lower(msg or "")
|
||||
local creatureStart,creatureEnd,creatureID=string.find(msg,"^creature%s+(%d+)$")
|
||||
local minimapStart,minimapEnd,minimapArg=string.find(msg,"^minimap%s+(.+)$")
|
||||
|
||||
if msg=="visualdiag" then
|
||||
local mm=QuestieOcto.Minimap
|
||||
local shown=0
|
||||
local objective=0
|
||||
local colored=0
|
||||
local glowing=0
|
||||
|
||||
if mm and mm.frames then
|
||||
for key,pin in pairs(mm.frames) do
|
||||
if pin:IsShown() then
|
||||
shown=shown+1
|
||||
local isObjective=pin.role=="objectiveCreature" or
|
||||
pin.role=="objectiveObject" or
|
||||
pin.role=="objectiveItemSource"
|
||||
if isObjective then
|
||||
objective=objective+1
|
||||
local r=pin.iconR or 1
|
||||
local g=pin.iconG or 1
|
||||
local b=pin.iconB or 1
|
||||
local glowShown=pin.glowTexture and pin.glowTexture:IsShown()
|
||||
if r~=1 or g~=1 or b~=1 then colored=colored+1 end
|
||||
if glowShown then glowing=glowing+1 end
|
||||
|
||||
QuestieOcto:Print("VIS pin role/q/obj/rgb/glow="..
|
||||
tostring(pin.role).."/"..
|
||||
tostring(pin.questID or 0).."/"..
|
||||
tostring((pin.entries and next(pin.entries)) and "yes" or "no").."/"..
|
||||
string.format("%.2f,%.2f,%.2f",r,g,b).."/"..
|
||||
tostring(glowShown and true or false))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
QuestieOcto:Print("VIS summary shown/objective/colored/glowing="..
|
||||
tostring(shown).."/"..tostring(objective).."/"..
|
||||
tostring(colored).."/"..tostring(glowing))
|
||||
|
||||
elseif msg=="" or msg=="options" or msg=="config" then
|
||||
QuestieOcto.Options:Toggle()
|
||||
|
||||
elseif msg=="quests" then
|
||||
if QuestieOcto.QuestResearch then QuestieOcto.QuestResearch:OpenWindow() end
|
||||
|
||||
elseif msg=="help" then
|
||||
QuestieOcto:Print("/qo -- toggle Questie-Octo options")
|
||||
QuestieOcto:Print("/qo quests -- open the Quests browser")
|
||||
QuestieOcto:Print("/qo options, /qo info, /qo minimap, /qo api, /qo resync, /qo questlog, /qo map")
|
||||
|
||||
elseif msg=="info" then
|
||||
QuestieOcto:Print(tostring(QuestieOcto.version).." infrastructure diagnostic")
|
||||
QuestieOcto:Print("enabled="..Bool(QuestieOcto.enabled).." ready="..Bool(QuestieOcto.ready)..
|
||||
" ClassicAPI="..Bool(QuestieOcto.API.valid))
|
||||
|
||||
local q=QuestieOcto.DatabaseAPI and QuestieOcto.DatabaseAPI:GetQuestCount() or 0
|
||||
QuestieOcto:Print("DB ready="..Bool(QuestieOcto.Database.ready)..
|
||||
" mergeJob="..tostring(QuestieOcto.Database.jobIndex).."/"..tostring(QuestieOcto.Database.stats.jobs)..
|
||||
" merged="..tostring(QuestieOcto.Database.stats.merged)..
|
||||
" quests="..tostring(q))
|
||||
|
||||
local ql=QuestieOcto.QuestLog
|
||||
local activeComplete=0
|
||||
local activeObjectives=0
|
||||
for _,state in pairs(ql.active or {}) do
|
||||
if state.complete then activeComplete=activeComplete+1 end
|
||||
activeObjectives=activeObjectives+table.getn(state.objectives or {})
|
||||
end
|
||||
QuestieOcto:Print("QuestLog running="..Bool(QuestieOcto.QuestLog.running)..
|
||||
" entries="..tostring(QuestieOcto.QuestLog.stats.entries)..
|
||||
" quests="..tostring(QuestieOcto.QuestLog.stats.quests)..
|
||||
" resolvedIDs="..tostring(QuestieOcto.QuestLog.stats.resolved)..
|
||||
" activeComplete/objectives="..tostring(activeComplete).."/"..tostring(activeObjectives)..
|
||||
" refreshes="..tostring(QuestieOcto.QuestLog.stats.refreshes)..
|
||||
" acceptedFast="..tostring(QuestieOcto.QuestLog.stats.acceptedFastRefreshes or 0)..
|
||||
" acceptedEvt/resolved/fromIndex/last="..
|
||||
tostring(QuestieOcto.QuestLog.stats.acceptedEvents or 0).."/"..
|
||||
tostring(QuestieOcto.QuestLog.stats.acceptedResolved or 0).."/"..
|
||||
tostring(QuestieOcto.QuestLog.stats.acceptedFromIndex or 0).."/"..
|
||||
tostring(QuestieOcto.QuestLog.stats.lastAcceptedQuestID or 0)..
|
||||
" acceptedHint/prime/poll="..
|
||||
tostring(QuestieOcto.QuestLog.stats.acceptedHintsUsed or 0).."/"..
|
||||
tostring(QuestieOcto.QuestLog.stats.acceptedPrimes or 0).."/"..
|
||||
tostring(QuestieOcto.QuestLog.stats.acceptedPolls or 0)..
|
||||
" removedEvt/resolved/fromIndex/last="..
|
||||
tostring(QuestieOcto.QuestLog.stats.removedEvents or 0).."/"..
|
||||
tostring(QuestieOcto.QuestLog.stats.removedResolved or 0).."/"..
|
||||
tostring(QuestieOcto.QuestLog.stats.removedFromIndex or 0).."/"..
|
||||
tostring(QuestieOcto.QuestLog.stats.lastRemovedQuestID or 0))
|
||||
QuestieOcto:Print("QuestLog complete raw/objectives/money="..tostring(ql.completeRaw or 0).."/"..tostring(ql.completeObjectives or 0).."/"..tostring(ql.completeMoney or 0))
|
||||
|
||||
local cp=QuestieOcto.Completion
|
||||
local completeIDs={}
|
||||
for questID,state in pairs(ql.active or {}) do
|
||||
if state.complete then table.insert(completeIDs,tostring(questID)) end
|
||||
end
|
||||
table.sort(completeIDs)
|
||||
QuestieOcto:Print("QuestLog complete IDs="..table.concat(completeIDs,","))
|
||||
QuestieOcto:Print("QuestLog complete raw/objectives/noObjectives/money="..
|
||||
tostring(QuestieOcto.QuestLog.stats.completeRaw or 0).."/"..
|
||||
tostring(QuestieOcto.QuestLog.stats.completeObjectives or 0).."/"..
|
||||
tostring(QuestieOcto.QuestLog.stats.completeNoObjectives or 0).."/"..
|
||||
tostring(QuestieOcto.QuestLog.stats.completeMoney or 0))
|
||||
|
||||
QuestieOcto:Print("Completion ready="..Bool(cp.ready)..
|
||||
" packets="..tostring(cp.receivedPackets)..
|
||||
" completed="..tostring(cp:Count())..
|
||||
" turnIns="..tostring(cp.stats.turnIns or 0))
|
||||
|
||||
local av=QuestieOcto.AvailableQuests
|
||||
local st=av.stats or {}
|
||||
QuestieOcto:Print("AvailableQuests ready="..Bool(av.ready)..
|
||||
" running="..Bool(av.running)..
|
||||
" scan="..tostring(math.min(av.pos or 0,table.getn(av.queue or {}))).."/"..tostring(table.getn(av.queue or {}))..
|
||||
" available="..tostring(st.available or 0))
|
||||
|
||||
QuestieOcto:Print("Availability rejected completed/active/level/pre/exclusive/race/class/event/noStarter="..
|
||||
tostring(st.completed or 0).."/"..tostring(st.active or 0).."/"..tostring(st.level or 0).."/"..
|
||||
tostring(st.prerequisite or 0).."/"..tostring(st.exclusive or 0).."/"..
|
||||
tostring(st.race or 0).."/"..tostring(st.class or 0).."/"..tostring(st.noStarter or 0))
|
||||
|
||||
local ob=QuestieOcto.Objectives
|
||||
local objectiveQuestModels=0
|
||||
for _ in pairs(ob.byQuest or {}) do objectiveQuestModels=objectiveQuestModels+1 end
|
||||
QuestieOcto:Print("Objectives ready/running="..Bool(ob.ready).."/"..Bool(ob.running)..
|
||||
" questModels="..tostring(objectiveQuestModels)..
|
||||
" scanned="..tostring(ob.stats.quests or 0)..
|
||||
" creature/object/item/itemSources="..
|
||||
tostring(ob.stats.creature or 0).."/"..tostring(ob.stats.object or 0).."/"..
|
||||
tostring(ob.stats.item or 0).."/"..tostring(ob.stats.itemSources or 0)..
|
||||
" mapped/unmapped="..tostring(ob.stats.mapped or 0).."/"..tostring(ob.stats.unmapped or 0)..
|
||||
" direct/fallback/typeMismatch="..tostring(ob.stats.direct or 0).."/"..
|
||||
tostring(ob.stats.fallback or 0).."/"..tostring(ob.stats.typeMismatch or 0)..
|
||||
" fuzzy/single="..tostring(ob.stats.fuzzy or 0).."/"..tostring(ob.stats.single or 0)..
|
||||
" rebuilds/waits="..tostring(ob.stats.rebuilds or 0).."/"..tostring(ob.stats.dependencyWaits or 0))
|
||||
|
||||
local it=QuestieOcto.ItemStarts
|
||||
QuestieOcto:Print("ItemStarts ready="..Bool(it.ready)..
|
||||
" quests/items/creatureSources/objectSources="..
|
||||
tostring(it.stats.quests or 0).."/"..tostring(it.stats.starterItems or 0).."/"..
|
||||
tostring(it.stats.creatureSources or 0).."/"..tostring(it.stats.objectSources or 0))
|
||||
|
||||
local nd=QuestieOcto.Nodes
|
||||
QuestieOcto:Print("Nodes ready="..Bool(nd.ready)..
|
||||
" total="..tostring(nd.stats.total or 0)..
|
||||
" availCreature/object/itemStart="..
|
||||
tostring(nd.stats.availableCreature or 0).."/"..tostring(nd.stats.availableObject or 0).."/"..
|
||||
tostring(nd.stats.itemStart or 0))
|
||||
QuestieOcto:Print("Nodes active creature/object/itemSource/turnin="..
|
||||
tostring(nd.stats.objectiveCreature or 0).."/"..tostring(nd.stats.objectiveObject or 0).."/"..
|
||||
tostring(nd.stats.objectiveItemSource or 0).."/"..tostring(nd.stats.turnin or 0))
|
||||
|
||||
local mp=QuestieOcto.Map
|
||||
QuestieOcto:Print("Map active/created/reused/hidden="..
|
||||
tostring(mp.stats.active or 0).."/"..tostring(mp.stats.created or 0).."/"..
|
||||
tostring(mp.stats.reused or 0).."/"..tostring(mp.stats.hidden or 0)..
|
||||
" syncs="..tostring(mp.stats.syncs or 0))
|
||||
QuestieOcto:Print("Map visible available/itemStart/objective/turnin="..
|
||||
tostring(mp.stats.visibleAvailable or 0).."/"..tostring(mp.stats.visibleItemStart or 0).."/"..
|
||||
tostring(mp.stats.visibleObjective or 0).."/"..tostring(mp.stats.visibleTurnin or 0)..
|
||||
" mapID="..tostring(mp.mapID)..
|
||||
" inputNodes="..tostring(mp.stats.inputNodes or 0)..
|
||||
" mergedPins="..tostring(mp.stats.multiEntryPins or 0))
|
||||
QuestieOcto:Print("ItemStart rawNodes/areaPins="..
|
||||
tostring(mp.stats.itemStartRawNodes or 0).."/"..tostring(mp.stats.itemStartAreaPins or 0))
|
||||
|
||||
local pm=QuestieOcto.PreparedMap
|
||||
QuestieOcto:Print("Prepared maps/descriptors/running/currentReady="..
|
||||
tostring(pm.stats.preparedMaps or 0).."/"..tostring(pm.stats.descriptors or 0).."/"..
|
||||
Bool(pm.running).."/"..Bool(pm.stats.currentReady)..
|
||||
" revision/bumps="..tostring(pm.stateRevision or 0).."/"..tostring(pm.stats.revisionBumps or 0))
|
||||
QuestieOcto:Print("Map prepared hits/misses/descriptors="..
|
||||
tostring(mp.stats.preparedHits or 0).."/"..tostring(mp.stats.preparedMisses or 0).."/"..
|
||||
tostring(mp.stats.preparedDescriptors or 0))
|
||||
|
||||
local ci=QuestieOcto.MapCandidateIndex
|
||||
QuestieOcto:Print("CandidateIndex ready/running/scanned/maps/links/currentReady="..
|
||||
Bool(ci.ready).."/"..Bool(ci.running).."/"..tostring(ci.stats.scanned or 0).."/"..
|
||||
tostring(ci.stats.maps or 0).."/"..tostring(ci.stats.links or 0).."/"..Bool(ci.stats.currentReady))
|
||||
|
||||
local zb=QuestieOcto.ZoneBootstrap
|
||||
QuestieOcto:Print("ZoneBootstrap ready/running/indexed/map/requested/scanned/candidates/available/nodes/itemSources="..
|
||||
Bool(zb.ready).."/"..Bool(zb.running).."/"..Bool(zb.stats.indexed).."/"..tostring(zb.mapID).."/"..tostring(zb.requestedMapID).."/"..
|
||||
tostring(zb.stats.scanned or 0).."/"..tostring(zb.stats.candidates or 0).."/"..
|
||||
tostring(zb.stats.available or 0).."/"..tostring(zb.stats.nodes or 0).."/"..
|
||||
tostring(zb.stats.itemSources or 0))
|
||||
QuestieOcto:Print("ZoneBootstrap requests/cancelled mapPriorityRequests="..
|
||||
tostring(zb.stats.requests or 0).."/"..tostring(zb.stats.cancelled or 0).."/"..
|
||||
tostring(mp.stats.mapPriorityRequests or 0))
|
||||
|
||||
QuestieOcto:Print("Quest visibility policy=low-level quests shown")
|
||||
QuestieOcto:Print("Quest refresh policy=Questie immediate unload + 335 fast refresh")
|
||||
QuestieOcto:Print("Scheduler policy=Questie-335 every-frame thread slices")
|
||||
QuestieOcto:Print("Startup policy=immediate completion/log + 335 fast initial availability")
|
||||
QuestieOcto:Print("Quest accept policy=immediate unload + fast objective-cache retry")
|
||||
|
||||
local mm=QuestieOcto.Minimap
|
||||
QuestieOcto:Print("Minimap enabled/active/map/refreshes/updates="..
|
||||
Bool(mm and mm.enabled).."/"..tostring(mm and mm.stats.active or 0).."/"..
|
||||
tostring(mm and mm.mapID or "nil").."/"..
|
||||
tostring(mm and mm.stats.refreshes or 0).."/"..
|
||||
tostring(mm and mm.stats.positionUpdates or 0))
|
||||
local ms=QuestieOcto.MinimapSettings
|
||||
QuestieOcto:Print("Minimap mapContext restores/reason="..
|
||||
tostring(mm and mm.stats.mapContextRestores or 0).."/"..
|
||||
tostring(mm and mm.stats.lastMapContextReason or "none"))
|
||||
QuestieOcto:Print("Scale rescalePasses map/minimap="..
|
||||
tostring(QuestieOcto.Map.stats.rescalePasses or 0).."/"..
|
||||
tostring(QuestieOcto.Minimap.stats.rescalePasses or 0))
|
||||
QuestieOcto:Print("Scale resize map count/last="..
|
||||
tostring(QuestieOcto.Map.stats.scaleResizes or 0).."/"..
|
||||
tostring(QuestieOcto.Map.stats.lastScaleSize or 0)..
|
||||
" minimap count/last="..
|
||||
tostring(QuestieOcto.Minimap.stats.scaleResizes or 0).."/"..
|
||||
tostring(QuestieOcto.Minimap.stats.lastScaleSize or 0))
|
||||
QuestieOcto:Print("Map settings enabled/scale/objectives/turnins/available="..
|
||||
Bool(ms:Get("enableMapIcons")).."/"..
|
||||
tostring(ms:Get("globalScale")).."/"..
|
||||
Bool(ms:Get("enableObjectives")).."/"..
|
||||
Bool(ms:Get("enableTurnins")).."/"..
|
||||
Bool(ms:Get("enableAvailable")))
|
||||
QuestieOcto:Print("Minimap settings enabled/scale="..
|
||||
Bool(ms:Get("enableMiniMapIcons")).."/"..tostring(ms:Get("globalMiniMapScale")))
|
||||
QuestieOcto:Print("Minimap unload policy=Questie quest-wide world+minimap + prepared-cache purge")
|
||||
QuestieOcto:Print("Minimap visibility policy=all marker centers visible to minimap edge")
|
||||
QuestieOcto:Print("Objective icon policy=Questie slay/loot/interact by objective kind")
|
||||
QuestieOcto:Print("Turnin icon policy=Questie separate exact frame + complete overlay 6 above available 5")
|
||||
QuestieOcto:Print("Quest remove policy=Questie immediate quest-wide unload before redraw")
|
||||
QuestieOcto:Print("Minimap visible available/itemStart/objective/turnin="..
|
||||
tostring(mm and mm.stats.visibleAvailable or 0).."/"..
|
||||
tostring(mm and mm.stats.visibleItemStart or 0).."/"..
|
||||
tostring(mm and mm.stats.visibleObjective or 0).."/"..
|
||||
tostring(mm and mm.stats.visibleTurnin or 0))
|
||||
local op=QuestieOcto.Options
|
||||
QuestieOcto:Print("Options Ace initialized/shown/opens/closes/changes="..
|
||||
Bool(op and op.initialized).."/"..
|
||||
Bool(op and op.configFrame and op.configFrame:IsShown()).."/"..
|
||||
tostring(op and op.stats.opens or 0).."/"..tostring(op and op.stats.closes or 0).."/"..
|
||||
tostring(op and op.stats.changes or 0))
|
||||
QuestieOcto:Print("Options tabs=General/Map/Minimap/Tooltips/Advanced/Quests")
|
||||
QuestieOcto:Print("Options visuals glowMap/glowMini/colorMap/colorMini="..
|
||||
tostring(QuestieOcto.MinimapSettings:Get("alwaysGlowMap")).."/"..
|
||||
tostring(QuestieOcto.MinimapSettings:Get("alwaysGlowMinimap")).."/"..
|
||||
tostring(QuestieOcto.MinimapSettings:Get("questObjectiveColors")).."/"..
|
||||
tostring(QuestieOcto.MinimapSettings:Get("questMinimapObjectiveColors")))
|
||||
|
||||
local miniGlow=0
|
||||
local miniColor=0
|
||||
if QuestieOcto.Minimap and QuestieOcto.Minimap.frames then
|
||||
for _,pin in pairs(QuestieOcto.Minimap.frames) do
|
||||
if pin.glowTexture and pin.glowTexture:IsShown() then miniGlow=miniGlow+1 end
|
||||
if (pin.iconR and pin.iconR~=1) or (pin.iconG and pin.iconG~=1) or (pin.iconB and pin.iconB~=1) then
|
||||
miniColor=miniColor+1
|
||||
end
|
||||
end
|
||||
end
|
||||
QuestieOcto:Print("Minimap visual applied glow/colored="..tostring(miniGlow).."/"..tostring(miniColor))
|
||||
QuestieOcto:Print("Options availability lowLevel/repeatable/event/pvp="..
|
||||
tostring(QuestieOcto.MinimapSettings:Get("showLowLevelQuests")).."/"..
|
||||
tostring(QuestieOcto.MinimapSettings:Get("showRepeatableQuests")).."/"..
|
||||
tostring(QuestieOcto.MinimapSettings:Get("showEventQuests")).."/"..
|
||||
tostring(QuestieOcto.MinimapSettings:Get("showPvPRelatedQuests")))
|
||||
QuestieOcto:Print("Options AceGUI/registry/dialog="..
|
||||
Bool(op and op.stats.aceGUI).."/"..Bool(op and op.stats.aceRegistry).."/"..Bool(op and op.stats.aceDialog))
|
||||
QuestieOcto:Print("Options lastSet key/value="..
|
||||
tostring(op and op.stats.lastSetKey or "none").."/"..
|
||||
tostring(op and op.stats.lastSetValue or "none"))
|
||||
local gm=QuestieOcto.GameMenu
|
||||
QuestieOcto:Print("GameMenu installed/clicks/anchor="..
|
||||
Bool(gm and gm.installed).."/"..tostring(gm and gm.stats.clicks or 0).."/"..
|
||||
tostring(gm and gm.stats.anchor or "none"))
|
||||
QuestieOcto:Print("Rare tooltip policy=static DB respawn only; no kill tracking")
|
||||
QuestieOcto:Print("Scheduler queued="..tostring(table.getn(QuestieOcto.Scheduler.queue))..
|
||||
" executed="..tostring(QuestieOcto.Scheduler.executed))
|
||||
|
||||
elseif msg=="minimap" then
|
||||
local ms=QuestieOcto.MinimapSettings
|
||||
QuestieOcto:Print("minimap enabled="..Bool(ms:Get("enableMiniMapIcons"))..
|
||||
" scale="..tostring(ms:Get("globalMiniMapScale")))
|
||||
QuestieOcto:Print("/qo minimap on|off, scale <0.01-4>, reset")
|
||||
|
||||
elseif minimapArg then
|
||||
local ms=QuestieOcto.MinimapSettings
|
||||
local actionStart,actionEnd,action,value=string.find(minimapArg,"^(%S+)%s*(.*)$")
|
||||
local changed=false
|
||||
|
||||
if action=="on" then
|
||||
changed=ms:Set("enableMiniMapIcons",true)
|
||||
elseif action=="off" then
|
||||
changed=ms:Set("enableMiniMapIcons",false)
|
||||
elseif action=="scale" then
|
||||
changed=ms:Set("globalMiniMapScale",tonumber(value))
|
||||
elseif action=="reset" then
|
||||
ms:Reset()
|
||||
changed=true
|
||||
end
|
||||
|
||||
if changed then
|
||||
QuestieOcto:Print("minimap setting updated")
|
||||
else
|
||||
QuestieOcto:Print("invalid minimap setting; use /qo minimap")
|
||||
end
|
||||
|
||||
elseif msg=="api" then
|
||||
local ok=QuestieOcto.API:Validate()
|
||||
QuestieOcto:Print("ClassicAPI contract valid="..Bool(ok))
|
||||
|
||||
if not ok then
|
||||
for _,name in pairs(QuestieOcto.API.missing) do
|
||||
QuestieOcto:Error("missing "..name)
|
||||
end
|
||||
else
|
||||
local o=QuestieOcto.API.optional
|
||||
QuestieOcto:Print("optional: coroutines="..Bool(o.coroutines)..
|
||||
" hooksecurefunc="..Bool(o.hooksecurefunc)..
|
||||
" questDetails="..Bool(o.questDetails)..
|
||||
" mapWorldSize="..Bool(o.mapWorldSize))
|
||||
end
|
||||
|
||||
elseif msg=="resync" then
|
||||
QuestieOcto.Completion:Start()
|
||||
QuestieOcto:Print("requested Turtle completion history")
|
||||
|
||||
elseif msg=="questlog" then
|
||||
QuestieOcto.QuestLog:Schedule(0)
|
||||
QuestieOcto:Print("scheduled quest-log refresh")
|
||||
|
||||
elseif msg=="map" then
|
||||
QuestieOcto.Map:RequestSync(true)
|
||||
QuestieOcto:Print("scheduled world-map sync")
|
||||
|
||||
elseif creatureID then
|
||||
QuestieOcto.CreatureDiagnostics:Trace(tonumber(creatureID))
|
||||
|
||||
elseif msg=="quest178" then
|
||||
local q=QuestieOcto.QuestModel:Get(178)
|
||||
if not q then
|
||||
QuestieOcto:Print("quest 178 model unavailable")
|
||||
else
|
||||
QuestieOcto:Print("quest178 title="..tostring(q.title)..
|
||||
" level="..tostring(q.level)..
|
||||
" required="..tostring(q.requiredLevel))
|
||||
QuestieOcto:Print("quest178 startItem="..tostring(q.starts.item and q.starts.item[1])..
|
||||
" completed="..Bool(QuestieOcto.Completion:IsComplete(178))..
|
||||
" available="..Bool(QuestieOcto.AvailableQuests:IsQuestAvailable(178)))
|
||||
|
||||
local resolved=QuestieOcto.ItemStarts.byQuest[178]
|
||||
local creatures=0
|
||||
local objects=0
|
||||
if resolved then
|
||||
for _,item in pairs(resolved.items) do
|
||||
creatures=creatures+table.getn(item.creatureSources or {})
|
||||
objects=objects+table.getn(item.objectSources or {})
|
||||
end
|
||||
end
|
||||
QuestieOcto:Print("quest178 resolved item-start sources creature/object="..
|
||||
tostring(creatures).."/"..tostring(objects))
|
||||
end
|
||||
|
||||
else
|
||||
QuestieOcto:Print("/qo -- options; /qo help for commands")
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,41 @@
|
||||
local f=CreateFrame("Frame","QuestieOctoBootstrapFrame",UIParent)
|
||||
f:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
|
||||
function QuestieOcto:OnFoundationServiceReady()
|
||||
if self.ready then return end
|
||||
|
||||
if self.Database.ready and self.DatabaseAPI:IsReady() and self.Completion.ready and self.QuestLog.snapshot then
|
||||
self.ready=true
|
||||
local q=self.DatabaseAPI:GetQuestCount()
|
||||
self:Print("foundation ready - "..tostring(q).." quests, "..tostring(self.Completion:Count())..
|
||||
" completed, "..tostring(self.QuestLog.stats.resolved).." active quest IDs resolved.")
|
||||
self:SendMessage("FOUNDATION_READY")
|
||||
end
|
||||
end
|
||||
|
||||
f:SetScript("OnEvent",function()
|
||||
f:UnregisterEvent("PLAYER_ENTERING_WORLD")
|
||||
QuestieOcto.startedAt=GetTime()
|
||||
|
||||
if not QuestieOcto.API:Validate() then
|
||||
QuestieOcto.enabled=false
|
||||
QuestieOcto:Error("ClassicAPI is required. Missing "..tostring(table.getn(QuestieOcto.API.missing)).." required API calls.")
|
||||
QuestieOcto:Error("Run /qo api after installing/updating ClassicAPI.")
|
||||
return
|
||||
end
|
||||
|
||||
QuestieOcto.enabled=true
|
||||
if QuestieOcto.Tooltips and QuestieOcto.Tooltips.Initialize then
|
||||
QuestieOcto.Tooltips:Initialize()
|
||||
end
|
||||
QuestieOcto:RegisterMessage("DATABASE_READY",QuestieOcto,"OnFoundationServiceReady")
|
||||
QuestieOcto:RegisterMessage("DATABASE_API_READY",QuestieOcto,"OnFoundationServiceReady")
|
||||
QuestieOcto:RegisterMessage("COMPLETION_READY",QuestieOcto,"OnFoundationServiceReady")
|
||||
QuestieOcto:RegisterMessage("QUEST_LOG_CHANGED",QuestieOcto,"OnFoundationServiceReady")
|
||||
|
||||
QuestieOcto:Print("ClassicAPI detected; starting Questie-Octo.")
|
||||
|
||||
QuestieOcto.Database:Start()
|
||||
QuestieOcto.QuestLog:Start()
|
||||
QuestieOcto.Completion:ScheduleStart()
|
||||
end)
|
||||
@@ -0,0 +1,59 @@
|
||||
QuestieOcto.Scheduler = QuestieOcto.Scheduler or {}
|
||||
local S = QuestieOcto.Scheduler
|
||||
|
||||
S.queue = {}
|
||||
S.delayed = {}
|
||||
S.elapsed = 0
|
||||
S.interval = 0
|
||||
S.executed = 0
|
||||
|
||||
function S:Enqueue(fn, label)
|
||||
if not fn then return end
|
||||
table.insert(self.queue, { fn=fn, label=label })
|
||||
end
|
||||
|
||||
function S:After(delay, fn, key)
|
||||
if not fn then return end
|
||||
if key then
|
||||
self.delayed[key] = { remaining=delay or 0, fn=fn }
|
||||
else
|
||||
table.insert(self.delayed, { remaining=delay or 0, fn=fn })
|
||||
end
|
||||
end
|
||||
|
||||
local function RunDelayed(self, delta)
|
||||
local remove = {}
|
||||
for k,v in pairs(self.delayed) do
|
||||
v.remaining = v.remaining - delta
|
||||
if v.remaining <= 0 then table.insert(remove, k) end
|
||||
end
|
||||
for _,k in pairs(remove) do
|
||||
local entry = self.delayed[k]
|
||||
self.delayed[k] = nil
|
||||
if entry and entry.fn then entry.fn() end
|
||||
end
|
||||
end
|
||||
|
||||
function S:Tick()
|
||||
-- Questie 3.3.5 ThreadLib resumes every active delay-0 thread once per frame.
|
||||
-- Snapshot the queue length so a continuation re-enqueued by its own slice
|
||||
-- cannot run twice in the same frame.
|
||||
local count=table.getn(self.queue)
|
||||
|
||||
for i=1,count do
|
||||
local entry=table.remove(self.queue,1)
|
||||
if entry and entry.fn then
|
||||
entry.fn()
|
||||
self.executed=self.executed+1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local f=CreateFrame("Frame","QuestieOctoSchedulerFrame",UIParent)
|
||||
f:SetScript("OnUpdate",function()
|
||||
local delta=arg1 or 0
|
||||
RunDelayed(S,delta)
|
||||
-- Questie ThreadLib delay < 0.05 means "every frame".
|
||||
S.elapsed=0
|
||||
S:Tick()
|
||||
end)
|
||||
@@ -0,0 +1,35 @@
|
||||
-- Questie-Octo curated Turtle WoW calendar rules.
|
||||
--
|
||||
-- These windows were transcribed from the in-game Turtle calendar for 2026.
|
||||
-- The calendar is treated as a recurring annual schedule: only visible event
|
||||
-- text counts. Raid Reset, roadmap/release announcements and graphic-only
|
||||
-- calendar cells are intentionally ignored.
|
||||
--
|
||||
-- Darkmoon Faire is not part of this table. It follows its own anchored
|
||||
-- 14-day Elwynn/Mulgore cycle in Quest/EventAvailability.lua.
|
||||
|
||||
QuestieOcto.CalendarEventRules = {
|
||||
-- Canonical seasonal/gameplay festivals.
|
||||
[1] = { name="Midsummer Fire Festival", startMonth=6, startDay=21, endMonth=7, endDay=12 },
|
||||
[2] = { name="Feast of Winter Veil", startMonth=12, startDay=3, endMonth=1, endDay=14 },
|
||||
[7] = { name="Lunar Festival", startMonth=2, startDay=16, endMonth=3, endDay=4 },
|
||||
[8] = { name="Love is in the Air", startMonth=2, startDay=1, endMonth=2, endDay=16 },
|
||||
|
||||
-- Turtle currently has no quest rows tied to the Noblegarden game_event,
|
||||
-- but keep both known IDs here so future DB revisions inherit the calendar
|
||||
-- without another code change.
|
||||
[9] = { name="Noblegarden", startMonth=4, startDay=17, endMonth=5, endDay=8 },
|
||||
[28] = { name="Noblegarden", startMonth=4, startDay=17, endMonth=5, endDay=8 },
|
||||
|
||||
[11] = { name="Harvest Festival", startMonth=10, startDay=1, endMonth=10, endDay=8 },
|
||||
[12] = { name="Hallow's End", startMonth=10, startDay=20, endMonth=11, endDay=2 },
|
||||
|
||||
-- Brewfest is a Turtle custom event ID present in quest data but absent
|
||||
-- from the bundled tw_world_game_event snapshot.
|
||||
[26] = { name="Brewfest", startMonth=9, startDay=20, endMonth=10, endDay=6 },
|
||||
}
|
||||
|
||||
-- Calendar entries intentionally NOT used for quest availability:
|
||||
-- Raid Reset; Phase 1/Phase 2; Festival; War; Frostmane Hollow;
|
||||
-- Windhorn Canyon; Dragonmaw Retreat; Northwind; Stormwrought Ruins;
|
||||
-- Moonwhisper Coast; and similar roadmap/release announcements.
|
||||
@@ -0,0 +1,101 @@
|
||||
-- Generated from authoritative Turtle WoW tw_world_game_event.sql.
|
||||
-- Do not hand-edit: event membership and event presentation are separate.
|
||||
QuestieOcto.EventScheduleData = {
|
||||
[1]={start="2020-06-22 03:00:00",finish="2031-01-01 06:59:59",occurrence=525600,length=30240,holiday=341,name="Midsummer Fire Festival",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[2]={start="2020-12-11 20:00:00",finish="2031-01-01 06:59:59",occurrence=525600,length=44640,holiday=141,name="Feast of Winter Veil",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[4]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=525600,length=2592000,holiday=374,name="Darkmoon Faire (Elwynn)",hardcoded=true,disabled=false,requiredPhase=0},
|
||||
[5]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=525600,length=2592000,holiday=375,name="Darkmoon Faire (Mulgore)",hardcoded=true,disabled=false,requiredPhase=0},
|
||||
[6]={start="2017-01-01 11:00:00",finish="2026-12-30 12:00:00",occurrence=525600,length=10,holiday=0,name="Fireworks",hardcoded=true,disabled=false,requiredPhase=0},
|
||||
[7]={start="2020-01-25 06:00:00",finish="2031-01-01 06:59:59",occurrence=525600,length=43200,holiday=327,name="Lunar Festival",hardcoded=false,disabled=true,requiredPhase=0},
|
||||
[8]={start="2021-02-12 06:00:00",finish="2030-02-17 06:00:00",occurrence=525600,length=20160,holiday=335,name="Love is in the Air",hardcoded=false,disabled=true,requiredPhase=0},
|
||||
[9]={start="2020-03-30 03:00:00",finish="2030-03-30 05:59:59",occurrence=525600,length=18720,holiday=181,name="Noblegarden",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[10]={start="2022-02-01 20:00:00",finish="2031-01-01 06:59:59",occurrence=40320,length=10080,holiday=201,name="Children's Week",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[11]={start="2020-09-30 05:00:00",finish="2031-01-01 06:59:59",occurrence=525600,length=10080,holiday=321,name="Harvest Festival",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[12]={start="2020-10-19 03:00:00",finish="2031-01-01 06:59:59",occurrence=525600,length=20160,holiday=324,name="Hallow's End",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[13]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=1,length=999999999,holiday=0,name="Elemental Invasion",hardcoded=true,disabled=false,requiredPhase=0},
|
||||
[14]={start="2017-01-07 16:00:00",finish="2027-01-01 07:00:00",occurrence=10080,length=1920,holiday=0,name="Stranglethorn Fishing Extravaganza: Announce",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[15]={start="2017-01-08 21:00:00",finish="2027-01-01 07:00:00",occurrence=10080,length=120,holiday=301,name="Stranglethorn Fishing Extravaganza: Tournament",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[16]={start="2021-01-01 07:00:00",finish="2031-01-01 06:59:59",occurrence=180,length=120,holiday=0,name="Gurubashi Arena Booty Run",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[17]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=525600,length=999999999,holiday=0,name="Scourge Invasion",hardcoded=true,disabled=true,requiredPhase=3},
|
||||
[18]={start="2020-05-01 07:00:01",finish="2031-01-01 06:59:59",occurrence=7200,length=1440,holiday=283,name="Call to arms: Alterac Valley",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[19]={start="2020-05-02 07:00:01",finish="2031-01-01 06:59:59",occurrence=7200,length=1440,holiday=284,name="Call to Arms: Warsong Gulch",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[20]={start="2020-05-03 07:00:01",finish="2031-01-01 06:59:59",occurrence=7200,length=1440,holiday=285,name="Call to Arms: Arathi Basin",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[21]={start="2020-12-25 08:00:00",finish="2030-01-03 07:59:59",occurrence=525600,length=12960,holiday=0,name="Feast of Winter Veil: Gifts",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[22]={start="2020-08-03 07:00:00",finish="2030-12-31 10:00:00",occurrence=1,length=2592000,holiday=0,name="AQ War Effort (NPC & GO 'Initial')",hardcoded=true,disabled=false,requiredPhase=2},
|
||||
[23]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=525600,length=2592000,holiday=374,name="Darkmoon Faire Building (Elwynn) (TODO)",hardcoded=true,disabled=false,requiredPhase=0},
|
||||
[24]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=525600,length=2592000,holiday=375,name="Darkmoon Faire Building (Mulgore) (TODO)",hardcoded=true,disabled=false,requiredPhase=0},
|
||||
[25]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=525600,length=1,holiday=0,name="Call to arms",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[27]={start="2020-01-02 08:00:00",finish="2030-12-31 11:00:00",occurrence=1440,length=720,holiday=0,name="Night",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[28]={start="2024-03-30 07:00:01",finish="2030-04-11 07:00:01",occurrence=525600,length=17280,holiday=0,name="Noblegarden",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[29]={start="2020-06-10 07:00:01",finish="2031-01-01 06:59:59",occurrence=80640,length=20160,holiday=0,name="Edge of Madness, Gri'lek",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[30]={start="2020-06-23 07:00:01",finish="2031-01-01 06:59:59",occurrence=80640,length=20160,holiday=0,name="Edge of Madness, Hazza'rah",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[31]={start="2020-05-12 07:00:01",finish="2031-01-01 06:59:59",occurrence=80640,length=20160,holiday=0,name="Edge of Madness, Renataki",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[32]={start="2020-05-26 07:00:01",finish="2031-01-01 06:59:59",occurrence=80640,length=20160,holiday=0,name="Edge of Madness, Wushoolay",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[33]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=5184000,length=2592000,holiday=0,name="Arena Tournament",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[34]={start="2020-12-31 14:00:00",finish="2030-01-01 14:00:05",occurrence=525600,length=1445,holiday=0,name="New Year's Eve",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[35]={start="2010-03-24 17:00:00",finish="2030-01-01 11:00:00",occurrence=1260,length=420,holiday=0,name="The Maul: Mushgog",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[36]={start="2010-03-25 00:00:00",finish="2030-01-01 11:00:00",occurrence=1260,length=420,holiday=0,name="The Maul: Skarr the Unbreakable",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[37]={start="2010-03-25 07:00:00",finish="2030-01-01 11:00:00",occurrence=1260,length=420,holiday=0,name="The Maul: Razza",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[38]={start="2020-02-08 14:00:00",finish="2030-02-09 14:00:00",occurrence=525600,length=1445,holiday=0,name="Chinese New Year",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[39]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=60,length=10,holiday=0,name="Post Firework Toasting Goblets",hardcoded=true,disabled=false,requiredPhase=0},
|
||||
[40]={start="2017-01-08 19:00:00",finish="2027-01-01 07:00:00",occurrence=10080,length=300,holiday=0,name="Stranglethorn Fishing Extravaganza: The Crew",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[41]={start="2020-06-04 07:00:00",finish="2027-06-05 07:00:00",occurrence=525600,length=1440,holiday=0,name="July 4th Fireworks Spectacular (US Only)",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[42]={start="2020-09-30 07:00:00",finish="2027-10-01 07:00:00",occurrence=525600,length=1440,holiday=0,name="September 30th Peon Day (EU Only)",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[45]={start="2020-03-20 17:00:00",finish="2030-01-01 12:00:00",occurrence=525600,length=262800,holiday=0,name="Fishing: summer period (for Raw Summer Bass)",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[46]={start="2020-09-23 16:00:00",finish="2030-01-01 12:00:00",occurrence=525600,length=262800,holiday=0,name="Fishing: winter period (for Winter Squid)",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[47]={start="2017-01-01 13:00:00",finish="2030-12-31 07:00:00",occurrence=1440,length=1080,holiday=0,name="Fishing: Sunscale Cycle",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[48]={start="2017-01-02 01:00:00",finish="2030-12-31 19:00:00",occurrence=1440,length=1080,holiday=0,name="Fishing: Nightfin Cycle",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[49]={start="2020-01-03 05:00:00",finish="2030-12-31 13:30:00",occurrence=1440,length=480,holiday=0,name="Pyrewood Village Night",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[50]={start="2020-05-04 07:00:01",finish="2031-01-01 06:59:59",occurrence=7200,length=1440,holiday=286,name="Call to Arms: Blood Ring",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[51]={start="2020-05-05 07:00:01",finish="2031-01-01 06:59:59",occurrence=7200,length=1440,holiday=287,name="Call to Arms: Sunnyglade",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[52]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=1,length=2592000,holiday=0,name="AQ War Effort (NPC Reput 'Only War Effort')",hardcoded=true,disabled=false,requiredPhase=2},
|
||||
[53]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=1,length=2592000,holiday=0,name="AQ War Effort (NPC Reput Named 'Officer')",hardcoded=true,disabled=false,requiredPhase=2},
|
||||
[54]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=1,length=2592000,holiday=0,name="AQ War Troop Silithus (NPC & GO) DAY 1",hardcoded=true,disabled=true,requiredPhase=2},
|
||||
[55]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=1,length=2592000,holiday=0,name="AQ War Troop Silithus (NPC & GO) DAY 2",hardcoded=true,disabled=true,requiredPhase=2},
|
||||
[56]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=1,length=2592000,holiday=0,name="AQ War Troop Silithus (NPC & GO) DAY 3",hardcoded=true,disabled=true,requiredPhase=2},
|
||||
[57]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=1,length=2592000,holiday=0,name="AQ War Troop Silithus (NPC & GO) DAY 4",hardcoded=true,disabled=true,requiredPhase=2},
|
||||
[58]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=1,length=2592000,holiday=0,name="AQ War Troop Silithus (NPC & GO) DAY 5",hardcoded=true,disabled=true,requiredPhase=2},
|
||||
[59]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=1,length=2592000,holiday=0,name="AQ War Effort (Cenarion Hold attack)",hardcoded=true,disabled=true,requiredPhase=2},
|
||||
[60]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=1,length=2592000,holiday=0,name="AQ War Troop Silithus 3 (NPC & GO)",hardcoded=true,disabled=false,requiredPhase=2},
|
||||
[61]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=1,length=2592000,holiday=0,name="AQ War Final Battle (NPC)",hardcoded=true,disabled=true,requiredPhase=2},
|
||||
[62]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=1,length=2592000,holiday=0,name="AQ War - Secrets of the Colossus Ashi",hardcoded=false,disabled=true,requiredPhase=2},
|
||||
[63]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=1,length=2592000,holiday=0,name="AQ War - Secrets of the Colossus Regal",hardcoded=false,disabled=true,requiredPhase=2},
|
||||
[64]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=1,length=2592000,holiday=0,name="AQ War - Secrets of the Colossus Zora",hardcoded=false,disabled=true,requiredPhase=2},
|
||||
[65]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=1,length=2592000,holiday=0,name="AQ War - Spawn of Crystals",hardcoded=true,disabled=true,requiredPhase=2},
|
||||
[66]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=1,length=999999999,holiday=0,name="Dragons of Nightmare Spawn",hardcoded=true,disabled=false,requiredPhase=1},
|
||||
[68]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=1,length=999999999,holiday=0,name="Elemental Invasion: Fire (Un'goro Crater)",hardcoded=true,disabled=false,requiredPhase=0},
|
||||
[69]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=1,length=999999999,holiday=0,name="Elemental Invasion: Air (Silithus)",hardcoded=true,disabled=false,requiredPhase=0},
|
||||
[70]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=1,length=999999999,holiday=0,name="Elemental Invasion: Earth (Azshara)",hardcoded=true,disabled=false,requiredPhase=0},
|
||||
[71]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=1,length=999999999,holiday=0,name="Elemental Invasion: Water (Winterspring)",hardcoded=true,disabled=false,requiredPhase=0},
|
||||
[72]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=1,length=999999999,holiday=0,name="Elemental Invasion: Baron Charr (Un'goro Crater)",hardcoded=true,disabled=false,requiredPhase=0},
|
||||
[73]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=1,length=999999999,holiday=0,name="Elemental Invasion: The Windreaver (Silithus)",hardcoded=true,disabled=false,requiredPhase=0},
|
||||
[74]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=1,length=999999999,holiday=0,name="Elemental Invasion: Avalanchion (Azshara)",hardcoded=true,disabled=false,requiredPhase=0},
|
||||
[75]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=1,length=999999999,holiday=0,name="Elemental Invasion: Princess Tempestria (Winterspring)",hardcoded=true,disabled=false,requiredPhase=0},
|
||||
[78]={start="2010-01-01 08:00:00",finish="2025-01-01 08:00:00",occurrence=60,length=1,holiday=0,name="Hourly Bells",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[80]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=525600,length=999999999,holiday=0,name="Scourge Invasion - Skeleton spawn / Quest activation lvl 9-11",hardcoded=false,disabled=false,requiredPhase=3},
|
||||
[81]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=525600,length=999999999,holiday=0,name="Scourge Invasion - Boss in instance activation",hardcoded=false,disabled=false,requiredPhase=3},
|
||||
[83]={start="2005-01-01 07:00:00",finish="2025-01-01 08:00:00",occurrence=1,length=2592000,holiday=0,name="AQ Gate",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[84]={start="2005-01-01 07:00:00",finish="2025-01-01 08:00:00",occurrence=1,length=2,holiday=0,name="AQ War Effort (master event)",hardcoded=true,disabled=false,requiredPhase=2},
|
||||
[85]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=1,length=999999999,holiday=0,name="AQ War Effort (gong)",hardcoded=true,disabled=true,requiredPhase=2},
|
||||
[86]={start="2005-01-01 07:00:00",finish="2025-01-01 08:00:00",occurrence=1,length=2,holiday=0,name="AQ War Effort (post-event)",hardcoded=true,disabled=false,requiredPhase=2},
|
||||
[103]={start="2020-09-08 11:00:00",finish="2030-12-31 11:00:00",occurrence=525600,length=33720,holiday=0,name="Event PVP Silithus",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[110]={start="2021-02-17 06:00:00",finish="2030-02-12 06:00:00",occurrence=525600,length=525600,holiday=335,name="Love is in the Air - Popularity Contest Winner: Darnassus",hardcoded=false,disabled=true,requiredPhase=0},
|
||||
[111]={start="2021-02-17 06:00:00",finish="2030-02-12 06:00:00",occurrence=525600,length=525600,holiday=335,name="Love is in the Air - Popularity Contest Winner: Ironforge",hardcoded=false,disabled=true,requiredPhase=0},
|
||||
[112]={start="2021-02-17 06:00:00",finish="2030-02-12 06:00:00",occurrence=525600,length=525600,holiday=335,name="Love is in the Air - Popularity Contest Winner: Stormwind",hardcoded=false,disabled=true,requiredPhase=0},
|
||||
[113]={start="2021-02-17 06:00:00",finish="2030-02-12 06:00:00",occurrence=525600,length=525600,holiday=335,name="Love is in the Air - Popularity Contest Winner: Orgrimmar",hardcoded=false,disabled=true,requiredPhase=0},
|
||||
[114]={start="2021-02-17 06:00:00",finish="2030-02-12 06:00:00",occurrence=525600,length=525600,holiday=335,name="Love is in the Air - Popularity Contest Winner: Thunder Bluff",hardcoded=false,disabled=true,requiredPhase=0},
|
||||
[115]={start="2021-02-17 06:00:00",finish="2030-02-12 06:00:00",occurrence=525600,length=525600,holiday=335,name="Love is in the Air - Popularity Contest Winner: Undercity",hardcoded=false,disabled=true,requiredPhase=0},
|
||||
[129]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=525600,length=999999999,holiday=0,name="Scourge Invasion - Phase 2 - Invasion Stormwind",hardcoded=false,disabled=false,requiredPhase=3},
|
||||
[130]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=525600,length=999999999,holiday=0,name="Scourge Invasion - Phase 2 - Invasion Undercity",hardcoded=false,disabled=false,requiredPhase=3},
|
||||
[150]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=525600,length=33720,holiday=0,name="Leprithus Spawn (Westfall)",hardcoded=true,disabled=false,requiredPhase=0},
|
||||
[151]={start="0000-00-00 00:00:00",finish="0000-00-00 00:00:00",occurrence=525600,length=33720,holiday=0,name="Fleshrippers Spawn (Westfall, Moonbrook)",hardcoded=true,disabled=false,requiredPhase=0},
|
||||
[152]={start="2022-01-02 01:00:00",finish="2030-04-01 01:00:00",occurrence=1440,length=60,holiday=0,name="Southshore Assassins",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[156]={start="2014-03-30 11:00:00",finish="2030-03-30 10:00:00",occurrence=1,length=2,holiday=0,name="DM release : Recipes and misc item",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[158]={start="2015-03-30 11:00:00",finish="2030-03-30 10:00:00",occurrence=1,length=2,holiday=0,name="1.10 Patch : Recipes",hardcoded=false,disabled=false,requiredPhase=2},
|
||||
[159]={start="2005-03-30 11:00:00",finish="2030-03-30 10:00:00",occurrence=1,length=2,holiday=0,name="DM Release : Cloth turning NPC",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[160]={start="2023-03-30 11:00:00",finish="2030-03-30 10:00:00",occurrence=1,length=2,holiday=0,name="1.10 Patch : t0.5 Quest Chain",hardcoded=false,disabled=false,requiredPhase=0},
|
||||
[161]={start="2017-01-02 01:00:00",finish="2030-12-31 19:00:00",occurrence=1,length=9999999999,holiday=0,name="Mirage Race",hardcoded=true,disabled=false,requiredPhase=0},
|
||||
[162]={start="2021-01-02 02:00:00",finish="2030-12-31 20:00:00",occurrence=1,length=9999999999,holiday=0,name="Uldum Boss",hardcoded=true,disabled=false,requiredPhase=0},
|
||||
[163]={start="2023-03-30 11:00:00",finish="2030-03-30 10:00:00",occurrence=1,length=2,holiday=0,name="1.6 Patch: BWL Attunement",hardcoded=false,disabled=false,requiredPhase=1},
|
||||
[164]={start="2023-03-30 11:00:00",finish="2030-03-30 10:00:00",occurrence=1,length=2,holiday=0,name="1.9 Patch: Quests",hardcoded=false,disabled=false,requiredPhase=2},
|
||||
}
|
||||
@@ -0,0 +1,244 @@
|
||||
-- Questie-Octo PvP quest type projection.
|
||||
-- Generated from the authoritative Turtle server quest_template supplied with the project.
|
||||
-- Type 41 is the canonical PvP quest type used by Questie 6.
|
||||
--
|
||||
-- The Blood Ring entries 41107-41110 are verified Turtle PvP quests whose
|
||||
-- current source rows report Type 0; Questie-Octo corrects those locally to 41.
|
||||
|
||||
QuestieOcto.PvPQuestTypes = {
|
||||
[1657] = 41,
|
||||
[1658] = 41,
|
||||
[5342] = 41,
|
||||
[5344] = 41,
|
||||
[6781] = 41,
|
||||
[6801] = 41,
|
||||
[6825] = 41,
|
||||
[6826] = 41,
|
||||
[6827] = 41,
|
||||
[6847] = 41,
|
||||
[6848] = 41,
|
||||
[6861] = 41,
|
||||
[6862] = 41,
|
||||
[6881] = 41,
|
||||
[6901] = 41,
|
||||
[6941] = 41,
|
||||
[6942] = 41,
|
||||
[6943] = 41,
|
||||
[7001] = 41,
|
||||
[7002] = 41,
|
||||
[7026] = 41,
|
||||
[7027] = 41,
|
||||
[7081] = 41,
|
||||
[7082] = 41,
|
||||
[7101] = 41,
|
||||
[7102] = 41,
|
||||
[7121] = 41,
|
||||
[7122] = 41,
|
||||
[7123] = 41,
|
||||
[7124] = 41,
|
||||
[7141] = 41,
|
||||
[7142] = 41,
|
||||
[7223] = 41,
|
||||
[7224] = 41,
|
||||
[7241] = 41,
|
||||
[7261] = 41,
|
||||
[7301] = 41,
|
||||
[7302] = 41,
|
||||
[7361] = 41,
|
||||
[7362] = 41,
|
||||
[7363] = 41,
|
||||
[7364] = 41,
|
||||
[7365] = 41,
|
||||
[7366] = 41,
|
||||
[7385] = 41,
|
||||
[7386] = 41,
|
||||
[7401] = 41,
|
||||
[7402] = 41,
|
||||
[7421] = 41,
|
||||
[7422] = 41,
|
||||
[7423] = 41,
|
||||
[7424] = 41,
|
||||
[7425] = 41,
|
||||
[7426] = 41,
|
||||
[7427] = 41,
|
||||
[7428] = 41,
|
||||
[7788] = 41,
|
||||
[7789] = 41,
|
||||
[7810] = 41,
|
||||
[7841] = 41,
|
||||
[7842] = 41,
|
||||
[7843] = 41,
|
||||
[7863] = 41,
|
||||
[7864] = 41,
|
||||
[7865] = 41,
|
||||
[7866] = 41,
|
||||
[7867] = 41,
|
||||
[7868] = 41,
|
||||
[7871] = 41,
|
||||
[7872] = 41,
|
||||
[7873] = 41,
|
||||
[7874] = 41,
|
||||
[7875] = 41,
|
||||
[7876] = 41,
|
||||
[7886] = 41,
|
||||
[7887] = 41,
|
||||
[7888] = 41,
|
||||
[7921] = 41,
|
||||
[7922] = 41,
|
||||
[7923] = 41,
|
||||
[7924] = 41,
|
||||
[7925] = 41,
|
||||
[8001] = 41,
|
||||
[8080] = 41,
|
||||
[8081] = 41,
|
||||
[8105] = 41,
|
||||
[8114] = 41,
|
||||
[8115] = 41,
|
||||
[8120] = 41,
|
||||
[8121] = 41,
|
||||
[8122] = 41,
|
||||
[8123] = 41,
|
||||
[8124] = 41,
|
||||
[8154] = 41,
|
||||
[8155] = 41,
|
||||
[8156] = 41,
|
||||
[8157] = 41,
|
||||
[8158] = 41,
|
||||
[8159] = 41,
|
||||
[8160] = 41,
|
||||
[8161] = 41,
|
||||
[8162] = 41,
|
||||
[8163] = 41,
|
||||
[8164] = 41,
|
||||
[8165] = 41,
|
||||
[8166] = 41,
|
||||
[8167] = 41,
|
||||
[8168] = 41,
|
||||
[8169] = 41,
|
||||
[8170] = 41,
|
||||
[8171] = 41,
|
||||
[8260] = 41,
|
||||
[8261] = 41,
|
||||
[8262] = 41,
|
||||
[8263] = 41,
|
||||
[8264] = 41,
|
||||
[8265] = 41,
|
||||
[8289] = 41,
|
||||
[8290] = 41,
|
||||
[8291] = 41,
|
||||
[8292] = 41,
|
||||
[8293] = 41,
|
||||
[8294] = 41,
|
||||
[8295] = 41,
|
||||
[8296] = 41,
|
||||
[8297] = 41,
|
||||
[8298] = 41,
|
||||
[8299] = 41,
|
||||
[8300] = 41,
|
||||
[8322] = 41,
|
||||
[8367] = 41,
|
||||
[8368] = 41,
|
||||
[8369] = 41,
|
||||
[8370] = 41,
|
||||
[8371] = 41,
|
||||
[8372] = 41,
|
||||
[8373] = 41,
|
||||
[8374] = 41,
|
||||
[8375] = 41,
|
||||
[8383] = 41,
|
||||
[8384] = 41,
|
||||
[8385] = 41,
|
||||
[8386] = 41,
|
||||
[8387] = 41,
|
||||
[8388] = 41,
|
||||
[8389] = 41,
|
||||
[8390] = 41,
|
||||
[8391] = 41,
|
||||
[8392] = 41,
|
||||
[8393] = 41,
|
||||
[8394] = 41,
|
||||
[8395] = 41,
|
||||
[8396] = 41,
|
||||
[8397] = 41,
|
||||
[8398] = 41,
|
||||
[8399] = 41,
|
||||
[8400] = 41,
|
||||
[8401] = 41,
|
||||
[8402] = 41,
|
||||
[8403] = 41,
|
||||
[8404] = 41,
|
||||
[8405] = 41,
|
||||
[8406] = 41,
|
||||
[8407] = 41,
|
||||
[8408] = 41,
|
||||
[8409] = 41,
|
||||
[8426] = 41,
|
||||
[8427] = 41,
|
||||
[8428] = 41,
|
||||
[8429] = 41,
|
||||
[8430] = 41,
|
||||
[8431] = 41,
|
||||
[8432] = 41,
|
||||
[8433] = 41,
|
||||
[8434] = 41,
|
||||
[8435] = 41,
|
||||
[8436] = 41,
|
||||
[8437] = 41,
|
||||
[8438] = 41,
|
||||
[8439] = 41,
|
||||
[8440] = 41,
|
||||
[8441] = 41,
|
||||
[8442] = 41,
|
||||
[8443] = 41,
|
||||
[8493] = 41,
|
||||
[8495] = 41,
|
||||
[8500] = 41,
|
||||
[8504] = 41,
|
||||
[8506] = 41,
|
||||
[8510] = 41,
|
||||
[8512] = 41,
|
||||
[8514] = 41,
|
||||
[8516] = 41,
|
||||
[8518] = 41,
|
||||
[8521] = 41,
|
||||
[8523] = 41,
|
||||
[8525] = 41,
|
||||
[8527] = 41,
|
||||
[8529] = 41,
|
||||
[8533] = 41,
|
||||
[8543] = 41,
|
||||
[8546] = 41,
|
||||
[8550] = 41,
|
||||
[8581] = 41,
|
||||
[8583] = 41,
|
||||
[8589] = 41,
|
||||
[8591] = 41,
|
||||
[8601] = 41,
|
||||
[8605] = 41,
|
||||
[8608] = 41,
|
||||
[8610] = 41,
|
||||
[8612] = 41,
|
||||
[8614] = 41,
|
||||
[8616] = 41,
|
||||
[8846] = 41,
|
||||
[8847] = 41,
|
||||
[8849] = 41,
|
||||
[8850] = 41,
|
||||
[8851] = 41,
|
||||
[8852] = 41,
|
||||
[8854] = 41,
|
||||
[8855] = 41,
|
||||
[9419] = 41,
|
||||
[9422] = 41,
|
||||
[9664] = 41,
|
||||
[9665] = 41,
|
||||
[40079] = 41,
|
||||
[41107] = 41, -- verified Blood Ring correction (server Type 0 -> 41)
|
||||
[41108] = 41, -- verified Blood Ring correction (server Type 0 -> 41)
|
||||
[41109] = 41, -- verified Blood Ring correction (server Type 0 -> 41)
|
||||
[41110] = 41, -- verified Blood Ring correction (server Type 0 -> 41)
|
||||
[42098] = 41,
|
||||
[42099] = 41,
|
||||
[140821] = 41,
|
||||
[1140820] = 41,
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,13 @@
|
||||
<Ui xmlns="http://www.blizzard.com/wow/ui/">
|
||||
<Include file="..\pfDB\items-turtle.lua"/>
|
||||
<Include file="..\pfDB\units-turtle.lua"/>
|
||||
<Include file="..\pfDB\objects-turtle.lua"/>
|
||||
<Include file="..\pfDB\refloot-turtle.lua"/>
|
||||
<Include file="..\pfDB\quests-itemreq-turtle.lua"/>
|
||||
<Include file="..\pfDB\quests-turtle.lua"/>
|
||||
<Include file="..\pfDB\patches-turtle.lua"/>
|
||||
<Include file="..\pfDB\zones-turtle.lua"/>
|
||||
<Include file="..\pfDB\minimap-turtle.lua"/>
|
||||
<Include file="..\pfDB\areatrigger-turtle.lua"/>
|
||||
<Include file="..\pfDB\meta-turtle.lua"/>
|
||||
</Ui>
|
||||
@@ -0,0 +1,13 @@
|
||||
<Ui xmlns="http://www.blizzard.com/wow/ui/">
|
||||
<Include file="..\pfDB\init.lua"/>
|
||||
<Include file="..\pfDB\items.lua"/>
|
||||
<Include file="..\pfDB\units.lua"/>
|
||||
<Include file="..\pfDB\objects.lua"/>
|
||||
<Include file="..\pfDB\refloot.lua"/>
|
||||
<Include file="..\pfDB\quests-itemreq.lua"/>
|
||||
<Include file="..\pfDB\quests.lua"/>
|
||||
<Include file="..\pfDB\zones.lua"/>
|
||||
<Include file="..\pfDB\minimap.lua"/>
|
||||
<Include file="..\pfDB\areatrigger.lua"/>
|
||||
<Include file="..\pfDB\meta.lua"/>
|
||||
</Ui>
|
||||
@@ -0,0 +1,8 @@
|
||||
<Ui xmlns="http://www.blizzard.com/wow/ui/">
|
||||
<Include file="..\pfDB\enUS\items-turtle.lua"/>
|
||||
<Include file="..\pfDB\enUS\units-turtle.lua"/>
|
||||
<Include file="..\pfDB\enUS\objects-turtle.lua"/>
|
||||
<Include file="..\pfDB\enUS\quests-turtle.lua"/>
|
||||
<Include file="..\pfDB\enUS\zones-turtle.lua"/>
|
||||
<Include file="..\pfDB\enUS\professions-turtle.lua"/>
|
||||
</Ui>
|
||||
@@ -0,0 +1,8 @@
|
||||
<Ui xmlns="http://www.blizzard.com/wow/ui/">
|
||||
<Include file="..\pfDB\enUS\items.lua"/>
|
||||
<Include file="..\pfDB\enUS\units.lua"/>
|
||||
<Include file="..\pfDB\enUS\objects.lua"/>
|
||||
<Include file="..\pfDB\enUS\quests.lua"/>
|
||||
<Include file="..\pfDB\enUS\zones.lua"/>
|
||||
<Include file="..\pfDB\enUS\professions.lua"/>
|
||||
</Ui>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,136 @@
|
||||
pfDB["professions"]["enUS-turtle"] = {
|
||||
[6] = "Frost",
|
||||
[8] = "Fire",
|
||||
[26] = "Arms",
|
||||
[38] = "Combat",
|
||||
[39] = "Subtlety",
|
||||
[40] = "Poisons",
|
||||
[43] = "Swords",
|
||||
[44] = "Axes",
|
||||
[45] = "Bows",
|
||||
[46] = "Guns",
|
||||
[50] = "Beast Mastery",
|
||||
[51] = "Survival",
|
||||
[54] = "Maces",
|
||||
[55] = "Two-Handed Swords",
|
||||
[56] = "Holy",
|
||||
[78] = "Shadow Magic",
|
||||
[95] = "Defense",
|
||||
[98] = "Language: Common",
|
||||
[101] = "Dwarven Racial",
|
||||
[109] = "Language: Orcish",
|
||||
[111] = "Language: Dwarven",
|
||||
[113] = "Language: Darnassian",
|
||||
[115] = "Language: Taurahe",
|
||||
[118] = "Dual Wield",
|
||||
[124] = "Tauren Racial",
|
||||
[125] = "Orc Racial",
|
||||
[126] = "Night Elf Racial",
|
||||
[129] = "First Aid",
|
||||
[134] = "Feral Combat",
|
||||
[136] = "Staves",
|
||||
[137] = "Language: Thalassian",
|
||||
[138] = "Language: Draconic",
|
||||
[139] = "Language: Demon Tongue",
|
||||
[140] = "Language: Titan",
|
||||
[141] = "Language: Old Tongue",
|
||||
[142] = "Survival",
|
||||
[148] = "Horse Riding",
|
||||
[149] = "Wolf Riding",
|
||||
[150] = "Tiger Riding",
|
||||
[152] = "Ram Riding",
|
||||
[155] = "Swimming",
|
||||
[160] = "Two-Handed Maces",
|
||||
[162] = "Unarmed",
|
||||
[163] = "Marksmanship",
|
||||
[164] = "Blacksmithing",
|
||||
[165] = "Leatherworking",
|
||||
[171] = "Alchemy",
|
||||
[172] = "Two-Handed Axes",
|
||||
[173] = "Daggers",
|
||||
[176] = "Thrown",
|
||||
[182] = "Herbalism",
|
||||
[183] = "GENERIC (DND)",
|
||||
[184] = "Retribution",
|
||||
[185] = "Cooking",
|
||||
[186] = "Mining",
|
||||
[188] = "Pet - Imp",
|
||||
[189] = "Pet - Felhunter",
|
||||
[197] = "Tailoring",
|
||||
[202] = "Engineering",
|
||||
[203] = "Pet - Spider",
|
||||
[204] = "Pet - Voidwalker",
|
||||
[205] = "Pet - Succubus",
|
||||
[206] = "Pet - Infernal",
|
||||
[207] = "Pet - Doomguard",
|
||||
[208] = "Pet - Wolf",
|
||||
[209] = "Pet - Cat",
|
||||
[210] = "Pet - Bear",
|
||||
[211] = "Pet - Boar",
|
||||
[212] = "Pet - Crocilisk",
|
||||
[213] = "Pet - Carrion Bird",
|
||||
[214] = "Pet - Crab",
|
||||
[215] = "Pet - Gorilla",
|
||||
[217] = "Pet - Raptor",
|
||||
[218] = "Pet - Tallstrider",
|
||||
[220] = "Racial - Undead",
|
||||
[226] = "Crossbows",
|
||||
[227] = "Spears",
|
||||
[228] = "Wands",
|
||||
[229] = "Polearms",
|
||||
[236] = "Pet - Scorpid",
|
||||
[237] = "Arcane",
|
||||
[251] = "Pet - Turtle",
|
||||
[253] = "Assassination",
|
||||
[256] = "Fury",
|
||||
[257] = "Protection",
|
||||
[261] = "Beast Training",
|
||||
[267] = "Protection",
|
||||
[270] = "Pet - Generic",
|
||||
[293] = "Plate Mail",
|
||||
[313] = "Language: Gnomish",
|
||||
[315] = "Language: Troll",
|
||||
[333] = "Enchanting",
|
||||
[354] = "Demonology",
|
||||
[355] = "Affliction",
|
||||
[356] = "Fishing",
|
||||
[373] = "Enhancement",
|
||||
[374] = "Restoration",
|
||||
[375] = "Elemental Combat",
|
||||
[393] = "Skinning",
|
||||
[413] = "Mail",
|
||||
[414] = "Leather",
|
||||
[415] = "Cloth",
|
||||
[433] = "Shield",
|
||||
[473] = "Fist Weapons",
|
||||
[533] = "Raptor Riding",
|
||||
[553] = "Mechanostrider Piloting",
|
||||
[554] = "Undead Horsemanship",
|
||||
[573] = "Restoration",
|
||||
[574] = "Balance",
|
||||
[593] = "Destruction",
|
||||
[594] = "Holy",
|
||||
[613] = "Discipline",
|
||||
[633] = "Lockpicking",
|
||||
[653] = "Pet - Bat",
|
||||
[654] = "Pet - Hyena",
|
||||
[655] = "Pet - Owl",
|
||||
[656] = "Pet - Wind Serpent",
|
||||
[673] = "Language: Gutterspeak",
|
||||
[713] = "Kodo Riding",
|
||||
[733] = "Racial - Troll",
|
||||
[753] = "Racial - Gnome",
|
||||
[754] = "Racial - Human",
|
||||
[755] = "Jewelcrafting",
|
||||
[756] = "Racial - Elf",
|
||||
[758] = "Pet - Event - Remote Control",
|
||||
[762] = "Riding",
|
||||
[790] = "Racial - Goblin",
|
||||
[792] = "Language: Goblin",
|
||||
[1005] = "ZzCompanions",
|
||||
[1006] = "ZMounts",
|
||||
[1007] = "ZzzGlyphs",
|
||||
[1008] = "ZzzzToys",
|
||||
[1009] = "Pet - Serpent",
|
||||
[1010] = "Pet - Fox",
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
pfDB["professions"]["enUS"] = {
|
||||
[6] = "Frost",
|
||||
[8] = "Fire",
|
||||
[26] = "Arms",
|
||||
[38] = "Combat",
|
||||
[39] = "Subtlety",
|
||||
[40] = "Poisons",
|
||||
[43] = "Swords",
|
||||
[44] = "Axes",
|
||||
[45] = "Bows",
|
||||
[46] = "Guns",
|
||||
[50] = "Beast Mastery",
|
||||
[51] = "Survival",
|
||||
[54] = "Maces",
|
||||
[55] = "Two-Handed Swords",
|
||||
[56] = "Holy",
|
||||
[78] = "Shadow Magic",
|
||||
[95] = "Defense",
|
||||
[98] = "Language: Common",
|
||||
[101] = "Dwarven Racial",
|
||||
[109] = "Language: Orcish",
|
||||
[111] = "Language: Dwarven",
|
||||
[113] = "Language: Darnassian",
|
||||
[115] = "Language: Taurahe",
|
||||
[118] = "Dual Wield",
|
||||
[124] = "Tauren Racial",
|
||||
[125] = "Orc Racial",
|
||||
[126] = "Night Elf Racial",
|
||||
[129] = "First Aid",
|
||||
[134] = "Feral Combat",
|
||||
[136] = "Staves",
|
||||
[137] = "Language: Thalassian",
|
||||
[138] = "Language: Draconic",
|
||||
[139] = "Language: Demon Tongue",
|
||||
[140] = "Language: Titan",
|
||||
[141] = "Language: Old Tongue",
|
||||
[142] = "Survival",
|
||||
[148] = "Horse Riding",
|
||||
[149] = "Wolf Riding",
|
||||
[150] = "Tiger Riding",
|
||||
[152] = "Ram Riding",
|
||||
[155] = "Swimming",
|
||||
[160] = "Two-Handed Maces",
|
||||
[162] = "Unarmed",
|
||||
[163] = "Marksmanship",
|
||||
[164] = "Blacksmithing",
|
||||
[165] = "Leatherworking",
|
||||
[171] = "Alchemy",
|
||||
[172] = "Two-Handed Axes",
|
||||
[173] = "Daggers",
|
||||
[176] = "Thrown",
|
||||
[182] = "Herbalism",
|
||||
[183] = "GENERIC (DND)",
|
||||
[184] = "Retribution",
|
||||
[185] = "Cooking",
|
||||
[186] = "Mining",
|
||||
[188] = "Pet - Imp",
|
||||
[189] = "Pet - Felhunter",
|
||||
[197] = "Tailoring",
|
||||
[202] = "Engineering",
|
||||
[203] = "Pet - Spider",
|
||||
[204] = "Pet - Voidwalker",
|
||||
[205] = "Pet - Succubus",
|
||||
[206] = "Pet - Infernal",
|
||||
[207] = "Pet - Doomguard",
|
||||
[208] = "Pet - Wolf",
|
||||
[209] = "Pet - Cat",
|
||||
[210] = "Pet - Bear",
|
||||
[211] = "Pet - Boar",
|
||||
[212] = "Pet - Crocilisk",
|
||||
[213] = "Pet - Carrion Bird",
|
||||
[214] = "Pet - Crab",
|
||||
[215] = "Pet - Gorilla",
|
||||
[217] = "Pet - Raptor",
|
||||
[218] = "Pet - Tallstrider",
|
||||
[220] = "Racial - Undead",
|
||||
[226] = "Crossbows",
|
||||
[228] = "Wands",
|
||||
[229] = "Polearms",
|
||||
[236] = "Pet - Scorpid",
|
||||
[237] = "Arcane",
|
||||
[251] = "Pet - Turtle",
|
||||
[253] = "Assassination",
|
||||
[256] = "Fury",
|
||||
[257] = "Protection",
|
||||
[261] = "Beast Training",
|
||||
[267] = "Protection",
|
||||
[270] = "Pet - Generic",
|
||||
[293] = "Plate Mail",
|
||||
[313] = "Language: Gnomish",
|
||||
[315] = "Language: Troll",
|
||||
[333] = "Enchanting",
|
||||
[354] = "Demonology",
|
||||
[355] = "Affliction",
|
||||
[356] = "Fishing",
|
||||
[373] = "Enhancement",
|
||||
[374] = "Restoration",
|
||||
[375] = "Elemental Combat",
|
||||
[393] = "Skinning",
|
||||
[413] = "Mail",
|
||||
[414] = "Leather",
|
||||
[415] = "Cloth",
|
||||
[433] = "Shield",
|
||||
[473] = "Fist Weapons",
|
||||
[533] = "Raptor Riding",
|
||||
[553] = "Mechanostrider Piloting",
|
||||
[554] = "Undead Horsemanship",
|
||||
[573] = "Restoration",
|
||||
[574] = "Balance",
|
||||
[593] = "Destruction",
|
||||
[594] = "Holy",
|
||||
[613] = "Discipline",
|
||||
[633] = "Lockpicking",
|
||||
[653] = "Pet - Bat",
|
||||
[654] = "Pet - Hyena",
|
||||
[655] = "Pet - Owl",
|
||||
[656] = "Pet - Wind Serpent",
|
||||
[673] = "Language: Gutterspeak",
|
||||
[713] = "Kodo Riding",
|
||||
[733] = "Racial - Troll",
|
||||
[753] = "Racial - Gnome",
|
||||
[754] = "Racial - Human",
|
||||
[758] = "Pet - Event - Remote Control",
|
||||
[762] = "Riding",
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,492 @@
|
||||
pfDB["zones"]["enUS-turtle"] = {
|
||||
[65] = "_",
|
||||
[296] = "South Seas",
|
||||
[409] = "Lapidis Isle",
|
||||
[2037] = "Quel\'Thalas",
|
||||
[2038] = "UNUSEDShadowfang Keep 003",
|
||||
[2040] = "Alah\'Thalas",
|
||||
[2041] = "Amani\'Alor",
|
||||
[2137] = "Windswept Heights",
|
||||
[3430] = "Eversong Woods",
|
||||
[3431] = "Sunstrider Isle",
|
||||
[3432] = "Shrine of Dath\'Remar",
|
||||
[3433] = "Ghostlands",
|
||||
[3434] = "Scarab Terrace",
|
||||
[3435] = "General\'s Terrace",
|
||||
[3436] = "The Reservoir",
|
||||
[3437] = "The Hatchery",
|
||||
[3438] = "The Comb",
|
||||
[3439] = "Watchers\' Terrace",
|
||||
[3440] = "Scarab Terrace",
|
||||
[3441] = "General\'s Terrace",
|
||||
[3442] = "The Reservoir",
|
||||
[3443] = "The Hatchery",
|
||||
[3444] = "The Comb",
|
||||
[3445] = "Watchers\' Terrace",
|
||||
[3455] = "The North Sea",
|
||||
[3457] = "Tower of Karazhan",
|
||||
[3460] = "Golden Strand",
|
||||
[3461] = "Sunsail Anchorage",
|
||||
[3462] = "Fairbreeze Village",
|
||||
[3463] = "Magisters Gate",
|
||||
[3464] = "Farstrider Retreat",
|
||||
[3465] = "North Sanctum",
|
||||
[3466] = "West Sanctum",
|
||||
[3467] = "East Sanctum",
|
||||
[3468] = "Saltheril\'s Haven",
|
||||
[3469] = "Thuron\'s Livery",
|
||||
[3470] = "Stillwhisper Pond",
|
||||
[3471] = "The Living Wood",
|
||||
[3472] = "Azurebreeze Coast",
|
||||
[3473] = "Lake Elrendar",
|
||||
[3474] = "The Scorched Grove",
|
||||
[3475] = "Zeb\'Watha",
|
||||
[3476] = "Tor\'Watha",
|
||||
[3479] = "The Veiled Sea",
|
||||
[3480] = "Duskwither Grounds",
|
||||
[3481] = "Duskwither Spire",
|
||||
[3482] = "The Dead Scar",
|
||||
[3484] = "The Sunspire",
|
||||
[3485] = "Falthrien Academy",
|
||||
[3487] = "Silvermoon City",
|
||||
[3488] = "Tranquillien",
|
||||
[3489] = "Suncrown Village",
|
||||
[3490] = "Goldenmist Village",
|
||||
[3491] = "Windrunner Village",
|
||||
[3492] = "Windrunner Spire",
|
||||
[3493] = "Sanctum of the Sun",
|
||||
[3494] = "Sanctum of the Moon",
|
||||
[3495] = "Dawnstar Spire",
|
||||
[3496] = "Farstrider Enclave",
|
||||
[3497] = "An\'daroth",
|
||||
[3498] = "An\'telas",
|
||||
[3499] = "An\'owyn",
|
||||
[3500] = "Deatholme",
|
||||
[3501] = "Bleeding Ziggurat",
|
||||
[3502] = "Howling Ziggurat",
|
||||
[3503] = "Shalandis Isle",
|
||||
[3504] = "Toryl Estate",
|
||||
[3505] = "Underlight Mines",
|
||||
[3506] = "Andilien Estate",
|
||||
[3507] = "Hatchet Hills",
|
||||
[3508] = "Amani Pass",
|
||||
[3509] = "Sungraze Peak",
|
||||
[3510] = "Amani Catacombs",
|
||||
[3511] = "Tower of the Damned",
|
||||
[3512] = "Zeb\'Sora",
|
||||
[3513] = "Lake Elrendar",
|
||||
[3514] = "The Dead Scar",
|
||||
[3515] = "Elrendar River",
|
||||
[3516] = "Zeb\'Tela",
|
||||
[3517] = "Zeb\'Nowa",
|
||||
[3531] = "Murder Row",
|
||||
[3532] = "Dawning Lane",
|
||||
[3533] = "Ruins of Silvermoon",
|
||||
[3534] = "Feth\'s Way",
|
||||
[3558] = "Elrendar Falls",
|
||||
[3805] = "Zul\'Aman",
|
||||
[3881] = "Silver Sun Mine",
|
||||
[3882] = "Citadel of the Sun",
|
||||
[3883] = "Golden Dawn Institute",
|
||||
[4010] = "Mudsprocket",
|
||||
[4011] = "Venture Company Camp",
|
||||
[4012] = "Scarlet Enclave",
|
||||
[4013] = "Lordaeron Arena",
|
||||
[4014] = "Blood Ring",
|
||||
[4015] = "Isle of the Spirits",
|
||||
[4016] = "Kamio",
|
||||
[4017] = "Kontsuma",
|
||||
[4018] = "Hawk\'s Vigil",
|
||||
[4019] = "Dun Agrath",
|
||||
[4020] = "Ironforge Airfields",
|
||||
[4021] = "Sparkwater Port",
|
||||
[4022] = "Scarlet Citadel",
|
||||
[4046] = "Direhorn Post",
|
||||
[4047] = "Nat\'s Landing",
|
||||
[4067] = "Plaguewood Tower",
|
||||
[4298] = "Plaguelands",
|
||||
[4343] = "New Avalon",
|
||||
[4346] = "New Avalon Town Hall",
|
||||
[4347] = "Havenshire",
|
||||
[4354] = "Light\'s Point",
|
||||
[4356] = "Gloom Hill",
|
||||
[4358] = "Tyr\'s Hand",
|
||||
[4359] = "King\'s Harbor",
|
||||
[4365] = "Havenshire Mine",
|
||||
[4381] = "Waygate",
|
||||
[4382] = "Shaper\'s Terrace",
|
||||
[4411] = "Stormwind Harbor",
|
||||
[4636] = "The Noxious Pass",
|
||||
[4688] = "The Turtle Farm",
|
||||
[5000] = "Thrallmar",
|
||||
[5001] = "Honor Hold",
|
||||
[5002] = "Sha\'naar",
|
||||
[5003] = "Illidari Point",
|
||||
[5004] = "Forge Camp: Rage",
|
||||
[5005] = "Watcher\'s Rise",
|
||||
[5006] = "Dark Portal",
|
||||
[5007] = "Pools of Aggonar",
|
||||
[5008] = "Devouring Flats",
|
||||
[5009] = "Shattered Wastes",
|
||||
[5010] = "Tanaan Crag",
|
||||
[5011] = "Farwell Stead",
|
||||
[5012] = "Wildtusk Village",
|
||||
[5013] = "Ruins of Zul\'Rasaz",
|
||||
[5014] = "The Rasaz Trails",
|
||||
[5015] = "The Highlands",
|
||||
[5016] = "The Grim Reaches",
|
||||
[5017] = "Dun Galar",
|
||||
[5018] = "Flickerlode Mine",
|
||||
[5019] = "Grimstone Field",
|
||||
[5020] = "The Parched Basin",
|
||||
[5021] = "The Grim Batol Memorial",
|
||||
[5022] = "Karfang Retreat",
|
||||
[5023] = "Sunnyglade Valley",
|
||||
[5024] = "Icepoint Rock",
|
||||
[5025] = "The Hidden Grove",
|
||||
[5026] = "The Perch",
|
||||
[5027] = "North Sea",
|
||||
[5028] = "Steepcliff Port",
|
||||
[5029] = "The Whispering Forest",
|
||||
[5030] = "The Rogue Heights",
|
||||
[5031] = "The Lafford House",
|
||||
[5032] = "The Garrick Stead",
|
||||
[5033] = "Crumblepoint Tower",
|
||||
[5034] = "Shatteridge Tower",
|
||||
[5035] = "The Remnants Camp",
|
||||
[5036] = "The Blacktower Inn",
|
||||
[5037] = "The Corinth Farmstead",
|
||||
[5038] = "The Jagged Hills",
|
||||
[5039] = "Gracestone Mine",
|
||||
[5040] = "Glenshire",
|
||||
[5041] = "Ishnu\'Danil",
|
||||
[5042] = "Shalla\'Aran",
|
||||
[5043] = "Shank\'s Reef",
|
||||
[5044] = "Crown Island",
|
||||
[5045] = "The Rock",
|
||||
[5046] = "Bright Coast",
|
||||
[5047] = "Zul\'Hazu",
|
||||
[5048] = "The Wallowing Coast",
|
||||
[5049] = "Hazzuri Glade",
|
||||
[5050] = "Gor\'dosh Heights",
|
||||
[5051] = "Caelan\'s Rest",
|
||||
[5052] = "Kaneq\'nuun",
|
||||
[5053] = "Moomoo Grove",
|
||||
[5054] = "The Broken Reef",
|
||||
[5055] = "Deeptide Sanctum",
|
||||
[5056] = "The Silver Coast",
|
||||
[5057] = "The Silver Sandbar",
|
||||
[5058] = "Zul\'Razar",
|
||||
[5059] = "The Tangled Wood",
|
||||
[5060] = "The Jade Mine",
|
||||
[5061] = "Ruins of Zul\'Razar",
|
||||
[5062] = "Gillijim Strand",
|
||||
[5063] = "Deepneck Cove",
|
||||
[5064] = "Gillijim Canyon",
|
||||
[5065] = "Maul\'ogg Refuge",
|
||||
[5066] = "Maul\'ogg Post",
|
||||
[5067] = "Kalkor Point",
|
||||
[5068] = "Kazon Island",
|
||||
[5069] = "The Southsea Sandbar",
|
||||
[5070] = "Distillery Island",
|
||||
[5071] = "Faelon\'s Folly",
|
||||
[5072] = "The Tower of Lapidis",
|
||||
[5073] = "Flaxwhisker Front",
|
||||
[5074] = "Bloodfist Point",
|
||||
[5075] = "Sorrowguard Keep",
|
||||
[5076] = "Tamatsune Shrine",
|
||||
[5077] = "Crescent Grove",
|
||||
[5078] = "Vilethorn Scar",
|
||||
[5079] = "Nalash\'ir Ruins",
|
||||
[5080] = "Tsatsuri Wilds",
|
||||
[5081] = "Kontsuma Logging Camp",
|
||||
[5082] = "Umikari Strand",
|
||||
[5083] = "Konko Depths",
|
||||
[5084] = "Bloodsail Retreat",
|
||||
[5085] = "Kontsuma Market",
|
||||
[5086] = "Karazhan Crypt",
|
||||
[5087] = "Stormwind Vault",
|
||||
[5088] = "Everwinter Vale",
|
||||
[5089] = "Kontsuma Harbor",
|
||||
[5090] = "The Dungeon",
|
||||
[5091] = "Frostmane Retreat",
|
||||
[5092] = "Zul\'Drakash",
|
||||
[5093] = "Karfang Hold",
|
||||
[5094] = "Gallant Square",
|
||||
[5095] = "Livingstone Croft",
|
||||
[5096] = "Red Cloud Roost",
|
||||
[5097] = "Emerald Sanctum",
|
||||
[5098] = "Hateforge Quarry",
|
||||
[5099] = "Sandmoon Village",
|
||||
[5100] = "Suntail Pass",
|
||||
[5101] = "Hateforge Excavation",
|
||||
[5102] = "Gartside Plot",
|
||||
[5103] = "Hateforge Quarry",
|
||||
[5104] = "Ruins of Corthan",
|
||||
[5105] = "Temple of Corthan",
|
||||
[5106] = "Angor Digsite",
|
||||
[5107] = "Ruins of Zeth",
|
||||
[5108] = "Crystalline Oasis",
|
||||
[5109] = "Crystalline Pinnacle",
|
||||
[5110] = "Redbrand\'s Digsite",
|
||||
[5111] = "Scalebane Ridge",
|
||||
[5112] = "Blackhorn Village",
|
||||
[5113] = "Deserter\'s Hideout",
|
||||
[5114] = "Westhaven Hollow",
|
||||
[5115] = "Davenburg",
|
||||
[5116] = "Anchor\'s Edge",
|
||||
[5117] = "Blacksand Oil Fields",
|
||||
[5118] = "Powder Town",
|
||||
[5119] = "Bramblethorn Pass",
|
||||
[5120] = "Bael Hardul",
|
||||
[5121] = "Tel\'Abim",
|
||||
[5122] = "The Shallow Strand",
|
||||
[5123] = "Tel Co. Basecamp",
|
||||
[5124] = "Bixxle\'s Storehouse",
|
||||
[5125] = "Highvale Rise",
|
||||
[5126] = "The Derelict Camp",
|
||||
[5127] = "Tazzo\'s Shack",
|
||||
[5128] = "The Jagged Isles",
|
||||
[5129] = "The Washing Shore",
|
||||
[5130] = "Winter Veil Vale",
|
||||
[5131] = "Icepaw Village",
|
||||
[5132] = "Shadowfang Keep",
|
||||
[5134] = "Gnomeregan",
|
||||
[5135] = "Scarlet Monastery Library",
|
||||
[5136] = "Scarlet Monastery Graveyard",
|
||||
[5137] = "The Temple of Atal\'Hakkar",
|
||||
[5138] = "The Deadmines",
|
||||
[5139] = "Blackrock Spire",
|
||||
[5140] = "Blackrock Depths",
|
||||
[5142] = "Scholomance",
|
||||
[5144] = "Deeprun Tram",
|
||||
[5145] = "Dire Maul",
|
||||
[5146] = "Blackwing Lair",
|
||||
[5147] = "Ahn\'Qiraj",
|
||||
[5148] = "The Upper Necropolis",
|
||||
[5150] = "Shadowfang Keep",
|
||||
[5152] = "Gnomeregan",
|
||||
[5153] = "Scarlet Monastery Armory",
|
||||
[5154] = "The Temple of Atal\'Hakkar",
|
||||
[5155] = "Blackrock Spire",
|
||||
[5156] = "Scholomance",
|
||||
[5157] = "Dire Maul",
|
||||
[5158] = "Blackwing Lair",
|
||||
[5161] = "Shadowfang Keep",
|
||||
[5162] = "Gnomeregan",
|
||||
[5163] = "Scarlet Monastery Cathedral",
|
||||
[5164] = "Blackrock Spire",
|
||||
[5165] = "Scholomance",
|
||||
[5166] = "Dire Maul",
|
||||
[5167] = "Blackwing Lair",
|
||||
[5169] = "Shadowfang Keep",
|
||||
[5170] = "Blackrock Spire",
|
||||
[5171] = "Dire Maul",
|
||||
[5173] = "Shadowfang Keep",
|
||||
[5174] = "Blackrock Spire",
|
||||
[5175] = "Dire Maul",
|
||||
[5177] = "Shadowfang Keep",
|
||||
[5178] = "Blackrock Spire",
|
||||
[5179] = "Gilneas",
|
||||
[5180] = "Gilneas City",
|
||||
[5181] = "Ravenshire",
|
||||
[5182] = "Ravenwood Keep",
|
||||
[5183] = "Brol\'ok Mound",
|
||||
[5184] = "Southmire Orchard",
|
||||
[5185] = "Hollow Web Woods",
|
||||
[5186] = "Hollow Web Cemetery",
|
||||
[5187] = "Shademore Tavern",
|
||||
[5188] = "Ruins of Greyshire",
|
||||
[5189] = "Northgate Tower",
|
||||
[5190] = "Westgate Tower",
|
||||
[5191] = "Rosewick Plantation",
|
||||
[5192] = "Glaymore Stead",
|
||||
[5193] = "Vagrant Encampment",
|
||||
[5194] = "Ebonmere Farm",
|
||||
[5195] = "The Overgrown Acre",
|
||||
[5196] = "The Dryrock Pit",
|
||||
[5197] = "The Dryrock Mine",
|
||||
[5198] = "Freyshear Keep",
|
||||
[5199] = "Greymane\'s Watch",
|
||||
[5200] = "Oldrock Pass",
|
||||
[5201] = "Stillward Church",
|
||||
[5202] = "Mossgrove Farm",
|
||||
[5203] = "The Greymane Wall",
|
||||
[5204] = "The Black Morass",
|
||||
[5205] = "Dryrock Valley",
|
||||
[5206] = "Blackthorn\'s Camp",
|
||||
[5207] = "Dawnstone Mine",
|
||||
[5208] = "Gilneas City",
|
||||
[5209] = "Greymane Tower",
|
||||
[5210] = "Chimaera Roost Vale",
|
||||
[5211] = "Gnomeregan Reclamation Facility",
|
||||
[5212] = "Bleakhollow Crater",
|
||||
[5213] = "Nordrassil Glade",
|
||||
[5214] = "Nordanaar",
|
||||
[5215] = "Barkskin Plateau",
|
||||
[5216] = "Barkskin Village",
|
||||
[5217] = "Circle of Power",
|
||||
[5218] = "The Ruins of Telennas",
|
||||
[5219] = "Zul\'Hatha",
|
||||
[5220] = "Darkhollow Pass",
|
||||
[5221] = "The Emerald Gateway",
|
||||
[5222] = "Darkroot Cave",
|
||||
[5223] = "Barkskin Hold",
|
||||
[5224] = "Shrine of the Betrayer",
|
||||
[5225] = "Thalassian Highlands",
|
||||
[5526] = "Wretched Ghetto",
|
||||
[5527] = "Ballador\'s Chapel",
|
||||
[5528] = "Felstrider Retreat",
|
||||
[5529] = "The Farstride",
|
||||
[5530] = "Deepmurk Cave",
|
||||
[5531] = "Isle of Eternal Autumn",
|
||||
[5532] = "Anasterian Park",
|
||||
[5533] = "Brinthilien",
|
||||
[5534] = "Ruins of Nashal\'aran",
|
||||
[5535] = "The Scourged Pass",
|
||||
[5536] = "Blackstone Island",
|
||||
[5537] = "Rustgate Ridge",
|
||||
[5538] = "Black Ash Coalpits",
|
||||
[5539] = "Black Ash Mine",
|
||||
[5540] = "The Water Hole",
|
||||
[5541] = "Gazzik\'s Workshop",
|
||||
[5542] = "Venture Co. Slums",
|
||||
[5543] = "Rustgate Lumber Yard",
|
||||
[5544] = "Thaumarium",
|
||||
[5545] = "Silver Covenant Camp",
|
||||
[5546] = "The Last Runestone",
|
||||
[5547] = "Forlorn Summit",
|
||||
[5548] = "Broken Cliff Mine",
|
||||
[5550] = "Ruins of Grim Batol",
|
||||
[5552] = "The Bazaar",
|
||||
[5553] = "Windrunner Pier",
|
||||
[5554] = "Sunsworn Mansion",
|
||||
[5555] = "Regency Spire",
|
||||
[5556] = "Feralkin Cave",
|
||||
[5557] = "The Rock of Desolation",
|
||||
[5558] = "The Rock of Desolation",
|
||||
[5559] = "Sanv Tribe Village",
|
||||
[5560] = "The Seat of Desolation",
|
||||
[5561] = "Balor",
|
||||
[5562] = "Gullwing Wreckage",
|
||||
[5563] = "Bilgerat Compound",
|
||||
[5564] = "SI:7 Outpost",
|
||||
[5565] = "Ruins of Breezehaven",
|
||||
[5566] = "Croaking Plateau",
|
||||
[5567] = "Langston Orchard",
|
||||
[5568] = "Sorrowmore Lake",
|
||||
[5569] = "Scurrying Thicket",
|
||||
[5570] = "Stormwrought Castle",
|
||||
[5571] = "Stormreaver Spire",
|
||||
[5572] = "Windrock Cliffs",
|
||||
[5573] = "Treacherous Crags",
|
||||
[5574] = "Vander Farmstead",
|
||||
[5575] = "Grahan Estate",
|
||||
[5576] = "Stormbreaker Point",
|
||||
[5579] = "Temple of Aka\'Sha",
|
||||
[5580] = "Redwall Keep",
|
||||
[5581] = "Northwind",
|
||||
[5582] = "Merchant\'s Highroad",
|
||||
[5583] = "Ambershire",
|
||||
[5584] = "Jousting Grounds",
|
||||
[5585] = "Amberwood Keep",
|
||||
[5586] = "Auburn Forest",
|
||||
[5587] = "Crystal Falls",
|
||||
[5588] = "Crawford Winery",
|
||||
[5589] = "Northwind Logging Camp",
|
||||
[5590] = "Witch Coven",
|
||||
[5591] = "Ruins of Birkhaven",
|
||||
[5592] = "Mildenhall Horse Farm",
|
||||
[5593] = "Sherwood Quarry",
|
||||
[5594] = "Blackrock Breach",
|
||||
[5595] = "Grimmen Lake",
|
||||
[5596] = "Abbey Gardens",
|
||||
[5597] = "Stillheart Port",
|
||||
[5598] = "Earthen Ring",
|
||||
[5599] = "Rugford\'s Mountain Rest",
|
||||
[5600] = "Dragonmaw Retreat",
|
||||
[5601] = "Dragonmaw Retreat",
|
||||
[5602] = "Grim Reaches",
|
||||
[5603] = "Dun Kithas",
|
||||
[5604] = "Grim Batol Burial Grounds",
|
||||
[5605] = "Davingrad\'s Camp",
|
||||
[5606] = "The Grim Hollow",
|
||||
[5607] = "Lake Kithas",
|
||||
[5608] = "Slatebeard\'s Forge",
|
||||
[5609] = "The High Pass",
|
||||
[5610] = "Baggoth\'s Wall",
|
||||
[5611] = "Sal\'Galaz Mines",
|
||||
[5612] = "East Ridge Outpost",
|
||||
[5613] = "Baggoth\'s Rampart",
|
||||
[5614] = "Ruins of Stolgaz Keep",
|
||||
[5615] = "Groldan\'s Excavation",
|
||||
[5616] = "Zarm\'geth Stronghold",
|
||||
[5617] = "Geth\'kar",
|
||||
[5618] = "Zarm\'geth Point",
|
||||
[5619] = "Shatterblade Post",
|
||||
[5620] = "Grim Batol Memorial",
|
||||
[5621] = "Brangar\'s Folly",
|
||||
[5622] = "Tower of Magilou",
|
||||
[5623] = "Bristlewhisker Cavern",
|
||||
[5624] = "Amberpaw Hideout",
|
||||
[5625] = "Northridge Point",
|
||||
[5626] = "Cinderfall Pass",
|
||||
[5627] = "Ursan Heights",
|
||||
[5628] = "Stormwrought Ruins",
|
||||
[5629] = "Hand of Mephistroth",
|
||||
[5630] = "Barleycrest Farmstead",
|
||||
[5631] = "Incindis\' Lair",
|
||||
[5632] = "Old Shadowforge",
|
||||
[5633] = "Maw of Ursoc",
|
||||
[5634] = "Zuluhed\'s Terrace",
|
||||
[5635] = "Slickwick Oil Rig",
|
||||
[5638] = "Sunstrider Court",
|
||||
[5639] = "Ruins of Grim Batol",
|
||||
-- Turtle WoW 1.18.x additions (from AreaTable.dbc)
|
||||
[5640] = "Timbermaw Hold",
|
||||
[5641] = "Windhorn Canyon",
|
||||
[5642] = "Moonwhisper Coast",
|
||||
[5643] = "Timbermaw Hold",
|
||||
[5644] = "Blackroot Village",
|
||||
[5645] = "Maras\'ethil",
|
||||
[5646] = "Moonsilk Hollow",
|
||||
[5647] = "Blackroot Hold",
|
||||
[5648] = "Shrine of Tides",
|
||||
[5649] = "Moro\'gai Village",
|
||||
[5650] = "Shimmerstar Lake",
|
||||
[5651] = "Grove of the Moon",
|
||||
[5652] = "Lunarclaw Den",
|
||||
[5653] = "Ruins of Nendis",
|
||||
[5654] = "Grove of the Sun",
|
||||
[5655] = "Shrine of Cyclones",
|
||||
[5656] = "Riverhorn Village",
|
||||
[5657] = "Moonhoof Village",
|
||||
[5658] = "Foulheart Sanctum",
|
||||
[5659] = "Narvalis Point",
|
||||
[5660] = "Tyrandas",
|
||||
[5661] = "Temple of Elunaris",
|
||||
[5662] = "Withered Enclave",
|
||||
[5663] = "Elun\'aran",
|
||||
[5664] = "Moonhoof Retreat",
|
||||
[5665] = "Shrine of Blazes",
|
||||
[5666] = "Shrine of Crags",
|
||||
[5667] = "An\'she\'s Respite",
|
||||
[5668] = "Ancestral Grounds",
|
||||
[5669] = "Whispering Shores",
|
||||
[5670] = "Servitor\'s Sanctuary",
|
||||
[5671] = "Starshard Cradle",
|
||||
[5672] = "Vysnagosa\'s Rest",
|
||||
[5722] = "Thorn Gorge",
|
||||
[5723] = "Lower Karazhan Halls",
|
||||
[5725] = "Amberhorn Bluffs",
|
||||
[5726] = "Dun Bardal",
|
||||
[5727] = "Mage Tower",
|
||||
[5728] = "Grimtotem Ruins",
|
||||
[5729] = "Amberhorn Village",
|
||||
[5730] = "Farseer Spire",
|
||||
[5731] = "Windhorn Caverns",
|
||||
[5732] = "Sunsworn Camp",
|
||||
[5733] = "Maw of Ursol",
|
||||
[5734] = "Frostmane Hollow",
|
||||
[5735] = "Frostmane Hollow",
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,15 @@
|
||||
pfDB = {
|
||||
["areatrigger"] = {},
|
||||
["items"] = {},
|
||||
["meta"] = {},
|
||||
["meta-tbc"] = {},
|
||||
["minimap"] = {},
|
||||
["minimap-tbc"] = {},
|
||||
["objects"] = {},
|
||||
["professions"] = {},
|
||||
["quests"] = {},
|
||||
["quests-itemreq"] = {},
|
||||
["refloot"] = {},
|
||||
["units"] = {},
|
||||
["zones"] = {},
|
||||
}
|
||||
+370579
File diff suppressed because it is too large
Load Diff
+284305
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+2212
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,100 @@
|
||||
pfDB["minimap-turtle"] = {
|
||||
[0] = { 0.0, 0.0 },
|
||||
[10] = { 2700.0, 1800.03 },
|
||||
[11] = { 4135.42, 2756.25 },
|
||||
[25] = { 711.56, 468.68 },
|
||||
[28] = { 4300.0, 2866.67 },
|
||||
[36] = { 2800.0, 1866.67 },
|
||||
[40] = { 3500.0, 2333.3 },
|
||||
[41] = { 2500.0, 1666.63 },
|
||||
[45] = { 3600.0, 2400.0 },
|
||||
[46] = { 2929.16, 1952.08 },
|
||||
[51] = { 2231.25, 1487.5 },
|
||||
[209] = { 381.0, 254.0 },
|
||||
[215] = { 5137.5, 3425.0 },
|
||||
[331] = { 5766.67, 3843.75 },
|
||||
[400] = { 4400.0, 2933.33 },
|
||||
[405] = { 4495.83, 2997.91 },
|
||||
[406] = { 6018.0, 4010.0 },
|
||||
[408] = { 3092.1, 2047.0 },
|
||||
[409] = { 2901.45, 1915.9 },
|
||||
[490] = { 3700.0, 2466.66 },
|
||||
[491] = { 736.45, 490.96 },
|
||||
[616] = { 3206.0, 2142.0 },
|
||||
[618] = { 7100.0, 4733.33 },
|
||||
[717] = { 378.15, 252.1 },
|
||||
[718] = { 572.78, 381.85 },
|
||||
[719] = { 1221.87, 806.42 },
|
||||
[721] = { 769.67, 513.11 },
|
||||
[722] = { 881.0, 589.0 },
|
||||
[796] = { 203.66, 135.04 },
|
||||
[876] = { 828.0, 541.0 },
|
||||
[1176] = { 1383.33, 922.91 },
|
||||
[1337] = { 893.67, 595.78 },
|
||||
[1377] = { 3483.33, 2322.92 },
|
||||
[1477] = { 695.03, 463.35 },
|
||||
[1497] = { 959.37, 640.11 },
|
||||
[1519] = { 1737.5, 1158.34 },
|
||||
[1537] = { 790.63, 527.61 },
|
||||
[1581] = { 449.89, 300.0 },
|
||||
[1583] = { 886.84, 591.23 },
|
||||
[1584] = { 1985.0, 1268.0 },
|
||||
[1941] = { 1348.24, 888.09 },
|
||||
[1977] = { 2120.83, 1414.6 },
|
||||
[2017] = { 1185.35, 789.86 },
|
||||
[2040] = { 1468.0, 976.0 },
|
||||
[2057] = { 320.05, 213.37 },
|
||||
[2100] = { 2112.09, 1410.89 },
|
||||
[2159] = { 483.11, 322.08 },
|
||||
[2257] = { 312.0, 208.0 },
|
||||
[2366] = { 1085.86, 726.61 },
|
||||
[2437] = { 738.86, 492.57 },
|
||||
[2557] = { 1324.0, 869.0 },
|
||||
[2677] = { 499.43, 332.95 },
|
||||
[2717] = { 1495.0, 983.0 },
|
||||
[3277] = { 1145.84, 764.58 },
|
||||
[3358] = { 1756.25, 1170.83 },
|
||||
[3428] = { 977.56, 651.7 },
|
||||
[3429] = { 2512.5, 1675.0 },
|
||||
[3456] = { 1991.69, 1318.42 },
|
||||
[3457] = { 823.0, 549.0 },
|
||||
[3478] = { 4139.02, 2946.0 },
|
||||
[4012] = { 3159.0, 2108.0 },
|
||||
[5023] = { 988.63, 1393.17 },
|
||||
[5024] = { 1608.0, 1075.0 },
|
||||
[5053] = { 1007.7, 671.8 },
|
||||
[5077] = { 2643.21, 1751.16 },
|
||||
[5086] = { 546.75, 391.9 },
|
||||
[5087] = { 354.5, 234.74 },
|
||||
[5097] = { 1273.1, 853.72 },
|
||||
[5103] = { 752.12, 510.33 },
|
||||
[5121] = { 3227.0, 2187.0 },
|
||||
[5130] = { 1432.0, 977.0 },
|
||||
[5135] = { 320.19, 213.46 },
|
||||
[5136] = { 619.98, 413.32 },
|
||||
[5138] = { 656.59, 434.97 },
|
||||
[5144] = { 309.0, 208.0 },
|
||||
[5147] = { 2777.54, 1851.69 },
|
||||
[5148] = { 652.1, 439.67 },
|
||||
[5153] = { 612.69, 408.46 },
|
||||
[5163] = { 703.3, 468.87 },
|
||||
[5179] = { 3666.0, 2442.0 },
|
||||
[5204] = { 1271.99, 845.48 },
|
||||
[5208] = { 1250.18, 837.44 },
|
||||
[5225] = { 3082.0, 2061.0 },
|
||||
[5536] = { 2472.0, 1665.0 },
|
||||
[5557] = { 2800.0, 1868.0 },
|
||||
[5561] = { 3098.0, 2068.0 },
|
||||
[5581] = { 3241.0, 2157.0 },
|
||||
[5601] = { 1634.0, 1073.0 },
|
||||
[5602] = { 5387.0, 3584.0 },
|
||||
[5628] = { 1980.0, 1350.0 },
|
||||
-- Turtle WoW 1.18.x additions (from WorldMapArea.dbc)
|
||||
[1769] = { 861, 607 },
|
||||
[5640] = { 962, 1425 },
|
||||
[5641] = { 829, 1234 },
|
||||
[5642] = { 7856, 5241 },
|
||||
[5722] = { 694, 1047 },
|
||||
[5731] = { 279, 440 },
|
||||
[5734] = { 653, 1011 },
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
pfDB["minimap"] = {
|
||||
[0] = { 35199.9, 23466.6 },
|
||||
[1] = { 4925.0, 3283.34 },
|
||||
[3] = { 2487.5, 1658.34 },
|
||||
[4] = { 3350.0, 2233.3 },
|
||||
[8] = { 2293.75, 1529.17 },
|
||||
[10] = { 2700.003, 1800.03 },
|
||||
[11] = { 4135.417, 2756.25 },
|
||||
[12] = { 3470.84, 2314.62 },
|
||||
[14] = { 5287.5, 3525.0 },
|
||||
[15] = { 5250.0, 3500.0 },
|
||||
[16] = { 5070.84, 3381.25 },
|
||||
[17] = { 10133.34, 6756.25 },
|
||||
[28] = { 4299.997, 2866.67 },
|
||||
[33] = { 6381.25, 4254.1 },
|
||||
[36] = { 2800.003, 1866.667 },
|
||||
[38] = { 2758.33, 1839.58 },
|
||||
[40] = { 3500.003, 2333.3 },
|
||||
[41] = { 2499.997, 1666.63 },
|
||||
[44] = { 2170.84, 1447.9 },
|
||||
[45] = { 3600.003, 2399.997 },
|
||||
[46] = { 2929.163, 1952.08 },
|
||||
[47] = { 3850.0, 2566.67 },
|
||||
[51] = { 2231.253, 1487.5 },
|
||||
[85] = { 4518.75, 3012.5 },
|
||||
[130] = { 4200.0, 2800.0 },
|
||||
[139] = { 3870.83, 2581.25 },
|
||||
[141] = { 5091.66, 3393.7 },
|
||||
[148] = { 6550.0, 4366.66 },
|
||||
[215] = { 5137.5, 3425.003 },
|
||||
[267] = { 3200.0, 2133.33 },
|
||||
[331] = { 5766.67, 3843.753 },
|
||||
[357] = { 6950.0, 4633.33 },
|
||||
[361] = { 5750.0, 3833.33 },
|
||||
[400] = { 4399.997, 2933.33 },
|
||||
[405] = { 4495.83, 2997.913 },
|
||||
[406] = { 4883.33, 3256.253 },
|
||||
[440] = { 6900.0, 4600.0 },
|
||||
[490] = { 3700.003, 2466.66 },
|
||||
[493] = { 2308.33, 1539.59 },
|
||||
[618] = { 7100.003, 4733.33 },
|
||||
[1377] = { 3483.334, 2322.92 },
|
||||
[1497] = { 959.3754, 640.11 },
|
||||
[1519] = { 1344.2694, 896.36 },
|
||||
[1537] = { 790.629, 527.61 },
|
||||
[1637] = { 1402.61, 935.42 },
|
||||
[1638] = { 1043.75, 695.83 },
|
||||
[1657] = { 1058.33, 705.71 },
|
||||
[2597] = { 4237.5, 2825.0 },
|
||||
[3277] = { 1145.837, 764.58 },
|
||||
[3358] = { 1756.247, 1170.83 },
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
+87371
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,528 @@
|
||||
pfDB["quests"]["patch"] = {
|
||||
-- Quests introduced in Turtle WoW 1.18.1 (absent from 1.17 quests-turtle.lua)
|
||||
[41898] = "1.18.1",
|
||||
[41899] = "1.18.1",
|
||||
[41900] = "1.18.1",
|
||||
[41901] = "1.18.1",
|
||||
[41902] = "1.18.1",
|
||||
[41903] = "1.18.1",
|
||||
[41904] = "1.18.1",
|
||||
[41905] = "1.18.1",
|
||||
[41906] = "1.18.1",
|
||||
[41907] = "1.18.1",
|
||||
[41908] = "1.18.1",
|
||||
[41909] = "1.18.1",
|
||||
[41910] = "1.18.1",
|
||||
[41911] = "1.18.1",
|
||||
[41912] = "1.18.1",
|
||||
[41913] = "1.18.1",
|
||||
[41914] = "1.18.1",
|
||||
[41915] = "1.18.1",
|
||||
[41916] = "1.18.1",
|
||||
[41917] = "1.18.1",
|
||||
[41918] = "1.18.1",
|
||||
[41919] = "1.18.1",
|
||||
[41920] = "1.18.1",
|
||||
[41921] = "1.18.1",
|
||||
[41922] = "1.18.1",
|
||||
[41923] = "1.18.1",
|
||||
[41924] = "1.18.1",
|
||||
[41925] = "1.18.1",
|
||||
[41926] = "1.18.1",
|
||||
[41927] = "1.18.1",
|
||||
[41928] = "1.18.1",
|
||||
[41929] = "1.18.1",
|
||||
[41930] = "1.18.1",
|
||||
[41931] = "1.18.1",
|
||||
[41932] = "1.18.1",
|
||||
[41933] = "1.18.1",
|
||||
[41934] = "1.18.1",
|
||||
[41935] = "1.18.1",
|
||||
[41936] = "1.18.1",
|
||||
[41937] = "1.18.1",
|
||||
[41938] = "1.18.1",
|
||||
[41939] = "1.18.1",
|
||||
[41940] = "1.18.1",
|
||||
[41941] = "1.18.1",
|
||||
[41942] = "1.18.1",
|
||||
[41943] = "1.18.1",
|
||||
[41944] = "1.18.1",
|
||||
[41945] = "1.18.1",
|
||||
[41946] = "1.18.1",
|
||||
[41947] = "1.18.1",
|
||||
[41948] = "1.18.1",
|
||||
[41949] = "1.18.1",
|
||||
[41950] = "1.18.1",
|
||||
[41951] = "1.18.1",
|
||||
[41952] = "1.18.1",
|
||||
[41953] = "1.18.1",
|
||||
[41954] = "1.18.1",
|
||||
[41955] = "1.18.1",
|
||||
[41956] = "1.18.1",
|
||||
[41957] = "1.18.1",
|
||||
[41958] = "1.18.1",
|
||||
[41959] = "1.18.1",
|
||||
[41960] = "1.18.1",
|
||||
[41961] = "1.18.1",
|
||||
[41962] = "1.18.1",
|
||||
[41963] = "1.18.1",
|
||||
[41964] = "1.18.1",
|
||||
[41965] = "1.18.1",
|
||||
[41966] = "1.18.1",
|
||||
[41967] = "1.18.1",
|
||||
[41968] = "1.18.1",
|
||||
[41969] = "1.18.1",
|
||||
[41970] = "1.18.1",
|
||||
[41972] = "1.18.1",
|
||||
[41973] = "1.18.1",
|
||||
[41974] = "1.18.1",
|
||||
[41975] = "1.18.1",
|
||||
[41976] = "1.18.1",
|
||||
[41977] = "1.18.1",
|
||||
[41978] = "1.18.1",
|
||||
[41979] = "1.18.1",
|
||||
[41980] = "1.18.1",
|
||||
[41981] = "1.18.1",
|
||||
[41982] = "1.18.1",
|
||||
[41983] = "1.18.1",
|
||||
[41984] = "1.18.1",
|
||||
[41985] = "1.18.1",
|
||||
[41986] = "1.18.1",
|
||||
[41987] = "1.18.1",
|
||||
[41988] = "1.18.1",
|
||||
[41989] = "1.18.1",
|
||||
[41990] = "1.18.1",
|
||||
[41991] = "1.18.1",
|
||||
[41992] = "1.18.1",
|
||||
[41993] = "1.18.1",
|
||||
[41994] = "1.18.1",
|
||||
[41995] = "1.18.1",
|
||||
[41996] = "1.18.1",
|
||||
[41997] = "1.18.1",
|
||||
[41998] = "1.18.1",
|
||||
[41999] = "1.18.1",
|
||||
[42000] = "1.18.1",
|
||||
[42001] = "1.18.1",
|
||||
[42002] = "1.18.1",
|
||||
[42003] = "1.18.1",
|
||||
[42004] = "1.18.1",
|
||||
[42005] = "1.18.1",
|
||||
[42006] = "1.18.1",
|
||||
[42007] = "1.18.1",
|
||||
[42008] = "1.18.1",
|
||||
[42009] = "1.18.1",
|
||||
[42010] = "1.18.1",
|
||||
[42011] = "1.18.1",
|
||||
[42012] = "1.18.1",
|
||||
[42013] = "1.18.1",
|
||||
[42014] = "1.18.1",
|
||||
[42015] = "1.18.1",
|
||||
[42016] = "1.18.1",
|
||||
[42017] = "1.18.1",
|
||||
[42018] = "1.18.1",
|
||||
[42019] = "1.18.1",
|
||||
[42020] = "1.18.1",
|
||||
[42021] = "1.18.1",
|
||||
[42022] = "1.18.1",
|
||||
[42023] = "1.18.1",
|
||||
[42024] = "1.18.1",
|
||||
[42025] = "1.18.1",
|
||||
[42026] = "1.18.1",
|
||||
[42027] = "1.18.1",
|
||||
[42028] = "1.18.1",
|
||||
[42029] = "1.18.1",
|
||||
[42030] = "1.18.1",
|
||||
[42031] = "1.18.1",
|
||||
[42032] = "1.18.1",
|
||||
[42033] = "1.18.1",
|
||||
[42034] = "1.18.1",
|
||||
[42035] = "1.18.1",
|
||||
[42036] = "1.18.1",
|
||||
[42037] = "1.18.1",
|
||||
[42038] = "1.18.1",
|
||||
[42039] = "1.18.1",
|
||||
[42040] = "1.18.1",
|
||||
[42041] = "1.18.1",
|
||||
[42042] = "1.18.1",
|
||||
[42043] = "1.18.1",
|
||||
[42044] = "1.18.1",
|
||||
[42045] = "1.18.1",
|
||||
[42046] = "1.18.1",
|
||||
[42047] = "1.18.1",
|
||||
[42048] = "1.18.1",
|
||||
[42049] = "1.18.1",
|
||||
[42050] = "1.18.1",
|
||||
[42051] = "1.18.1",
|
||||
[42052] = "1.18.1",
|
||||
[42053] = "1.18.1",
|
||||
[42054] = "1.18.1",
|
||||
[42055] = "1.18.1",
|
||||
[42056] = "1.18.1",
|
||||
[42057] = "1.18.1",
|
||||
[42058] = "1.18.1",
|
||||
[42059] = "1.18.1",
|
||||
[42060] = "1.18.1",
|
||||
[42061] = "1.18.1",
|
||||
[42062] = "1.18.1",
|
||||
[42063] = "1.18.1",
|
||||
[42064] = "1.18.1",
|
||||
[42065] = "1.18.1",
|
||||
[42066] = "1.18.1",
|
||||
[42067] = "1.18.1",
|
||||
[42068] = "1.18.1",
|
||||
[42069] = "1.18.1",
|
||||
[42070] = "1.18.1",
|
||||
[42071] = "1.18.1",
|
||||
[42072] = "1.18.1",
|
||||
[42073] = "1.18.1",
|
||||
[42074] = "1.18.1",
|
||||
[42075] = "1.18.1",
|
||||
[42076] = "1.18.1",
|
||||
[42077] = "1.18.1",
|
||||
[42078] = "1.18.1",
|
||||
[42079] = "1.18.1",
|
||||
[42080] = "1.18.1",
|
||||
[42081] = "1.18.1",
|
||||
[42082] = "1.18.1",
|
||||
[42083] = "1.18.1",
|
||||
[42084] = "1.18.1",
|
||||
[42085] = "1.18.1",
|
||||
[42086] = "1.18.1",
|
||||
[42087] = "1.18.1",
|
||||
[42088] = "1.18.1",
|
||||
[42089] = "1.18.1",
|
||||
[42090] = "1.18.1",
|
||||
[42091] = "1.18.1",
|
||||
[42092] = "1.18.1",
|
||||
[42093] = "1.18.1",
|
||||
[42094] = "1.18.1",
|
||||
[42095] = "1.18.1",
|
||||
[42096] = "1.18.1",
|
||||
[42097] = "1.18.1",
|
||||
[42098] = "1.18.1",
|
||||
[42099] = "1.18.1",
|
||||
[42100] = "1.18.1",
|
||||
[42101] = "1.18.1",
|
||||
}
|
||||
|
||||
pfDB["units"]["patch"] = {
|
||||
-- NPCs introduced in Turtle WoW 1.18.1 (absent from 1.17 units-turtle.lua)
|
||||
[29479] = "1.18.1",
|
||||
[60686] = "1.18.1",
|
||||
[62757] = "1.18.1",
|
||||
[62759] = "1.18.1",
|
||||
[62760] = "1.18.1",
|
||||
[62761] = "1.18.1",
|
||||
[62762] = "1.18.1",
|
||||
[62763] = "1.18.1",
|
||||
[62764] = "1.18.1",
|
||||
[62765] = "1.18.1",
|
||||
[62766] = "1.18.1",
|
||||
[62767] = "1.18.1",
|
||||
[62768] = "1.18.1",
|
||||
[62769] = "1.18.1",
|
||||
[62770] = "1.18.1",
|
||||
[62771] = "1.18.1",
|
||||
[62772] = "1.18.1",
|
||||
[62773] = "1.18.1",
|
||||
[62774] = "1.18.1",
|
||||
[62777] = "1.18.1",
|
||||
[62778] = "1.18.1",
|
||||
[62779] = "1.18.1",
|
||||
[62780] = "1.18.1",
|
||||
[62781] = "1.18.1",
|
||||
[62782] = "1.18.1",
|
||||
[62783] = "1.18.1",
|
||||
[62784] = "1.18.1",
|
||||
[62786] = "1.18.1",
|
||||
[62787] = "1.18.1",
|
||||
[62788] = "1.18.1",
|
||||
[62789] = "1.18.1",
|
||||
[62790] = "1.18.1",
|
||||
[62791] = "1.18.1",
|
||||
[62792] = "1.18.1",
|
||||
[62793] = "1.18.1",
|
||||
[62794] = "1.18.1",
|
||||
[62795] = "1.18.1",
|
||||
[62796] = "1.18.1",
|
||||
[62797] = "1.18.1",
|
||||
[62802] = "1.18.1",
|
||||
[62803] = "1.18.1",
|
||||
[62804] = "1.18.1",
|
||||
[62806] = "1.18.1",
|
||||
[62807] = "1.18.1",
|
||||
[62808] = "1.18.1",
|
||||
[62809] = "1.18.1",
|
||||
[62810] = "1.18.1",
|
||||
[62811] = "1.18.1",
|
||||
[62812] = "1.18.1",
|
||||
[62813] = "1.18.1",
|
||||
[62814] = "1.18.1",
|
||||
[62815] = "1.18.1",
|
||||
[62816] = "1.18.1",
|
||||
[62817] = "1.18.1",
|
||||
[62818] = "1.18.1",
|
||||
[62820] = "1.18.1",
|
||||
[62821] = "1.18.1",
|
||||
[62822] = "1.18.1",
|
||||
[62823] = "1.18.1",
|
||||
[62824] = "1.18.1",
|
||||
[62825] = "1.18.1",
|
||||
[62826] = "1.18.1",
|
||||
[62827] = "1.18.1",
|
||||
[62828] = "1.18.1",
|
||||
[62829] = "1.18.1",
|
||||
[62830] = "1.18.1",
|
||||
[62831] = "1.18.1",
|
||||
[62832] = "1.18.1",
|
||||
[62834] = "1.18.1",
|
||||
[62835] = "1.18.1",
|
||||
[62836] = "1.18.1",
|
||||
[62838] = "1.18.1",
|
||||
[62839] = "1.18.1",
|
||||
[62842] = "1.18.1",
|
||||
[62843] = "1.18.1",
|
||||
[62849] = "1.18.1",
|
||||
[62862] = "1.18.1",
|
||||
[62865] = "1.18.1",
|
||||
[62867] = "1.18.1",
|
||||
[62870] = "1.18.1",
|
||||
[62871] = "1.18.1",
|
||||
[62872] = "1.18.1",
|
||||
[62873] = "1.18.1",
|
||||
[62875] = "1.18.1",
|
||||
[62876] = "1.18.1",
|
||||
[62877] = "1.18.1",
|
||||
[62878] = "1.18.1",
|
||||
[62879] = "1.18.1",
|
||||
[62880] = "1.18.1",
|
||||
[62881] = "1.18.1",
|
||||
[62882] = "1.18.1",
|
||||
[62883] = "1.18.1",
|
||||
[62884] = "1.18.1",
|
||||
[62885] = "1.18.1",
|
||||
[62887] = "1.18.1",
|
||||
[62888] = "1.18.1",
|
||||
[62889] = "1.18.1",
|
||||
[62890] = "1.18.1",
|
||||
[62891] = "1.18.1",
|
||||
[62892] = "1.18.1",
|
||||
[62893] = "1.18.1",
|
||||
[62894] = "1.18.1",
|
||||
[62895] = "1.18.1",
|
||||
[62899] = "1.18.1",
|
||||
[62900] = "1.18.1",
|
||||
[62901] = "1.18.1",
|
||||
[62902] = "1.18.1",
|
||||
[62904] = "1.18.1",
|
||||
[62905] = "1.18.1",
|
||||
[62906] = "1.18.1",
|
||||
[62907] = "1.18.1",
|
||||
[62910] = "1.18.1",
|
||||
[62913] = "1.18.1",
|
||||
[62914] = "1.18.1",
|
||||
[62917] = "1.18.1",
|
||||
[62924] = "1.18.1",
|
||||
[62925] = "1.18.1",
|
||||
[62926] = "1.18.1",
|
||||
[62927] = "1.18.1",
|
||||
[62928] = "1.18.1",
|
||||
[62929] = "1.18.1",
|
||||
[62930] = "1.18.1",
|
||||
[62931] = "1.18.1",
|
||||
[62932] = "1.18.1",
|
||||
[62933] = "1.18.1",
|
||||
[62934] = "1.18.1",
|
||||
[62935] = "1.18.1",
|
||||
[62936] = "1.18.1",
|
||||
[62938] = "1.18.1",
|
||||
[62940] = "1.18.1",
|
||||
[62941] = "1.18.1",
|
||||
[62942] = "1.18.1",
|
||||
[62946] = "1.18.1",
|
||||
[62947] = "1.18.1",
|
||||
[62948] = "1.18.1",
|
||||
[62949] = "1.18.1",
|
||||
[62950] = "1.18.1",
|
||||
[62951] = "1.18.1",
|
||||
[62952] = "1.18.1",
|
||||
[62953] = "1.18.1",
|
||||
[62954] = "1.18.1",
|
||||
[62955] = "1.18.1",
|
||||
[62956] = "1.18.1",
|
||||
[62957] = "1.18.1",
|
||||
[62958] = "1.18.1",
|
||||
[62959] = "1.18.1",
|
||||
[62960] = "1.18.1",
|
||||
[62961] = "1.18.1",
|
||||
[62962] = "1.18.1",
|
||||
[62964] = "1.18.1",
|
||||
[62965] = "1.18.1",
|
||||
[62966] = "1.18.1",
|
||||
[62967] = "1.18.1",
|
||||
[62972] = "1.18.1",
|
||||
[62973] = "1.18.1",
|
||||
[62974] = "1.18.1",
|
||||
[62976] = "1.18.1",
|
||||
[62977] = "1.18.1",
|
||||
[62978] = "1.18.1",
|
||||
[62979] = "1.18.1",
|
||||
[62980] = "1.18.1",
|
||||
[62981] = "1.18.1",
|
||||
[62983] = "1.18.1",
|
||||
[62984] = "1.18.1",
|
||||
[62985] = "1.18.1",
|
||||
[62988] = "1.18.1",
|
||||
[62990] = "1.18.1",
|
||||
[62992] = "1.18.1",
|
||||
[62996] = "1.18.1",
|
||||
[62997] = "1.18.1",
|
||||
[62998] = "1.18.1",
|
||||
[62999] = "1.18.1",
|
||||
[63000] = "1.18.1",
|
||||
[63001] = "1.18.1",
|
||||
[63002] = "1.18.1",
|
||||
[63003] = "1.18.1",
|
||||
[63004] = "1.18.1",
|
||||
[63005] = "1.18.1",
|
||||
[63006] = "1.18.1",
|
||||
[63007] = "1.18.1",
|
||||
[63008] = "1.18.1",
|
||||
[63009] = "1.18.1",
|
||||
[63010] = "1.18.1",
|
||||
[63011] = "1.18.1",
|
||||
[63014] = "1.18.1",
|
||||
[63015] = "1.18.1",
|
||||
[63019] = "1.18.1",
|
||||
[63026] = "1.18.1",
|
||||
[63027] = "1.18.1",
|
||||
[63028] = "1.18.1",
|
||||
[63029] = "1.18.1",
|
||||
[63030] = "1.18.1",
|
||||
[63031] = "1.18.1",
|
||||
[63032] = "1.18.1",
|
||||
[63033] = "1.18.1",
|
||||
[63034] = "1.18.1",
|
||||
[63035] = "1.18.1",
|
||||
[63036] = "1.18.1",
|
||||
[63037] = "1.18.1",
|
||||
[63038] = "1.18.1",
|
||||
[63039] = "1.18.1",
|
||||
[63040] = "1.18.1",
|
||||
[63041] = "1.18.1",
|
||||
[63042] = "1.18.1",
|
||||
[63043] = "1.18.1",
|
||||
[63052] = "1.18.1",
|
||||
[63054] = "1.18.1",
|
||||
[63055] = "1.18.1",
|
||||
[63056] = "1.18.1",
|
||||
[63059] = "1.18.1",
|
||||
[63061] = "1.18.1",
|
||||
[63062] = "1.18.1",
|
||||
[63063] = "1.18.1",
|
||||
[63064] = "1.18.1",
|
||||
[63065] = "1.18.1",
|
||||
[63066] = "1.18.1",
|
||||
[63067] = "1.18.1",
|
||||
[63068] = "1.18.1",
|
||||
[63071] = "1.18.1",
|
||||
[63072] = "1.18.1",
|
||||
[63075] = "1.18.1",
|
||||
[63078] = "1.18.1",
|
||||
[63079] = "1.18.1",
|
||||
[63080] = "1.18.1",
|
||||
[63081] = "1.18.1",
|
||||
[63083] = "1.18.1",
|
||||
[63084] = "1.18.1",
|
||||
[63085] = "1.18.1",
|
||||
[63086] = "1.18.1",
|
||||
[63087] = "1.18.1",
|
||||
[63088] = "1.18.1",
|
||||
[63090] = "1.18.1",
|
||||
[63092] = "1.18.1",
|
||||
[63094] = "1.18.1",
|
||||
[63095] = "1.18.1",
|
||||
[63096] = "1.18.1",
|
||||
[63097] = "1.18.1",
|
||||
[63098] = "1.18.1",
|
||||
[63099] = "1.18.1",
|
||||
[63102] = "1.18.1",
|
||||
[63106] = "1.18.1",
|
||||
[63116] = "1.18.1",
|
||||
[63117] = "1.18.1",
|
||||
[63118] = "1.18.1",
|
||||
[63119] = "1.18.1",
|
||||
[63121] = "1.18.1",
|
||||
[63122] = "1.18.1",
|
||||
[63124] = "1.18.1",
|
||||
[63127] = "1.18.1",
|
||||
[63129] = "1.18.1",
|
||||
[63130] = "1.18.1",
|
||||
[63131] = "1.18.1",
|
||||
[63133] = "1.18.1",
|
||||
[63134] = "1.18.1",
|
||||
[63135] = "1.18.1",
|
||||
[63136] = "1.18.1",
|
||||
[63137] = "1.18.1",
|
||||
[63138] = "1.18.1",
|
||||
[63139] = "1.18.1",
|
||||
[63141] = "1.18.1",
|
||||
[63142] = "1.18.1",
|
||||
[63143] = "1.18.1",
|
||||
[63144] = "1.18.1",
|
||||
[63145] = "1.18.1",
|
||||
[63146] = "1.18.1",
|
||||
[63147] = "1.18.1",
|
||||
[63148] = "1.18.1",
|
||||
[63149] = "1.18.1",
|
||||
[63150] = "1.18.1",
|
||||
[63151] = "1.18.1",
|
||||
[63152] = "1.18.1",
|
||||
[63153] = "1.18.1",
|
||||
[63154] = "1.18.1",
|
||||
[63155] = "1.18.1",
|
||||
[63156] = "1.18.1",
|
||||
[63157] = "1.18.1",
|
||||
[63158] = "1.18.1",
|
||||
[63159] = "1.18.1",
|
||||
[63160] = "1.18.1",
|
||||
[63161] = "1.18.1",
|
||||
[63162] = "1.18.1",
|
||||
[63163] = "1.18.1",
|
||||
[63164] = "1.18.1",
|
||||
[63165] = "1.18.1",
|
||||
[63166] = "1.18.1",
|
||||
[63167] = "1.18.1",
|
||||
[63168] = "1.18.1",
|
||||
[63169] = "1.18.1",
|
||||
[63170] = "1.18.1",
|
||||
[63172] = "1.18.1",
|
||||
[63173] = "1.18.1",
|
||||
[63182] = "1.18.1",
|
||||
[63183] = "1.18.1",
|
||||
[63184] = "1.18.1",
|
||||
[63185] = "1.18.1",
|
||||
[63186] = "1.18.1",
|
||||
[63187] = "1.18.1",
|
||||
[63188] = "1.18.1",
|
||||
[63189] = "1.18.1",
|
||||
[63190] = "1.18.1",
|
||||
[63192] = "1.18.1",
|
||||
[63193] = "1.18.1",
|
||||
[63194] = "1.18.1",
|
||||
[63195] = "1.18.1",
|
||||
[63196] = "1.18.1",
|
||||
[63197] = "1.18.1",
|
||||
[63198] = "1.18.1",
|
||||
[63199] = "1.18.1",
|
||||
[63201] = "1.18.1",
|
||||
[63203] = "1.18.1",
|
||||
[63204] = "1.18.1",
|
||||
[63205] = "1.18.1",
|
||||
[63206] = "1.18.1",
|
||||
[63207] = "1.18.1",
|
||||
[63208] = "1.18.1",
|
||||
[63209] = "1.18.1",
|
||||
[63210] = "1.18.1",
|
||||
[93353] = "1.18.1",
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
pfDB["quests-itemreq"]["data-turtle"] = {
|
||||
[4702] = {
|
||||
[-3000687] = "4954",
|
||||
[-3000684] = "4954",
|
||||
[-184617] = "4954",
|
||||
[-181130] = "4954",
|
||||
[-180913] = "4954",
|
||||
[-179924] = "4954",
|
||||
[-179886] = "4954",
|
||||
[-179863] = "4954",
|
||||
[-179844] = "4954",
|
||||
[-178684] = "4954",
|
||||
[-176895] = "4954",
|
||||
[-176509] = "4954",
|
||||
[-175851] = "4954",
|
||||
[-175144] = "4954",
|
||||
[-173095] = "4954",
|
||||
[-173064] = "4954",
|
||||
[-173063] = "4954",
|
||||
[-171717] = "4954",
|
||||
[-171716] = "4954",
|
||||
[-169969] = "4954",
|
||||
[-161487] = "4954",
|
||||
[-153459] = "4954",
|
||||
[-152045] = "4954",
|
||||
[-152042] = "4954",
|
||||
[-152034] = "4954",
|
||||
[-148960] = "4954",
|
||||
[-147285] = "4954",
|
||||
[-144133] = "4954",
|
||||
[-142078] = "4954",
|
||||
[-141841] = "4954",
|
||||
[-141838] = "4954",
|
||||
[-138317] = "4954",
|
||||
[-130668] = "4954",
|
||||
[-123210] = "4954",
|
||||
[-123209] = "4954",
|
||||
[-123208] = "4954",
|
||||
[-123207] = "4954",
|
||||
[-113754] = "4954",
|
||||
[-92490] = "4954",
|
||||
[-56897] = "4954",
|
||||
[-52176] = "4954",
|
||||
[-52175] = "4954",
|
||||
[-51949] = "4954",
|
||||
[-50985] = "4954",
|
||||
[-50984] = "4954",
|
||||
[-50983] = "4954",
|
||||
[-50831] = "4954",
|
||||
[-50469] = "4954",
|
||||
[-38491] = "4954",
|
||||
[-34572] = "4954",
|
||||
[-34571] = "4954",
|
||||
[-24746] = "4954",
|
||||
[-24745] = "4954",
|
||||
[-23305] = "4954",
|
||||
[-23304] = "4954",
|
||||
[-21679] = "4954",
|
||||
[-20986] = "4954",
|
||||
[-20738] = "4954",
|
||||
[-19902] = "4954",
|
||||
[-17190] = "4954",
|
||||
[-4090] = "4954",
|
||||
[-3223] = "4954",
|
||||
[-2728] = "4954",
|
||||
[-2727] = "4954",
|
||||
[-2575] = "4954",
|
||||
[-2573] = "4954",
|
||||
[-2015] = "4954",
|
||||
[-1896] = "4954",
|
||||
[-1797] = "4954",
|
||||
[-1749] = "4954",
|
||||
[-1745] = "4954",
|
||||
[-1743] = "4954",
|
||||
[-1685] = "4954",
|
||||
},
|
||||
[5623] = "_",
|
||||
[9364] = {
|
||||
[6218] = "12709",
|
||||
[6219] = "12709",
|
||||
[6220] = "12709",
|
||||
[6329] = "12709",
|
||||
},
|
||||
[11473] = "_",
|
||||
[15826] = {
|
||||
[12296] = 0,
|
||||
[12298] = 0,
|
||||
},
|
||||
[18488] = "_",
|
||||
[18688] = {
|
||||
[-187115] = "23180",
|
||||
[-180632] = "23180",
|
||||
[-180631] = "23180",
|
||||
[-177387] = "23180",
|
||||
},
|
||||
[19710] = "_",
|
||||
[19711] = "_",
|
||||
[19712] = "_",
|
||||
[19713] = "_",
|
||||
[19714] = "_",
|
||||
[19715] = "_",
|
||||
[41064] = {
|
||||
[61700] = 0,
|
||||
},
|
||||
[41065] = {
|
||||
[61695] = 0,
|
||||
},
|
||||
[41066] = {
|
||||
[61776] = 0,
|
||||
},
|
||||
[41557] = {
|
||||
[12296] = 0,
|
||||
},
|
||||
[50445] = {
|
||||
[61662] = 0,
|
||||
},
|
||||
[50446] = {
|
||||
[61680] = 0,
|
||||
},
|
||||
[50447] = {
|
||||
[61657] = 0,
|
||||
},
|
||||
[60329] = {
|
||||
[1547] = 0,
|
||||
},
|
||||
[60330] = {
|
||||
[1553] = 0,
|
||||
},
|
||||
[60331] = {
|
||||
[80466] = 0,
|
||||
},
|
||||
[61812] = {
|
||||
[113] = 0,
|
||||
},
|
||||
[61813] = {
|
||||
[118] = 0,
|
||||
},
|
||||
[61814] = {
|
||||
[822] = 0,
|
||||
},
|
||||
[91770] = {
|
||||
[3099] = 0,
|
||||
},
|
||||
[91772] = {
|
||||
[3126] = 0,
|
||||
},
|
||||
[91773] = {
|
||||
[1126] = 0,
|
||||
},
|
||||
[91775] = {
|
||||
[1196] = 0,
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,708 @@
|
||||
pfDB["quests-itemreq"]["data"] = {
|
||||
[3467] = {
|
||||
[-1721] = 0,
|
||||
},
|
||||
[3499] = {
|
||||
[-1722] = 0,
|
||||
},
|
||||
[3710] = {
|
||||
[-1770] = 0,
|
||||
[-1769] = 0,
|
||||
[-1768] = 0,
|
||||
},
|
||||
[3912] = {
|
||||
[2530] = 0,
|
||||
},
|
||||
[4027] = {
|
||||
[-2576] = 0,
|
||||
},
|
||||
[4472] = {
|
||||
[-2705] = "4141",
|
||||
},
|
||||
[4479] = {
|
||||
[2762] = "4132",
|
||||
},
|
||||
[4480] = {
|
||||
[2761] = "4131",
|
||||
},
|
||||
[4481] = {
|
||||
[2760] = "4130",
|
||||
},
|
||||
[4529] = {
|
||||
[-2715] = 0,
|
||||
},
|
||||
[4702] = {
|
||||
[-181130] = "4954",
|
||||
[-180913] = "4954",
|
||||
[-179924] = "4954",
|
||||
[-179886] = "4954",
|
||||
[-179863] = "4954",
|
||||
[-179844] = "4954",
|
||||
[-178684] = "4954",
|
||||
[-176895] = "4954",
|
||||
[-176509] = "4954",
|
||||
[-175851] = "4954",
|
||||
[-175144] = "4954",
|
||||
[-173095] = "4954",
|
||||
[-173064] = "4954",
|
||||
[-173063] = "4954",
|
||||
[-171717] = "4954",
|
||||
[-171716] = "4954",
|
||||
[-169969] = "4954",
|
||||
[-161487] = "4954",
|
||||
[-153459] = "4954",
|
||||
[-152045] = "4954",
|
||||
[-152042] = "4954",
|
||||
[-152034] = "4954",
|
||||
[-148960] = "4954",
|
||||
[-147285] = "4954",
|
||||
[-144133] = "4954",
|
||||
[-142078] = "4954",
|
||||
[-141841] = "4954",
|
||||
[-141838] = "4954",
|
||||
[-138317] = "4954",
|
||||
[-130668] = "4954",
|
||||
[-123210] = "4954",
|
||||
[-123209] = "4954",
|
||||
[-123208] = "4954",
|
||||
[-123207] = "4954",
|
||||
[-113754] = "4954",
|
||||
[-92490] = "4954",
|
||||
[-56897] = "4954",
|
||||
[-52176] = "4954",
|
||||
[-52175] = "4954",
|
||||
[-51949] = "4954",
|
||||
[-50985] = "4954",
|
||||
[-50984] = "4954",
|
||||
[-50983] = "4954",
|
||||
[-50831] = "4954",
|
||||
[-50469] = "4954",
|
||||
[-38491] = "4954",
|
||||
[-34572] = "4954",
|
||||
[-34571] = "4954",
|
||||
[-24746] = "4954",
|
||||
[-24745] = "4954",
|
||||
[-23305] = "4954",
|
||||
[-23304] = "4954",
|
||||
[-21679] = "4954",
|
||||
[-20986] = "4954",
|
||||
[-20738] = "4954",
|
||||
[-19902] = "4954",
|
||||
[-17190] = "4954",
|
||||
[-4090] = "4954",
|
||||
[-3223] = "4954",
|
||||
[-2728] = "4954",
|
||||
[-2727] = "4954",
|
||||
[-2575] = "4954",
|
||||
[-2573] = "4954",
|
||||
[-2015] = "4954",
|
||||
[-1896] = "4954",
|
||||
[-1797] = "4954",
|
||||
[-1749] = "4954",
|
||||
[-1745] = "4954",
|
||||
[-1743] = "4954",
|
||||
[-1685] = "4954",
|
||||
},
|
||||
[4823] = {
|
||||
[-2914] = "4981",
|
||||
},
|
||||
[5021] = {
|
||||
[-3644] = 0,
|
||||
},
|
||||
[5068] = {
|
||||
[-3737] = 0,
|
||||
},
|
||||
[5165] = {
|
||||
[-6908] = 0,
|
||||
[-6907] = 0,
|
||||
[-6906] = 0,
|
||||
},
|
||||
[5185] = {
|
||||
[-19549] = "4976",
|
||||
},
|
||||
[5338] = {
|
||||
[-16393] = 0,
|
||||
},
|
||||
[5411] = {
|
||||
[-2913] = "4975",
|
||||
},
|
||||
[5415] = {
|
||||
[-2911] = "4977",
|
||||
},
|
||||
[5416] = {
|
||||
[-2909] = "4978",
|
||||
},
|
||||
[5619] = {
|
||||
[-19550] = "6609",
|
||||
},
|
||||
[5621] = {
|
||||
[-19551] = "6610",
|
||||
},
|
||||
[5623] = {
|
||||
[-19552] = "6611",
|
||||
},
|
||||
[5638] = {
|
||||
[-19594] = "6620",
|
||||
},
|
||||
[5692] = {
|
||||
[-19592] = "6627",
|
||||
},
|
||||
[5693] = {
|
||||
[-19601] = "6656",
|
||||
},
|
||||
[5694] = {
|
||||
[-19600] = "6630",
|
||||
},
|
||||
[5695] = {
|
||||
[-19591] = "6626",
|
||||
},
|
||||
[5810] = {
|
||||
[-19876] = "6717",
|
||||
},
|
||||
[5867] = {
|
||||
[-20806] = "6803",
|
||||
},
|
||||
[5880] = {
|
||||
[-20919] = "6918",
|
||||
},
|
||||
[6074] = {
|
||||
[-138497] = 0,
|
||||
},
|
||||
[6284] = {
|
||||
[-37097] = "9221",
|
||||
[37097] = "9221",
|
||||
},
|
||||
[6286] = {
|
||||
[-37097] = "9223",
|
||||
[37097] = "9223",
|
||||
},
|
||||
[6436] = {
|
||||
[4663] = "7914",
|
||||
[4664] = "7914",
|
||||
[4665] = "7914",
|
||||
[4666] = "7914",
|
||||
[4667] = "7914",
|
||||
},
|
||||
[6626] = {
|
||||
[-105576] = "9224",
|
||||
[105576] = "9224",
|
||||
},
|
||||
[6635] = {
|
||||
[-100035] = "8202",
|
||||
[-63674] = "8202",
|
||||
[100028] = "8202",
|
||||
[101749] = "8202",
|
||||
},
|
||||
[6637] = {
|
||||
[-100035] = "8899",
|
||||
[-63674] = "8899",
|
||||
[101750] = "8899",
|
||||
[113791] = "8899",
|
||||
},
|
||||
[6684] = {
|
||||
[4781] = "8283",
|
||||
},
|
||||
[6866] = {
|
||||
[6172] = "8593",
|
||||
[6177] = "8593",
|
||||
},
|
||||
[6913] = {
|
||||
[-92015] = "8674",
|
||||
[92015] = "8674",
|
||||
},
|
||||
[6928] = {
|
||||
[-92015] = "7728",
|
||||
[92015] = "7728",
|
||||
},
|
||||
[6931] = {
|
||||
[-92388] = "8712",
|
||||
[92252] = "8712",
|
||||
[92388] = "8712",
|
||||
},
|
||||
[6997] = {
|
||||
[-92388] = "8712",
|
||||
[92252] = "8712",
|
||||
[92388] = "8712",
|
||||
},
|
||||
[6999] = {
|
||||
[-92388] = "8712",
|
||||
[92252] = "8712",
|
||||
[92388] = "8712",
|
||||
},
|
||||
[7207] = {
|
||||
[-174794] = "8919",
|
||||
},
|
||||
[7247] = {
|
||||
[-103708] = "9082",
|
||||
[6492] = "9082",
|
||||
},
|
||||
[7269] = {
|
||||
[-174797] = "9052",
|
||||
},
|
||||
[7273] = {
|
||||
[-103660] = "9055",
|
||||
},
|
||||
[7297] = {
|
||||
[1200] = "8913",
|
||||
},
|
||||
[7308] = {
|
||||
[-103708] = "9095",
|
||||
[6492] = "9095",
|
||||
},
|
||||
[7464] = {
|
||||
[-105576] = "9222",
|
||||
[105576] = "9222",
|
||||
},
|
||||
[7766] = {
|
||||
[-107046] = "9586",
|
||||
},
|
||||
[7767] = {
|
||||
[-107047] = "9584",
|
||||
},
|
||||
[7768] = {
|
||||
[-107045] = "9583",
|
||||
},
|
||||
[8051] = {
|
||||
[7233] = "10113",
|
||||
},
|
||||
[8149] = {
|
||||
[7318] = 0,
|
||||
},
|
||||
[8155] = {
|
||||
[-138498] = "10459",
|
||||
},
|
||||
[8584] = {
|
||||
[-174796] = "11758",
|
||||
},
|
||||
[9189] = {
|
||||
[7774] = "11402",
|
||||
},
|
||||
[9263] = {
|
||||
[-144013] = "11537",
|
||||
},
|
||||
[9283] = {
|
||||
[6213] = "11513",
|
||||
[6329] = "11513",
|
||||
},
|
||||
[9323] = {
|
||||
[-142716] = "11548",
|
||||
},
|
||||
[9328] = {
|
||||
[7977] = 0,
|
||||
},
|
||||
[9364] = {
|
||||
[6218] = "12709",
|
||||
[6219] = "12709",
|
||||
[6220] = "12709",
|
||||
},
|
||||
[9466] = {
|
||||
[144050] = "11757",
|
||||
},
|
||||
[9472] = {
|
||||
[-144070] = 0,
|
||||
[144070] = "11792",
|
||||
},
|
||||
[9530] = {
|
||||
[-144569] = "11840",
|
||||
},
|
||||
[9606] = {
|
||||
[7584] = 0,
|
||||
},
|
||||
[9618] = {
|
||||
[2927] = 0,
|
||||
[2928] = 0,
|
||||
[2929] = 0,
|
||||
[7808] = 0,
|
||||
},
|
||||
[9619] = {
|
||||
[5300] = 0,
|
||||
[5304] = 0,
|
||||
[5305] = 0,
|
||||
[5306] = 0,
|
||||
},
|
||||
[9620] = {
|
||||
[5276] = 0,
|
||||
[5278] = 0,
|
||||
},
|
||||
[9621] = {
|
||||
[5357] = 0,
|
||||
[5358] = 0,
|
||||
[14604] = 0,
|
||||
[14640] = 0,
|
||||
},
|
||||
[10327] = {
|
||||
[-164651] = "12189",
|
||||
},
|
||||
[10338] = {
|
||||
[-164644] = "12199",
|
||||
},
|
||||
[10465] = {
|
||||
[-148422] = "12346",
|
||||
},
|
||||
[10515] = {
|
||||
[-149032] = 0,
|
||||
[-149031] = 0,
|
||||
[-149030] = 0,
|
||||
[-149025] = 0,
|
||||
},
|
||||
[10622] = {
|
||||
[-152093] = "12684",
|
||||
},
|
||||
[10699] = {
|
||||
[5307] = "12699",
|
||||
[5308] = "12699",
|
||||
},
|
||||
[10757] = {
|
||||
[-153205] = 0,
|
||||
},
|
||||
[11079] = {
|
||||
[-160840] = 0,
|
||||
},
|
||||
[11132] = {
|
||||
[-174793] = "13630",
|
||||
},
|
||||
[11169] = {
|
||||
[-148507] = "13978",
|
||||
},
|
||||
[11231] = {
|
||||
[9016] = "13982",
|
||||
},
|
||||
[11243] = {
|
||||
[-164799] = "14050",
|
||||
},
|
||||
[11286] = {
|
||||
[9520] = "14250",
|
||||
},
|
||||
[11412] = {
|
||||
[-165678] = "14929",
|
||||
},
|
||||
[11473] = {
|
||||
[-166807] = "15066",
|
||||
},
|
||||
[11522] = {
|
||||
[9376] = "14247",
|
||||
},
|
||||
[11682] = {
|
||||
[-138498] = "15491",
|
||||
},
|
||||
[11804] = {
|
||||
[9999] = "15591",
|
||||
},
|
||||
[11833] = {
|
||||
[-210338] = "15627",
|
||||
[-210337] = "15627",
|
||||
[-174792] = "15627",
|
||||
},
|
||||
[12262] = {
|
||||
[10221] = "15998",
|
||||
},
|
||||
[12284] = {
|
||||
[7047] = "16007",
|
||||
[7048] = "16007",
|
||||
},
|
||||
[12287] = {
|
||||
[175124] = "15958",
|
||||
},
|
||||
[12346] = {
|
||||
[-174795] = "16073",
|
||||
},
|
||||
[12350] = {
|
||||
[-175371] = "16077",
|
||||
[-4005] = "16077",
|
||||
},
|
||||
[12368] = {
|
||||
[-176111] = "17045",
|
||||
},
|
||||
[12472] = {
|
||||
[-148503] = "16378",
|
||||
[10541] = "16378",
|
||||
},
|
||||
[12565] = {
|
||||
[-148501] = "15647",
|
||||
},
|
||||
[12566] = {
|
||||
[-148501] = "15649",
|
||||
},
|
||||
[12627] = {
|
||||
[-175795] = "16613",
|
||||
[175795] = "16613",
|
||||
},
|
||||
[12647] = {
|
||||
[4678] = 0,
|
||||
[4681] = 0,
|
||||
[4685] = 0,
|
||||
},
|
||||
[12733] = {
|
||||
[-103819] = "16796",
|
||||
},
|
||||
[12785] = {
|
||||
[-175944] = 0,
|
||||
},
|
||||
[12807] = {
|
||||
[-176088] = "16989",
|
||||
},
|
||||
[12815] = {
|
||||
[-176097] = "17016",
|
||||
[-176096] = "17016",
|
||||
[-176095] = "17016",
|
||||
[-176094] = "17016",
|
||||
[176094] = "17016",
|
||||
[176095] = "17016",
|
||||
[176096] = "17016",
|
||||
[176097] = "17016",
|
||||
},
|
||||
[12848] = {
|
||||
[10899] = "17048",
|
||||
},
|
||||
[12906] = {
|
||||
[-176161] = 0,
|
||||
[-176160] = 0,
|
||||
[-176159] = 0,
|
||||
[-176158] = 0,
|
||||
},
|
||||
[12922] = {
|
||||
[-176184] = "17161",
|
||||
},
|
||||
[12928] = {
|
||||
[7583] = "17166",
|
||||
[10977] = "17166",
|
||||
[10978] = "17166",
|
||||
},
|
||||
[13289] = {
|
||||
[10384] = "17368",
|
||||
[10385] = "17368",
|
||||
[11122] = "17368",
|
||||
},
|
||||
[13536] = {
|
||||
[11218] = "17536",
|
||||
},
|
||||
[13752] = {
|
||||
[10508] = "17179",
|
||||
},
|
||||
[14338] = {
|
||||
[-174795] = "18397",
|
||||
},
|
||||
[14523] = {
|
||||
[-176581] = 0,
|
||||
},
|
||||
[14547] = {
|
||||
[-177400] = 0,
|
||||
[-177399] = 0,
|
||||
[-177398] = 0,
|
||||
[-177397] = 0,
|
||||
[-177369] = 0,
|
||||
[-177368] = 0,
|
||||
[-177367] = 0,
|
||||
[-177366] = 0,
|
||||
[-177365] = 0,
|
||||
[-177243] = 0,
|
||||
},
|
||||
[14644] = {
|
||||
[-4004] = "18711",
|
||||
},
|
||||
[15208] = {
|
||||
[-177525] = "18974",
|
||||
},
|
||||
[15209] = {
|
||||
[-177528] = "18987",
|
||||
},
|
||||
[15710] = {
|
||||
[-177525] = "19138",
|
||||
},
|
||||
[15736] = {
|
||||
[-177668] = "19250",
|
||||
[177668] = "19250",
|
||||
},
|
||||
[15842] = {
|
||||
[-19464] = "19565",
|
||||
},
|
||||
[15844] = {
|
||||
[-19463] = "19564",
|
||||
},
|
||||
[15848] = {
|
||||
[-177748] = "19588",
|
||||
},
|
||||
[15877] = {
|
||||
[-177788] = "19719",
|
||||
},
|
||||
[15883] = {
|
||||
[-177788] = "19720",
|
||||
},
|
||||
[15908] = {
|
||||
[1196] = 0,
|
||||
},
|
||||
[15911] = {
|
||||
[1126] = 0,
|
||||
},
|
||||
[15913] = {
|
||||
[1201] = 0,
|
||||
},
|
||||
[15914] = {
|
||||
[2956] = 0,
|
||||
},
|
||||
[15915] = {
|
||||
[2959] = 0,
|
||||
},
|
||||
[15916] = {
|
||||
[2970] = 0,
|
||||
},
|
||||
[15917] = {
|
||||
[3099] = 0,
|
||||
},
|
||||
[15919] = {
|
||||
[3107] = 0,
|
||||
},
|
||||
[15920] = {
|
||||
[3126] = 0,
|
||||
},
|
||||
[15921] = {
|
||||
[1998] = 0,
|
||||
},
|
||||
[15922] = {
|
||||
[2043] = 0,
|
||||
},
|
||||
[15923] = {
|
||||
[1996] = 0,
|
||||
},
|
||||
[16208] = {
|
||||
[-177929] = 0,
|
||||
},
|
||||
[16333] = {
|
||||
[-178090] = 0,
|
||||
},
|
||||
[16603] = {
|
||||
[-178145] = 0,
|
||||
},
|
||||
[16972] = {
|
||||
[-178206] = "20737",
|
||||
},
|
||||
[16974] = {
|
||||
[-178225] = "20814",
|
||||
},
|
||||
[17626] = {
|
||||
[10981] = "21794",
|
||||
},
|
||||
[17689] = {
|
||||
[10990] = "21866",
|
||||
},
|
||||
[17693] = {
|
||||
[-178907] = "21884",
|
||||
},
|
||||
[17696] = {
|
||||
[178905] = "21885",
|
||||
[178908] = "21885",
|
||||
},
|
||||
[18152] = {
|
||||
[-19552] = "22562",
|
||||
},
|
||||
[18488] = {
|
||||
[10184] = "22906",
|
||||
},
|
||||
[18601] = {
|
||||
[12396] = "23015",
|
||||
},
|
||||
[18626] = {
|
||||
[-179677] = "23054",
|
||||
},
|
||||
[18688] = {
|
||||
[-180632] = "23180",
|
||||
[-180631] = "23180",
|
||||
[-177387] = "23180",
|
||||
},
|
||||
[18746] = {
|
||||
[-179746] = "23204",
|
||||
},
|
||||
[18749] = {
|
||||
[-179746] = "23254",
|
||||
},
|
||||
[18752] = {
|
||||
[-179747] = "23208",
|
||||
[179747] = "23208",
|
||||
},
|
||||
[18904] = {
|
||||
[5357] = "23359",
|
||||
[5358] = "23359",
|
||||
[5359] = "23359",
|
||||
[5360] = "23359",
|
||||
[5361] = "23359",
|
||||
},
|
||||
[19036] = {
|
||||
[-179912] = "23514",
|
||||
},
|
||||
[19710] = {
|
||||
[-180375] = "24377",
|
||||
},
|
||||
[19711] = {
|
||||
[-180375] = "24377",
|
||||
},
|
||||
[19712] = {
|
||||
[-180375] = "24377",
|
||||
},
|
||||
[19713] = {
|
||||
[-180375] = "24377",
|
||||
},
|
||||
[19714] = {
|
||||
[-180375] = "24377",
|
||||
},
|
||||
[19715] = {
|
||||
[-180375] = "24377",
|
||||
},
|
||||
[19850] = {
|
||||
[-180204] = "24194",
|
||||
},
|
||||
[19851] = {
|
||||
[-180205] = "24195",
|
||||
},
|
||||
[20387] = {
|
||||
[-180504] = "24706",
|
||||
},
|
||||
[20464] = {
|
||||
[-180505] = "24815",
|
||||
},
|
||||
[20604] = {
|
||||
[180449] = "24973",
|
||||
[180450] = "24973",
|
||||
},
|
||||
[21136] = {
|
||||
[-300057] = "25783",
|
||||
[-180669] = "25783",
|
||||
},
|
||||
[21144] = {
|
||||
[-180673] = "25793",
|
||||
},
|
||||
[21986] = {
|
||||
[-181059] = "27517",
|
||||
[16079] = "27517",
|
||||
},
|
||||
[22048] = {
|
||||
[16042] = 0,
|
||||
},
|
||||
[22049] = {
|
||||
[-181046] = "27184",
|
||||
[16044] = "27184",
|
||||
},
|
||||
[22050] = {
|
||||
[-181047] = "27190",
|
||||
[16045] = "27190",
|
||||
},
|
||||
[22051] = {
|
||||
[-181048] = "27191",
|
||||
[16046] = "27191",
|
||||
},
|
||||
[22052] = {
|
||||
[-181049] = "27201",
|
||||
[16047] = "27201",
|
||||
},
|
||||
[22056] = {
|
||||
[-181050] = "27202",
|
||||
[16048] = "27202",
|
||||
},
|
||||
[22432] = {
|
||||
[6498] = 0,
|
||||
[6499] = 0,
|
||||
[6500] = 0,
|
||||
},
|
||||
[22737] = {
|
||||
[-181206] = "28354",
|
||||
},
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
+56030
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+30786
File diff suppressed because it is too large
Load Diff
+158332
File diff suppressed because it is too large
Load Diff
+127159
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,150 @@
|
||||
pfDB["zones"]["data-turtle"] = {
|
||||
[460] = { 406, 7.49, 7.49, 49.55, 61.98 },
|
||||
[461] = { 406, 14.47, 18.71, 66.32, 51.57 },
|
||||
[464] = { 406, 8.88, 10.33, 51.05, 45.88 },
|
||||
[465] = { 406, 10.28, 11.83, 38.27, 68.64 },
|
||||
[467] = { 406, 12.67, 13.47, 41.67, 22.16 },
|
||||
[1076] = { 406, 15.17, 30.54, 60.88, 70.36 },
|
||||
[2040] = { 0, 0, 0, 0, 0 },
|
||||
[2041] = { 406, 5.99, 9.28, 24.05, 12.13 },
|
||||
[2537] = { 406, 9.28, 5.84, 75.3, 83.16 },
|
||||
[2538] = { 406, 4.69, 5.99, 75.1, 88.47 },
|
||||
[2539] = { 406, 6.29, 5.99, 71.21, 90.87 },
|
||||
[2540] = { 406, 6.19, 6.89, 63.47, 88.62 },
|
||||
[2541] = { 406, 5.49, 7.63, 56.04, 72.83 },
|
||||
[3881] = { 5225, 3.19, 3.14, 41.42, 74.33 },
|
||||
[4011] = { 406, 7.19, 7.49, 41.12, 40.27 },
|
||||
[5043] = { 409, 10.58, 9.58, 57.19, 22.31 },
|
||||
[5044] = { 409, 9.98, 9.13, 57.58, 12.35 },
|
||||
[5045] = { 409, 5.09, 8.23, 72.21, 28.22 },
|
||||
[5046] = { 409, 12.28, 14.82, 33.68, 58.31 },
|
||||
[5047] = { 409, 14.17, 14.37, 47.5, 75.45 },
|
||||
[5048] = { 409, 6.29, 14.22, 69.81, 61.6 },
|
||||
[5049] = { 409, 6.09, 7.63, 52.94, 52.02 },
|
||||
[5050] = { 409, 11.68, 23.8, 37.87, 33.91 },
|
||||
[5051] = { 409, 7.58, 9.13, 59.98, 43.94 },
|
||||
[5052] = { 5024, 9.28, 8.83, 55.34, 64.45 },
|
||||
[5055] = { 408, 16.27, 10.48, 29.69, 87.28 },
|
||||
[5056] = { 408, 13.27, 7.04, 45.16, 80.16 },
|
||||
[5057] = { 408, 3.39, 15.42, 27.84, 69.39 },
|
||||
[5058] = { 408, 6.39, 12.13, 45.61, 57.11 },
|
||||
[5059] = { 408, 7.98, 12.87, 64.27, 57.19 },
|
||||
[5060] = { 408, 4.19, 5.09, 58.48, 48.2 },
|
||||
[5061] = { 408, 7.78, 6.14, 45.51, 69.99 },
|
||||
[5062] = { 408, 6.89, 21.11, 70.81, 56.36 },
|
||||
[5065] = { 408, 9.58, 14.07, 69.46, 78.74 },
|
||||
[5066] = { 408, 3.79, 5.09, 59.08, 82.04 },
|
||||
[5067] = { 408, 4.29, 6.44, 49.75, 38.1 },
|
||||
[5068] = { 408, 17.27, 14.22, 52.45, 15.49 },
|
||||
[5069] = { 408, 10.78, 22.16, 24.35, 22.01 },
|
||||
[5070] = { 408, 7.29, 7.34, 27.69, 37.5 },
|
||||
[5071] = { 408, 6.99, 10.18, 37.62, 52.1 },
|
||||
[5072] = { 409, 5.29, 7.34, 60.03, 31.81 },
|
||||
[5117] = { 406, 13.27, 20.51, 28.19, 32.41 },
|
||||
[5118] = { 406, 6.49, 6.14, 36.98, 50.07 },
|
||||
[5119] = { 406, 13.27, 13.62, 75, 72.38 },
|
||||
[5120] = { 406, 6.19, 7.49, 77.84, 61.83 },
|
||||
[5123] = { 5121, 7.58, 6.59, 42.12, 79.04 },
|
||||
[5124] = { 5121, 5.49, 4.94, 51.35, 33.76 },
|
||||
[5125] = { 5121, 9.58, 17.81, 55.19, 50.37 },
|
||||
[5126] = { 5121, 3.69, 4.94, 41.57, 52.77 },
|
||||
[5127] = { 5121, 4.59, 6.59, 53.09, 81.44 },
|
||||
[5128] = { 5121, 19.26, 23.2, 53.84, 19.54 },
|
||||
[5180] = { 5179, 11.78, 23.95, 23.15, 36.23 },
|
||||
[5181] = { 5179, 6.69, 7.34, 58.63, 72.23 },
|
||||
[5182] = { 5179, 7.19, 12.43, 63.67, 83.61 },
|
||||
[5183] = { 5179, 7.29, 7.04, 54.84, 63.55 },
|
||||
[5184] = { 5179, 5.79, 5.09, 44.61, 65.57 },
|
||||
[5185] = { 5179, 11.78, 7.63, 42.91, 75.37 },
|
||||
[5186] = { 5179, 3.09, 3.44, 33.38, 76.27 },
|
||||
[5187] = { 5179, 2, 2.54, 33.53, 53.67 },
|
||||
[5188] = { 5179, 7.49, 6.14, 33.68, 47.68 },
|
||||
[5189] = { 5179, 2.5, 2.99, 47.95, 35.63 },
|
||||
[5191] = { 5179, 2.4, 3.74, 43.81, 27.77 },
|
||||
[5192] = { 5179, 2.99, 3.74, 53.39, 29.27 },
|
||||
[5195] = { 5179, 3.09, 4.34, 48.05, 56.66 },
|
||||
[5196] = { 5179, 4.19, 10.48, 20.26, 64.67 },
|
||||
[5197] = { 5179, 0, 0, 0, 0 },
|
||||
[5198] = { 5179, 2.79, 4.04, 66.17, 65.19 },
|
||||
[5199] = { 5179, 2.59, 4.34, 64.97, 57.86 },
|
||||
[5200] = { 5179, 4.79, 16.32, 39.62, 15.94 },
|
||||
[5201] = { 5179, 4.89, 5.84, 56.94, 40.04 },
|
||||
[5203] = { 5179, 5.09, 6.59, 46.76, 17.07 },
|
||||
[5206] = { 5179, 3.29, 4.64, 14.32, 33.76 },
|
||||
[5207] = { 5179, 0, 0, 0, 0 },
|
||||
[5212] = { 616, 22.16, 30.39, 55.49, 32.11 },
|
||||
[5213] = { 616, 14.77, 33.53, 73.95, 31.89 },
|
||||
[5214] = { 616, 5.49, 7.19, 84.08, 28.89 },
|
||||
[5215] = { 616, 13.37, 12.72, 50.7, 55.46 },
|
||||
[5216] = { 616, 13.27, 7.78, 63.52, 67.07 },
|
||||
[5217] = { 616, 8.28, 9.13, 33.68, 40.94 },
|
||||
[5218] = { 616, 11.18, 18.11, 21.76, 49.33 },
|
||||
[5219] = { 616, 10.08, 12.13, 9.93, 44.84 },
|
||||
[5220] = { 616, 9.08, 11.98, 43.26, 76.5 },
|
||||
[5221] = { 616, 5.59, 6.59, 20.56, 60.48 },
|
||||
[5528] = { 5225, 13.37, 20.21, 27.74, 78.82 },
|
||||
[5529] = { 5225, 16.77, 10.03, 32.24, 48.13 },
|
||||
[5531] = { 5225, 16.07, 19.01, 33.38, 28.97 },
|
||||
[5532] = { 5225, 11.08, 12.43, 52.05, 49.48 },
|
||||
[5533] = { 5225, 10.48, 12.87, 48.65, 85.48 },
|
||||
[5534] = { 5225, 13.67, 16.32, 16.92, 44.99 },
|
||||
[5537] = { 5536, 9.78, 10.33, 48.3, 65.79 },
|
||||
[5538] = { 5536, 8.48, 9.73, 35.78, 61.15 },
|
||||
[5539] = { 5536, 9.18, 9.43, 53.29, 50.22 },
|
||||
[5540] = { 5536, 5.29, 6.59, 57.83, 24.1 },
|
||||
[5541] = { 5536, 9.28, 11.23, 62.62, 82.41 },
|
||||
[5542] = { 5536, 5.19, 8.08, 54.89, 32.34 },
|
||||
[5543] = { 5536, 8.68, 10.33, 62.33, 58.46 },
|
||||
[5546] = { 5225, 7.58, 8.83, 57.19, 71.33 },
|
||||
[5548] = { 406, 5.29, 6.44, 47.55, 34.96 },
|
||||
[5558] = { 5557, 9.28, 8.83, 55.34, 64.45 },
|
||||
[5562] = { 5561, 6.29, 8.53, 27.3, 12.8 },
|
||||
[5563] = { 5561, 7.58, 13.02, 41.42, 21.63 },
|
||||
[5564] = { 5561, 6.49, 5.84, 70.11, 77.32 },
|
||||
[5565] = { 5561, 8.28, 8.08, 53.64, 49.25 },
|
||||
[5566] = { 5561, 5.69, 7.49, 46.96, 45.36 },
|
||||
[5567] = { 5561, 5.49, 5.69, 47.85, 57.93 },
|
||||
[5568] = { 5561, 8.88, 10.93, 39.07, 52.62 },
|
||||
[5569] = { 5561, 7.19, 16.92, 35.03, 37.05 },
|
||||
[5570] = { 5561, 9.68, 13.32, 56.94, 63.4 },
|
||||
[5571] = { 5561, 7.68, 7.78, 55.34, 74.55 },
|
||||
[5572] = { 5561, 6.99, 32.78, 30.14, 65.34 },
|
||||
[5573] = { 5561, 13.57, 7.49, 52.69, 86.68 },
|
||||
[5574] = { 5561, 5.09, 8.53, 39.87, 62.95 },
|
||||
[5575] = { 5561, 4.39, 7.78, 35.63, 66.17 },
|
||||
[5576] = { 5561, 5.69, 9.88, 71.11, 47.6 },
|
||||
[5582] = { 5581, 9.98, 6.44, 47.01, 81.96 },
|
||||
[5583] = { 5581, 7.39, 7.63, 46.71, 58.61 },
|
||||
[5585] = { 5581, 4.89, 5.54, 32.88, 60.55 },
|
||||
[5587] = { 5581, 9.78, 11.08, 76.35, 86.38 },
|
||||
[5588] = { 5581, 4.39, 6.29, 56.99, 58.83 },
|
||||
[5589] = { 5581, 5.09, 7.93, 38.77, 43.34 },
|
||||
[5590] = { 5581, 5.89, 6.59, 32.88, 26.05 },
|
||||
[5591] = { 5581, 5.29, 9.13, 74, 31.06 },
|
||||
[5593] = { 5581, 13.47, 30.39, 84.18, 19.69 },
|
||||
[5594] = { 5581, 5.49, 21.26, 82.98, 47.9 },
|
||||
[5595] = { 5581, 5.69, 13.62, 67.91, 69.24 },
|
||||
[5596] = { 5581, 8.28, 9.88, 62.23, 23.8 },
|
||||
[5597] = { 5581, 6.39, 8.08, 21.26, 44.16 },
|
||||
[5598] = { 406, 5.79, 8.68, 49.6, 71.56 },
|
||||
[5603] = { 5602, 5.89, 5.84, 53.74, 56.81 },
|
||||
[5606] = { 5602, 19.26, 18.26, 55.14, 83.08 },
|
||||
[5607] = { 5602, 5.99, 7.63, 54.19, 48.13 },
|
||||
[5608] = { 5602, 3.99, 5.54, 56.19, 70.13 },
|
||||
[5609] = { 5602, 2.59, 9.58, 45.21, 56.29 },
|
||||
[5611] = { 5602, 6.49, 10.03, 60.03, 66.24 },
|
||||
[5612] = { 5602, 3.99, 5.09, 46.91, 35.33 },
|
||||
[5613] = { 5602, 5.39, 4.19, 44.51, 42.22 },
|
||||
[5614] = { 5602, 6.09, 5.24, 42.76, 17.14 },
|
||||
[5615] = { 5602, 4.99, 7.49, 61.78, 44.16 },
|
||||
[5616] = { 5602, 5.89, 7.49, 54.64, 15.42 },
|
||||
[5617] = { 5602, 3.29, 4.49, 50.05, 21.26 },
|
||||
[5618] = { 5602, 2.99, 4.34, 50.4, 10.4 },
|
||||
[5619] = { 5602, 5.59, 5.69, 59.48, 32.04 },
|
||||
[5621] = { 5602, 3.09, 5.99, 60.73, 14.97 },
|
||||
[5622] = { 5581, 4.89, 6.29, 30.39, 42.96 },
|
||||
[5623] = { 5581, 3.99, 4.79, 66.67, 45.36 },
|
||||
[5625] = { 5581, 3.89, 4.79, 54.24, 32.04 },
|
||||
[5626] = { 5581, 9.58, 15.42, 83.73, 70.43 },
|
||||
[5630] = { 5602, 3.09, 5.54, 57.44, 39.45 },
|
||||
}
|
||||
@@ -0,0 +1,528 @@
|
||||
pfDB["zones"]["data"] = {
|
||||
[9] = { 12, 17.47, 27.69, 51.15, 42.29 },
|
||||
[18] = { 12, 15.47, 14.22, 52.64, 64 },
|
||||
[19] = { 33, 14.97, 22.46, 59.88, 18.71 },
|
||||
[20] = { 40, 10.48, 20.21, 44.16, 65.49 },
|
||||
[35] = { 33, 8.48, 10.48, 26.2, 74.1 },
|
||||
[37] = { 33, 5.99, 7.49, 40.42, 18.71 },
|
||||
[42] = { 10, 12.48, 14.97, 77.1, 44.91 },
|
||||
[43] = { 33, 4.99, 7.49, 32.44, 79.34 },
|
||||
[57] = { 12, 16.97, 15.72, 38.42, 84.21 },
|
||||
[60] = { 12, 9.98, 29.94, 24.95, 81.59 },
|
||||
[62] = { 12, 11.98, 10.48, 67.37, 79.34 },
|
||||
[68] = { 44, 34.93, 20.96, 41.92, 59.13 },
|
||||
[69] = { 44, 17.96, 11.98, 25.45, 43.41 },
|
||||
[70] = { 44, 13.47, 20.21, 66.12, 55.01 },
|
||||
[71] = { 44, 18.46, 12.72, 74.6, 66.99 },
|
||||
[72] = { 4, 12.97, 15.72, 58.38, 56.51 },
|
||||
[73] = { 4, 22.95, 36.68, 37.92, 62.5 },
|
||||
[74] = { 8, 18.46, 26.2, 71.11, 52.77 },
|
||||
[75] = { 8, 21.46, 20.21, 47.65, 55.01 },
|
||||
[76] = { 8, 22.46, 26.95, 65.12, 22.46 },
|
||||
[86] = { 12, 15.47, 24.7, 75.1, 49.78 },
|
||||
[87] = { 12, 8.48, 9.73, 41.17, 64.75 },
|
||||
[88] = { 12, 12.48, 12.72, 83.58, 66.24 },
|
||||
[91] = { 12, 13.47, 13.47, 67.61, 66.62 },
|
||||
[93] = { 10, 15.47, 16.47, 36.18, 73.35 },
|
||||
[94] = { 10, 10.48, 10.48, 20.71, 56.14 },
|
||||
[95] = { 44, 22.46, 18.71, 28.69, 28.07 },
|
||||
[97] = { 44, 11.98, 18.71, 53.39, 42.29 },
|
||||
[99] = { 33, 7.98, 5.24, 37.43, 5.61 },
|
||||
[100] = { 33, 7.49, 8.23, 34.18, 13.1 },
|
||||
[101] = { 33, 7.98, 8.23, 45.41, 9.36 },
|
||||
[102] = { 33, 7.98, 8.23, 25.95, 12.35 },
|
||||
[103] = { 33, 6.49, 9.73, 46.66, 42.29 },
|
||||
[104] = { 33, 12.48, 14.97, 24.2, 27.69 },
|
||||
[105] = { 33, 7.98, 11.98, 49.4, 29.94 },
|
||||
[107] = { 40, 9.98, 11.23, 55.39, 32.56 },
|
||||
[108] = { 40, 8.98, 15.72, 55.89, 49.78 },
|
||||
[109] = { 40, 8.98, 12.72, 50.9, 21.33 },
|
||||
[111] = { 40, 8.48, 11.23, 44.66, 24.33 },
|
||||
[113] = { 40, 11.98, 14.22, 31.44, 41.54 },
|
||||
[115] = { 40, 11.98, 13.47, 31.94, 86.08 },
|
||||
[116] = { 8, 16.47, 14.97, 13.22, 35.93 },
|
||||
[117] = { 33, 6.49, 6.74, 31.69, 27.32 },
|
||||
[118] = { 11, 9.98, 9.73, 35.93, 49.03 },
|
||||
[121] = { 10, 9.48, 11.23, 80.09, 69.99 },
|
||||
[122] = { 33, 4.49, 5.99, 21.21, 14.97 },
|
||||
[123] = { 33, 4.99, 5.24, 29.44, 19.84 },
|
||||
[125] = { 33, 4.99, 5.99, 34.43, 20.96 },
|
||||
[127] = { 33, 5.49, 6.74, 41.67, 31.06 },
|
||||
[128] = { 33, 4.49, 11.98, 40.67, 41.17 },
|
||||
[129] = { 33, 3.99, 5.24, 36.93, 29.57 },
|
||||
[131] = { 1, 10.98, -18.71, 49.9, 67.74 },
|
||||
[132] = { 1, 14.97, 17.22, 26.45, 75.22 },
|
||||
[133] = { 1, 7.49, 11.98, 24.2, 38.17 },
|
||||
[134] = { 1, 9.48, 13.47, 68.61, 57.63 },
|
||||
[135] = { 1, 4.49, 8.98, 28.19, 51.65 },
|
||||
[136] = { 1, 5.99, 11.23, 40.92, 58.01 },
|
||||
[137] = { 1, 4.99, 9.73, 30.44, 46.03 },
|
||||
[138] = { 1, 5.99, 11.98, 57.39, 42.66 },
|
||||
[142] = { 38, 13.97, 17.22, 69.36, 65.49 },
|
||||
[143] = { 38, 17.96, 18.71, 70.86, 25.07 },
|
||||
[144] = { 38, 9.98, 12.72, 34.93, 46.03 },
|
||||
[146] = { 38, 19.96, 11.98, 47.9, 12.72 },
|
||||
[147] = { 38, 8.48, 11.98, 83.08, 62.87 },
|
||||
[149] = { 38, 10.98, 16.47, 34.43, 21.71 },
|
||||
[150] = { 11, 6.49, 10.48, 10.23, 56.89 },
|
||||
[152] = { 85, 13.47, 25.45, 83.58, 69.61 },
|
||||
[154] = { 85, 13.17, 18.26, 34.43, 63.92 },
|
||||
[156] = { 85, 15.27, 12.13, 35.98, 49.48 },
|
||||
[157] = { 85, 13.77, 17.96, 45.21, 36.38 },
|
||||
[159] = { 85, 7.49, 14.67, 59.63, 55.24 },
|
||||
[160] = { 85, 16.67, 22.6, 84.78, 32.86 },
|
||||
[162] = { 85, 10.18, 34.88, 68.26, 42.14 },
|
||||
[164] = { 85, 9.58, 21.86, 57.78, 38.17 },
|
||||
[165] = { 85, 13.07, 23.05, 72.8, 61.68 },
|
||||
[166] = { 85, 7.29, 10.63, 53.74, 59.96 },
|
||||
[167] = { 85, 14.47, 15.42, 77.89, 51.42 },
|
||||
[172] = { 130, 18.96, 20.21, 71.86, 28.82 },
|
||||
[186] = { 141, 11.48, 11.98, 55.14, 56.89 },
|
||||
[188] = { 141, 12.48, 18.71, 59.63, 40.04 },
|
||||
[190] = { 28, 21.46, 19.46, 47.16, 17.96 },
|
||||
[192] = { 28, 9.98, 14.22, 47.41, 36.3 },
|
||||
[193] = { 28, 11.48, 12.72, 43.66, 69.24 },
|
||||
[197] = { 28, 9.48, 13.47, 51.65, 79.34 },
|
||||
[198] = { 28, 7.49, 12.72, 65.12, 42.29 },
|
||||
[199] = { 28, 7.98, 9.73, 37.43, 55.76 },
|
||||
[200] = { 28, 8.98, 11.23, 46.41, 52.77 },
|
||||
[201] = { 28, 9.98, 11.23, 62.87, 57.26 },
|
||||
[202] = { 28, 6.99, 9.73, 53.39, 65.49 },
|
||||
[204] = { 130, 7.98, 8.23, 44.91, 73.73 },
|
||||
[205] = { 11, 9.98, 9.73, 49.4, 16.84 },
|
||||
[211] = { 1, 6.99, 18.71, 34.93, 38.55 },
|
||||
[212] = { 1, 7.98, 14.22, 76.85, 54.27 },
|
||||
[213] = { 130, 6.49, 11.23, 56.14, 48.28 },
|
||||
[219] = { 40, 11.48, 16.47, 38.17, 52.4 },
|
||||
[220] = { 215, 21.96, 21.71, 44.91, 82.71 },
|
||||
[222] = { 215, 11.98, 14.97, 47.41, 59.13 },
|
||||
[224] = { 215, 7.98, 8.98, 54.39, 47.16 },
|
||||
[225] = { 215, 11.48, 17.96, 61.13, 20.21 },
|
||||
[226] = { 130, 9.98, 10.48, 37.43, 15.72 },
|
||||
[228] = { 130, 8.48, 9.73, 44.66, 40.79 },
|
||||
[229] = { 130, 7.98, 8.98, 46.91, 53.89 },
|
||||
[230] = { 130, 8.98, 13.47, 46.41, 86.08 },
|
||||
[231] = { 130, 7.98, 9.73, 58.88, 72.23 },
|
||||
[233] = { 130, 10.98, 14.97, 63.37, 62.87 },
|
||||
[236] = { 130, 10.48, 9.73, 44.16, 66.24 },
|
||||
[237] = { 130, 8.98, 11.23, 55.39, 36.3 },
|
||||
[238] = { 130, 6.49, 5.99, 56.64, 10.48 },
|
||||
[240] = { 130, 6.99, 8.98, 46.41, 21.71 },
|
||||
[241] = { 10, 12.48, 17.22, 64.12, 72.98 },
|
||||
[242] = { 10, 11.48, 32.19, 62.62, 40.79 },
|
||||
[245] = { 10, 9.48, 14.97, 49.15, 73.35 },
|
||||
[246] = { 51, 29.44, 20.96, 46.16, 49.4 },
|
||||
[247] = { 51, 17.96, 14.22, 64.87, 58.76 },
|
||||
[249] = { 46, 13.97, 21.71, 81.34, 41.54 },
|
||||
[250] = { 46, 20.46, 25.45, 65.12, 34.43 },
|
||||
[252] = { 46, 13.47, 22.46, 43.66, 35.18 },
|
||||
[253] = { 46, 17.47, 15.72, 50.15, 56.51 },
|
||||
[254] = { 46, 15.97, 20.21, 29.94, 31.81 },
|
||||
[255] = { 46, 11.48, 19.46, 15.72, 32.19 },
|
||||
[259] = { 141, 16.47, 14.97, 57.63, 71.11 },
|
||||
[260] = { 141, 10.48, 11.98, 65.62, 57.63 },
|
||||
[261] = { 141, 7.98, 10.48, 43.91, 74.85 },
|
||||
[264] = { 141, 5.99, 21.71, 37.92, 36.3 },
|
||||
[266] = { 141, 10.98, 21.71, 46.91, 35.55 },
|
||||
[271] = { 267, 10.48, 17.96, 49.65, 55.39 },
|
||||
[272] = { 267, 13.47, 21.71, 61.13, 25.82 },
|
||||
[275] = { 267, 12.97, 15.72, 76.85, 40.79 },
|
||||
[278] = { 36, 8.98, 12.72, 20.46, 84.96 },
|
||||
[279] = { 36, 15.47, 23.95, 15.22, 65.87 },
|
||||
[280] = { 36, 12.97, 14.22, 63.37, 45.28 },
|
||||
[281] = { 36, 13.97, 18.71, 39.92, 53.52 },
|
||||
[282] = { 36, 9.98, 19.46, 48.4, 41.92 },
|
||||
[284] = { 36, 12.97, 18.71, 56.39, 27.32 },
|
||||
[285] = { 267, 15.97, 18.71, 15.47, 46.03 },
|
||||
[286] = { 267, 19.96, 29.94, 34.93, 44.91 },
|
||||
[288] = { 267, 9.48, 11.23, 26.2, 57.26 },
|
||||
[289] = { 267, 11.98, 23.95, 63.87, 55.39 },
|
||||
[290] = { 267, 9.48, 21.71, 72.11, 71.48 },
|
||||
[294] = { 267, 13.97, 17.22, 61.88, 74.48 },
|
||||
[295] = { 267, 23.45, 11.98, 35.68, 68.11 },
|
||||
[297] = { 33, 7.98, 11.98, 38.92, 82.34 },
|
||||
[300] = { 8, 13.97, 83.08, 88.32, 52.77 },
|
||||
[307] = { 47, 7.98, 32.93, 79.34, 68.86 },
|
||||
[309] = { 11, 12.48, 17.22, 44.66, 31.06 },
|
||||
[310] = { 33, 5.99, 8.23, 40.92, 50.52 },
|
||||
[311] = { 33, 4.49, 5.99, 39.67, 59.13 },
|
||||
[313] = { 45, 8.48, 17.96, 31.69, 31.44 },
|
||||
[314] = { 45, 7.98, 11.23, 61.38, 56.51 },
|
||||
[315] = { 45, 9.48, 10.48, 55.14, 39.67 },
|
||||
[316] = { 45, 13.47, 20.21, 54.14, 73.73 },
|
||||
[317] = { 45, 14.47, 11.23, 66.62, 66.99 },
|
||||
[320] = { 45, 7.98, 16.47, 45.91, 47.16 },
|
||||
[321] = { 45, 12.48, 16.47, 75.1, 36.68 },
|
||||
[324] = { 45, 17.47, 22.46, 22.7, 62.13 },
|
||||
[327] = { 45, 18.96, 17.22, 30.94, 79.72 },
|
||||
[333] = { 45, 8.48, 15.72, 63.62, 34.06 },
|
||||
[334] = { 45, 10.48, 17.96, 22.21, 25.45 },
|
||||
[335] = { 45, 10.48, 14.22, 36.68, 61.75 },
|
||||
[336] = { 45, 8.48, 9.73, 52.64, 52.77 },
|
||||
[337] = { 3, 11.48, 15.72, 15.72, 61.75 },
|
||||
[338] = { 3, 13.97, 15.72, 42.91, 33.31 },
|
||||
[339] = { 3, 19.96, 34.43, 78.34, 50.9 },
|
||||
[340] = { 3, 15.47, 15.72, 8.73, 47.53 },
|
||||
[341] = { 3, 12.48, 14.97, 66.12, 22.46 },
|
||||
[342] = { 3, 13.97, 25.45, 61.38, 72.6 },
|
||||
[344] = { 3, 18.46, 20.96, 13.22, 81.59 },
|
||||
[345] = { 3, 14.47, 22.46, 47.16, 74.1 },
|
||||
[346] = { 3, 13.47, 15.72, 56.64, 36.3 },
|
||||
[348] = { 47, 12.48, 15.72, 14.72, 50.52 },
|
||||
[350] = { 47, 11.98, 18.71, 31.44, 43.04 },
|
||||
[351] = { 47, 8.48, 11.23, 59.13, 43.04 },
|
||||
[353] = { 47, 10.48, 14.22, 34.68, 71.48 },
|
||||
[354] = { 47, 14.97, 31.44, 62.38, 69.61 },
|
||||
[355] = { 47, 9.48, 11.23, 48.65, 66.24 },
|
||||
[356] = { 47, 16.47, 23.95, 64.12, 25.45 },
|
||||
[359] = { 17, 5.49, 8.98, 47.65, 83.83 },
|
||||
[360] = { 215, 6.49, 16.47, 61.63, 50.15 },
|
||||
[362] = { 14, 9.48, 11.98, 54.64, 42.66 },
|
||||
[363] = { 14, 9.98, 15.72, 44.41, 66.99 },
|
||||
[366] = { 14, 5.99, 8.98, 48.9, 79.34 },
|
||||
[367] = { 14, 7.49, 11.23, 56.14, 72.98 },
|
||||
[368] = { 14, 10.98, 28.44, 65.37, 84.58 },
|
||||
[369] = { 14, 10.48, 17.22, 40.67, 24.33 },
|
||||
[370] = { 14, 9.98, 13.47, 52.4, 24.7 },
|
||||
[372] = { 14, 8.48, 14.97, 57.63, 56.14 },
|
||||
[378] = { 17, 6.49, 8.23, 45.66, 61 },
|
||||
[379] = { 17, 4.49, 8.23, 61.13, 21.33 },
|
||||
[380] = { 17, 6.49, 7.49, 51.65, 28.44 },
|
||||
[381] = { 17, 4.99, 10.48, 61.88, 6.74 },
|
||||
[382] = { 17, 9.98, 8.98, 55.39, 7.49 },
|
||||
[383] = { 17, 9.48, 11.23, 39.67, 14.6 },
|
||||
[384] = { 17, 6.99, 8.23, 48.4, 18.34 },
|
||||
[385] = { 17, 7.49, 8.98, 61.13, 55.39 },
|
||||
[386] = { 17, 6.99, 9.73, 45.41, 23.58 },
|
||||
[387] = { 17, 6.49, 10.48, 46.66, 38.92 },
|
||||
[388] = { 17, 5.49, 8.98, 55.64, 42.66 },
|
||||
[390] = { 17, 7.49, 8.23, 46.16, 70.73 },
|
||||
[391] = { 17, 4.49, 9.73, 63.62, 45.28 },
|
||||
[392] = { 17, 5.49, 7.49, 62.62, 37.43 },
|
||||
[396] = { 215, 7.49, 8.98, 54.14, 65.87 },
|
||||
[397] = { 215, 6.49, 10.48, 44.66, 45.66 },
|
||||
[398] = { 215, 12.97, 9.73, 39.42, 12.35 },
|
||||
[404] = { 215, 9.48, 14.97, 33.68, 46.41 },
|
||||
[413] = { 331, 8.48, 24.7, 29.19, 25.82 },
|
||||
[414] = { 331, 16.97, 26.2, 12.97, 22.08 },
|
||||
[415] = { 331, 12.48, 14.97, 37.18, 51.65 },
|
||||
[416] = { 331, 9.48, 14.22, 22.21, 52.77 },
|
||||
[417] = { 331, 6.49, 10.48, 26.7, 63.62 },
|
||||
[418] = { 331, 7.98, 13.47, 33.43, 67.37 },
|
||||
[419] = { 331, 12.48, 14.22, 56.14, 37.05 },
|
||||
[421] = { 331, 14.97, 17.96, 49.4, 73.35 },
|
||||
[422] = { 331, 11.48, 12.72, 69.11, 81.96 },
|
||||
[424] = { 331, 6.99, 11.23, 46.41, 46.78 },
|
||||
[426] = { 331, 9.98, 11.98, 60.88, 51.65 },
|
||||
[428] = { 331, 11.48, 16.47, 71.61, 59.13 },
|
||||
[430] = { 331, 13.97, 9.73, 81.84, 48.28 },
|
||||
[434] = { 331, 16.47, 15.72, 83.08, 77.47 },
|
||||
[437] = { 331, 11.48, 11.98, 91.07, 59.13 },
|
||||
[438] = { 331, 8.98, 12.72, 93.81, 36.3 },
|
||||
[439] = { 400, 24.95, 48.65, 78.34, 72.98 },
|
||||
[441] = { 331, 5.99, 11.98, 20.46, 40.42 },
|
||||
[442] = { 148, 7.49, 11.23, 39.17, 43.79 },
|
||||
[443] = { 148, 6.49, 14.97, 58.63, 16.47 },
|
||||
[444] = { 148, 8.98, 8.98, 56.39, 26.2 },
|
||||
[446] = { 148, 6.99, 8.23, 44.91, 36.3 },
|
||||
[447] = { 148, 6.49, 10.48, 42.66, 57.63 },
|
||||
[448] = { 148, 8.98, 11.98, 42.91, 77.1 },
|
||||
[449] = { 148, 8.98, 11.23, 41.42, 88.7 },
|
||||
[450] = { 148, 5.99, 8.98, 34.93, 85.33 },
|
||||
[456] = { 148, 10.48, 9.73, 53.64, 33.31 },
|
||||
[459] = { 85, 7.98, 31.59, 77.84, 32.86 },
|
||||
[460] = { 406, 10.98, 13.47, 46.41, 58.38 },
|
||||
[461] = { 406, 25.95, 29.19, 69.86, 50.52 },
|
||||
[464] = { 406, 13.47, 15.72, 49.15, 40.79 },
|
||||
[465] = { 406, 14.97, 21.71, 31.94, 66.99 },
|
||||
[467] = { 406, 20.46, 17.96, 37.18, 13.47 },
|
||||
[477] = { 33, 4.49, 5.99, 35.68, 51.65 },
|
||||
[478] = { 141, 5.99, 13.47, 40.42, 63.62 },
|
||||
[480] = { 400, 19.46, 23.2, 16.22, 17.59 },
|
||||
[481] = { 400, 15.97, 14.97, 47.9, 41.17 },
|
||||
[482] = { 400, 12.97, 23.2, 13.47, 34.06 },
|
||||
[483] = { 400, 16.47, 24.7, 30.69, 47.53 },
|
||||
[484] = { 400, 12.48, 15.72, 46.16, 52.77 },
|
||||
[485] = { 400, 9.48, 10.48, 32.19, 22.46 },
|
||||
[492] = { 10, 11.48, 20.96, 20.21, 41.92 },
|
||||
[496] = { 15, 12.97, 24.7, 36.93, 22.83 },
|
||||
[502] = { 15, 18.96, 27.69, 53.89, 22.83 },
|
||||
[509] = { 15, 10.98, 19.46, 36.93, 61.38 },
|
||||
[511] = { 15, 17.47, 20.21, 52.64, 75.22 },
|
||||
[513] = { 15, 13.47, 18.71, 68.11, 51.27 },
|
||||
[536] = { 10, 11.48, 14.22, 21.71, 69.24 },
|
||||
[537] = { 490, 17.96, 24.7, 50.4, 49.78 },
|
||||
[538] = { 490, 30.44, 33.68, 50.65, 20.58 },
|
||||
[539] = { 490, 14.47, 23.95, 37.18, 74.1 },
|
||||
[540] = { 490, 15.47, 19.46, 51.65, 80.09 },
|
||||
[543] = { 490, 17.47, 29.94, 30.19, 50.15 },
|
||||
[556] = { 38, 19.46, 50.15, 50.15, 42.29 },
|
||||
[596] = { 405, 14.47, 18.71, 50.65, 58.01 },
|
||||
[599] = { 405, 10.98, 11.23, 54.39, 28.07 },
|
||||
[602] = { 405, 15.97, 17.96, 53.39, 79.34 },
|
||||
[603] = { 405, 12.97, 17.22, 75.85, 22.83 },
|
||||
[604] = { 405, 12.48, 18.71, 71.11, 72.98 },
|
||||
[606] = { 405, 12.97, 16.47, 38.42, 89.07 },
|
||||
[607] = { 405, 16.47, 27.69, 33.18, 52.02 },
|
||||
[608] = { 405, 9.98, 11.23, 64.87, 9.36 },
|
||||
[609] = { 405, 9.98, 14.97, 74.35, 48.65 },
|
||||
[656] = { 493, 28.44, 38.92, 50.65, 54.64 },
|
||||
[657] = { 8, 12.48, 14.97, 27.69, 35.93 },
|
||||
[702] = { 141, 1.5, 2.25, 55.64, 90.94 },
|
||||
[736] = { 141, 8.98, 23.2, 46.41, 57.26 },
|
||||
[797] = { 12, 15.47, 17.96, 53.64, 83.08 },
|
||||
[798] = { 12, 12.48, 9.73, 85.08, 80.46 },
|
||||
[799] = { 10, 84.33, 17.22, 54.64, 21.33 },
|
||||
[800] = { 1, 5.99, 10.48, 34.93, 68.11 },
|
||||
[801] = { 1, 7.98, 10.48, 35.93, 53.14 },
|
||||
[802] = { 1, 5.99, 14.22, 40.92, 40.04 },
|
||||
[803] = { 1, 5.99, 6.74, 63.37, 50.52 },
|
||||
[804] = { 1, 8.98, 8.23, 59.88, 57.26 },
|
||||
[806] = { 1, 5.99, 10.48, 85.33, 50.9 },
|
||||
[808] = { 1, 5.99, 14.22, 82.83, 37.8 },
|
||||
[809] = { 1, 10.98, 13.47, 49.4, 37.43 },
|
||||
[810] = { 85, 10.28, 10.63, 47.95, 51.27 },
|
||||
[811] = { 85, 14.57, 14.07, 47.31, 66.32 },
|
||||
[812] = { 85, 19.26, 25.15, 87.18, 48.5 },
|
||||
[813] = { 28, 11.98, 11.23, 26.45, 58.01 },
|
||||
[816] = { 14, 12.48, 17.96, 41.17, 43.41 },
|
||||
[817] = { 14, 7.49, 7.49, 53.64, 11.98 },
|
||||
[818] = { 215, 6.99, 17.96, 36.43, 62.13 },
|
||||
[819] = { 215, 10.48, 10.48, 50.15, 11.98 },
|
||||
[820] = { 215, 8.98, 23.95, 52.89, 29.94 },
|
||||
[821] = { 215, 10.98, 12.72, 62.87, 67.74 },
|
||||
[838] = { 38, 12.97, 17.22, 22.46, 15.34 },
|
||||
[856] = { 10, 21.46, 37.43, 47.65, 40.42 },
|
||||
[880] = { 45, 11.98, 20.96, 45.91, 83.08 },
|
||||
[896] = { 267, 12.48, 15.72, 17.22, 79.72 },
|
||||
[916] = { 40, 9.48, 12.72, 56.64, 17.59 },
|
||||
[917] = { 40, 9.98, 11.98, 62.38, 61.38 },
|
||||
[918] = { 40, 10.98, 12.72, 44.91, 36.3 },
|
||||
[920] = { 40, 17.96, 11.23, 46.91, 78.97 },
|
||||
[921] = { 40, 10.48, 13.47, 31.19, 69.61 },
|
||||
[922] = { 40, 14.97, 10.48, 63.37, 72.6 },
|
||||
[923] = { 38, 14.97, 26.95, 34.93, 77.84 },
|
||||
[924] = { 38, 10.98, 27.69, 20.46, 73.73 },
|
||||
[927] = { 130, 6.49, 11.23, 54.14, 22.83 },
|
||||
[928] = { 130, 7.98, 8.98, 40.42, 28.44 },
|
||||
[936] = { 38, 11.48, 19.46, 45.16, 68.86 },
|
||||
[976] = { 440, 10.48, 12.72, 51.15, 27.32 },
|
||||
[977] = { 440, 7.98, 9.73, 66.87, 21.33 },
|
||||
[978] = { 440, 14.97, 17.96, 37.43, 12.72 },
|
||||
[979] = { 440, 6.99, 10.48, 39.92, 28.44 },
|
||||
[980] = { 440, 12.48, 17.22, 30.69, 62.5 },
|
||||
[981] = { 440, 10.98, 17.22, 54.39, 70.73 },
|
||||
[982] = { 440, 7.49, 14.97, 34.68, 45.66 },
|
||||
[983] = { 440, 7.98, 11.98, 41.92, 56.14 },
|
||||
[984] = { 440, 6.49, 7.49, 46.66, 65.12 },
|
||||
[985] = { 440, 9.48, 12.72, 59.63, 37.8 },
|
||||
[986] = { 440, 5.99, 9.73, 66.87, 33.31 },
|
||||
[987] = { 440, 13.97, 14.22, 54.89, 91.69 },
|
||||
[990] = { 440, 7.98, 14.22, 36.93, 80.46 },
|
||||
[992] = { 440, 7.49, 9.73, 40.17, 71.48 },
|
||||
[996] = { 44, 19.46, 26.2, 40.17, 16.84 },
|
||||
[997] = { 44, 39.42, 14.97, 73.1, 77.84 },
|
||||
[1000] = { 44, 16.47, 26.95, 78.09, 42.66 },
|
||||
[1001] = { 44, 32.44, 13.47, 38.17, 73.35 },
|
||||
[1002] = { 44, 17.96, 26.2, 18.46, 69.24 },
|
||||
[1016] = { 11, 11.48, 20.21, 60.63, 32.56 },
|
||||
[1017] = { 11, 11.48, 13.47, 72.11, 38.17 },
|
||||
[1018] = { 11, 14.97, 12.72, 19.96, 49.03 },
|
||||
[1020] = { 11, 10.98, 17.96, 61.88, 54.64 },
|
||||
[1021] = { 11, 11.98, 16.47, 56.39, 68.86 },
|
||||
[1022] = { 11, 14.47, 11.23, 19.21, 36.3 },
|
||||
[1023] = { 11, 13.47, 20.21, 34.18, 24.33 },
|
||||
[1024] = { 11, 18.46, 14.97, 23.2, 28.44 },
|
||||
[1025] = { 11, 10.48, 22.46, 53.64, 36.68 },
|
||||
[1036] = { 11, 14.97, 15.72, 47.41, 48.28 },
|
||||
[1038] = { 11, 21.96, 43.41, 81.84, 63.62 },
|
||||
[1056] = { 267, 14.97, 10.48, 50.9, 33.68 },
|
||||
[1076] = { 406, 20.96, 42.66, 60.38, 68.49 },
|
||||
[1097] = { 10, 8.88, 31.74, 10.03, 44.46 },
|
||||
[1098] = { 10, 9.98, 8.98, 74.35, 33.68 },
|
||||
[1099] = { 357, 7.98, 9.73, 75.35, 42.29 },
|
||||
[1100] = { 357, 5.99, 14.97, 67.86, 40.42 },
|
||||
[1101] = { 357, 16.97, 20.21, 72.85, 61 },
|
||||
[1103] = { 357, 9.98, 9.73, 77.35, 31.06 },
|
||||
[1105] = { 357, 6.99, 8.98, 54.39, 56.89 },
|
||||
[1106] = { 357, 6.49, 17.96, 53.64, 71.11 },
|
||||
[1108] = { 357, 6.99, 41.92, 46.41, 62.13 },
|
||||
[1111] = { 357, 4.99, 8.23, 51.4, 10.1 },
|
||||
[1113] = { 357, 5.49, 5.24, 54.64, 16.84 },
|
||||
[1114] = { 357, 7.49, 8.23, 39.67, 10.85 },
|
||||
[1119] = { 357, 15.47, 20.96, 47.16, 25.45 },
|
||||
[1120] = { 357, 13.47, 16.47, 30.19, 50.15 },
|
||||
[1121] = { 357, 14.47, 35.18, 29.69, 78.97 },
|
||||
[1137] = { 357, 12.48, 14.22, 86.08, 43.04 },
|
||||
[1216] = { 16, 10.48, 15.72, 37.18, 33.31 },
|
||||
[1219] = { 16, 16.97, 8.98, 57.88, 17.96 },
|
||||
[1220] = { 16, 14.97, 9.73, 60.88, 28.82 },
|
||||
[1221] = { 16, 12.48, 15.72, 36.68, 54.27 },
|
||||
[1225] = { 16, 7.98, 11.98, 46.91, 28.44 },
|
||||
[1226] = { 16, 10.48, 14.97, 76.6, 41.17 },
|
||||
[1227] = { 16, 16.97, 32.93, 58.88, 54.64 },
|
||||
[1228] = { 16, 5.49, 18.71, 45.66, 46.03 },
|
||||
[1229] = { 16, 6.99, 12.72, 88.32, 30.31 },
|
||||
[1230] = { 16, 47.9, 11.98, 63.87, 11.23 },
|
||||
[1231] = { 16, 28.94, 17.96, 58.38, 71.86 },
|
||||
[1232] = { 16, 9.48, 9.73, 70.61, 84.96 },
|
||||
[1233] = { 16, 14.97, 15.72, 29.44, 71.48 },
|
||||
[1234] = { 16, 11.48, 13.47, 43.16, 80.09 },
|
||||
[1235] = { 16, 9.98, 13.47, 17.47, 74.85 },
|
||||
[1236] = { 16, 8.48, 9.73, 20.71, 60.25 },
|
||||
[1237] = { 16, 9.98, 8.23, 21.46, 50.52 },
|
||||
[1256] = { 16, 28.44, 9.73, 58.13, 91.69 },
|
||||
[1316] = { 17, 8.98, 9.73, 48.9, 91.69 },
|
||||
[1336] = { 440, 8.48, 17.96, 71.61, 47.16 },
|
||||
[1357] = { 36, 8.48, 11.23, 50.15, 58.76 },
|
||||
[1437] = { 4, 9.48, 8.98, 43.16, 14.22 },
|
||||
[1438] = { 4, 9.98, 11.23, 64.37, 18.34 },
|
||||
[1439] = { 4, 10.98, 11.98, 50.4, 44.16 },
|
||||
[1440] = { 4, 10.98, 9.73, 62.87, 33.31 },
|
||||
[1441] = { 4, 6.49, 9.73, 39.67, 31.81 },
|
||||
[1442] = { 51, 23.95, 28.44, 27.94, 33.68 },
|
||||
[1444] = { 51, 23.95, 30.69, 44.91, 84.21 },
|
||||
[1457] = { 4, 7.98, 8.23, 55.89, 13.85 },
|
||||
[1497] = { 0, 14.57, 21.71, 61.88, 71.63 },
|
||||
[1519] = { 0, 25.45, 35.18, 24.2, 35.55 },
|
||||
[1637] = { 0, 22.95, 7.49, 46.91, 5.24 },
|
||||
[1638] = { 0, 18.46, 23.95, 38.67, 27.69 },
|
||||
[1657] = { 0, 14.97, 28.44, 27.45, 57.63 },
|
||||
[1677] = { 36, 7.49, 14.22, 30.69, 85.7 },
|
||||
[1678] = { 36, 8.98, 13.47, 58.38, 68.86 },
|
||||
[1679] = { 36, 9.48, 19.46, 48.15, 83.83 },
|
||||
[1680] = { 36, 8.98, 17.22, 38.92, 90.19 },
|
||||
[1681] = { 36, 12.48, 18.71, 28.19, 37.8 },
|
||||
[1682] = { 36, 6.99, 13.47, 40.42, 17.22 },
|
||||
[1683] = { 36, 10.48, 12.72, 39.67, 69.24 },
|
||||
[1684] = { 36, 18.46, 34.43, 82.09, 66.62 },
|
||||
[1697] = { 17, 5.99, 6.74, 55.89, 51.27 },
|
||||
[1698] = { 17, 4.49, 10.48, 50.65, 58.38 },
|
||||
[1699] = { 17, 5.99, 7.49, 56.89, 28.44 },
|
||||
[1700] = { 17, 8.48, 14.22, 43.16, 48.28 },
|
||||
[1701] = { 17, 6.49, 11.23, 41.67, 78.97 },
|
||||
[1702] = { 17, 7.98, 10.48, 37.43, 28.44 },
|
||||
[1703] = { 17, 7.98, 8.98, 47.9, 6.74 },
|
||||
[1704] = { 17, 5.49, 6.74, 55.64, 19.09 },
|
||||
[1717] = { 17, 7.98, 10.48, 40.92, 88.32 },
|
||||
[1737] = { 33, 3.49, 10.48, 33.68, 64.37 },
|
||||
[1738] = { 33, 5.49, 9.73, 25.7, 62.5 },
|
||||
[1739] = { 33, 9.98, 9.73, 26.95, 53.52 },
|
||||
[1740] = { 33, 4.49, 9.73, 44.16, 19.84 },
|
||||
[1741] = { 33, 8.98, 11.98, 29.44, 44.16 },
|
||||
[1761] = { 361, 8.48, 8.98, 49.15, 91.32 },
|
||||
[1762] = { 361, 9.98, 11.23, 63.37, 10.85 },
|
||||
[1763] = { 361, 12.97, 7.49, 36.43, 59.88 },
|
||||
[1765] = { 361, 12.97, 8.98, 42.42, 48.65 },
|
||||
[1766] = { 361, 10.48, 17.96, 42.17, 35.18 },
|
||||
[1767] = { 361, 9.48, 11.23, 50.15, 23.58 },
|
||||
[1777] = { 8, 9.98, 20.96, 14.97, 62.87 },
|
||||
[1778] = { 8, 12.97, 40.42, 83.83, 46.41 },
|
||||
[1780] = { 8, 18.96, 17.96, 24.45, 52.4 },
|
||||
[1797] = { 8, 17.96, 21.71, 70.36, 78.97 },
|
||||
[1798] = { 8, 23.95, 21.71, 43.91, 34.81 },
|
||||
[1857] = { 45, 10.48, 21.71, 17.71, 37.8 },
|
||||
[1858] = { 45, 5.49, 18.71, 37.67, 41.54 },
|
||||
[1877] = { 3, 12.97, 17.96, 46.41, 56.89 },
|
||||
[1878] = { 3, 16.97, 20.96, 30.44, 51.65 },
|
||||
[1879] = { 3, 18.46, 24.7, 30.69, 75.22 },
|
||||
[1882] = { 47, 7.49, 22.46, 22.7, 38.17 },
|
||||
[1883] = { 47, 7.49, 10.48, 40.17, 58.38 },
|
||||
[1884] = { 47, 11.48, 12.72, 49.65, 37.05 },
|
||||
[1885] = { 47, 10.48, 14.22, 28.19, 61.75 },
|
||||
[1886] = { 47, 9.48, 12.72, 50.15, 53.52 },
|
||||
[1897] = { 3, 18.46, 17.96, 49.15, 16.47 },
|
||||
[1898] = { 3, 12.48, 18.71, 62.62, 46.03 },
|
||||
[1917] = { 47, 13.47, 15.72, 70.11, 50.52 },
|
||||
[1937] = { 440, 5.99, 7.49, 59.88, 24.7 },
|
||||
[1938] = { 440, 6.49, 8.98, 53.14, 45.66 },
|
||||
[1939] = { 440, 9.48, 13.47, 45.66, 42.66 },
|
||||
[1940] = { 440, 10.98, 9.73, 62.38, 59.51 },
|
||||
[1942] = { 490, 16.47, 35.18, 69.61, 63.25 },
|
||||
[1943] = { 490, 19.96, 26.2, 72.36, 34.81 },
|
||||
[1957] = { 51, 14.97, 22.46, 22.95, 73.35 },
|
||||
[1958] = { 51, 17.96, 20.96, 69.36, 76.35 },
|
||||
[1959] = { 51, 28.94, 40.42, 67.37, 29.19 },
|
||||
[1998] = { 361, 7.49, 9.73, 62.13, 24.33 },
|
||||
[2079] = { 15, 12.48, 18.71, 75.6, 17.59 },
|
||||
[2097] = { 400, 8.98, 15.72, 34.93, 36.3 },
|
||||
[2198] = { 405, 8.98, 13.47, 80.34, 79.34 },
|
||||
[2241] = { 618, 10.98, 8.98, 49.4, 12.72 },
|
||||
[2242] = { 618, 9.48, 10.48, 64.62, 17.22 },
|
||||
[2243] = { 618, 7.49, 5.99, 40.17, 43.41 },
|
||||
[2244] = { 618, 6.99, 7.49, 68.36, 36.68 },
|
||||
[2245] = { 618, 5.99, 8.23, 58.38, 58.01 },
|
||||
[2246] = { 618, 11.98, 7.49, 33.43, 36.68 },
|
||||
[2247] = { 618, 6.49, 11.98, 68.11, 45.66 },
|
||||
[2249] = { 618, 8.98, 11.23, 61.88, 68.49 },
|
||||
[2250] = { 618, 6.99, 9.73, 65.37, 61.75 },
|
||||
[2251] = { 618, 9.48, 11.98, 53.14, 43.41 },
|
||||
[2253] = { 618, 10.48, 8.98, 49.65, 28.44 },
|
||||
[2255] = { 618, 8.98, 9.73, 60.88, 37.8 },
|
||||
[2256] = { 618, 17.96, 16.47, 57.88, 83.08 },
|
||||
[2258] = { 139, 9.98, 14.22, 40.42, 52.02 },
|
||||
[2260] = { 139, 10.48, 10.48, 26.7, 73.35 },
|
||||
[2261] = { 139, 7.98, 13.47, 28.44, 84.58 },
|
||||
[2262] = { 139, 11.98, 11.98, 39.92, 89.82 },
|
||||
[2263] = { 139, 8.48, 11.98, 38.67, 75.6 },
|
||||
[2264] = { 139, 9.48, 11.98, 59.63, 70.36 },
|
||||
[2266] = { 139, 16.97, 14.97, 84.83, 83.08 },
|
||||
[2268] = { 139, 7.49, 11.98, 82.09, 58.38 },
|
||||
[2270] = { 139, 11.98, 15.72, 84.33, 41.54 },
|
||||
[2271] = { 139, 6.99, 12.72, 67.86, 49.78 },
|
||||
[2272] = { 139, 8.48, 12.72, 70.61, 31.81 },
|
||||
[2273] = { 139, 12.48, 11.23, 73.1, 14.6 },
|
||||
[2275] = { 139, 12.97, 13.47, 57.88, 28.44 },
|
||||
[2276] = { 139, 8.98, 8.98, 52.89, 16.47 },
|
||||
[2277] = { 139, 25.95, 19.46, 36.43, 33.68 },
|
||||
[2279] = { 139, 13.47, 20.21, 31.19, 15.34 },
|
||||
[2297] = { 28, 25.95, 24.7, 68.36, 73.73 },
|
||||
[2298] = { 28, 9.98, 14.22, 68.86, 75.22 },
|
||||
[2300] = { 440, 9.48, 10.48, 64.12, 49.4 },
|
||||
[2301] = { 331, 6.99, 8.98, 36.93, 36.68 },
|
||||
[2302] = { 15, 24.95, 25.45, 44.41, 48.65 },
|
||||
[2303] = { 400, 14.97, 24.7, 62.38, 55.01 },
|
||||
[2404] = { 405, 9.98, 9.73, 54.39, 12.35 },
|
||||
[2405] = { 405, 12.97, 20.96, 40.92, 30.69 },
|
||||
[2406] = { 405, 6.99, 8.98, 28.94, 8.23 },
|
||||
[2407] = { 405, 10.98, 11.98, 64.37, 40.42 },
|
||||
[2408] = { 405, 11.98, 14.97, 25.45, 70.36 },
|
||||
[2417] = { 46, 14.47, 21.71, 75.1, 68.49 },
|
||||
[2418] = { 46, 16.47, 24.7, 88.57, 64.75 },
|
||||
[2420] = { 46, 21.46, 37.43, 88.57, 35.93 },
|
||||
[2421] = { 46, 30.94, 32.19, 27.94, 65.49 },
|
||||
[2478] = { 361, 7.49, 8.23, 57.63, 87.95 },
|
||||
[2479] = { 361, 9.48, 8.23, 51.65, 79.72 },
|
||||
[2480] = { 361, 8.48, 12.72, 41.17, 82.71 },
|
||||
[2481] = { 361, 8.98, 11.23, 37.92, 69.24 },
|
||||
[2497] = { 16, 16.47, 14.97, 76.6, 19.46 },
|
||||
[2517] = { 4, 8.48, 11.98, 48.65, 29.94 },
|
||||
[2522] = { 357, 9.98, 21.71, 61.38, 66.99 },
|
||||
[2537] = { 406, 11.48, 7.49, 75.6, 86.83 },
|
||||
[2538] = { 406, 5.99, 5.24, 77.35, 92.44 },
|
||||
[2539] = { 406, 6.99, 8.23, 72.85, 94.69 },
|
||||
[2540] = { 406, 9.98, 11.98, 64.87, 92.81 },
|
||||
[2541] = { 406, 8.98, 10.48, 54.39, 74.85 },
|
||||
[2561] = { 41, 15.47, 32.19, 58.63, 64.75 },
|
||||
[2562] = { 41, 18.46, 23.95, 42.66, 68.86 },
|
||||
[2577] = { 357, 12.97, 13.47, 58.88, 41.92 },
|
||||
[2618] = { 361, 8.48, 10.48, 41.17, 17.96 },
|
||||
[2619] = { 139, 10.48, 44.16, 7.73, 60.25 },
|
||||
[2620] = { 28, 10.48, 41.17, 67.61, 38.55 },
|
||||
[2621] = { 139, 12.48, 13.47, 62.62, 80.09 },
|
||||
[2622] = { 139, 9.48, 18.71, 74.1, 62.5 },
|
||||
[2623] = { 139, 10.48, 11.98, 52.64, 66.62 },
|
||||
[2624] = { 139, 8.98, 12.72, 51.9, 49.78 },
|
||||
[2627] = { 139, 12.48, 10.48, 17.71, 32.19 },
|
||||
[2697] = { 41, 27.45, 34.43, 45.16, 35.93 },
|
||||
[2737] = { 1377, 13.97, 5.99, 28.94, 95.06 },
|
||||
[2738] = { 1377, 7.98, 11.98, 62.38, 53.14 },
|
||||
[2740] = { 1377, 16.47, 20.21, 23.2, 17.59 },
|
||||
[2742] = { 1377, 12.97, 18.71, 44.91, 24.33 },
|
||||
[2743] = { 1377, 16.47, 23.95, 24.7, 58.38 },
|
||||
[2744] = { 1377, 16.47, 33.68, 57.14, 80.46 },
|
||||
[2959] = { 2597, 28.94, 26.2, 41.92, 20.58 },
|
||||
[2977] = { 2597, 21.96, 29.94, 48.9, 49.4 },
|
||||
[2978] = { 2597, 16.97, 29.19, 51.9, 78.22 },
|
||||
[3425] = { 1377, 6.49, 10.48, 50.65, 37.43 },
|
||||
}
|
||||
@@ -0,0 +1,353 @@
|
||||
-- Questie-Octo canonical database facade.
|
||||
--
|
||||
-- IMPORTANT:
|
||||
-- pfDB is not exposed beyond Database/. The rest of Questie-Octo talks only
|
||||
-- through this API.
|
||||
|
||||
QuestieOcto.DatabaseAPI = QuestieOcto.DatabaseAPI or {}
|
||||
local DB = QuestieOcto.DatabaseAPI
|
||||
|
||||
DB.ready = false
|
||||
DB.questIDs = DB.questIDs or nil
|
||||
DB.questTitleCache = DB.questTitleCache or {}
|
||||
DB.questSearchTitleCache = DB.questSearchTitleCache or {}
|
||||
|
||||
local function RawQuest(id)
|
||||
return QuestieOcto.Database:GetRawQuest(id)
|
||||
end
|
||||
|
||||
local function QuestLocale(id)
|
||||
return QuestieOcto.Database:GetQuestLocale(id)
|
||||
end
|
||||
|
||||
function DB:IsReady()
|
||||
return self.ready and true or false
|
||||
end
|
||||
|
||||
function DB:GetQuestCount()
|
||||
-- questIDs is built incrementally before DATABASE_API_READY is published, so
|
||||
-- counting it is O(1) and avoids walking the entire pfDB quest table again.
|
||||
return self.questIDs and table.getn(self.questIDs) or 0
|
||||
end
|
||||
|
||||
function DB:BuildQuestIDCache()
|
||||
local result={}
|
||||
if not pfDB or not pfDB.quests or not pfDB.quests.data then
|
||||
self.questIDs=result
|
||||
return result
|
||||
end
|
||||
for id in pairs(pfDB.quests.data) do table.insert(result,id) end
|
||||
self.questIDs=result
|
||||
return result
|
||||
end
|
||||
|
||||
function DB:GetQuestIDs()
|
||||
if not self.ready then return {} end
|
||||
return self.questIDs or self:BuildQuestIDCache()
|
||||
end
|
||||
|
||||
function DB:GetQuestRaw(id)
|
||||
if not self.ready then return nil end
|
||||
return RawQuest(id)
|
||||
end
|
||||
|
||||
function DB:GetQuestTitle(id)
|
||||
if not self.ready then return nil end
|
||||
local cached=self.questTitleCache and self.questTitleCache[id]
|
||||
if cached then return cached end
|
||||
local loc=QuestLocale(id)
|
||||
local title=nil
|
||||
if type(loc)=="table" then title=loc["T"] or loc[1]
|
||||
elseif type(loc)=="string" then title=loc end
|
||||
title=title or ("Quest "..tostring(id))
|
||||
self.questTitleCache[id]=title
|
||||
self.questSearchTitleCache[id]=string.lower(title)
|
||||
return title
|
||||
end
|
||||
|
||||
function DB:GetQuestSearchTitle(id)
|
||||
if not self.ready then return nil end
|
||||
local cached=self.questSearchTitleCache and self.questSearchTitleCache[id]
|
||||
if cached then return cached end
|
||||
local title=self:GetQuestTitle(id)
|
||||
return title and string.lower(title) or nil
|
||||
end
|
||||
|
||||
function DB:GetQuestSearchIndex()
|
||||
if not self.ready then return {} end
|
||||
return self.questSearchTitleCache or {}
|
||||
end
|
||||
|
||||
function DB:GetQuestRewards(id)
|
||||
if not self.ready then return nil end
|
||||
return QuestieOcto.QuestRewardsData and QuestieOcto.QuestRewardsData[tonumber(id)] or nil
|
||||
end
|
||||
|
||||
-- Questie Journey presents the quest's authored objective/description text
|
||||
-- rather than reconstructing every objective from database entity rows.
|
||||
-- pfDB's localized quest table stores that objective sentence in field "O".
|
||||
function DB:GetQuestObjectiveText(id)
|
||||
if not self.ready then return nil end
|
||||
local loc=QuestLocale(id)
|
||||
if type(loc)=="table" then
|
||||
local text=loc["O"]
|
||||
if type(text)=="string" and text~="" then return text end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
-- pfDB's localized quest table stores the main quest-offer description in
|
||||
-- field "D". Keep it separate from "O" (the objective summary), matching the
|
||||
-- way the Vanilla quest dialog presents description and objectives.
|
||||
function DB:GetQuestDescriptionText(id)
|
||||
if not self.ready then return nil end
|
||||
local loc=QuestLocale(id)
|
||||
if type(loc)=="table" then
|
||||
local text=loc["D"]
|
||||
if type(text)=="string" and text~="" then return text end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function DB:GetItemRaw(id)
|
||||
if not self.ready then return nil end
|
||||
return QuestieOcto.Database:GetRawItem(id)
|
||||
end
|
||||
|
||||
function DB:GetCreatureRaw(id)
|
||||
if not self.ready then return nil end
|
||||
return QuestieOcto.Database:GetRawUnit(id)
|
||||
end
|
||||
|
||||
function DB:GetObjectRaw(id)
|
||||
if not self.ready then return nil end
|
||||
return QuestieOcto.Database:GetRawObject(id)
|
||||
end
|
||||
|
||||
function DB:GetItemName(id)
|
||||
if pfDB and pfDB.items and pfDB.items.loc then
|
||||
local loc=pfDB.items.loc[id]
|
||||
if type(loc)=="string" and loc~="" then return loc end
|
||||
end
|
||||
|
||||
if C_Item and C_Item.GetItemNameByID then
|
||||
local name=C_Item.GetItemNameByID(id)
|
||||
if name then return name end
|
||||
end
|
||||
|
||||
if GetItemInfo then
|
||||
local name=GetItemInfo(id)
|
||||
if name then return name end
|
||||
end
|
||||
|
||||
return "Item "..tostring(id)
|
||||
end
|
||||
|
||||
function DB:GetCreatureName(id)
|
||||
if pfDB and pfDB.units and pfDB.units.loc then
|
||||
local loc=pfDB.units.loc[id]
|
||||
if type(loc)=="string" then return loc end
|
||||
end
|
||||
return "Creature "..tostring(id)
|
||||
end
|
||||
|
||||
function DB:GetObjectName(id)
|
||||
if pfDB and pfDB.objects and pfDB.objects.loc then
|
||||
local loc=pfDB.objects.loc[id]
|
||||
if type(loc)=="string" then return loc end
|
||||
end
|
||||
return "Object "..tostring(id)
|
||||
end
|
||||
|
||||
function DB:GetZoneName(id)
|
||||
if not self.ready then return nil end
|
||||
id=tonumber(id)
|
||||
if not id then return nil end
|
||||
if pfDB and pfDB.zones and pfDB.zones.loc then
|
||||
local loc=pfDB.zones.loc[id]
|
||||
if type(loc)=="string" and loc~="" then return loc end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function DB:GetItemSources(id)
|
||||
local raw=self:GetItemRaw(id)
|
||||
if not raw then return nil end
|
||||
|
||||
return {
|
||||
Creature=raw["U"],
|
||||
GameObject=raw["O"],
|
||||
Reference=raw["R"],
|
||||
Vendor=raw["V"],
|
||||
}
|
||||
end
|
||||
|
||||
function DB:GetReferenceLootRaw(id)
|
||||
if not self.ready then return nil end
|
||||
if not pfDB or not pfDB.refloot or not pfDB.refloot.data then return nil end
|
||||
return pfDB.refloot.data[id]
|
||||
end
|
||||
|
||||
function DB:GetCreatureCoords(id)
|
||||
local raw=self:GetCreatureRaw(id)
|
||||
return raw and raw["coords"] or nil
|
||||
end
|
||||
|
||||
function DB:GetObjectCoords(id)
|
||||
local raw=self:GetObjectRaw(id)
|
||||
return raw and raw["coords"] or nil
|
||||
end
|
||||
|
||||
function DB:OnLegacyReady()
|
||||
-- Build the quest-ID index incrementally as well. Iterating the entire quest
|
||||
-- database in the DATABASE_READY callback creates an avoidable single-frame
|
||||
-- spike on Vanilla clients. No consumer is released until the cache is done.
|
||||
self.ready=false
|
||||
self.questIDs={}
|
||||
self.questTitleCache={}
|
||||
self.questSearchTitleCache={}
|
||||
local data=pfDB and pfDB.quests and pfDB.quests.data or {}
|
||||
local cursor=nil
|
||||
|
||||
local function Slice()
|
||||
local count=0
|
||||
while count<200 do
|
||||
local key=next(data,cursor)
|
||||
if key==nil then
|
||||
DB.ready=true
|
||||
QuestieOcto:SendMessage("DATABASE_API_READY")
|
||||
return
|
||||
end
|
||||
cursor=key
|
||||
table.insert(DB.questIDs,key)
|
||||
local loc=QuestLocale(key)
|
||||
local title=nil
|
||||
if type(loc)=="table" then title=loc["T"] or loc[1]
|
||||
elseif type(loc)=="string" then title=loc end
|
||||
title=title or ("Quest "..tostring(key))
|
||||
DB.questTitleCache[key]=title
|
||||
DB.questSearchTitleCache[key]=string.lower(title)
|
||||
count=count+1
|
||||
end
|
||||
QuestieOcto.Scheduler:Enqueue(Slice,"database-quest-id-cache")
|
||||
end
|
||||
|
||||
QuestieOcto.Scheduler:Enqueue(Slice,"database-quest-id-cache")
|
||||
end
|
||||
|
||||
QuestieOcto:RegisterMessage("DATABASE_READY",DB,"OnLegacyReady")
|
||||
|
||||
|
||||
function DB:GetQuestItemRequirementRaw(id)
|
||||
if not self.ready then return nil end
|
||||
if not pfDB or not pfDB["quests-itemreq"] or not pfDB["quests-itemreq"].data then return nil end
|
||||
return pfDB["quests-itemreq"].data[id]
|
||||
end
|
||||
|
||||
function DB:GetCreatureType(id)
|
||||
local raw=self:GetCreatureRaw(id)
|
||||
return raw and raw["type"] or nil
|
||||
end
|
||||
|
||||
function DB:GetCreatureRank(id)
|
||||
local raw=self:GetCreatureRaw(id)
|
||||
return raw and (raw["rnk"] or raw["rank"]) or nil
|
||||
end
|
||||
|
||||
function DB:GetCreatureFaction(id)
|
||||
local raw=self:GetCreatureRaw(id)
|
||||
return raw and (raw["fac"] or raw["faction"]) or nil
|
||||
end
|
||||
|
||||
|
||||
function DB:GetMapIDByName(name)
|
||||
if not self.ready or not name then return nil end
|
||||
if not pfDB or not pfDB.zones or not pfDB.zones.loc then return nil end
|
||||
|
||||
for id,zoneName in pairs(pfDB.zones.loc) do
|
||||
if zoneName==name then return id end
|
||||
end
|
||||
|
||||
-- The active localized table uses English through __index for missing direct
|
||||
-- lookups. pairs() does not enumerate __index entries on Vanilla Lua, so
|
||||
-- search the English fallback explicitly for untranslated Turtle zones.
|
||||
if pfDB.zones.enUS and pfDB.zones.loc~=pfDB.zones.enUS then
|
||||
for id,zoneName in pairs(pfDB.zones.enUS) do
|
||||
if pfDB.zones.loc[id]==nil and zoneName==name then return id end
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
function DB:GetCreatureLevel(id)
|
||||
local raw=self:GetCreatureRaw(id)
|
||||
return raw and raw["lvl"] or nil
|
||||
end
|
||||
|
||||
function DB:GetCreatureRespawnSeconds(id)
|
||||
local coords=self:GetCreatureCoords(id)
|
||||
if not coords then return nil end
|
||||
|
||||
local best=nil
|
||||
for _,coord in pairs(coords) do
|
||||
if type(coord)=="table" then
|
||||
local seconds=tonumber(coord[4])
|
||||
if seconds and seconds>0 then
|
||||
if not best or seconds>best then best=seconds end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return best
|
||||
end
|
||||
|
||||
function DB:GetCreatureMapIDs(id)
|
||||
local result={}
|
||||
local seen={}
|
||||
local coords=self:GetCreatureCoords(id)
|
||||
|
||||
if coords then
|
||||
for _,coord in pairs(coords) do
|
||||
if type(coord)=="table" and tonumber(coord[3]) then
|
||||
local mapID=tonumber(coord[3])
|
||||
if not seen[mapID] then
|
||||
seen[mapID]=true
|
||||
table.insert(result,mapID)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
table.sort(result)
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
|
||||
function DB:GetProfessionName(id)
|
||||
if not self.ready then return nil end
|
||||
id=tonumber(id)
|
||||
if not id then return nil end
|
||||
local loc=pfDB and pfDB.professions and (pfDB.professions.loc or pfDB.professions.enUS)
|
||||
return loc and loc[id] or nil
|
||||
end
|
||||
|
||||
function DB:GetTrackingMeta(metaKey)
|
||||
if not self.ready or not metaKey or not pfDB then return nil end
|
||||
local turtle=pfDB["meta-turtle"]
|
||||
if turtle and turtle[metaKey] then return turtle[metaKey] end
|
||||
return pfDB.meta and pfDB.meta[metaKey] or nil
|
||||
end
|
||||
|
||||
function DB:GetMinimapSize(mapID)
|
||||
mapID=tonumber(mapID)
|
||||
if not self.ready or not mapID then return nil,nil end
|
||||
if not pfDB or not pfDB["minimap"] then return nil,nil end
|
||||
|
||||
local size=pfDB["minimap"][mapID]
|
||||
if type(size)~="table" then return nil,nil end
|
||||
|
||||
return tonumber(size[1]),tonumber(size[2])
|
||||
end
|
||||
@@ -0,0 +1,202 @@
|
||||
QuestieOcto.Database = QuestieOcto.Database or {}
|
||||
local D = QuestieOcto.Database
|
||||
|
||||
D.ready = false
|
||||
D.running = false
|
||||
D.jobs = {}
|
||||
D.jobIndex = 1
|
||||
D.stats = { merged=0, jobs=0 }
|
||||
|
||||
local DATASETS = {
|
||||
"items", "quests", "quests-itemreq", "objects", "units",
|
||||
"zones", "professions", "areatrigger", "refloot", "minimap", "meta"
|
||||
}
|
||||
|
||||
local TEXT_DATASETS = {
|
||||
"items", "quests", "objects", "units", "zones", "professions"
|
||||
}
|
||||
|
||||
local FIELD_MERGE_DATASETS = { items=true, quests=true, objects=true, units=true }
|
||||
|
||||
local function AddMergeJob(target,patch,name,mode)
|
||||
if target and patch then
|
||||
table.insert(D.jobs,{ target=target, patch=patch, name=name, mode=mode or "replace" })
|
||||
end
|
||||
end
|
||||
|
||||
local function BuildMergeJobs()
|
||||
D.jobs = {}
|
||||
D.jobIndex = 1
|
||||
D.stats = { merged=0, jobs=0 }
|
||||
|
||||
if not pfDB then return end
|
||||
|
||||
-- Locale-independent Turtle patches always merge into the core data first.
|
||||
for _,name in pairs(DATASETS) do
|
||||
local bucket=pfDB[name]
|
||||
if bucket and bucket["data-turtle"] and bucket["data"] then
|
||||
AddMergeJob(bucket["data"],bucket["data-turtle"],name..".data",FIELD_MERGE_DATASETS[name] and "fields" or "replace")
|
||||
end
|
||||
end
|
||||
|
||||
-- English is the only packaged presentation database.
|
||||
for _,name in pairs(TEXT_DATASETS) do
|
||||
local bucket=pfDB[name]
|
||||
if bucket then
|
||||
AddMergeJob(bucket["enUS"],bucket["enUS-turtle"],name..".enUS","locale")
|
||||
end
|
||||
end
|
||||
|
||||
if pfDB["minimap-turtle"] and pfDB["minimap"] then
|
||||
AddMergeJob(pfDB["minimap"],pfDB["minimap-turtle"],"minimap")
|
||||
end
|
||||
if pfDB["meta-turtle"] and pfDB["meta"] then
|
||||
AddMergeJob(pfDB["meta"],pfDB["meta-turtle"],"meta")
|
||||
end
|
||||
|
||||
D.stats.jobs=table.getn(D.jobs)
|
||||
end
|
||||
|
||||
local function StartJob(job)
|
||||
if job.started then return end
|
||||
-- Never materialize every patch key in one frame. Some Turtle datasets are
|
||||
-- large enough that the old key-array construction caused a visible startup
|
||||
-- hitch before the incremental merge even began.
|
||||
job.started=true
|
||||
job.cursor=nil
|
||||
end
|
||||
|
||||
local function ProcessJob(job)
|
||||
StartJob(job)
|
||||
local count=0
|
||||
|
||||
while count<256 do
|
||||
local key,value=next(job.patch,job.cursor)
|
||||
if key==nil then return true end
|
||||
job.cursor=key
|
||||
|
||||
if type(value)=="string" and value=="_" then
|
||||
job.target[key]=nil
|
||||
elseif (job.mode=="fields" or job.mode=="locale") and type(value)=="table" and type(job.target[key])=="table" then
|
||||
local base=job.target[key]
|
||||
for field,fieldValue in pairs(value) do
|
||||
if type(fieldValue)=="string" and fieldValue=="_" then
|
||||
base[field]=nil
|
||||
else
|
||||
base[field]=fieldValue
|
||||
end
|
||||
end
|
||||
else
|
||||
job.target[key]=value
|
||||
end
|
||||
|
||||
D.stats.merged=D.stats.merged+1
|
||||
count=count+1
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local function Finalize()
|
||||
if pfDB.items then pfDB.items.loc=pfDB.items.enUS end
|
||||
if pfDB.units then pfDB.units.loc=pfDB.units.enUS end
|
||||
if pfDB.objects then pfDB.objects.loc=pfDB.objects.enUS end
|
||||
if pfDB.quests then pfDB.quests.loc=pfDB.quests.enUS end
|
||||
if pfDB.zones then pfDB.zones.loc=pfDB.zones.enUS end
|
||||
if pfDB.professions then pfDB.professions.loc=pfDB.professions.enUS end
|
||||
|
||||
for _,name in pairs(TEXT_DATASETS) do
|
||||
local bucket=pfDB[name]
|
||||
if bucket then bucket["enUS-turtle"]=nil end
|
||||
end
|
||||
|
||||
-- Apply the sparse Tortoise/Octo enrichment only after the base + Turtle
|
||||
-- field-by-field merge is final. This restores server fields the compact
|
||||
-- pfQuest runtime database intentionally discarded without replacing the
|
||||
-- working pfQuest quest records wholesale.
|
||||
if QuestieOcto.Enrichment then
|
||||
if not QuestieOcto.Enrichment:Apply() then
|
||||
D.running=false
|
||||
D.ready=false
|
||||
QuestieOcto:Error("quest-truth enrichment could not be applied")
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if QuestieOcto.QuestModel and QuestieOcto.QuestModel.Clear then
|
||||
QuestieOcto.QuestModel:Clear()
|
||||
end
|
||||
|
||||
D.running=false
|
||||
D.ready=true
|
||||
QuestieOcto:SendMessage("DATABASE_READY")
|
||||
end
|
||||
|
||||
function D:Start()
|
||||
if self.ready or self.running then return end
|
||||
|
||||
if not pfDB then
|
||||
QuestieOcto:Error("raw quest database did not load")
|
||||
return
|
||||
end
|
||||
|
||||
BuildMergeJobs()
|
||||
self.running=true
|
||||
|
||||
local function step()
|
||||
local job=D.jobs[D.jobIndex]
|
||||
if not job then
|
||||
Finalize()
|
||||
return
|
||||
end
|
||||
|
||||
if ProcessJob(job) then D.jobIndex=D.jobIndex+1 end
|
||||
QuestieOcto.Scheduler:Enqueue(step,"database-merge")
|
||||
end
|
||||
|
||||
QuestieOcto.Scheduler:Enqueue(step,"database-merge")
|
||||
end
|
||||
|
||||
local function Count(t)
|
||||
local n=0
|
||||
if t then for _ in pairs(t) do n=n+1 end end
|
||||
return n
|
||||
end
|
||||
|
||||
function D:GetActiveLocale()
|
||||
return "enUS"
|
||||
end
|
||||
|
||||
function D:Counts()
|
||||
if not pfDB then return 0,0,0,0 end
|
||||
return
|
||||
Count(pfDB.quests and pfDB.quests.data),
|
||||
Count(pfDB.items and pfDB.items.data),
|
||||
Count(pfDB.units and pfDB.units.data),
|
||||
Count(pfDB.objects and pfDB.objects.data)
|
||||
end
|
||||
|
||||
function D:GetRawQuest(id)
|
||||
if not self.ready then return nil end
|
||||
return pfDB.quests and pfDB.quests.data and pfDB.quests.data[id]
|
||||
end
|
||||
|
||||
function D:GetQuestLocale(id)
|
||||
if not self.ready then return nil end
|
||||
return pfDB.quests and pfDB.quests.loc and pfDB.quests.loc[id]
|
||||
end
|
||||
|
||||
function D:GetRawItem(id)
|
||||
if not self.ready then return nil end
|
||||
return pfDB.items and pfDB.items.data and pfDB.items.data[id]
|
||||
end
|
||||
|
||||
function D:GetRawUnit(id)
|
||||
if not self.ready then return nil end
|
||||
return pfDB.units and pfDB.units.data and pfDB.units.data[id]
|
||||
end
|
||||
|
||||
function D:GetRawObject(id)
|
||||
if not self.ready then return nil end
|
||||
return pfDB.objects and pfDB.objects.data and pfDB.objects.data[id]
|
||||
end
|
||||
@@ -0,0 +1,197 @@
|
||||
-- Questie-Octo canonical quest model.
|
||||
-- Questie-facing semantic model over pfQuest/Tortoise quest truth.
|
||||
|
||||
QuestieOcto.QuestModel = QuestieOcto.QuestModel or {}
|
||||
local QM = QuestieOcto.QuestModel
|
||||
|
||||
QM.cache = {}
|
||||
|
||||
local function CopyArray(src)
|
||||
if not src then return nil end
|
||||
local out={}
|
||||
for _,v in pairs(src) do table.insert(out,v) end
|
||||
return out
|
||||
end
|
||||
|
||||
local function CopyGroups(src)
|
||||
if not src then return nil end
|
||||
local out={}
|
||||
for _,group in pairs(src) do
|
||||
table.insert(out,CopyArray(group) or {})
|
||||
end
|
||||
return out
|
||||
end
|
||||
|
||||
-- Supplied Questie 3.3.5 classic corrections:
|
||||
-- these quests have their item objective before the normal category order.
|
||||
local ITEM_OBJECTIVE_FIRST={
|
||||
[503]=true,
|
||||
[5088]=true,
|
||||
}
|
||||
|
||||
-- Quests that are not normal static NPC offers. Questie 6 blacklists 7946
|
||||
-- because Morja only exposes it after the Dark Iron Ale/Jubjub interaction.
|
||||
local CONDITIONAL_OFFERS={
|
||||
[7946]="Requires Jubjub to be lured back with Dark Iron Ale.",
|
||||
}
|
||||
|
||||
local function AddObjectiveData(list,kind,id)
|
||||
if not id then return end
|
||||
|
||||
local typ=nil
|
||||
if kind=="creature" then typ="monster"
|
||||
elseif kind=="gameObject" then typ="object"
|
||||
elseif kind=="item" then typ="item"
|
||||
end
|
||||
|
||||
table.insert(list,{
|
||||
kind=kind,
|
||||
type=typ,
|
||||
id=id
|
||||
})
|
||||
end
|
||||
|
||||
local function BuildObjectiveData(questID,objectives)
|
||||
local result={}
|
||||
local itemFirst=ITEM_OBJECTIVE_FIRST[questID] and true or false
|
||||
|
||||
if itemFirst then
|
||||
for i=1,table.getn(objectives.item or {}) do
|
||||
AddObjectiveData(result,"item",objectives.item[i])
|
||||
end
|
||||
end
|
||||
|
||||
-- Questie 3.3.5/7/8 DB compiler category order.
|
||||
for i=1,table.getn(objectives.creature or {}) do
|
||||
AddObjectiveData(result,"creature",objectives.creature[i])
|
||||
end
|
||||
|
||||
for i=1,table.getn(objectives.gameObject or {}) do
|
||||
AddObjectiveData(result,"gameObject",objectives.gameObject[i])
|
||||
end
|
||||
|
||||
if not itemFirst then
|
||||
for i=1,table.getn(objectives.item or {}) do
|
||||
AddObjectiveData(result,"item",objectives.item[i])
|
||||
end
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
function QM:Clear()
|
||||
self.cache={}
|
||||
end
|
||||
|
||||
|
||||
local function ObservedRepeatables()
|
||||
QuestieOctoGlobalDB=QuestieOctoGlobalDB or {}
|
||||
QuestieOctoGlobalDB.observedRepeatableQuests=QuestieOctoGlobalDB.observedRepeatableQuests or {}
|
||||
return QuestieOctoGlobalDB.observedRepeatableQuests
|
||||
end
|
||||
|
||||
function QM:MarkObservedRepeatable(questID)
|
||||
questID=tonumber(questID)
|
||||
if not questID then return false end
|
||||
local db=ObservedRepeatables()
|
||||
if db[questID] then return false end
|
||||
db[questID]=true
|
||||
if self.cache[questID] then self.cache[questID].repeatable=true end
|
||||
if QuestieOcto.AvailableQuests and QuestieOcto.AvailableQuests.Schedule then
|
||||
QuestieOcto.AvailableQuests:Schedule(true,0.02)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function QM:Get(questID)
|
||||
if self.cache[questID] then return self.cache[questID] end
|
||||
if not QuestieOcto.DatabaseAPI:IsReady() then return nil end
|
||||
|
||||
local raw=QuestieOcto.DatabaseAPI:GetQuestRaw(questID)
|
||||
if not raw then return nil end
|
||||
|
||||
local q={
|
||||
id=questID,
|
||||
title=QuestieOcto.DatabaseAPI:GetQuestTitle(questID),
|
||||
descriptionText=QuestieOcto.DatabaseAPI.GetQuestDescriptionText and QuestieOcto.DatabaseAPI:GetQuestDescriptionText(questID) or nil,
|
||||
objectiveText=QuestieOcto.DatabaseAPI.GetQuestObjectiveText and QuestieOcto.DatabaseAPI:GetQuestObjectiveText(questID) or nil,
|
||||
|
||||
-- lvl is the displayed quest level. min/max are the actual server
|
||||
-- acceptance bounds and are deliberately kept separate.
|
||||
level=tonumber(raw["lvl"] or 0) or 0,
|
||||
requiredLevel=tonumber(raw["min"] or 0) or 0,
|
||||
maximumLevel=tonumber(raw["max"] or 0) or 0,
|
||||
|
||||
-- Questie 6 uses quest Type 41 as the canonical PvP classification.
|
||||
-- This comes from the authoritative Turtle enrichment, including only
|
||||
-- verified local corrections for misclassified custom PvP quests.
|
||||
questType=tonumber(raw["type"] or 0) or 0,
|
||||
pvp=(tonumber(raw["type"] or 0) or 0)==41,
|
||||
|
||||
raceMask=raw["race"],
|
||||
classMask=raw["class"],
|
||||
requiredSkill=raw["skill"],
|
||||
requiredSkillValue=tonumber(raw["skillValue"] or 1) or 1,
|
||||
repMinFaction=tonumber(raw["repMinFaction"]),
|
||||
repMinValue=tonumber(raw["repMinValue"] or 0) or 0,
|
||||
repMaxFaction=tonumber(raw["repMaxFaction"]),
|
||||
repMaxValue=tonumber(raw["repMaxValue"] or 0) or 0,
|
||||
|
||||
-- Preserve the authoritative raw event association, but normalize the two
|
||||
-- Darkmoon Faire location IDs into one logical event for every runtime
|
||||
-- consumer. Turtle/pfQuest reuse the same Faire NPCs and quest offers at
|
||||
-- both Elwynn and Mulgore while many shared quest rows are inconsistently
|
||||
-- tagged as event 4 or event 5. Keeping rawEventID makes diagnostics lossless;
|
||||
-- eventID is the logical availability/presentation identity.
|
||||
rawEventID=tonumber(raw["event"]),
|
||||
eventID=(tonumber(raw["event"])==5 and 4 or tonumber(raw["event"])),
|
||||
event=raw["event"],
|
||||
repeatable=(raw["repeatable"] or ObservedRepeatables()[tonumber(questID)]) and true or false,
|
||||
hideAfterFirstCompletion=raw["hideAfterFirstCompletion"] and true or false,
|
||||
daily=raw["daily"] and true or false,
|
||||
yearly=raw["yearly"] and true or false,
|
||||
hardcore=raw["hardcore"] and true or false,
|
||||
timed=raw["timed"] and true or false,
|
||||
disabled=raw["disabled"] and true or false,
|
||||
conditionalOffer=CONDITIONAL_OFFERS[tonumber(questID)],
|
||||
exclusive=raw["exclusive"] and true or false,
|
||||
nextChain=tonumber(raw["nextChain"]),
|
||||
|
||||
-- pfQuest's ordinary pre remains OR semantics. The enrichment restores
|
||||
-- signed active predecessors and negative ExclusiveGroup all-of groups
|
||||
-- separately so their server meaning is not flattened again.
|
||||
preQuestSingle=CopyArray(raw["pre"]),
|
||||
preQuestActive=CopyArray(raw["preActive"]),
|
||||
preQuestAll=CopyGroups(raw["preAll"]),
|
||||
|
||||
-- close is only authoritative when the migrated server still marks the
|
||||
-- quest as a positive ExclusiveGroup member (q.exclusive=true).
|
||||
exclusiveTo=CopyArray(raw["close"]),
|
||||
|
||||
starts={
|
||||
creature=raw["start"] and CopyArray(raw["start"]["U"]) or nil,
|
||||
gameObject=raw["start"] and CopyArray(raw["start"]["O"]) or nil,
|
||||
item=raw["start"] and CopyArray(raw["start"]["I"]) or nil,
|
||||
},
|
||||
|
||||
finishes={
|
||||
creature=raw["end"] and CopyArray(raw["end"]["U"]) or nil,
|
||||
gameObject=raw["end"] and CopyArray(raw["end"]["O"]) or nil,
|
||||
},
|
||||
|
||||
objectives={
|
||||
creature=raw["obj"] and CopyArray(raw["obj"]["U"]) or nil,
|
||||
gameObject=raw["obj"] and CopyArray(raw["obj"]["O"]) or nil,
|
||||
item=raw["obj"] and CopyArray(raw["obj"]["I"]) or nil,
|
||||
irItems=raw["obj"] and CopyArray(raw["obj"]["IR"]) or nil,
|
||||
},
|
||||
}
|
||||
|
||||
-- IR items are intentionally NOT added to objectiveData. They are a
|
||||
-- pfQuest-special interaction relationship that becomes target guidance
|
||||
-- only while the player actually possesses the required item.
|
||||
q.objectiveData=BuildObjectiveData(questID,q.objectives)
|
||||
|
||||
self.cache[questID]=q
|
||||
return q
|
||||
end
|
||||
@@ -0,0 +1,90 @@
|
||||
# Questie-Octo architecture base
|
||||
|
||||
## Non-negotiable design
|
||||
|
||||
- ClassicAPI is the only required enhanced-client compatibility layer.
|
||||
- SuperWoW and Nampower may be detected later, but no core feature may depend on them.
|
||||
- Questie 5.2.3 is the main UI/behavior target.
|
||||
- Questie 6.0.0 is the architecture bridge.
|
||||
- Questie 7-9 are bug-fix references.
|
||||
- Questie 10-11 are references for service separation and mature availability logic.
|
||||
- Questie 11.34.1 is an edge-case reference, not a runtime base.
|
||||
- pfQuest/pfQuest-turtle are transitional raw data/reference sources only.
|
||||
- Tortoise/Turtle server data should become the authoritative offline-generated relationship layer.
|
||||
- No heavy whole-world calculation may run in one frame.
|
||||
- Login and zone changes must remain responsive.
|
||||
- Map nodes will use persistent diff/reuse, never continuous clear/recreate.
|
||||
|
||||
## Runtime service order
|
||||
|
||||
ClassicAPI contract
|
||||
-> Scheduler
|
||||
-> raw-data provider merge (incremental)
|
||||
-> QuestLog cache (ClassicAPI IDs)
|
||||
-> Turtle completion history
|
||||
-> canonical Quest model
|
||||
-> AvailableQuests
|
||||
-> Objectives / ItemStarts
|
||||
-> persistent Map + Minimap
|
||||
-> Tracker / Tooltips / Options
|
||||
|
||||
## 0.1.0 scope
|
||||
|
||||
0.1.0 intentionally stops after:
|
||||
- ClassicAPI verification
|
||||
- gentle scheduler
|
||||
- isolated raw DB provider
|
||||
- ClassicAPI quest-ID quest log cache
|
||||
- Turtle .queststatus / TWQUEST completion service
|
||||
- diagnostics
|
||||
|
||||
No map, minimap, tracker, availability engine, or tooltip UI yet.
|
||||
|
||||
|
||||
## 0.1.1 milestone
|
||||
|
||||
Introduces the public database boundary and canonical quest services:
|
||||
|
||||
Legacy/raw data provider
|
||||
-> DatabaseAPI
|
||||
-> QuestModel
|
||||
-> Completion + QuestLog
|
||||
-> AvailableQuests
|
||||
|
||||
No module outside Database/ should add new direct pfDB dependencies.
|
||||
|
||||
|
||||
## 0.1.3 milestone
|
||||
|
||||
Adds the canonical node-generation boundary:
|
||||
|
||||
QuestModel
|
||||
-> Objectives
|
||||
-> ItemStarts
|
||||
-> Nodes
|
||||
-> future persistent Map/Minimap
|
||||
|
||||
Map/Minimap must consume Nodes and must not rediscover quest/item/source
|
||||
relationships itself.
|
||||
|
||||
## Quest-truth publication rules
|
||||
|
||||
The runtime quest system is intentionally layered:
|
||||
|
||||
pfQuest/Turtle raw DB truth
|
||||
-> QuestModel semantic normalization
|
||||
-> Completion / EventAvailability / QuestLog runtime truth
|
||||
-> AvailableQuests transactional snapshot
|
||||
-> Objectives / ItemStarts
|
||||
-> Nodes transactional snapshot
|
||||
-> PreparedMap
|
||||
-> World Map / Minimap / Tracker / Quests browser
|
||||
|
||||
Important invariants:
|
||||
|
||||
- `lvl` is presentation/difficulty; `min` is the minimum-level availability gate.
|
||||
- A quest DB `event` value is event membership only. It never means the event is active now.
|
||||
- Repeatability and event membership are independent flags; rendering must use an explicit precedence instead of assuming one classification excludes the other.
|
||||
- Completion data must be queried authoritatively before it is published. When `QueryQuestsCompleted` exists, request the cache and wait for `QUEST_QUERY_COMPLETE` before reading `GetQuestsCompleted`; otherwise use the Turtle `.queststatus` / `TWQUEST` fallback.
|
||||
- Async services never clear a published live snapshot while rebuilding it. Build into a private buffer and atomically swap at the publication boundary. This prevents map/minimap blinking during settings or quest-state refreshes.
|
||||
- Prepared/map presentation stays valid until a complete replacement node snapshot exists.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,356 @@
|
||||
## 1.0.1 first patch release
|
||||
|
||||
- Turtle quest `42045` (Tainted Rune) now carries `class = 256` in `Data/pfDB/quests-turtle.lua`, matching Tortoise WoW's Warlock-only requirement while preserving its Dwarf race mask and prerequisite 179.
|
||||
- First-time quest acceptance keeps the native quest-log priming/fast-poll path validated during post-1.0 testing.
|
||||
- World-map objective glow defaults OFF with the existing one-time migration from the former default ON state.
|
||||
- World Map density refresh prioritizes the currently displayed map zone, then the player's minimap zone, before background prepared-map work.
|
||||
- Official release metadata is version `1.0.1`; future patch releases follow `1.0.2`, `1.0.3`, and so on.
|
||||
|
||||
## 1.0 final quest-option and branding pass
|
||||
|
||||
- Added character option `showPvPRelatedQuests` (default ON), matching Questie 6's PvP quest visibility semantics for map/minimap markers. OFF hides available PvP starts, active PvP objectives, and PvP turn-ins.
|
||||
- Reordered Quest Options so Event follows Repeatable and added the requested `Show PVP Related Quests` toggle.
|
||||
- Final release metadata is version 1.0 and the startup chat message no longer includes a Beta suffix.
|
||||
|
||||
## Beta 1.6 world-map visibility scope correction
|
||||
|
||||
- `showAllQuestsWorldMap` and `showSpecialQuestsWorldMap` are continent/world-overview filters only.
|
||||
- Selected zone and city maps no longer apply those overview filters to available/item-start/turn-in quest markers.
|
||||
- Zone/city quest marker visibility remains governed by the ordinary available/completed/item-start controls.
|
||||
- `showSpecialQuestsWorldMap` remains default OFF.
|
||||
|
||||
## Beta 1.3 world-map special markers / tracker defaults / scrollable rewards
|
||||
|
||||
- `showSpecialQuestsWorldMap` defaults OFF and controls special blue/red/green quest pickup/turn-in markers independently from ordinary yellow quest markers.
|
||||
- Tracker defaults are font size 11, 30 visible rows, background opacity 0.
|
||||
- Rewards are children of the quest-detail scroll content and scroll naturally after Turn In.
|
||||
|
||||
- Internal addon folder is permanently `Questie-Octo` and the TOC is permanently `Questie-Octo.toc`; ZIP filenames carry the version instead.
|
||||
- Version metadata: `Beta 1.3`.
|
||||
- Quest 7946 (`Spawn of Jubjub`) is a conditional world-interaction offer and is not advertised as a static Morja pickup.
|
||||
- Unavailable-reason strings were shortened for player readability.
|
||||
- Rewards are rendered inside the scrollable quest-detail content with money and native item hyperlink buttons.
|
||||
|
||||
## Beta 1.1 post-package corrections
|
||||
|
||||
- Darkmoon event IDs 4 and 5 are treated as one logical active Faire for quest
|
||||
eligibility/presentation during the six active days. The DB assigns shared
|
||||
Faire quests to both IDs even though those NPCs exist at both locations.
|
||||
- Auctioneer, Banker, and Mailbox markers use a hidden 0.90 intrinsic multiplier; global scale 1 remains
|
||||
the user-facing default.
|
||||
- General options expose direct World Map Visibility controls for
|
||||
Show Quests on the World Map, Show Special Quests on the World Map, and Show Flight Master on the World Map.
|
||||
|
||||
# Quest system infrastructure audit — Beta 1.1
|
||||
|
||||
## Full Beta 1.1 regression audit (2026-08-14)
|
||||
|
||||
- 100 Lua files syntax-load cleanly under the supplied Lua compatibility checker.
|
||||
- TOC/XML/file references resolve; addon identity is `Questie-Octo`, author `Questie-Octo`, version `Beta 1.1`.
|
||||
- No unrelated generated data, code or assets are present in the addon package.
|
||||
- pfDB access remains confined to the Database/Data boundary.
|
||||
- `pfquest_node.tga` and Questie 6 `repeatable.blp` still match the supplied authoritative assets byte-for-byte.
|
||||
- PvP Type-41 enrichment and the verified Blood Ring Type-0 corrections are present; marker priority remains PvP > Repeatable > Event > Normal.
|
||||
- Quests browser search no longer depends on the shared scheduler. It performs a bounded direct scan of the already-cached lowercase title index and caps visible results at 100.
|
||||
- General-tab World Map controls are flat AceConfig entries rather than an inline nested group for Ace3v/Vanilla compatibility.
|
||||
- Seasonal event presentation is emitted only for a currently scheduled/active seasonal quest; repeatable and PvP presentation still take priority.
|
||||
|
||||
## Reference sources used
|
||||
|
||||
This pass was checked against the user-supplied reference archives rather than
|
||||
an online mirror:
|
||||
|
||||
- current `pfQuest.zip` base source/database;
|
||||
- current `pfQuest-turtle.zip` Turtle overlay/database;
|
||||
- `Questie-v6.0.0.zip` for Questie presentation behavior/artwork;
|
||||
- the supplied Turtle server source/database snapshot for quest requirements,
|
||||
rewards and game-event scheduling.
|
||||
|
||||
The normal pfQuest/Turtle entity and coordinate database remains the primary
|
||||
static data source. Questie-Octo layers its own normalization/enrichment after
|
||||
that data instead of maintaining a second independent quest database.
|
||||
|
||||
`UI/Icons/pfquest_node.tga` is byte-for-byte identical to pfQuest's `img/node.tga`.
|
||||
`UI/Icons/repeatable.blp` is byte-for-byte identical to Questie 6.0.0's
|
||||
`Icons/repeatable.blp`.
|
||||
|
||||
## Authority chain
|
||||
|
||||
1. pfQuest + Turtle + Octo static data — quest/entity/source truth.
|
||||
2. `DatabaseAPI` — raw-data boundary for the rest of the addon.
|
||||
3. `QuestModel` — normalized quest semantics (`lvl`, `min`, restrictions,
|
||||
prerequisites, repeatability and event membership).
|
||||
4. Runtime truth:
|
||||
- `QuestLog` — active/objective/failure state;
|
||||
- `Completion` — rewarded/completed history;
|
||||
- `EventAvailability` — current server event state.
|
||||
5. `AvailableQuests` — transactional availability snapshot.
|
||||
6. `Objectives` / `ItemStarts` — source relationships.
|
||||
7. `Nodes` — normalized map-node snapshot.
|
||||
8. `PreparedMap` — shared immutable render plan.
|
||||
9. World Map / Minimap / Tracker / Quests — presentation only.
|
||||
|
||||
No first-party runtime module outside `Database/` reads raw `pfDB` directly.
|
||||
|
||||
## Availability invariants
|
||||
|
||||
- `lvl` is display/difficulty information only.
|
||||
- `min` is the minimum-level acceptance gate.
|
||||
- The old user-facing Level Above Player option is gone.
|
||||
- Active/completed state, chain prerequisites, exclusivity, race, class,
|
||||
Hardcore, skill/profession, reputation, event activity, level bounds,
|
||||
repeatability and valid starters are evaluated before publication.
|
||||
- `Show Low-Level Quests`, `Show Event Quests` and `Show Repeatable Quests` are
|
||||
display/availability preferences, not replacements for server truth.
|
||||
- Repeatability and event membership are independent properties.
|
||||
|
||||
`AvailableQuests:GetUnavailableReason()` exposes the first authoritative failing
|
||||
condition to the Quests browser. It can identify disabled/not-currently-
|
||||
obtainable quests, active/completed state, chain/exclusive prerequisites, race,
|
||||
class, Hardcore, skill, reputation, inactive event, level bounds, hidden
|
||||
repeatables, timed-quest conflicts and quests with no valid starter/source.
|
||||
Unknown server-only conditions are reported as unknown instead of guessed.
|
||||
|
||||
## Completion and repeatables
|
||||
|
||||
Completion initialization runs the server completed-quest query protocol before
|
||||
reading completed history, with the Turtle quest-status path retained as a
|
||||
fallback.
|
||||
|
||||
Repeatable flags come from the server-derived enrichment or trustworthy live
|
||||
observation. One-and-done repeatables can opt into `hideAfterFirstCompletion`;
|
||||
`CLUCK!` uses that rule.
|
||||
|
||||
The cloth donation chain is intentionally not flattened into one repeatable
|
||||
category: Wool/Silk/Mageweave/Runecloth donation steps are one-time quests, while
|
||||
the `Additional Runecloth` follow-ups carry the repeatable flag.
|
||||
|
||||
Questie 6 presentation is used for repeatables: available repeatable starters
|
||||
use the authentic blue `repeatable.blp`; repeatable turn-ins use Questie's
|
||||
ordinary completion question-mark artwork. If a quest is both repeatable and an
|
||||
event quest, PvP presentation wins first; otherwise repeatable presentation wins instead of turning the marker green.
|
||||
|
||||
## Event activity and presentation
|
||||
|
||||
The pfQuest quest `event` field means membership in a server game-event group.
|
||||
It does **not** by itself mean either “active now” or “draw this quest green.”
|
||||
Questie-Octo now resolves those concepts separately.
|
||||
|
||||
`Data/EventSchedule.lua` is a compact projection of the supplied Turtle
|
||||
`game_event` table. Ordinary scheduled events are evaluated against realm wall
|
||||
clock. Continuous release/content gates (`length >= occurrence`) remain usable
|
||||
for availability but do not receive seasonal-event presentation. This prevents
|
||||
permanent content such as event 159 (`DM Release : Cloth turning NPC`) from
|
||||
making normal cloth donation quests green.
|
||||
|
||||
Darkmoon Faire uses the manually verified Turtle 14-day cycle, anchored at
|
||||
2026-08-13:
|
||||
|
||||
- six days Elwynn (Thursday through Tuesday);
|
||||
- one Wednesday construction day;
|
||||
- six days Mulgore (Thursday through Tuesday);
|
||||
- one Wednesday construction day;
|
||||
- repeat indefinitely.
|
||||
|
||||
Major annual festivals use `Data/CalendarEventRules.lua`, transcribed from the
|
||||
2026 in-game Turtle calendar. Only visible event text counts. Raid Reset,
|
||||
roadmap/release announcements and graphic-only calendar cells are ignored.
|
||||
Known calendar windows are authoritative for quest visibility; clicking a
|
||||
festival NPC outside its verified window cannot reactivate that festival.
|
||||
Unknown/custom event IDs still require runtime evidence.
|
||||
|
||||
A few quest event IDs exist in the current pfQuest/Turtle quest data without a
|
||||
matching row in the supplied `game_event` table. Event 172 is explicitly
|
||||
handled as a persistent compatibility gate because the authoritative quest data
|
||||
uses it for Molten Core attunement. Missing true-event IDs 26, 99, 166 and 171
|
||||
retain event presentation but require runtime observation rather than being
|
||||
assumed active globally.
|
||||
|
||||
## Map/node invariants
|
||||
|
||||
- Availability, node and prepared-map rebuilds publish transactionally; the
|
||||
previous complete snapshot remains visible until its replacement is ready.
|
||||
- Full Nodes use pfQuest's exact `node.tga` and **native 14 px pfQuest baseline
|
||||
at global scale 1.0**.
|
||||
- Full Nodes keep the requested additional 15% transparency and subdued color.
|
||||
- There is no separate Full Node or category scale setting. Only global World
|
||||
Map and global Minimap scale remain.
|
||||
- Global scaling changes frame dimensions only; it cannot replace Full Node
|
||||
artwork with Questie objective artwork.
|
||||
- Full-node semantic state survives visual refreshes/rescaling.
|
||||
- World map and minimap retain a hidden 1000-node emergency cap.
|
||||
- General -> Show All Quests on World Map defaults enabled. It controls available pickup/item-start presentation on the World Map only; active objectives/turn-ins, minimap, and tracker are unaffected.
|
||||
- Distance fading is absent.
|
||||
- Object-ID display is absent; Quest, NPC and Item IDs remain optional.
|
||||
|
||||
## Quests browser
|
||||
|
||||
The browser remains a fixed native frame rather than a large AceGUI result tree:
|
||||
|
||||
- 18 recycled result rows;
|
||||
- no full-database scan merely for opening the browser;
|
||||
- Options-to-Quests handoff is deferred until after AceConfig's execute refresh,
|
||||
then Questie Options and the Game Menu are explicitly hidden;
|
||||
- searches only run on Enter/Search;
|
||||
- search titles are lowercased/cached during the existing incremental database
|
||||
index build;
|
||||
- full text/ID searches run in 33-quest scheduler slices (about 32% more work per
|
||||
frame than the previous 25-row search while remaining frame-sliced);
|
||||
- visible results remain capped at 100;
|
||||
- Available/Active/Completed no-query views use their state tables directly;
|
||||
- closing the browser invalidates an outstanding search generation.
|
||||
|
||||
Unavailable rows explain *why* the quest cannot currently be taken in the right
|
||||
pane.
|
||||
|
||||
`Data/QuestRewards.lua` is a compact projection of the supplied authoritative
|
||||
Turtle `quest_template` reward fields. The right pane shows positive money
|
||||
rewards in gold/silver/copper text, guaranteed reward items as native clickable
|
||||
item hyperlinks, and choice rewards under `Choose one:`. No reward icons are
|
||||
created. Item links use the same Vanilla `SetItemRef` / `GameTooltip:SetHyperlink`
|
||||
pattern as pfQuest's item browser.
|
||||
|
||||
## Static audit completed for Beta 1.1
|
||||
|
||||
- 99 bundled Lua files pass a Lua parser syntax-load check.
|
||||
- Every TOC file reference exists.
|
||||
- Every XML Include/Script reference exists.
|
||||
- All literal settings reads/writes resolve to defined defaults.
|
||||
- No first-party runtime module outside `Database/` directly reads `pfDB`.
|
||||
- No runtime distance-fading option/path remains.
|
||||
- No user-facing Level Above Player setting/path remains.
|
||||
- No Completion tracker-sort mode remains.
|
||||
- No Object-ID option/render path remains (only stale SavedVariable cleanup).
|
||||
- Only global Map and Minimap scale sliders remain.
|
||||
- Full-node 1000-pin safety caps remain in both renderers.
|
||||
- pfQuest Full Node and Questie repeatable assets match their supplied reference
|
||||
files byte-for-byte.
|
||||
- 33 of the 34 raw loaded pfQuest/Turtle DB files are byte-identical to their
|
||||
supplied source files; the remaining Turtle `patchtable.lua` is the existing
|
||||
Questie-Octo compatibility adaptation that applies the overlay without
|
||||
loading pfQuest's addon UI/runtime.
|
||||
|
||||
## Recommended in-game regression pass
|
||||
|
||||
1. Open **Quests** from Questie Options and confirm Options/Game Menu disappear.
|
||||
2. Search `defias`; compare response time and inspect several Unavailable rows.
|
||||
3. Select quests with money, fixed-item and choice-item rewards; hover/click the
|
||||
hyperlink text.
|
||||
4. Compare a normal cloth donation with an `Additional Runecloth` follow-up.
|
||||
5. Verify `Give Gerard a Drink` uses the authentic blue repeatable pickup icon.
|
||||
6. Verify Darkmoon immediately after `/reload` and again across its Wednesday
|
||||
installation transition.
|
||||
7. Move global Map/Minimap scale repeatedly while Full Nodes are visible.
|
||||
8. Recheck failed timed quests, reputation gates and multi-step prerequisites.
|
||||
|
||||
|
||||
## 0.3.6 corrective notes
|
||||
|
||||
- Event availability now mirrors pfQuest: a quest's `event` membership does not
|
||||
locally gate availability. The Show Event Quests toggle is the display gate.
|
||||
The separate presentation classifier still prevents permanent Turtle content
|
||||
gates such as event 159 from being painted as festival quests.
|
||||
- Quests search uses the database's already-cached lowercase titles in 768-ID
|
||||
bounded slices (roughly nine frames for the entire current DB) and exact numeric
|
||||
quest IDs bypass the scan entirely.
|
||||
- Authoritative donation verification: 80374 (Additional Runecloth: Silvermoon
|
||||
Remnants) and 80379 (Additional Runecloth: Revantusk Tribe) are repeatable.
|
||||
80374 has server minimum level 50; it is correctly unavailable to a level-34
|
||||
character. Goblin donation quests 41115 (Cartel Gold Donations, min 30) and
|
||||
41123 (Donations to Vizlow, min 1) are repeatable and level-eligible at 34.
|
||||
|
||||
|
||||
## 0.3.7 conservative event beta notes
|
||||
|
||||
- Fresh installs default `showEventQuests=false`; existing character choices are
|
||||
not overwritten.
|
||||
- `IsPresentationEvent` separates true festival presentation from permanent
|
||||
game_event release/content gates.
|
||||
- Available festival markers require both the user toggle and
|
||||
`EventAvailability:IsActiveForQuest()`. Scheduled/hardcoded event truth is
|
||||
preferred; unknown schedules require runtime observation.
|
||||
- Runtime observation triggers a bounded availability refresh only on the first
|
||||
inactive-to-active transition.
|
||||
- Active quests already in the quest log bypass available-quest filtering and
|
||||
therefore retain objectives/turn-ins even if event display is disabled.
|
||||
|
||||
|
||||
## 0.3.8 curated Turtle calendar notes
|
||||
|
||||
The manually verified annual windows are:
|
||||
|
||||
- Love is in the Air: February 1-16
|
||||
- Lunar Festival: February 16-March 4
|
||||
- Noblegarden: April 17-May 8
|
||||
- Midsummer Fire Festival: June 21-July 12
|
||||
- Brewfest: September 20-October 6
|
||||
- Harvest Festival: October 1-8
|
||||
- Hallow's End: October 20-November 2
|
||||
- Feast of Winter Veil: December 3-January 14
|
||||
|
||||
Darkmoon Faire is intentionally separate from the annual calendar and uses the
|
||||
anchored alternating 14-day rule described above. Roadmap names such as
|
||||
Frostmane Hollow, Windhorn Canyon, Dragonmaw Retreat, Northwind, Stormwrought
|
||||
Ruins, Moonwhisper Coast, Phase 1/2 and similar release notices never affect
|
||||
quest availability.
|
||||
|
||||
## Beta 1.1 event standby policy
|
||||
|
||||
Event membership is not itself proof of a seasonal event. Beta 1.1 uses an
|
||||
explicit three-way classification:
|
||||
|
||||
- verified non-seasonal/content gates: ordinary quest availability/presentation;
|
||||
- verified seasonal events: gated by the curated annual calendar, the anchored
|
||||
Darkmoon cycle, or a separately verified narrow timer;
|
||||
- unknown/unverified event IDs: standby and therefore not published as available
|
||||
quest markers. Active quests already accepted by the player remain visible.
|
||||
|
||||
Event 159 is explicitly verified as the cloth-turn-in content/release gate and
|
||||
is not seasonal. Repeatability remains independent of event classification.
|
||||
|
||||
## Beta 1.1 package identity
|
||||
|
||||
- Install folder: `Questie-Octo`
|
||||
- TOC file: `Questie-Octo.toc`
|
||||
- Display title: `Questie-Octo`
|
||||
- Author: `Questie-Octo`
|
||||
- Version: `Beta 1.1`
|
||||
|
||||
The versioned install folder is intentional for this beta package. First-party
|
||||
texture paths were updated to the same folder name and validated before packaging.
|
||||
|
||||
## PvP quest classification
|
||||
|
||||
Questie-Octo preserves the authoritative Turtle quest `Type` for PvP quests.
|
||||
`Type == 41` is the canonical PvP classification used by Questie 6.
|
||||
|
||||
Presentation priority for quest pickup/turn-in markers is:
|
||||
|
||||
1. PvP (red)
|
||||
2. Repeatable (blue)
|
||||
3. verified Event (green)
|
||||
4. Normal (yellow)
|
||||
|
||||
The supplied Turtle source currently reports Blood Ring quests 41107-41110 as
|
||||
Type 0 even though their objectives/rewards explicitly identify them as PvP.
|
||||
Questie-Octo corrects only those verified rows locally to Type 41; Type 0 is
|
||||
not broadly reinterpreted.
|
||||
|
||||
## Beta 1.1 Darkmoon live-offer correction
|
||||
|
||||
Live Elwynn Faire cross-checks on 2026-08-14 confirmed that Turtle reuses the
|
||||
same Darkmoon hand-in NPCs/quests across Elwynn and Mulgore while pfQuest splits
|
||||
those shared rows between event IDs 4 and 5. The verified starter set is Silas
|
||||
Darkmoon (14823), Gelvas Grimegate (14828), Yebb Neblegear (14829), Kerri Hicks
|
||||
(14832), Chronos (14833), and Rinling (14841).
|
||||
|
||||
For quests tagged event 4/5 and started by those NPCs, Questie-Octo treats the
|
||||
Faire as one logical active event. During an active Faire it keeps completion,
|
||||
race/class, level, max-level, timed and repeatable-option checks, but does not
|
||||
let stale pfQuest Darkmoon reputation/chain metadata suppress an offer that the
|
||||
live Turtle quest dialog exposes. Silas's one-time Torta's Egg remains hidden
|
||||
once historical completion says it was rewarded.
|
||||
|
||||
### Darkmoon logical event alias
|
||||
|
||||
Turtle/pfQuest quest rows use both `event = 4` and `event = 5` for quest offers that are shared by the same Darkmoon Faire NPCs in both Elwynn and Mulgore. Questie-Octo preserves the authoritative value as `rawEventID`, but normalizes runtime `eventID` 5 to logical event 4. Availability and presentation therefore see one `DARKMOON_FAIRE` event; the anchored 14-day schedule and NPC coordinates determine the physical location. Construction events 23/24 remain distinct.
|
||||
@@ -0,0 +1,113 @@
|
||||
# Questie-Octo source provenance and licensing audit
|
||||
|
||||
Audit date: 2026-08-15
|
||||
|
||||
## Purpose
|
||||
|
||||
This document records the source snapshots available during the GitHub/licensing
|
||||
pass and preserves provenance for future human and AI-assisted maintenance.
|
||||
This pass is documentation/licensing-only: no gameplay, Lua logic, TOC entry,
|
||||
quest data, map behavior, tracker behavior, artwork, settings, or existing
|
||||
project note was changed or removed.
|
||||
|
||||
The baseline addon archive audited here was:
|
||||
|
||||
- `Questie-Octo(1).zip`
|
||||
- SHA-256: `3e0528012df2a0a36cd9185850ec71a330e5feb2abc87dc6b44e8f765e5f2fea`
|
||||
- 139 regular files before licensing documents were added.
|
||||
|
||||
## Source snapshots available for this audit
|
||||
|
||||
| Source snapshot | SHA-256 | Role / note |
|
||||
| --- | --- | --- |
|
||||
| Questie 5.2.3 | `806a12d894a9d8568b73d86a95aeda79f29bebf90320a5f0007bec8db9803335` | Main historical UI/behavior target; no project-level Questie license found in supplied ZIP. |
|
||||
| Questie 6.0.0 | `de997f793871b898f6a8f9f6494b79fcd55fc82f8e087b88a026a3dfc99550b9` | Architecture bridge and source of some reference assets/libraries; no project-level Questie license found in supplied ZIP. |
|
||||
| Ace3v | `0482801133653d0e611e29335b22e77ad3de05a14ab8c35c163eb3f05eaaebeb` | Bundled/adapted Ace3 compatibility libraries. |
|
||||
| pfQuest-classicAPI-octo | `484553544a30f4031273873c9673b779240339626455aa0e3c05f5c3df577dfb` | pfQuest-family data/runtime heritage and compatibility reference. |
|
||||
| pfQuest-octo | `f4180ff88fbca25e7c673ab8fb5903c8a94807678b89ca70eefede0a8b3bd7c4` | Octo-specific pfQuest branch/reference. |
|
||||
| ShaguTweaks | `3d772e41ea576a9b8e3d25017cb3cc2f93347d7ee4da4fa7bb69f2e403bcc007` | Vanilla UI/compatibility reference. |
|
||||
| ShaguTweaks-extras | `2727f09cbbbdc08b2a06f424758363d0f206fef2ff0485449e03867a41a84357` | Additional Shagu compatibility/reference material. |
|
||||
| MoveAnything | `452b9d7dc5c74d7f0c4a2f51954bfcaa0b20b951fbf742951a48390dd21cf7fd` | Compatibility/debugging reference; no general license file found in supplied snapshot. |
|
||||
| Tortoise/Turtle server snapshot | `ed3b3638f26733d30993e0d2a1fac1e31a0738d5f66bd11a23c52509f7d47ee9` | Offline server-data provenance recorded by existing generated-data notes. |
|
||||
| Calendar reference archive | `f4418d71aaf86fcc1067f3f02b7291aab6f3c37bb4d607a440127879270553a9` | Event/calendar verification material. |
|
||||
|
||||
The filenames used for upload can carry duplicate suffixes such as `(2)` or
|
||||
`(3)`. The SHA-256 values above identify the actual snapshots independently of
|
||||
those local upload names.
|
||||
|
||||
## Later compatibility reference snapshots
|
||||
|
||||
The following snapshots were supplied later in the same project and were used
|
||||
only to cross-check UI compatibility behavior. They are not bundled with
|
||||
Questie-Octo and this record does not change their licensing or ownership.
|
||||
|
||||
| Compatibility reference | SHA-256 | Role / note |
|
||||
| --- | --- | --- |
|
||||
| pfUI-classicAPI-octo | `5b4ed17b4ca94712ea7cc35cd86f31dfdc7b5d94a83bb51abb3cfca2e8e4911b` | Tooltip lifecycle, minimap shape, and Vanilla/ClassicAPI UI compatibility reference. |
|
||||
| DragonflightUI-Reforged | `2c08e1ae203f54d7969262b65056d58d5e9e8c26f3b61f2c935ff0825525ac68` | Replacement ESC/GameMenu behavior and square-minimap compatibility reference. |
|
||||
|
||||
## Historical sources no longer available as exact archives
|
||||
|
||||
Existing Questie-Octo comments and README history establish that Questie 3.3.5,
|
||||
7.0.0, and 8.0.0 were used during the earlier backport work. Those exact source
|
||||
archives are no longer available in the current workspace, so they cannot be
|
||||
re-hashed during this licensing pass.
|
||||
|
||||
Do not delete their references from source comments or documentation. Those
|
||||
references are the remaining provenance record for the earlier work.
|
||||
|
||||
Later `Docs/ARCHITECTURE.md` records additional Questie generations as reference
|
||||
material, including Questie 7-9, Questie 10-11, and Questie 11.34.1 as an
|
||||
edge-case reference. Earlier README sections saying Questie 9/10/11 were not
|
||||
used are historical stage-specific notes and intentionally remain intact.
|
||||
|
||||
## Exact-match audit observations
|
||||
|
||||
The baseline Questie-Octo archive contained many files that are byte-identical
|
||||
to supplied source snapshots, especially under `Libs/` and `Data/`. Exact hash
|
||||
matches are only one kind of provenance: adapted code, generated tables,
|
||||
converted artwork, copied behavior, and compatibility patterns can remain
|
||||
third-party-derived even when a whole-file hash no longer matches.
|
||||
|
||||
For this reason future audits must consult both hashes and the retained source
|
||||
comments/documentation.
|
||||
|
||||
## License findings
|
||||
|
||||
### Questie-Octo original contributions
|
||||
|
||||
Original portions first authored for Questie-Octo are offered under the MIT
|
||||
License. See `../LICENSE` and `../LICENSES/Questie-Octo-MIT.txt`.
|
||||
|
||||
### Ace3v
|
||||
|
||||
The supplied Ace3v snapshot includes the Ace3 Development Team license. Its
|
||||
verbatim text is preserved at `../LICENSES/Ace3v-LICENSE.txt`.
|
||||
|
||||
### pfQuest / Shagu
|
||||
|
||||
The supplied pfQuest and Shagu snapshots contain MIT license files. Their exact
|
||||
texts are preserved individually in `../LICENSES/` so their original copyright
|
||||
years and notices are not collapsed into a generic replacement.
|
||||
|
||||
### Questie
|
||||
|
||||
No project-level Questie license file was found in the supplied Questie 5.2.3
|
||||
or 6.0.0 snapshots. The `Questie/Libs/LICENSE.txt` file in those snapshots is
|
||||
Ace3's license and is not treated as Questie's project license. Questie-derived
|
||||
material is therefore excluded from the scope of the Questie-Octo MIT grant in
|
||||
this repository notice.
|
||||
|
||||
### ClassicAPI
|
||||
|
||||
ClassicAPI.dll is an external dependency and is not bundled. Upstream states
|
||||
GPL v3 or later. The upstream GPLv3 license document is included at
|
||||
`../LICENSES/ClassicAPI-GPL-3.0.txt` for reference and compliance clarity.
|
||||
|
||||
## Packaging invariant
|
||||
|
||||
The GitHub/licensing package must preserve every pre-existing archive member's
|
||||
uncompressed bytes. Licensing/provenance files are additions only. A future AI
|
||||
or human contributor should not use a licensing cleanup as a reason to rewrite
|
||||
source, change gameplay, strip comments, remove historical notes, or normalize
|
||||
third-party files.
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 Questie-Octo contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,29 @@
|
||||
Copyright (c) 2007, Ace3 Development Team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Redistribution of a stand alone version is strictly prohibited without
|
||||
prior written authorization from the Lead of the Ace3 Development Team.
|
||||
* Neither the name of the Ace3 Development Team nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
@@ -0,0 +1,11 @@
|
||||
LibStub public-domain notice
|
||||
============================
|
||||
|
||||
The bundled LibStub source contains the following upstream notice:
|
||||
|
||||
"LibStub is hereby placed in the Public Domain"
|
||||
|
||||
Credits recorded in the bundled source:
|
||||
Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke.
|
||||
|
||||
The notice is also retained directly in Libs/LibStub/LibStub.lua.
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 Questie-Octo contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,34 @@
|
||||
Questie-Octo Licensing Notice
|
||||
=============================
|
||||
|
||||
Questie-Octo is a mixed-source open-source project.
|
||||
|
||||
Original Questie-Octo contributions
|
||||
------------------------------------
|
||||
Code, documentation, integration work, and other material first authored for
|
||||
Questie-Octo, to the extent that those portions are not copied from or derived
|
||||
from third-party material, are licensed under the MIT License.
|
||||
|
||||
The full MIT text for those original contributions is in:
|
||||
|
||||
LICENSES/Questie-Octo-MIT.txt
|
||||
|
||||
Third-party material
|
||||
--------------------
|
||||
This notice does not relicense third-party code, data, artwork, libraries, or
|
||||
other material. Third-party material remains under its own copyright and
|
||||
license terms. See THIRD_PARTY_NOTICES.md and the files in LICENSES/.
|
||||
|
||||
In particular, the MIT grant for original Questie-Octo contributions must not
|
||||
be read as a claim that Questie-derived material, Ace3 material, pfQuest/Shagu
|
||||
material, ClassicAPI, or any other third-party material has been relicensed by
|
||||
Questie-Octo.
|
||||
|
||||
Where the exact upstream project license could not be verified from the source
|
||||
snapshot used during development, the upstream rights are expressly retained
|
||||
and no additional permission is asserted here.
|
||||
|
||||
This licensing layout is intentionally additive. Historical README sections,
|
||||
source comments, architecture notes, audit notes, generated-data headers, and
|
||||
AI-oriented maintenance notes are part of the project's provenance record and
|
||||
should be preserved when modifying or redistributing the project.
|
||||
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2021 Eric Mauser (Shagu)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2025 Eric Mauser (Shagu)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017-2021 Eric Mauser (Shagu)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 Eric Mauser (Shagu)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,4 @@
|
||||
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
|
||||
..\FrameXML\UI.xsd">
|
||||
<Script file="AceConfigDialog-3.0.lua"/>
|
||||
</Ui>
|
||||
@@ -0,0 +1,352 @@
|
||||
--- AceConfigRegistry-3.0 handles central registration of options tables in use by addons and modules.\\
|
||||
-- Options tables can be registered as raw tables, OR as function refs that return a table.\\
|
||||
-- Such functions receive three arguments: "uiType", "uiName", "appName". \\
|
||||
-- * Valid **uiTypes**: "cmd", "dropdown", "dialog". This is verified by the library at call time. \\
|
||||
-- * The **uiName** field is expected to contain the full name of the calling addon, including version, e.g. "FooBar-1.0". This is verified by the library at call time.\\
|
||||
-- * The **appName** field is the options table name as given at registration time \\
|
||||
--
|
||||
-- :IterateOptionsTables() (and :GetOptionsTable() if only given one argument) return a function reference that the requesting config handling addon must call with valid "uiType", "uiName".
|
||||
-- @class file
|
||||
-- @name AceConfigRegistry-3.0
|
||||
-- @release $Id: AceConfigRegistry-3.0.lua 1139 2016-07-03 07:43:51Z nevcairiel $
|
||||
local MAJOR, MINOR = "AceConfigRegistry-3.0", 16
|
||||
local AceConfigRegistry = LibStub:NewLibrary(MAJOR, MINOR)
|
||||
|
||||
if not AceConfigRegistry then return end
|
||||
|
||||
AceConfigRegistry.tables = AceConfigRegistry.tables or {}
|
||||
|
||||
local CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0")
|
||||
|
||||
if not AceConfigRegistry.callbacks then
|
||||
AceConfigRegistry.callbacks = CallbackHandler:New(AceConfigRegistry)
|
||||
end
|
||||
|
||||
-- Lua APIs
|
||||
local tinsert, tconcat, tgetn = table.insert, table.concat, table.getn
|
||||
local strfind = string.find
|
||||
local type, tostring, pairs = type, tostring, pairs
|
||||
local error, assert = error, assert
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
-- Validating options table consistency:
|
||||
|
||||
|
||||
AceConfigRegistry.validated = {
|
||||
-- list of options table names ran through :ValidateOptionsTable automatically.
|
||||
-- CLEARED ON PURPOSE, since newer versions may have newer validators
|
||||
cmd = {},
|
||||
dropdown = {},
|
||||
dialog = {},
|
||||
}
|
||||
|
||||
local function err(msg, errlvl, ...)
|
||||
local l = tgetn(arg)
|
||||
local i,j = 1,l
|
||||
while i < j do
|
||||
arg[i], arg[j] = arg[j], arg[i]
|
||||
i = i+1
|
||||
j = j-1
|
||||
end
|
||||
error(MAJOR..":ValidateOptionsTable(): "..tconcat(arg,".")..msg, errlvl+2)
|
||||
end
|
||||
|
||||
local isstring={["string"]=true, _="string"}
|
||||
local isstringfunc={["string"]=true,["function"]=true, _="string or funcref"}
|
||||
local istable={["table"]=true, _="table"}
|
||||
local ismethodtable={["table"]=true,["string"]=true,["function"]=true, _="methodname, funcref or table"}
|
||||
local optstring={["nil"]=true,["string"]=true, _="string"}
|
||||
local optstringfunc={["nil"]=true,["string"]=true,["function"]=true, _="string or funcref"}
|
||||
local optstringnumberfunc={["nil"]=true,["string"]=true,["number"]=true,["function"]=true, _="string, number or funcref"}
|
||||
local optnumber={["nil"]=true,["number"]=true, _="number"}
|
||||
local optmethod={["nil"]=true,["string"]=true,["function"]=true, _="methodname or funcref"}
|
||||
local optmethodfalse={["nil"]=true,["string"]=true,["function"]=true,["boolean"]={[false]=true}, _="methodname, funcref or false"}
|
||||
local optmethodnumber={["nil"]=true,["string"]=true,["function"]=true,["number"]=true, _="methodname, funcref or number"}
|
||||
local optmethodtable={["nil"]=true,["string"]=true,["function"]=true,["table"]=true, _="methodname, funcref or table"}
|
||||
local optmethodbool={["nil"]=true,["string"]=true,["function"]=true,["boolean"]=true, _="methodname, funcref or boolean"}
|
||||
local opttable={["nil"]=true,["table"]=true, _="table"}
|
||||
local optbool={["nil"]=true,["boolean"]=true, _="boolean"}
|
||||
local optboolnumber={["nil"]=true,["boolean"]=true,["number"]=true, _="boolean or number"}
|
||||
|
||||
local basekeys={
|
||||
type=isstring,
|
||||
name=isstringfunc,
|
||||
desc=optstringfunc,
|
||||
descStyle=optstring,
|
||||
order=optmethodnumber,
|
||||
validate=optmethodfalse,
|
||||
confirm=optmethodbool,
|
||||
confirmText=optstring,
|
||||
disabled=optmethodbool,
|
||||
hidden=optmethodbool,
|
||||
guiHidden=optmethodbool,
|
||||
dialogHidden=optmethodbool,
|
||||
dropdownHidden=optmethodbool,
|
||||
cmdHidden=optmethodbool,
|
||||
icon=optstringnumberfunc,
|
||||
iconCoords=optmethodtable,
|
||||
handler=opttable,
|
||||
get=optmethodfalse,
|
||||
set=optmethodfalse,
|
||||
func=optmethodfalse,
|
||||
arg={["*"]=true},
|
||||
width=optstring,
|
||||
}
|
||||
|
||||
local typedkeys={
|
||||
header={},
|
||||
description={
|
||||
image=optstringnumberfunc,
|
||||
imageCoords=optmethodtable,
|
||||
imageHeight=optnumber,
|
||||
imageWidth=optnumber,
|
||||
fontSize=optstringfunc,
|
||||
},
|
||||
group={
|
||||
args=istable,
|
||||
plugins=opttable,
|
||||
inline=optbool,
|
||||
cmdInline=optbool,
|
||||
guiInline=optbool,
|
||||
dropdownInline=optbool,
|
||||
dialogInline=optbool,
|
||||
childGroups=optstring,
|
||||
},
|
||||
execute={
|
||||
image=optstringnumberfunc,
|
||||
imageCoords=optmethodtable,
|
||||
imageHeight=optnumber,
|
||||
imageWidth=optnumber,
|
||||
},
|
||||
input={
|
||||
pattern=optstring,
|
||||
usage=optstring,
|
||||
control=optstring,
|
||||
dialogControl=optstring,
|
||||
dropdownControl=optstring,
|
||||
multiline=optboolnumber,
|
||||
nullable=optbool,
|
||||
},
|
||||
toggle={
|
||||
tristate=optbool,
|
||||
image=optstringnumberfunc,
|
||||
imageCoords=optmethodtable,
|
||||
},
|
||||
tristate={
|
||||
},
|
||||
range={
|
||||
min=optnumber,
|
||||
softMin=optnumber,
|
||||
max=optnumber,
|
||||
softMax=optnumber,
|
||||
step=optnumber,
|
||||
bigStep=optnumber,
|
||||
isPercent=optbool,
|
||||
},
|
||||
select={
|
||||
values=ismethodtable,
|
||||
valuesTableDestroyable=optbool, -- Ace3v: if the values table is generated by AceCore.new
|
||||
style={
|
||||
["nil"]=true,
|
||||
["string"]={dropdown=true,radio=true},
|
||||
_="string: 'dropdown' or 'radio'"
|
||||
},
|
||||
control=optstring,
|
||||
dialogControl=optstring,
|
||||
dropdownControl=optstring,
|
||||
itemControl=optstring,
|
||||
},
|
||||
multiselect={
|
||||
values=ismethodtable,
|
||||
valuesTableDestroyable=optbool, -- Ace3v: if the values table is generated by AceCore.new
|
||||
style=optstring,
|
||||
tristate=optbool,
|
||||
control=optstring,
|
||||
dialogControl=optstring,
|
||||
dropdownControl=optstring,
|
||||
},
|
||||
color={
|
||||
hasAlpha=optmethodbool,
|
||||
},
|
||||
keybinding={
|
||||
-- TODO
|
||||
},
|
||||
}
|
||||
|
||||
local function validateKey(k,errlvl,arg)
|
||||
errlvl=(errlvl or 0)+1
|
||||
if type(k)~="string" then
|
||||
err("["..tostring(k).."] - key is not a string", errlvl, arg)
|
||||
end
|
||||
if strfind(k, "[%c\127]") then
|
||||
err("["..tostring(k).."] - key name contained control characters", errlvl, arg)
|
||||
end
|
||||
end
|
||||
|
||||
local function validateVal(v, oktypes, errlvl, arg)
|
||||
errlvl=(errlvl or 0)+1
|
||||
local isok=oktypes[type(v)] or oktypes["*"]
|
||||
|
||||
if not isok then
|
||||
err(": expected a "..oktypes._..", got '"..tostring(v).."'", errlvl, arg)
|
||||
end
|
||||
if type(isok)=="table" then -- isok was a table containing specific values to be tested for!
|
||||
if not isok[v] then
|
||||
err(": did not expect "..type(v).." value '"..tostring(v).."'", errlvl, arg)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function validate(options,errlvl,arg)
|
||||
errlvl=(errlvl or 0)+1
|
||||
-- basic consistency
|
||||
if type(options)~="table" then
|
||||
err(": expected a table, got a "..type(options), errlvl, arg)
|
||||
end
|
||||
if type(options.type)~="string" then
|
||||
err(".type: expected a string, got a "..type(options.type), errlvl, arg)
|
||||
end
|
||||
|
||||
-- get type and 'typedkeys' member
|
||||
local tk = typedkeys[options.type]
|
||||
if not tk then
|
||||
err(".type: unknown type '"..options.type.."'", errlvl, arg)
|
||||
end
|
||||
|
||||
-- make sure that all options[] are known parameters
|
||||
for k,v in pairs(options) do
|
||||
if not (tk[k] or basekeys[k]) then
|
||||
err(": unknown parameter", errlvl,tostring(k), arg)
|
||||
end
|
||||
end
|
||||
|
||||
-- verify that required params are there, and that everything is the right type
|
||||
for k,oktypes in pairs(basekeys) do
|
||||
validateVal(options[k], oktypes, errlvl, k, arg)
|
||||
end
|
||||
for k,oktypes in pairs(tk) do
|
||||
validateVal(options[k], oktypes, errlvl, k, arg)
|
||||
end
|
||||
|
||||
-- extra logic for groups
|
||||
if options.type=="group" then
|
||||
for k,v in pairs(options.args) do
|
||||
validateKey(k,errlvl,"args", arg)
|
||||
validate(v, errlvl,k,"args", arg)
|
||||
end
|
||||
if options.plugins then
|
||||
for plugname,plugin in pairs(options.plugins) do
|
||||
if type(plugin)~="table" then
|
||||
err(": expected a table, got '"..tostring(plugin).."'", errlvl,tostring(plugname), "plugins", arg)
|
||||
end
|
||||
for k,v in pairs(plugin) do
|
||||
validateKey(k,errlvl,tostring(plugname),"plugins",arg)
|
||||
validate(v, errlvl,k,tostring(plugname),"plugins",arg)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Validates basic structure and integrity of an options table \\
|
||||
-- Does NOT verify that get/set etc actually exist, since they can be defined at any depth
|
||||
-- @param options The table to be validated
|
||||
-- @param name The name of the table to be validated (shown in any error message)
|
||||
-- @param errlvl (optional number) error level offset, default 0 (=errors point to the function calling :ValidateOptionsTable)
|
||||
function AceConfigRegistry:ValidateOptionsTable(options,name,errlvl)
|
||||
errlvl=(errlvl or 0)+1
|
||||
name = name or "Optionstable"
|
||||
if not options.name then
|
||||
options.name=name -- bit of a hack, the root level doesn't really need a .name :-/
|
||||
end
|
||||
validate(options,errlvl,name)
|
||||
end
|
||||
|
||||
--- Fires a "ConfigTableChange" callback for those listening in on it, allowing config GUIs to refresh.
|
||||
-- You should call this function if your options table changed from any outside event, like a game event
|
||||
-- or a timer.
|
||||
-- @param appName The application name as given to `:RegisterOptionsTable()`
|
||||
function AceConfigRegistry:NotifyChange(appName)
|
||||
if not AceConfigRegistry.tables[appName] then return end
|
||||
AceConfigRegistry.callbacks:Fire("ConfigTableChange", 1, appName)
|
||||
end
|
||||
|
||||
-- -------------------------------------------------------------------
|
||||
-- Registering and retreiving options tables:
|
||||
|
||||
|
||||
-- validateGetterArgs: helper function for :GetOptionsTable (or, rather, the getter functions returned by it)
|
||||
|
||||
local function validateGetterArgs(uiType, uiName, errlvl)
|
||||
errlvl=(errlvl or 0)+2
|
||||
if uiType~="cmd" and uiType~="dropdown" and uiType~="dialog" then
|
||||
error(MAJOR..": Requesting options table: 'uiType' - invalid configuration UI type, expected 'cmd', 'dropdown' or 'dialog'", errlvl)
|
||||
end
|
||||
if not strfind(uiName, "[A-Za-z]+-[0-9]") then -- Expecting e.g. "MyLib-1.2"
|
||||
error(MAJOR..": Requesting options table: 'uiName' - badly formatted or missing version number. Expected e.g. 'MyLib-1.2'", errlvl)
|
||||
end
|
||||
end
|
||||
|
||||
--- Register an options table with the config registry.
|
||||
-- @param appName The application name as given to `:RegisterOptionsTable()`
|
||||
-- @param options The options table, OR a function reference that generates it on demand. \\
|
||||
-- See the top of the page for info on arguments passed to such functions.
|
||||
-- @param skipValidation Skip options table validation (primarily useful for extremely huge options, with a noticeable slowdown)
|
||||
function AceConfigRegistry:RegisterOptionsTable(appName, options, skipValidation)
|
||||
if type(options)=="table" then
|
||||
if options.type~="group" then -- quick sanity checker
|
||||
error(MAJOR..": RegisterOptionsTable(appName, options): 'options' - missing type='group' member in root group", 2)
|
||||
end
|
||||
AceConfigRegistry.tables[appName] = function(uiType, uiName, errlvl)
|
||||
errlvl=(errlvl or 0)+1
|
||||
validateGetterArgs(uiType, uiName, errlvl)
|
||||
if not AceConfigRegistry.validated[uiType][appName] and not skipValidation then
|
||||
AceConfigRegistry:ValidateOptionsTable(options, appName, errlvl) -- upgradable
|
||||
AceConfigRegistry.validated[uiType][appName] = true
|
||||
end
|
||||
return options
|
||||
end
|
||||
elseif type(options)=="function" then
|
||||
AceConfigRegistry.tables[appName] = function(uiType, uiName, errlvl)
|
||||
errlvl=(errlvl or 0)+1
|
||||
validateGetterArgs(uiType, uiName, errlvl)
|
||||
local tab = assert(options(uiType, uiName, appName))
|
||||
if not AceConfigRegistry.validated[uiType][appName] and not skipValidation then
|
||||
AceConfigRegistry:ValidateOptionsTable(tab, appName, errlvl) -- upgradable
|
||||
AceConfigRegistry.validated[uiType][appName] = true
|
||||
end
|
||||
return tab
|
||||
end
|
||||
else
|
||||
error(MAJOR..": RegisterOptionsTable(appName, options): 'options' - expected table or function reference", 2)
|
||||
end
|
||||
end
|
||||
|
||||
--- Returns an iterator of ["appName"]=funcref pairs
|
||||
function AceConfigRegistry:IterateOptionsTables()
|
||||
return pairs(AceConfigRegistry.tables)
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
--- Query the registry for a specific options table.
|
||||
-- If only appName is given, a function is returned which you
|
||||
-- can call with (uiType,uiName) to get the table.\\
|
||||
-- If uiType&uiName are given, the table is returned.
|
||||
-- @param appName The application name as given to `:RegisterOptionsTable()`
|
||||
-- @param uiType The type of UI to get the table for, one of "cmd", "dropdown", "dialog"
|
||||
-- @param uiName The name of the library/addon querying for the table, e.g. "MyLib-1.0"
|
||||
function AceConfigRegistry:GetOptionsTable(appName, uiType, uiName)
|
||||
local f = AceConfigRegistry.tables[appName]
|
||||
if not f then
|
||||
return nil
|
||||
end
|
||||
|
||||
if uiType then
|
||||
return f(uiType,uiName,1) -- get the table for us
|
||||
else
|
||||
return f -- return the function
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,4 @@
|
||||
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
|
||||
..\FrameXML\UI.xsd">
|
||||
<Script file="AceConfigRegistry-3.0.lua"/>
|
||||
</Ui>
|
||||
@@ -0,0 +1,205 @@
|
||||
local ACECORE_MAJOR, ACECORE_MINOR = "AceCore-3.0", 1
|
||||
local AceCore, oldminor = LibStub:NewLibrary(ACECORE_MAJOR, ACECORE_MINOR)
|
||||
|
||||
if not AceCore then return end -- No upgrade needed
|
||||
|
||||
AceCore._G = AceCore._G or getfenv()
|
||||
local _G = AceCore._G
|
||||
local strsub, strgsub, strfind = string.sub, string.gsub, string.find
|
||||
local tremove, tconcat = table.remove, table.concat
|
||||
local tgetn, tsetn = table.getn, table.setn
|
||||
|
||||
local new, del
|
||||
do
|
||||
local list = setmetatable({}, {__mode = "k"})
|
||||
function new()
|
||||
local t = next(list)
|
||||
if not t then
|
||||
return {}
|
||||
end
|
||||
list[t] = nil
|
||||
return t
|
||||
end
|
||||
|
||||
function del(t)
|
||||
setmetatable(t, nil)
|
||||
for k in pairs(t) do
|
||||
t[k] = nil
|
||||
end
|
||||
tsetn(t,0)
|
||||
list[t] = true
|
||||
end
|
||||
|
||||
-- debug
|
||||
function AceCore.listcount()
|
||||
local count = 0
|
||||
for k in list do
|
||||
count = count + 1
|
||||
end
|
||||
return count
|
||||
end
|
||||
end -- AceCore.new, AceCore.del
|
||||
AceCore.new, AceCore.del = new, del
|
||||
|
||||
local function errorhandler(err)
|
||||
return geterrorhandler()(err)
|
||||
end
|
||||
AceCore.errorhandler = errorhandler
|
||||
|
||||
local function CreateSafeDispatcher(argCount)
|
||||
local code = [[
|
||||
local errorhandler = LibStub("AceCore-3.0").errorhandler
|
||||
local method, UP_ARGS
|
||||
local function call()
|
||||
local func, ARGS = method, UP_ARGS
|
||||
method, UP_ARGS = nil, NILS
|
||||
return func(ARGS)
|
||||
end
|
||||
return function(func, ARGS)
|
||||
method, UP_ARGS = func, ARGS
|
||||
return xpcall(call, errorhandler)
|
||||
end
|
||||
]]
|
||||
local c = 4*argCount-1
|
||||
local s = "b01,b02,b03,b04,b05,b06,b07,b08,b09,b10,b11,b12,b13,b14,b15,b16,b17,b18,b19,b20"
|
||||
code = strgsub(code, "UP_ARGS", string.sub(s,1,c))
|
||||
s = "a01,a02,a03,a04,a05,a06,a07,a08,a09,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20"
|
||||
code = strgsub(code, "ARGS", string.sub(s,1,c))
|
||||
s = "nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil"
|
||||
code = strgsub(code, "NILS", string.sub(s,1,c))
|
||||
return assert(loadstring(code, "safecall SafeDispatcher["..tostring(argCount).."]"))()
|
||||
end
|
||||
|
||||
local SafeDispatchers = setmetatable({}, {__index=function(self, argCount)
|
||||
local dispatcher
|
||||
if not tonumber(argCount) then dbg(debugstack()) end
|
||||
if argCount > 0 then
|
||||
dispatcher = CreateSafeDispatcher(argCount)
|
||||
else
|
||||
dispatcher = function(func) return xpcall(func,errorhandler) end
|
||||
end
|
||||
rawset(self, argCount, dispatcher)
|
||||
return dispatcher
|
||||
end})
|
||||
|
||||
local function safecall(func,argc,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
-- we check to see if the func is passed is actually a function here and don't error when it isn't
|
||||
-- this safecall is used for optional functions like OnInitialize OnEnable etc. When they are not
|
||||
-- present execution should continue without hinderance
|
||||
if type(func) == "function" then
|
||||
return SafeDispatchers[argc](func,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
|
||||
end
|
||||
end
|
||||
AceCore.safecall = safecall
|
||||
|
||||
local function CreateDispatcher(argCount)
|
||||
local code = [[
|
||||
return function(func,ARGS)
|
||||
return func(ARGS)
|
||||
end
|
||||
]]
|
||||
local s = "a01,a02,a03,a04,a05,a06,a07,a08,a09,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20"
|
||||
code = strgsub(code, "ARGS", string.sub(s,1,4*argCount-1))
|
||||
return assert(loadstring(code, "call Dispatcher["..tostring(argCount).."]"))()
|
||||
end
|
||||
|
||||
AceCore.Dispatchers = setmetatable({}, {__index=function(self, argCount)
|
||||
local dispatcher
|
||||
if argCount > 0 then
|
||||
dispatcher = CreateDispatcher(argCount)
|
||||
else
|
||||
dispatcher = function(func) return func() end
|
||||
end
|
||||
rawset(self, argCount, dispatcher)
|
||||
return dispatcher
|
||||
end})
|
||||
|
||||
-- some string functions
|
||||
-- vanilla available string operations:
|
||||
-- sub, gfind, rep, gsub, char, dump, find, upper, len, format, byte, lower
|
||||
-- we will just replace every string.match with string.find in the code
|
||||
function AceCore.strtrim(s)
|
||||
return strgsub(s, "^%s*(.-)%s*$", "%1")
|
||||
end
|
||||
|
||||
local function strsplit(delim, s, n)
|
||||
if n and n < 2 then return s end
|
||||
beg = beg or 1
|
||||
local i,j = string.find(s,delim,beg)
|
||||
if not i then
|
||||
return s, nil
|
||||
end
|
||||
return string.sub(s,1,j-1), strsplit(delim, string.sub(s,j+1), n and n-1 or nil)
|
||||
end
|
||||
AceCore.strsplit = strsplit
|
||||
|
||||
-- Ace3v: fonctions copied from AceHook-2.1
|
||||
local protFuncs = {
|
||||
CameraOrSelectOrMoveStart = true, CameraOrSelectOrMoveStop = true,
|
||||
TurnOrActionStart = true, TurnOrActionStop = true,
|
||||
PitchUpStart = true, PitchUpStop = true,
|
||||
PitchDownStart = true, PitchDownStop = true,
|
||||
MoveBackwardStart = true, MoveBackwardStop = true,
|
||||
MoveForwardStart = true, MoveForwardStop = true,
|
||||
Jump = true, StrafeLeftStart = true,
|
||||
StrafeLeftStop = true, StrafeRightStart = true,
|
||||
StrafeRightStop = true, ToggleMouseMove = true,
|
||||
ToggleRun = true, TurnLeftStart = true,
|
||||
TurnLeftStop = true, TurnRightStart = true,
|
||||
TurnRightStop = true,
|
||||
}
|
||||
|
||||
local function issecurevariable(x)
|
||||
return protFuncs[x] and 1 or nil
|
||||
end
|
||||
AceCore.issecurevariable = issecurevariable
|
||||
|
||||
local function hooksecurefunc(arg1, arg2, arg3)
|
||||
if type(arg1) == "string" then
|
||||
arg1, arg2, arg3 = _G, arg1, arg2
|
||||
end
|
||||
local orig = arg1[arg2]
|
||||
if type(orig) ~= "function" then
|
||||
error("The function "..arg2.." does not exist", 2)
|
||||
end
|
||||
arg1[arg2] = function(...)
|
||||
local tmp = {orig(unpack(arg))}
|
||||
arg3(unpack(arg))
|
||||
return unpack(tmp)
|
||||
end
|
||||
end
|
||||
AceCore.hooksecurefunc = hooksecurefunc
|
||||
|
||||
-- pickfirstset() - picks the first non-nil value and returns it
|
||||
local function pickfirstset(argc,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
|
||||
if (argc <= 1) or (a1 ~= nil) then
|
||||
return a1
|
||||
else
|
||||
return pickfirstset(argc-1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
|
||||
end
|
||||
end
|
||||
AceCore.pickfirstset = pickfirstset
|
||||
|
||||
local function countargs(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
|
||||
if (a1 == nil) then return 0 end
|
||||
return 1 + countargs(a2,a3,a4,a5,a6,a7,a8,a9,a10)
|
||||
end
|
||||
AceCore.countargs = countargs
|
||||
|
||||
-- wipe preserves metatable
|
||||
function AceCore.wipe(t)
|
||||
for k,v in pairs(t) do t[k] = nil end
|
||||
tsetn(t,0)
|
||||
return t
|
||||
end
|
||||
|
||||
function AceCore.truncate(t,e)
|
||||
e = e or tgetn(t)
|
||||
for i=1,e do
|
||||
if t[i] == nil then
|
||||
tsetn(t,i-1)
|
||||
return
|
||||
end
|
||||
end
|
||||
tsetn(t,e)
|
||||
end
|
||||
@@ -0,0 +1,4 @@
|
||||
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
|
||||
..\FrameXML\UI.xsd">
|
||||
<Script file="AceCore-3.0.lua"/>
|
||||
</Ui>
|
||||
@@ -0,0 +1,809 @@
|
||||
--- **AceGUI-3.0** provides access to numerous widgets which can be used to create GUIs.
|
||||
-- AceGUI is used by AceConfigDialog to create the option GUIs, but you can use it by itself
|
||||
-- to create any custom GUI. There are more extensive examples in the test suite in the Ace3
|
||||
-- stand-alone distribution.
|
||||
--
|
||||
-- **Note**: When using AceGUI-3.0 directly, please do not modify the frames of the widgets directly,
|
||||
-- as any "unknown" change to the widgets will cause addons that get your widget out of the widget pool
|
||||
-- to misbehave. If you think some part of a widget should be modifiable, please open a ticket, and we"ll
|
||||
-- implement a proper API to modify it.
|
||||
-- @usage
|
||||
-- local AceGUI = LibStub("AceGUI-3.0")
|
||||
-- -- Create a container frame
|
||||
-- local f = AceGUI:Create("Frame")
|
||||
-- f:SetCallback("OnClose",function(widget) AceGUI:Release(widget) end)
|
||||
-- f:SetTitle("AceGUI-3.0 Example")
|
||||
-- f:SetStatusText("Status Bar")
|
||||
-- f:SetLayout("Flow")
|
||||
-- -- Create a button
|
||||
-- local btn = AceGUI:Create("Button")
|
||||
-- btn:SetWidth(170)
|
||||
-- btn:SetText("Button !")
|
||||
-- btn:SetCallback("OnClick", function() print("Click!") end)
|
||||
-- -- Add the button to the container
|
||||
-- f:AddChild(btn)
|
||||
-- @class file
|
||||
-- @name AceGUI-3.0
|
||||
-- @release $Id: AceGUI-3.0.lua 1102 2013-10-25 14:15:23Z nevcairiel $
|
||||
local ACEGUI_MAJOR, ACEGUI_MINOR = "AceGUI-3.0", 34
|
||||
local AceGUI, oldminor = LibStub:NewLibrary(ACEGUI_MAJOR, ACEGUI_MINOR)
|
||||
|
||||
if not AceGUI then return end -- No upgrade needed
|
||||
|
||||
local AceCore = LibStub("AceCore-3.0")
|
||||
local hooksecurefunc = AceCore.hooksecurefunc
|
||||
local safecall = AceCore.safecall
|
||||
|
||||
-- Lua APIs
|
||||
local tconcat, tremove, tinsert, tgetn, tsetn = table.concat, table.remove, table.insert, table.getn, table.setn
|
||||
local pairs, next, type = pairs, next, type
|
||||
local error, assert, loadstring = error, assert, loadstring
|
||||
local setmetatable, rawget, rawset = setmetatable, rawget, rawset
|
||||
local math_max = math.max
|
||||
local strupper, strfmt = string.upper, string.format
|
||||
|
||||
-- WoW APIs
|
||||
local UIParent = UIParent
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: geterrorhandler, LibStub
|
||||
|
||||
--local con = LibStub("AceConsole-3.0",true)
|
||||
|
||||
AceGUI.WidgetRegistry = AceGUI.WidgetRegistry or {}
|
||||
AceGUI.LayoutRegistry = AceGUI.LayoutRegistry or {}
|
||||
AceGUI.WidgetBase = AceGUI.WidgetBase or {}
|
||||
AceGUI.WidgetContainerBase = AceGUI.WidgetContainerBase or {}
|
||||
AceGUI.WidgetVersions = AceGUI.WidgetVersions or {}
|
||||
AceGUI.HookedFunctions = AceGUI.HookedFunctions or {}
|
||||
|
||||
-- local upvalues
|
||||
local WidgetRegistry = AceGUI.WidgetRegistry
|
||||
local LayoutRegistry = AceGUI.LayoutRegistry
|
||||
local WidgetVersions = AceGUI.WidgetVersions
|
||||
local HookedFunctions = AceGUI.HookedFunctions
|
||||
|
||||
-- Recycling functions
|
||||
local newWidget, delWidget
|
||||
do
|
||||
AceGUI.objPools = AceGUI.objPools or {}
|
||||
local objPools = AceGUI.objPools
|
||||
--Returns a new instance, if none are available either returns a new table or calls the given contructor
|
||||
function newWidget(type)
|
||||
if not WidgetRegistry[type] then
|
||||
error("Attempt to instantiate unknown widget type", 2)
|
||||
end
|
||||
|
||||
if not objPools[type] then
|
||||
objPools[type] = {}
|
||||
end
|
||||
|
||||
local newObj = next(objPools[type])
|
||||
if not newObj then
|
||||
newObj = WidgetRegistry[type]()
|
||||
newObj.AceGUIWidgetVersion = WidgetVersions[type]
|
||||
else
|
||||
objPools[type][newObj] = nil
|
||||
-- if the widget is older then the latest, don't even try to reuse it
|
||||
-- just forget about it, and grab a new one.
|
||||
if not newObj.AceGUIWidgetVersion or newObj.AceGUIWidgetVersion < WidgetVersions[type] then
|
||||
return newWidget(type)
|
||||
end
|
||||
end
|
||||
return newObj
|
||||
end
|
||||
-- Releases an instance to the Pool
|
||||
function delWidget(obj,type)
|
||||
if not objPools[type] then
|
||||
objPools[type] = {}
|
||||
end
|
||||
if objPools[type][obj] then
|
||||
error("Attempt to Release Widget that is already released", 2)
|
||||
end
|
||||
objPools[type][obj] = true
|
||||
end
|
||||
end
|
||||
|
||||
-- Ace3v: when a container contains many children, we can only use the variable arguments
|
||||
local function _fixlevels(parent, ...)
|
||||
local lv = parent:GetFrameLevel() + 1
|
||||
for i = 1, tgetn(arg) do
|
||||
local child = arg[i]
|
||||
child:SetFrameLevel(lv)
|
||||
_fixlevels(child, child:GetChildren())
|
||||
end
|
||||
end
|
||||
|
||||
local function fixlevels(parent)
|
||||
return _fixlevels(parent, parent:GetChildren())
|
||||
end
|
||||
AceGUI.fixlevels = fixlevels
|
||||
|
||||
-- Ace3v: attention! this function is recursive
|
||||
local function _fixstrata(strata, parent, ...)
|
||||
parent:SetFrameStrata(strata)
|
||||
for i = 1, tgetn(arg) do
|
||||
local child = arg[i]
|
||||
_fixstrata(strata, child, child:GetChildren())
|
||||
end
|
||||
end
|
||||
|
||||
local function fixstrata(strata, parent)
|
||||
return _fixstrata(strata, parent, parent:GetChildren())
|
||||
end
|
||||
AceGUI.fixstrata = fixstrata
|
||||
|
||||
|
||||
-------------------
|
||||
-- API Functions --
|
||||
-------------------
|
||||
|
||||
-- Gets a widget Object
|
||||
|
||||
--- Create a new Widget of the given type.
|
||||
-- This function will instantiate a new widget (or use one from the widget pool), and call the
|
||||
-- OnAcquire function on it, before returning.
|
||||
-- @param type The type of the widget.
|
||||
-- @return The newly created widget.
|
||||
function AceGUI:Create(type)
|
||||
if WidgetRegistry[type] then
|
||||
local widget = newWidget(type)
|
||||
|
||||
if widget.OnAcquire then
|
||||
widget:OnAcquire()
|
||||
else
|
||||
error(strfmt("Widget type %s doesn't supply an OnAcquire Function", type))
|
||||
end
|
||||
|
||||
-- Set the default Layout ("List")
|
||||
safecall(widget.SetLayout, 2, widget, "List")
|
||||
safecall(widget.ResumeLayout, 1, widget)
|
||||
return widget
|
||||
end
|
||||
end
|
||||
|
||||
--- Releases a widget Object.
|
||||
-- This function calls OnRelease on the widget and places it back in the widget pool.
|
||||
-- Any data on the widget is being erased, and the widget will be hidden.\\
|
||||
-- If this widget is a Container-Widget, all of its Child-Widgets will be releases as well.
|
||||
-- @param widget The widget to release
|
||||
function AceGUI:Release(widget)
|
||||
safecall(widget.PauseLayout, 1, widget)
|
||||
widget:Fire("OnRelease")
|
||||
safecall(widget.ReleaseChildren, 1, widget)
|
||||
|
||||
if widget.OnRelease then
|
||||
widget:OnRelease()
|
||||
-- else
|
||||
-- error(strfmt("Widget type %s doesn't supply an OnRelease Function", widget.type))
|
||||
end
|
||||
for k in pairs(widget.userdata) do
|
||||
widget.userdata[k] = nil
|
||||
end
|
||||
for k in pairs(widget.events) do
|
||||
widget.events[k] = nil
|
||||
end
|
||||
widget.width = nil
|
||||
widget.relWidth = nil
|
||||
widget.height = nil
|
||||
widget.relHeight = nil
|
||||
widget.noAutoHeight = nil
|
||||
widget.frame:ClearAllPoints()
|
||||
widget.frame:Hide()
|
||||
widget.frame:SetParent(UIParent)
|
||||
widget.frame.width = nil
|
||||
widget.frame.height = nil
|
||||
if widget.content then
|
||||
widget.content.width = nil
|
||||
widget.content.height = nil
|
||||
end
|
||||
delWidget(widget, widget.type)
|
||||
end
|
||||
|
||||
-----------
|
||||
-- Focus --
|
||||
-----------
|
||||
|
||||
|
||||
--- Called when a widget has taken focus.
|
||||
-- e.g. Dropdowns opening, Editboxes gaining kb focus
|
||||
-- @param widget The widget that should be focused
|
||||
function AceGUI:SetFocus(widget)
|
||||
if self.FocusedWidget and self.FocusedWidget ~= widget then
|
||||
safecall(self.FocusedWidget.ClearFocus, 1, self.FocusedWidget)
|
||||
end
|
||||
self.FocusedWidget = widget
|
||||
end
|
||||
|
||||
|
||||
--- Called when something has happened that could cause widgets with focus to drop it
|
||||
-- e.g. titlebar of a frame being clicked
|
||||
function AceGUI:ClearFocus()
|
||||
if self.FocusedWidget then
|
||||
safecall(self.FocusedWidget.ClearFocus, 1, self.FocusedWidget)
|
||||
self.FocusedWidget = nil
|
||||
end
|
||||
end
|
||||
|
||||
-------------
|
||||
-- Widgets --
|
||||
-------------
|
||||
--[[
|
||||
Widgets must provide the following functions
|
||||
OnAcquire() - Called when the object is acquired, should set everything to a default hidden state
|
||||
|
||||
And the following members
|
||||
frame - the frame or derivitive object that will be treated as the widget for size and anchoring purposes
|
||||
type - the type of the object, same as the name given to :RegisterWidget()
|
||||
|
||||
Widgets contain a table called userdata, this is a safe place to store data associated with the wigdet
|
||||
It will be cleared automatically when a widget is released
|
||||
Placing values directly into a widget object should be avoided
|
||||
|
||||
If the Widget can act as a container for other Widgets the following
|
||||
content - frame or derivitive that children will be anchored to
|
||||
|
||||
The Widget can supply the following Optional Members
|
||||
:OnRelease() - Called when the object is Released, should remove any additional anchors and clear any data
|
||||
:OnWidthSet(width) - Called when the width of the widget is changed
|
||||
:OnHeightSet(height) - Called when the height of the widget is changed
|
||||
Widgets should not use the OnSizeChanged events of thier frame or content members, use these methods instead
|
||||
AceGUI already sets a handler to the event
|
||||
:LayoutFinished(width, height) - called after a layout has finished, the width and height will be the width and height of the
|
||||
area used for controls. These can be nil if the layout used the existing size to layout the controls.
|
||||
|
||||
]]
|
||||
|
||||
--------------------------
|
||||
-- Widget Base Template --
|
||||
--------------------------
|
||||
do
|
||||
local WidgetBase = AceGUI.WidgetBase
|
||||
|
||||
WidgetBase.SetParent = function(self, parent)
|
||||
local frame = self.frame
|
||||
frame:SetParent(nil)
|
||||
frame:SetParent(parent.content)
|
||||
self.parent = parent
|
||||
fixlevels(frame)
|
||||
end
|
||||
|
||||
WidgetBase.SetCallback = function(self, name, func)
|
||||
if type(func) == "function" then
|
||||
self.events[name] = func
|
||||
end
|
||||
end
|
||||
|
||||
WidgetBase.Fire = function(self,name,argc,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
|
||||
argc = argc or 0
|
||||
local func = self.events[name]
|
||||
if func then
|
||||
local success, ret = safecall(func,argc+3,self,name,argc,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
|
||||
if success then
|
||||
return ret
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
WidgetBase.SetWidth = function(self, width)
|
||||
self.frame:SetWidth(width)
|
||||
self.frame.width = width
|
||||
if self.OnWidthSet then
|
||||
self:OnWidthSet(width)
|
||||
end
|
||||
end
|
||||
|
||||
WidgetBase.SetRelativeWidth = function(self, width)
|
||||
if width <= 0 or width > 1 then
|
||||
error(":SetRelativeWidth(width): Invalid relative width.", 2)
|
||||
end
|
||||
self.relWidth = width
|
||||
self.width = "relative"
|
||||
end
|
||||
|
||||
WidgetBase.SetHeight = function(self, height)
|
||||
self.frame:SetHeight(height)
|
||||
self.frame.height = height
|
||||
if self.OnHeightSet then
|
||||
self:OnHeightSet(height)
|
||||
end
|
||||
end
|
||||
|
||||
--[[ WidgetBase.SetRelativeHeight = function(self, height)
|
||||
if height <= 0 or height > 1 then
|
||||
error(":SetRelativeHeight(height): Invalid relative height.", 2)
|
||||
end
|
||||
self.relHeight = height
|
||||
self.height = "relative"
|
||||
end ]]
|
||||
|
||||
WidgetBase.IsVisible = function(self)
|
||||
return self.frame:IsVisible()
|
||||
end
|
||||
|
||||
WidgetBase.IsShown= function(self)
|
||||
return self.frame:IsShown()
|
||||
end
|
||||
|
||||
WidgetBase.Release = function(self)
|
||||
AceGUI:Release(self)
|
||||
end
|
||||
|
||||
WidgetBase.SetPoint = function(self,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
|
||||
return self.frame:SetPoint(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
|
||||
end
|
||||
|
||||
WidgetBase.ClearAllPoints = function(self)
|
||||
return self.frame:ClearAllPoints()
|
||||
end
|
||||
|
||||
WidgetBase.GetNumPoints = function(self)
|
||||
return self.frame:GetNumPoints()
|
||||
end
|
||||
|
||||
WidgetBase.GetPoint = function(self,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
|
||||
return self.frame:GetPoint(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
|
||||
end
|
||||
|
||||
WidgetBase.GetUserDataTable = function(self)
|
||||
return self.userdata
|
||||
end
|
||||
|
||||
WidgetBase.SetUserData = function(self, key, value)
|
||||
self.userdata[key] = value
|
||||
end
|
||||
|
||||
WidgetBase.GetUserData = function(self, key)
|
||||
return self.userdata[key]
|
||||
end
|
||||
|
||||
WidgetBase.IsFullHeight = function(self)
|
||||
return self.height == "fill"
|
||||
end
|
||||
|
||||
WidgetBase.SetFullHeight = function(self, isFull)
|
||||
if isFull then
|
||||
self.height = "fill"
|
||||
else
|
||||
self.height = nil
|
||||
end
|
||||
end
|
||||
|
||||
WidgetBase.IsFullWidth = function(self)
|
||||
return self.width == "fill"
|
||||
end
|
||||
|
||||
WidgetBase.SetFullWidth = function(self, isFull)
|
||||
if isFull then
|
||||
self.width = "fill"
|
||||
else
|
||||
self.width = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- local function LayoutOnUpdate(this)
|
||||
-- this:SetScript("OnUpdate",nil)
|
||||
-- this.obj:PerformLayout()
|
||||
-- end
|
||||
|
||||
local WidgetContainerBase = AceGUI.WidgetContainerBase
|
||||
|
||||
WidgetContainerBase.PauseLayout = function(self)
|
||||
self.LayoutPaused = true
|
||||
end
|
||||
|
||||
WidgetContainerBase.ResumeLayout = function(self)
|
||||
self.LayoutPaused = nil
|
||||
end
|
||||
|
||||
WidgetContainerBase.PerformLayout = function(self)
|
||||
if self.LayoutPaused then
|
||||
return
|
||||
end
|
||||
safecall(self.LayoutFunc, 2, self.content, self.children)
|
||||
end
|
||||
|
||||
--call this function to layout, makes sure layed out objects get a frame to get sizes etc
|
||||
WidgetContainerBase.DoLayout = function(self)
|
||||
self:PerformLayout()
|
||||
-- if not self.parent then
|
||||
-- self.frame:SetScript("OnUpdate", LayoutOnUpdate)
|
||||
-- end
|
||||
end
|
||||
|
||||
WidgetContainerBase.AddChild = function(self, child, beforeWidget)
|
||||
if beforeWidget then
|
||||
local siblingIndex = 1
|
||||
for _, widget in pairs(self.children) do
|
||||
if widget == beforeWidget then
|
||||
break
|
||||
end
|
||||
siblingIndex = siblingIndex + 1
|
||||
end
|
||||
tinsert(self.children, siblingIndex, child)
|
||||
else
|
||||
tinsert(self.children, child)
|
||||
end
|
||||
child:SetParent(self)
|
||||
child.frame:Show()
|
||||
self:DoLayout()
|
||||
end
|
||||
|
||||
do
|
||||
local args = {nil,nil,nil,nil,nil,nil,nil,nil,nil,nil}
|
||||
WidgetContainerBase.AddChildren = function(self,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
|
||||
args[1] = a1
|
||||
args[2] = a2
|
||||
args[3] = a3
|
||||
args[4] = a4
|
||||
args[5] = a5
|
||||
args[6] = a6
|
||||
args[7] = a7
|
||||
args[8] = a8
|
||||
args[9] = a9
|
||||
args[10] = a10
|
||||
for i = 1,10 do
|
||||
local child = args[i]
|
||||
arg[i] = nil
|
||||
|
||||
if not child then break end
|
||||
tinsert(self.children, child)
|
||||
child:SetParent(self)
|
||||
child.frame:Show()
|
||||
end
|
||||
self:DoLayout()
|
||||
end
|
||||
end -- WidgetContainerBase.AddChildren
|
||||
|
||||
WidgetContainerBase.ReleaseChildren = function(self)
|
||||
local children = self.children
|
||||
for i = 1,tgetn(children) do
|
||||
AceGUI:Release(tremove(children))
|
||||
end
|
||||
end
|
||||
|
||||
WidgetContainerBase.SetParent = function(self, parent)
|
||||
WidgetBase.SetParent(self, parent)
|
||||
|
||||
local lv = self.frame:GetFrameLevel()
|
||||
self.content:SetFrameLevel(lv+1)
|
||||
local children = self.children
|
||||
for i = 1,tgetn(children) do
|
||||
local child = children[i]
|
||||
child:SetParent(self)
|
||||
end
|
||||
end
|
||||
|
||||
WidgetContainerBase.SetLayout = function(self, Layout)
|
||||
self.LayoutFunc = AceGUI:GetLayout(Layout)
|
||||
end
|
||||
|
||||
WidgetContainerBase.SetAutoAdjustHeight = function(self, adjust)
|
||||
if adjust then
|
||||
self.noAutoHeight = nil
|
||||
else
|
||||
self.noAutoHeight = true
|
||||
end
|
||||
end
|
||||
|
||||
local function FrameResize()
|
||||
local self = this.obj
|
||||
if this:GetWidth() and this:GetHeight() then
|
||||
if self.OnWidthSet then
|
||||
self:OnWidthSet(this:GetWidth())
|
||||
end
|
||||
if self.OnHeightSet then
|
||||
self:OnHeightSet(this:GetHeight())
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function ContentResize()
|
||||
if this:GetWidth() and this:GetHeight() then
|
||||
this.width = this:GetWidth()
|
||||
this.height = this:GetHeight()
|
||||
this.obj:DoLayout()
|
||||
end
|
||||
end
|
||||
|
||||
setmetatable(WidgetContainerBase, {__index=WidgetBase})
|
||||
|
||||
--One of these function should be called on each Widget Instance as part of its creation process
|
||||
|
||||
--- Register a widget-class as a container for newly created widgets.
|
||||
-- @param widget The widget class
|
||||
function AceGUI:RegisterAsContainer(widget)
|
||||
widget.children = {}
|
||||
widget.userdata = {}
|
||||
widget.events = {}
|
||||
widget.base = WidgetContainerBase
|
||||
widget.content.obj = widget
|
||||
widget.frame.obj = widget
|
||||
widget.content:SetScript("OnSizeChanged", ContentResize)
|
||||
widget.frame:SetScript("OnSizeChanged", FrameResize)
|
||||
setmetatable(widget, {__index = WidgetContainerBase})
|
||||
widget:SetLayout("List")
|
||||
return widget
|
||||
end
|
||||
|
||||
--- Register a widget-class as a widget.
|
||||
-- @param widget The widget class
|
||||
function AceGUI:RegisterAsWidget(widget)
|
||||
widget.userdata = {}
|
||||
widget.events = {}
|
||||
widget.base = WidgetBase
|
||||
widget.frame.obj = widget
|
||||
widget.frame:SetScript("OnSizeChanged", FrameResize)
|
||||
setmetatable(widget, {__index = WidgetBase})
|
||||
return widget
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
------------------
|
||||
-- Widget API --
|
||||
------------------
|
||||
|
||||
--- Registers a widget Constructor, this function returns a new instance of the Widget
|
||||
-- @param Name The name of the widget
|
||||
-- @param Constructor The widget constructor function
|
||||
-- @param Version The version of the widget
|
||||
function AceGUI:RegisterWidgetType(Name, Constructor, Version)
|
||||
assert(type(Constructor) == "function")
|
||||
assert(type(Version) == "number")
|
||||
|
||||
local oldVersion = WidgetVersions[Name]
|
||||
if oldVersion and oldVersion >= Version then return end
|
||||
|
||||
WidgetVersions[Name] = Version
|
||||
WidgetRegistry[Name] = Constructor
|
||||
end
|
||||
|
||||
--- Registers a Layout Function
|
||||
-- @param Name The name of the layout
|
||||
-- @param LayoutFunc Reference to the layout function
|
||||
function AceGUI:RegisterLayout(Name, LayoutFunc)
|
||||
assert(type(LayoutFunc) == "function")
|
||||
if type(Name) == "string" then
|
||||
Name = string.upper(Name)
|
||||
end
|
||||
LayoutRegistry[Name] = LayoutFunc
|
||||
end
|
||||
|
||||
--- Get a Layout Function from the registry
|
||||
-- @param Name The name of the layout
|
||||
function AceGUI:GetLayout(Name)
|
||||
if type(Name) == "string" then
|
||||
Name = strupper(Name)
|
||||
end
|
||||
return LayoutRegistry[Name]
|
||||
end
|
||||
|
||||
AceGUI.counts = AceGUI.counts or {}
|
||||
|
||||
--- A type-based counter to count the number of widgets created.
|
||||
-- This is used by widgets that require a named frame, e.g. when a Blizzard
|
||||
-- Template requires it.
|
||||
-- @param type The widget type
|
||||
function AceGUI:GetNextWidgetNum(type)
|
||||
if not self.counts[type] then
|
||||
self.counts[type] = 0
|
||||
end
|
||||
self.counts[type] = self.counts[type] + 1
|
||||
return self.counts[type]
|
||||
end
|
||||
|
||||
--- Return the number of created widgets for this type.
|
||||
-- In contrast to GetNextWidgetNum, the number is not incremented.
|
||||
-- @param type The widget type
|
||||
function AceGUI:GetWidgetCount(type)
|
||||
return self.counts[type] or 0
|
||||
end
|
||||
|
||||
--- Return the version of the currently registered widget type.
|
||||
-- @param type The widget type
|
||||
function AceGUI:GetWidgetVersion(type)
|
||||
return WidgetVersions[type]
|
||||
end
|
||||
|
||||
-------------
|
||||
-- Layouts --
|
||||
-------------
|
||||
|
||||
--[[
|
||||
A Layout is a func that takes 2 parameters
|
||||
content - the frame that widgets will be placed inside
|
||||
children - a table containing the widgets to layout
|
||||
]]
|
||||
|
||||
-- Very simple Layout, Children are stacked on top of each other down the left side
|
||||
AceGUI:RegisterLayout("List",
|
||||
function(content, children)
|
||||
local height = 0
|
||||
local width = content.width or content:GetWidth() or 0
|
||||
for i = 1, tgetn(children) do
|
||||
local child = children[i]
|
||||
|
||||
local frame = child.frame
|
||||
frame:ClearAllPoints()
|
||||
frame:Show()
|
||||
if i == 1 then
|
||||
frame:SetPoint("TOPLEFT", content)
|
||||
else
|
||||
frame:SetPoint("TOPLEFT", children[i-1].frame, "BOTTOMLEFT")
|
||||
end
|
||||
|
||||
if child.width == "fill" then
|
||||
child:SetWidth(width)
|
||||
frame:SetPoint("RIGHT", content)
|
||||
|
||||
if child.DoLayout then
|
||||
child:DoLayout()
|
||||
end
|
||||
elseif child.width == "relative" then
|
||||
child:SetWidth(width * child.relWidth)
|
||||
|
||||
if child.DoLayout then
|
||||
child:DoLayout()
|
||||
end
|
||||
end
|
||||
|
||||
height = height + (frame.height or frame:GetHeight() or 0)
|
||||
end
|
||||
safecall(content.obj.LayoutFinished, 3, content.obj, nil, height)
|
||||
end)
|
||||
|
||||
-- A single control fills the whole content area
|
||||
AceGUI:RegisterLayout("Fill",
|
||||
function(content, children)
|
||||
if children[1] then
|
||||
children[1]:SetWidth(content:GetWidth() or 0)
|
||||
children[1]:SetHeight(content:GetHeight() or 0)
|
||||
children[1].frame:SetAllPoints(content)
|
||||
children[1].frame:Show()
|
||||
safecall(content.obj.LayoutFinished, 3, content.obj, nil, children[1].frame:GetHeight())
|
||||
end
|
||||
end)
|
||||
|
||||
-- Ace3v: currently only a1 used
|
||||
local layoutrecursionblock = nil
|
||||
local function safelayoutcall(object, func, a1)
|
||||
layoutrecursionblock = true
|
||||
object[func](object, a1)
|
||||
layoutrecursionblock = nil
|
||||
end
|
||||
|
||||
AceGUI:RegisterLayout("Flow",
|
||||
function(content, children)
|
||||
if layoutrecursionblock then return end
|
||||
--used height so far
|
||||
local height = 0
|
||||
--width used in the current row
|
||||
local usedwidth = 0
|
||||
--height of the current row
|
||||
local rowheight = 0
|
||||
local rowoffset = 0
|
||||
local lastrowoffset
|
||||
|
||||
local width = content.width or content:GetWidth() or 0
|
||||
|
||||
--control at the start of the row
|
||||
local rowstart
|
||||
local rowstartoffset
|
||||
local lastrowstart
|
||||
local isfullheight
|
||||
|
||||
local frameoffset
|
||||
local lastframeoffset
|
||||
local oversize
|
||||
for i = 1, tgetn(children) do
|
||||
local child = children[i]
|
||||
oversize = nil
|
||||
local frame = child.frame
|
||||
local frameheight = frame.height or frame:GetHeight() or 0
|
||||
local framewidth = frame.width or frame:GetWidth() or 0
|
||||
lastframeoffset = frameoffset
|
||||
-- HACK: Why did we set a frameoffset of (frameheight / 2) ?
|
||||
-- That was moving all widgets half the widgets size down, is that intended?
|
||||
-- Actually, it seems to be neccessary for many cases, we'll leave it in for now.
|
||||
-- If widgets seem to anchor weirdly with this, provide a valid alignoffset for them.
|
||||
-- TODO: Investigate moar!
|
||||
frameoffset = child.alignoffset or (frameheight / 2)
|
||||
|
||||
if child.width == "relative" then
|
||||
framewidth = width * child.relWidth
|
||||
end
|
||||
|
||||
frame:Show()
|
||||
frame:ClearAllPoints()
|
||||
if i == 1 then
|
||||
-- anchor the first control to the top left
|
||||
frame:SetPoint("TOPLEFT", content)
|
||||
rowheight = frameheight
|
||||
rowoffset = frameoffset
|
||||
rowstart = frame
|
||||
rowstartoffset = frameoffset
|
||||
usedwidth = framewidth
|
||||
if usedwidth > width then
|
||||
oversize = true
|
||||
end
|
||||
else
|
||||
-- if there isn't available width for the control start a new row
|
||||
-- if a control is "fill" it will be on a row of its own full width
|
||||
if usedwidth == 0 or ((framewidth) + usedwidth > width) or child.width == "fill" then
|
||||
if isfullheight then
|
||||
-- a previous row has already filled the entire height, there's nothing we can usefully do anymore
|
||||
-- (maybe error/warn about this?)
|
||||
break
|
||||
end
|
||||
--anchor the previous row, we will now know its height and offset
|
||||
rowstart:SetPoint("TOPLEFT", content, "TOPLEFT", 0, -(height + (rowoffset - rowstartoffset) + 3))
|
||||
height = height + rowheight + 3
|
||||
--save this as the rowstart so we can anchor it after the row is complete and we have the max height and offset of controls in it
|
||||
rowstart = frame
|
||||
rowstartoffset = frameoffset
|
||||
rowheight = frameheight
|
||||
rowoffset = frameoffset
|
||||
usedwidth = framewidth
|
||||
if usedwidth > width then
|
||||
oversize = true
|
||||
end
|
||||
-- put the control on the current row, adding it to the width and checking if the height needs to be increased
|
||||
else
|
||||
--handles cases where the new height is higher than either control because of the offsets
|
||||
--math.max(rowheight-rowoffset+frameoffset, frameheight-frameoffset+rowoffset)
|
||||
|
||||
--offset is always the larger of the two offsets
|
||||
rowoffset = math_max(rowoffset, frameoffset)
|
||||
rowheight = math_max(rowheight, rowoffset + (frameheight / 2))
|
||||
|
||||
frame:SetPoint("TOPLEFT", children[i-1].frame, "TOPRIGHT", 0, frameoffset - lastframeoffset)
|
||||
usedwidth = framewidth + usedwidth
|
||||
end
|
||||
end
|
||||
|
||||
if child.width == "fill" then
|
||||
safelayoutcall(child, "SetWidth", width)
|
||||
frame:SetPoint("RIGHT", content)
|
||||
|
||||
usedwidth = 0
|
||||
rowstart = frame
|
||||
rowstartoffset = frameoffset
|
||||
|
||||
if child.DoLayout then
|
||||
child:DoLayout()
|
||||
end
|
||||
rowheight = frame.height or frame:GetHeight() or 0
|
||||
rowoffset = child.alignoffset or (rowheight / 2)
|
||||
rowstartoffset = rowoffset
|
||||
elseif child.width == "relative" then
|
||||
safelayoutcall(child, "SetWidth", width * child.relWidth)
|
||||
|
||||
if child.DoLayout then
|
||||
child:DoLayout()
|
||||
end
|
||||
elseif oversize then
|
||||
if width > 1 then
|
||||
frame:SetPoint("RIGHT", content)
|
||||
end
|
||||
end
|
||||
|
||||
if child.height == "fill" then
|
||||
frame:SetPoint("BOTTOM", content)
|
||||
isfullheight = true
|
||||
end
|
||||
end
|
||||
|
||||
--anchor the last row, if its full height needs a special case since its height has just been changed by the anchor
|
||||
if isfullheight then
|
||||
rowstart:SetPoint("TOPLEFT", content, "TOPLEFT", 0, -height)
|
||||
elseif rowstart then
|
||||
rowstart:SetPoint("TOPLEFT", content, "TOPLEFT", 0, -(height + (rowoffset - rowstartoffset) + 3))
|
||||
end
|
||||
|
||||
height = height + rowheight + 3
|
||||
safecall(content.obj.LayoutFinished, 3, content.obj, nil, height)
|
||||
end)
|
||||
@@ -0,0 +1,4 @@
|
||||
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
|
||||
..\FrameXML\UI.xsd">
|
||||
<Script file="AceGUI-3.0.lua"/>
|
||||
</Ui>
|
||||
@@ -0,0 +1,138 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
BlizOptionsGroup Container
|
||||
Simple container widget for the integration of AceGUI into the Blizzard Interface Options
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "BlizOptionsGroup", 21
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
-- Lua APIs
|
||||
local pairs = pairs
|
||||
|
||||
-- WoW APIs
|
||||
local CreateFrame = CreateFrame
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Scripts
|
||||
-------------------------------------------------------------------------------]]
|
||||
|
||||
local function OnShow(frame)
|
||||
frame.obj:Fire("OnShow")
|
||||
end
|
||||
|
||||
local function OnHide(frame)
|
||||
frame.obj:Fire("OnHide")
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Support functions
|
||||
-------------------------------------------------------------------------------]]
|
||||
|
||||
local function okay(frame)
|
||||
frame.obj:Fire("okay")
|
||||
end
|
||||
|
||||
local function cancel(frame)
|
||||
frame.obj:Fire("cancel")
|
||||
end
|
||||
|
||||
local function default(frame)
|
||||
frame.obj:Fire("default")
|
||||
end
|
||||
|
||||
local function refresh(frame)
|
||||
frame.obj:Fire("refresh")
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
self:SetName()
|
||||
self:SetTitle()
|
||||
end,
|
||||
|
||||
-- ["OnRelease"] = nil,
|
||||
|
||||
["OnWidthSet"] = function(self, width)
|
||||
local content = self.content
|
||||
local contentwidth = width - 63
|
||||
if contentwidth < 0 then
|
||||
contentwidth = 0
|
||||
end
|
||||
content:SetWidth(contentwidth)
|
||||
content.width = contentwidth
|
||||
end,
|
||||
|
||||
["OnHeightSet"] = function(self, height)
|
||||
local content = self.content
|
||||
local contentheight = height - 26
|
||||
if contentheight < 0 then
|
||||
contentheight = 0
|
||||
end
|
||||
content:SetHeight(contentheight)
|
||||
content.height = contentheight
|
||||
end,
|
||||
|
||||
["SetName"] = function(self, name, parent)
|
||||
self.frame.name = name
|
||||
self.frame.parent = parent
|
||||
end,
|
||||
|
||||
["SetTitle"] = function(self, title)
|
||||
local content = self.content
|
||||
content:ClearAllPoints()
|
||||
if not title or title == "" then
|
||||
content:SetPoint("TOPLEFT", 10, -10)
|
||||
self.label:SetText("")
|
||||
else
|
||||
content:SetPoint("TOPLEFT", 10, -40)
|
||||
self.label:SetText(title)
|
||||
end
|
||||
content:SetPoint("BOTTOMRIGHT", -10, 10)
|
||||
end
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Constructor()
|
||||
local frame = CreateFrame("Frame")
|
||||
frame:Hide()
|
||||
|
||||
-- support functions for the Blizzard Interface Options
|
||||
frame.okay = okay
|
||||
frame.cancel = cancel
|
||||
frame.default = default
|
||||
frame.refresh = refresh
|
||||
|
||||
frame:SetScript("OnHide", OnHide)
|
||||
frame:SetScript("OnShow", OnShow)
|
||||
|
||||
local label = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
|
||||
label:SetPoint("TOPLEFT", 10, -15)
|
||||
label:SetPoint("BOTTOMRIGHT", frame, "TOPRIGHT", 10, -45)
|
||||
label:SetJustifyH("LEFT")
|
||||
label:SetJustifyV("TOP")
|
||||
|
||||
--Container Support
|
||||
local content = CreateFrame("Frame", nil, frame)
|
||||
content:SetPoint("TOPLEFT", 10, -10)
|
||||
content:SetPoint("BOTTOMRIGHT", -10, 10)
|
||||
|
||||
local widget = {
|
||||
label = label,
|
||||
frame = frame,
|
||||
content = content,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
|
||||
return AceGUI:RegisterAsContainer(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
@@ -0,0 +1,157 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
DropdownGroup Container
|
||||
Container controlled by a dropdown on the top.
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "DropdownGroup", 21
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
-- Lua APIs
|
||||
local assert, pairs, type = assert, pairs, type
|
||||
|
||||
-- WoW APIs
|
||||
local CreateFrame = CreateFrame
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Scripts
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function SelectedGroup(self, event, _, value)
|
||||
local group = self.parentgroup
|
||||
local status = group.status or group.localstatus
|
||||
status.selected = value
|
||||
self.parentgroup:Fire("OnGroupSelected", 1, value)
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
self.dropdown:SetText("")
|
||||
self:SetDropdownWidth(200)
|
||||
self:SetTitle("")
|
||||
end,
|
||||
|
||||
["OnRelease"] = function(self)
|
||||
self.dropdown.list = nil
|
||||
self.status = nil
|
||||
for k in pairs(self.localstatus) do
|
||||
self.localstatus[k] = nil
|
||||
end
|
||||
end,
|
||||
|
||||
["SetTitle"] = function(self, title)
|
||||
self.titletext:SetText(title)
|
||||
self.dropdown.frame:ClearAllPoints()
|
||||
if title and title ~= "" then
|
||||
self.dropdown.frame:SetPoint("TOPRIGHT", -2, 0)
|
||||
else
|
||||
self.dropdown.frame:SetPoint("TOPLEFT", -1, 0)
|
||||
end
|
||||
end,
|
||||
|
||||
["SetGroupList"] = function(self,list,order)
|
||||
self.dropdown:SetList(list,order)
|
||||
end,
|
||||
|
||||
["SetStatusTable"] = function(self, status)
|
||||
assert(type(status) == "table")
|
||||
self.status = status
|
||||
end,
|
||||
|
||||
["SetGroup"] = function(self,group)
|
||||
self.dropdown:SetValue(group)
|
||||
local status = self.status or self.localstatus
|
||||
status.selected = group
|
||||
self:Fire("OnGroupSelected", 1, group)
|
||||
end,
|
||||
|
||||
["OnWidthSet"] = function(self, width)
|
||||
local content = self.content
|
||||
local contentwidth = width - 26
|
||||
if contentwidth < 0 then
|
||||
contentwidth = 0
|
||||
end
|
||||
content:SetWidth(contentwidth)
|
||||
content.width = contentwidth
|
||||
end,
|
||||
|
||||
["OnHeightSet"] = function(self, height)
|
||||
local content = self.content
|
||||
local contentheight = height - 63
|
||||
if contentheight < 0 then
|
||||
contentheight = 0
|
||||
end
|
||||
content:SetHeight(contentheight)
|
||||
content.height = contentheight
|
||||
end,
|
||||
|
||||
["LayoutFinished"] = function(self, width, height)
|
||||
self:SetHeight((height or 0) + 63)
|
||||
end,
|
||||
|
||||
["SetDropdownWidth"] = function(self, width)
|
||||
self.dropdown:SetWidth(width)
|
||||
end
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local PaneBackdrop = {
|
||||
bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
|
||||
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
||||
tile = true, tileSize = 16, edgeSize = 16,
|
||||
insets = { left = 3, right = 3, top = 5, bottom = 3 }
|
||||
}
|
||||
|
||||
local function Constructor()
|
||||
local frame = CreateFrame("Frame")
|
||||
frame:SetHeight(100)
|
||||
frame:SetWidth(100)
|
||||
frame:SetFrameStrata("FULLSCREEN_DIALOG")
|
||||
|
||||
local titletext = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
||||
titletext:SetPoint("TOPLEFT", 4, -5)
|
||||
titletext:SetPoint("TOPRIGHT", -4, -5)
|
||||
titletext:SetJustifyH("LEFT")
|
||||
titletext:SetHeight(18)
|
||||
|
||||
local dropdown = AceGUI:Create("Dropdown")
|
||||
dropdown.frame:SetParent(frame)
|
||||
dropdown.frame:SetFrameLevel(dropdown.frame:GetFrameLevel() + 2)
|
||||
dropdown:SetCallback("OnValueChanged", SelectedGroup)
|
||||
dropdown.frame:SetPoint("TOPLEFT", -1, 0)
|
||||
dropdown.frame:Show()
|
||||
dropdown:SetLabel("")
|
||||
|
||||
local border = CreateFrame("Frame", nil, frame)
|
||||
border:SetPoint("TOPLEFT", 0, -26)
|
||||
border:SetPoint("BOTTOMRIGHT", 0, 3)
|
||||
border:SetBackdrop(PaneBackdrop)
|
||||
border:SetBackdropColor(0.1,0.1,0.1,0.5)
|
||||
border:SetBackdropBorderColor(0.4,0.4,0.4)
|
||||
|
||||
--Container Support
|
||||
local content = CreateFrame("Frame", nil, border)
|
||||
content:SetPoint("TOPLEFT", 10, -10)
|
||||
content:SetPoint("BOTTOMRIGHT", -10, 10)
|
||||
|
||||
local widget = {
|
||||
frame = frame,
|
||||
localstatus = {},
|
||||
titletext = titletext,
|
||||
dropdown = dropdown,
|
||||
border = border,
|
||||
content = content,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
dropdown.parentgroup = widget
|
||||
|
||||
return AceGUI:RegisterAsContainer(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
@@ -0,0 +1,303 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Frame Container
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "Frame", 24
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
local AceCore = LibStub("AceCore-3.0")
|
||||
local wipe = AceCore.wipe
|
||||
|
||||
-- Lua APIs
|
||||
local pairs, assert, type = pairs, assert, type
|
||||
|
||||
-- WoW APIs
|
||||
local PlaySound = PlaySound
|
||||
local CreateFrame, UIParent = CreateFrame, UIParent
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: CLOSE
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Scripts
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Button_OnClick()
|
||||
PlaySound("gsTitleOptionExit")
|
||||
this.obj:Hide()
|
||||
end
|
||||
|
||||
local function Frame_OnClose()
|
||||
this.obj:Fire("OnClose")
|
||||
end
|
||||
|
||||
local function Frame_OnMouseDown()
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
local function Title_OnMouseDown()
|
||||
this:GetParent():StartMoving()
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
local function MoverSizer_OnMouseUp()
|
||||
local frame = this:GetParent()
|
||||
frame:StopMovingOrSizing()
|
||||
local self = frame.obj
|
||||
local status = self.status or self.localstatus
|
||||
status.width = frame:GetWidth()
|
||||
status.height = frame:GetHeight()
|
||||
status.top = frame:GetTop()
|
||||
status.left = frame:GetLeft()
|
||||
end
|
||||
|
||||
local function SizerSE_OnMouseDown()
|
||||
this:GetParent():StartSizing("BOTTOMRIGHT")
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
local function SizerS_OnMouseDown()
|
||||
this:GetParent():StartSizing("BOTTOM")
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
local function SizerE_OnMouseDown()
|
||||
this:GetParent():StartSizing("RIGHT")
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
local function StatusBar_OnEnter()
|
||||
this.obj:Fire("OnEnterStatusBar")
|
||||
end
|
||||
|
||||
local function StatusBar_OnLeave()
|
||||
this.obj:Fire("OnLeaveStatusBar")
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
self.frame:SetParent(UIParent)
|
||||
self.frame:SetFrameStrata("FULLSCREEN_DIALOG")
|
||||
self:SetTitle()
|
||||
self:SetStatusText()
|
||||
self:ApplyStatus()
|
||||
self:Show()
|
||||
self:EnableResize(true)
|
||||
end,
|
||||
|
||||
["OnRelease"] = function(self)
|
||||
self.status = nil
|
||||
wipe(self.localstatus)
|
||||
end,
|
||||
|
||||
["OnWidthSet"] = function(self, width)
|
||||
local content = self.content
|
||||
local contentwidth = width - 34
|
||||
if contentwidth < 0 then
|
||||
contentwidth = 0
|
||||
end
|
||||
content:SetWidth(contentwidth)
|
||||
content.width = contentwidth
|
||||
end,
|
||||
|
||||
["OnHeightSet"] = function(self, height)
|
||||
local content = self.content
|
||||
local contentheight = height - 57
|
||||
if contentheight < 0 then
|
||||
contentheight = 0
|
||||
end
|
||||
content:SetHeight(contentheight)
|
||||
content.height = contentheight
|
||||
end,
|
||||
|
||||
["SetTitle"] = function(self, title)
|
||||
self.titletext:SetText(title)
|
||||
self.titlebg:SetWidth((self.titletext:GetWidth() or 0) + 10)
|
||||
end,
|
||||
|
||||
["SetStatusText"] = function(self, text)
|
||||
self.statustext:SetText(text)
|
||||
end,
|
||||
|
||||
["Hide"] = function(self)
|
||||
self.frame:Hide()
|
||||
end,
|
||||
|
||||
["Show"] = function(self)
|
||||
self.frame:Show()
|
||||
end,
|
||||
|
||||
["EnableResize"] = function(self, state)
|
||||
local func = state and "Show" or "Hide"
|
||||
self.sizer_se[func](self.sizer_se)
|
||||
self.sizer_s[func](self.sizer_s)
|
||||
self.sizer_e[func](self.sizer_e)
|
||||
end,
|
||||
|
||||
-- called to set an external table to store status in
|
||||
["SetStatusTable"] = function(self, status)
|
||||
assert(type(status) == "table")
|
||||
self.status = status
|
||||
self:ApplyStatus()
|
||||
end,
|
||||
|
||||
["ApplyStatus"] = function(self)
|
||||
local status = self.status or self.localstatus
|
||||
local frame = self.frame
|
||||
self:SetWidth(status.width or 700)
|
||||
self:SetHeight(status.height or 500)
|
||||
frame:ClearAllPoints()
|
||||
if status.top and status.left then
|
||||
frame:SetPoint("TOP", UIParent, "BOTTOM", 0, status.top)
|
||||
frame:SetPoint("LEFT", UIParent, "LEFT", status.left, 0)
|
||||
else
|
||||
frame:SetPoint("CENTER", UIParent)
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local FrameBackdrop = {
|
||||
bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background",
|
||||
edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
|
||||
tile = true, tileSize = 32, edgeSize = 32,
|
||||
insets = { left = 8, right = 8, top = 8, bottom = 8 }
|
||||
}
|
||||
|
||||
local PaneBackdrop = {
|
||||
bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
|
||||
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
||||
tile = true, tileSize = 16, edgeSize = 16,
|
||||
insets = { left = 3, right = 3, top = 5, bottom = 3 }
|
||||
}
|
||||
|
||||
local function Constructor()
|
||||
local frame = CreateFrame("Frame", nil, UIParent)
|
||||
frame:Hide()
|
||||
|
||||
frame:EnableMouse(true)
|
||||
frame:SetMovable(true)
|
||||
frame:SetResizable(true)
|
||||
frame:SetFrameStrata("FULLSCREEN_DIALOG")
|
||||
frame:SetBackdrop(FrameBackdrop)
|
||||
frame:SetBackdropColor(0, 0, 0, 1)
|
||||
frame:SetMinResize(400, 200)
|
||||
frame:SetToplevel(true)
|
||||
frame:SetScript("OnHide", Frame_OnClose)
|
||||
frame:SetScript("OnMouseDown", Frame_OnMouseDown)
|
||||
|
||||
local closebutton = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
|
||||
closebutton:SetScript("OnClick", Button_OnClick)
|
||||
closebutton:SetPoint("BOTTOMRIGHT", -27, 17)
|
||||
closebutton:SetHeight(20)
|
||||
closebutton:SetWidth(100)
|
||||
closebutton:SetText(CLOSE)
|
||||
|
||||
local statusbg = CreateFrame("Button", nil, frame)
|
||||
statusbg:SetPoint("BOTTOMLEFT", 15, 15)
|
||||
statusbg:SetPoint("BOTTOMRIGHT", -132, 15)
|
||||
statusbg:SetHeight(24)
|
||||
statusbg:SetBackdrop(PaneBackdrop)
|
||||
statusbg:SetBackdropColor(0.1,0.1,0.1)
|
||||
statusbg:SetBackdropBorderColor(0.4,0.4,0.4)
|
||||
statusbg:SetScript("OnEnter", StatusBar_OnEnter)
|
||||
statusbg:SetScript("OnLeave", StatusBar_OnLeave)
|
||||
|
||||
local statustext = statusbg:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
||||
statustext:SetPoint("TOPLEFT", 7, -2)
|
||||
statustext:SetPoint("BOTTOMRIGHT", -7, 2)
|
||||
statustext:SetHeight(20)
|
||||
statustext:SetJustifyH("LEFT")
|
||||
statustext:SetText("")
|
||||
|
||||
local titlebg = frame:CreateTexture(nil, "OVERLAY")
|
||||
titlebg:SetTexture("Interface\\DialogFrame\\UI-DialogBox-Header")
|
||||
titlebg:SetTexCoord(0.31, 0.67, 0, 0.63)
|
||||
titlebg:SetPoint("TOP", 0, 12)
|
||||
titlebg:SetWidth(100)
|
||||
titlebg:SetHeight(40)
|
||||
|
||||
local title = CreateFrame("Frame", nil, frame)
|
||||
title:EnableMouse(true)
|
||||
title:SetScript("OnMouseDown", Title_OnMouseDown)
|
||||
title:SetScript("OnMouseUp", MoverSizer_OnMouseUp)
|
||||
title:SetAllPoints(titlebg)
|
||||
|
||||
local titletext = title:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
||||
titletext:SetPoint("TOP", titlebg, "TOP", 0, -14)
|
||||
|
||||
local titlebg_l = frame:CreateTexture(nil, "OVERLAY")
|
||||
titlebg_l:SetTexture("Interface\\DialogFrame\\UI-DialogBox-Header")
|
||||
titlebg_l:SetTexCoord(0.21, 0.31, 0, 0.63)
|
||||
titlebg_l:SetPoint("RIGHT", titlebg, "LEFT")
|
||||
titlebg_l:SetWidth(30)
|
||||
titlebg_l:SetHeight(40)
|
||||
|
||||
local titlebg_r = frame:CreateTexture(nil, "OVERLAY")
|
||||
titlebg_r:SetTexture("Interface\\DialogFrame\\UI-DialogBox-Header")
|
||||
titlebg_r:SetTexCoord(0.67, 0.77, 0, 0.63)
|
||||
titlebg_r:SetPoint("LEFT", titlebg, "RIGHT")
|
||||
titlebg_r:SetWidth(30)
|
||||
titlebg_r:SetHeight(40)
|
||||
|
||||
-- bottom right sizer
|
||||
local sizer_se = CreateFrame("Frame", nil, frame)
|
||||
sizer_se:SetPoint("BOTTOMRIGHT", 0, 0)
|
||||
sizer_se:SetWidth(25)
|
||||
sizer_se:SetHeight(25)
|
||||
sizer_se:EnableMouse()
|
||||
sizer_se:SetScript("OnMouseDown",SizerSE_OnMouseDown)
|
||||
sizer_se:SetScript("OnMouseUp", MoverSizer_OnMouseUp)
|
||||
|
||||
local line1 = sizer_se:CreateTexture(nil, "BACKGROUND")
|
||||
line1:SetPoint("BOTTOMRIGHT", -10, 10)
|
||||
line1:SetTexture("Interface\\Cursor\\Item")
|
||||
line1:SetTexCoord(1, 0, 1, 0)
|
||||
|
||||
local sizer_s = CreateFrame("Frame", nil, frame)
|
||||
sizer_s:SetPoint("BOTTOMRIGHT", -25, 0)
|
||||
sizer_s:SetPoint("BOTTOMLEFT", 0, 0)
|
||||
sizer_s:SetHeight(25)
|
||||
sizer_s:EnableMouse(true)
|
||||
sizer_s:SetScript("OnMouseDown", SizerS_OnMouseDown)
|
||||
sizer_s:SetScript("OnMouseUp", MoverSizer_OnMouseUp)
|
||||
|
||||
local sizer_e = CreateFrame("Frame", nil, frame)
|
||||
sizer_e:SetPoint("BOTTOMRIGHT", 0, 25)
|
||||
sizer_e:SetPoint("TOPRIGHT", 0, 0)
|
||||
sizer_e:SetWidth(25)
|
||||
sizer_e:EnableMouse(true)
|
||||
sizer_e:SetScript("OnMouseDown", SizerE_OnMouseDown)
|
||||
sizer_e:SetScript("OnMouseUp", MoverSizer_OnMouseUp)
|
||||
|
||||
--Container Support
|
||||
local content = CreateFrame("Frame", nil, frame)
|
||||
content:SetPoint("TOPLEFT", 17, -27)
|
||||
content:SetPoint("BOTTOMRIGHT", -17, 40)
|
||||
|
||||
local widget = {
|
||||
localstatus = {},
|
||||
titletext = titletext,
|
||||
statustext = statustext,
|
||||
titlebg = titlebg,
|
||||
sizer_se = sizer_se,
|
||||
sizer_s = sizer_s,
|
||||
sizer_e = sizer_e,
|
||||
content = content,
|
||||
frame = frame,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
closebutton.obj, statusbg.obj = widget, widget
|
||||
|
||||
return AceGUI:RegisterAsContainer(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
@@ -0,0 +1,103 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
InlineGroup Container
|
||||
Simple container widget that creates a visible "box" with an optional title.
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "InlineGroup", 21
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
-- Lua APIs
|
||||
local pairs = pairs
|
||||
|
||||
-- WoW APIs
|
||||
local CreateFrame, UIParent = CreateFrame, UIParent
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
self:SetWidth(300)
|
||||
self:SetHeight(100)
|
||||
self:SetTitle("")
|
||||
end,
|
||||
|
||||
-- ["OnRelease"] = nil,
|
||||
|
||||
["SetTitle"] = function(self,title)
|
||||
self.titletext:SetText(title)
|
||||
end,
|
||||
|
||||
|
||||
["LayoutFinished"] = function(self, width, height)
|
||||
if self.noAutoHeight then return end
|
||||
self:SetHeight((height or 0) + 40)
|
||||
end,
|
||||
|
||||
["OnWidthSet"] = function(self, width)
|
||||
local content = self.content
|
||||
local contentwidth = width - 20
|
||||
if contentwidth < 0 then
|
||||
contentwidth = 0
|
||||
end
|
||||
content:SetWidth(contentwidth)
|
||||
content.width = contentwidth
|
||||
end,
|
||||
|
||||
["OnHeightSet"] = function(self, height)
|
||||
local content = self.content
|
||||
local contentheight = height - 20
|
||||
if contentheight < 0 then
|
||||
contentheight = 0
|
||||
end
|
||||
content:SetHeight(contentheight)
|
||||
content.height = contentheight
|
||||
end
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local PaneBackdrop = {
|
||||
bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
|
||||
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
||||
tile = true, tileSize = 16, edgeSize = 16,
|
||||
insets = { left = 3, right = 3, top = 5, bottom = 3 }
|
||||
}
|
||||
|
||||
local function Constructor()
|
||||
local frame = CreateFrame("Frame", nil, UIParent)
|
||||
frame:SetFrameStrata("FULLSCREEN_DIALOG")
|
||||
|
||||
local titletext = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
||||
titletext:SetPoint("TOPLEFT", 14, 0)
|
||||
titletext:SetPoint("TOPRIGHT", -14, 0)
|
||||
titletext:SetJustifyH("LEFT")
|
||||
titletext:SetHeight(18)
|
||||
|
||||
local border = CreateFrame("Frame", nil, frame)
|
||||
border:SetPoint("TOPLEFT", 0, -17)
|
||||
border:SetPoint("BOTTOMRIGHT", -1, 3)
|
||||
border:SetBackdrop(PaneBackdrop)
|
||||
border:SetBackdropColor(0.1, 0.1, 0.1, 0.5)
|
||||
border:SetBackdropBorderColor(0.4, 0.4, 0.4)
|
||||
|
||||
--Container Support
|
||||
local content = CreateFrame("Frame", nil, border)
|
||||
content:SetPoint("TOPLEFT", 10, -10)
|
||||
content:SetPoint("BOTTOMRIGHT", -10, 10)
|
||||
|
||||
local widget = {
|
||||
frame = frame,
|
||||
content = content,
|
||||
titletext = titletext,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
|
||||
return AceGUI:RegisterAsContainer(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
@@ -0,0 +1,213 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
ScrollFrame Container
|
||||
Plain container that scrolls its content and doesn't grow in height.
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "ScrollFrame", 24
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
local fixlevels = AceGUI.fixlevels
|
||||
|
||||
-- Lua APIs
|
||||
local pairs, assert, type = pairs, assert, type
|
||||
local min, max, floor, abs = math.min, math.max, math.floor, math.abs
|
||||
local format = string.format
|
||||
|
||||
-- WoW APIs
|
||||
local CreateFrame, UIParent = CreateFrame, UIParent
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Support functions
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function FixScrollOnUpdate()
|
||||
this:SetScript("OnUpdate", nil)
|
||||
this.obj:FixScroll()
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Scripts
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function ScrollFrame_OnMouseWheel()
|
||||
this.obj:MoveScroll(arg1)
|
||||
end
|
||||
|
||||
local function ScrollFrame_OnSizeChanged()
|
||||
this:SetScript("OnUpdate", FixScrollOnUpdate)
|
||||
end
|
||||
|
||||
local function ScrollBar_OnScrollValueChanged()
|
||||
this.obj:SetScroll(arg1)
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
self:SetScroll(0)
|
||||
self.scrollframe:SetScript("OnUpdate", FixScrollOnUpdate)
|
||||
end,
|
||||
|
||||
["OnRelease"] = function(self)
|
||||
self.status = nil
|
||||
for k in pairs(self.localstatus) do
|
||||
self.localstatus[k] = nil
|
||||
end
|
||||
self.scrollframe:SetPoint("BOTTOMRIGHT",0,0)
|
||||
self.scrollbar:Hide()
|
||||
self.scrollBarShown = nil
|
||||
self.content.height, self.content.width = nil, nil
|
||||
end,
|
||||
|
||||
["SetScroll"] = function(self, value)
|
||||
local status = self.status or self.localstatus
|
||||
local viewheight = self.scrollframe:GetHeight()
|
||||
local height = self.content:GetHeight()
|
||||
local offset
|
||||
|
||||
if viewheight > height then
|
||||
offset = 0
|
||||
else
|
||||
offset = floor((height - viewheight) / 1000.0 * value)
|
||||
end
|
||||
self.content:ClearAllPoints()
|
||||
self.content:SetPoint("TOPLEFT", 0, offset)
|
||||
self.content:SetPoint("TOPRIGHT", 0, offset)
|
||||
status.offset = offset
|
||||
status.scrollvalue = value
|
||||
end,
|
||||
|
||||
["MoveScroll"] = function(self, value)
|
||||
local status = self.status or self.localstatus
|
||||
local height, viewheight = self.scrollframe:GetHeight(), self.content:GetHeight()
|
||||
|
||||
if self.scrollBarShown then
|
||||
local diff = height - viewheight
|
||||
local delta = 1
|
||||
if value < 0 then
|
||||
delta = -1
|
||||
end
|
||||
self.scrollbar:SetValue(min(max(status.scrollvalue + delta*(1000/(diff/45)),0), 1000))
|
||||
end
|
||||
end,
|
||||
|
||||
["FixScroll"] = function(self)
|
||||
|
||||
if self.updateLock then return end
|
||||
self.updateLock = true
|
||||
local status = self.status or self.localstatus
|
||||
local scrollframe, content, scrollbar = self.scrollframe, self.content, self.scrollbar
|
||||
local viewheight, height = self.scrollframe:GetHeight(), self.content:GetHeight()
|
||||
local offset = status.offset or 0
|
||||
local curvalue = scrollbar:GetValue()
|
||||
-- Give us a margin of error of 2 pixels to stop some conditions that i would blame on floating point inaccuracys
|
||||
-- No-one is going to miss 2 pixels at the bottom of the frame, anyhow!
|
||||
|
||||
if height < viewheight + 2 then
|
||||
if self.scrollBarShown then
|
||||
self.scrollBarShown = nil
|
||||
scrollbar:Hide()
|
||||
scrollbar:SetValue(0)
|
||||
scrollframe:SetPoint("BOTTOMRIGHT",0,0)
|
||||
self:DoLayout()
|
||||
end
|
||||
offset = 0
|
||||
else
|
||||
if not self.scrollBarShown then
|
||||
self.scrollBarShown = true
|
||||
scrollbar:Show()
|
||||
scrollframe:SetPoint("BOTTOMRIGHT", -20, 0)
|
||||
self:DoLayout()
|
||||
end
|
||||
local value = (offset / (height - viewheight) * 1000)
|
||||
if value > 1000 then
|
||||
value = 1000
|
||||
offset = height - viewheight
|
||||
end
|
||||
scrollbar:SetValue(value)
|
||||
self:SetScroll(value)
|
||||
end
|
||||
status.offset = offset
|
||||
scrollframe:SetScrollChild(content)
|
||||
content:ClearAllPoints()
|
||||
content:SetPoint("TOPLEFT", 0, offset)
|
||||
content:SetPoint("TOPRIGHT", 0, offset)
|
||||
self.updateLock = nil
|
||||
end,
|
||||
|
||||
["LayoutFinished"] = function(self, width, height)
|
||||
self.content:SetHeight(height or 0 + 20)
|
||||
self.scrollframe:SetScript("OnUpdate", FixScrollOnUpdate)
|
||||
end,
|
||||
|
||||
["SetStatusTable"] = function(self, status)
|
||||
assert(type(status) == "table")
|
||||
self.status = status
|
||||
if not status.scrollvalue then
|
||||
status.scrollvalue = 0
|
||||
end
|
||||
end,
|
||||
|
||||
["OnWidthSet"] = function(self, width)
|
||||
local content = self.content
|
||||
content.width = width
|
||||
end,
|
||||
|
||||
["OnHeightSet"] = function(self, height)
|
||||
local content = self.content
|
||||
content.height = height
|
||||
end
|
||||
}
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Constructor()
|
||||
local frame = CreateFrame("Frame", nil, UIParent)
|
||||
local num = AceGUI:GetNextWidgetNum(Type)
|
||||
|
||||
local scrollframe = CreateFrame("ScrollFrame", nil, frame)
|
||||
scrollframe:SetPoint("TOPLEFT",0,0)
|
||||
scrollframe:SetPoint("BOTTOMRIGHT",0,0)
|
||||
scrollframe:EnableMouseWheel(true)
|
||||
scrollframe:SetScript("OnMouseWheel", ScrollFrame_OnMouseWheel)
|
||||
scrollframe:SetScript("OnSizeChanged", ScrollFrame_OnSizeChanged)
|
||||
|
||||
local scrollbar = CreateFrame("Slider", format("AceConfigDialogScrollFrame%dScrollBar", num), scrollframe, "UIPanelScrollBarTemplate")
|
||||
scrollbar:SetPoint("TOPLEFT", scrollframe, "TOPRIGHT", 4, -16)
|
||||
scrollbar:SetPoint("BOTTOMLEFT", scrollframe, "BOTTOMRIGHT", 4, 16)
|
||||
scrollbar:SetMinMaxValues(0, 1000)
|
||||
scrollbar:SetValueStep(1)
|
||||
scrollbar:SetValue(0)
|
||||
scrollbar:SetWidth(16)
|
||||
scrollbar:Hide()
|
||||
-- set the script as the last step, so it doesn't fire yet
|
||||
scrollbar:SetScript("OnValueChanged", ScrollBar_OnScrollValueChanged)
|
||||
|
||||
local scrollbg = scrollbar:CreateTexture(nil, "BACKGROUND")
|
||||
scrollbg:SetAllPoints(scrollbar)
|
||||
scrollbg:SetTexture(0, 0, 0, 0.4)
|
||||
|
||||
--Container Support
|
||||
local content = CreateFrame("Frame", nil, scrollframe)
|
||||
content:SetPoint("TOPLEFT",0,0)
|
||||
content:SetPoint("TOPRIGHT",0,0)
|
||||
content:SetHeight(400)
|
||||
scrollframe:SetScrollChild(content)
|
||||
|
||||
local widget = {
|
||||
localstatus = { scrollvalue = 0 },
|
||||
scrollframe = scrollframe,
|
||||
scrollbar = scrollbar,
|
||||
content = content,
|
||||
frame = frame,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
scrollframe.obj, scrollbar.obj = widget, widget
|
||||
|
||||
return AceGUI:RegisterAsContainer(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
@@ -0,0 +1,69 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
SimpleGroup Container
|
||||
Simple container widget that just groups widgets.
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "SimpleGroup", 20
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
-- Lua APIs
|
||||
local pairs = pairs
|
||||
|
||||
-- WoW APIs
|
||||
local CreateFrame, UIParent = CreateFrame, UIParent
|
||||
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
self:SetWidth(300)
|
||||
self:SetHeight(100)
|
||||
end,
|
||||
|
||||
-- ["OnRelease"] = nil,
|
||||
|
||||
["LayoutFinished"] = function(self, width, height)
|
||||
if self.noAutoHeight then return end
|
||||
self:SetHeight(height or 0)
|
||||
end,
|
||||
|
||||
["OnWidthSet"] = function(self, width)
|
||||
local content = self.content
|
||||
content:SetWidth(width)
|
||||
content.width = width
|
||||
end,
|
||||
|
||||
["OnHeightSet"] = function(self, height)
|
||||
local content = self.content
|
||||
content:SetHeight(height)
|
||||
content.height = height
|
||||
end
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Constructor()
|
||||
local frame = CreateFrame("Frame", nil, UIParent)
|
||||
frame:SetFrameStrata("FULLSCREEN_DIALOG")
|
||||
|
||||
--Container Support
|
||||
local content = CreateFrame("Frame", nil, frame)
|
||||
content:SetPoint("TOPLEFT")
|
||||
content:SetPoint("BOTTOMRIGHT")
|
||||
|
||||
local widget = {
|
||||
frame = frame,
|
||||
content = content,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
|
||||
return AceGUI:RegisterAsContainer(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
@@ -0,0 +1,378 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
TabGroup Container
|
||||
Container that uses tabs on top to switch between groups.
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "TabGroup", 35
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
local AceCore = LibStub("AceCore-3.0")
|
||||
local wipe = AceCore.wipe
|
||||
|
||||
-- Lua APIs
|
||||
local pairs, ipairs, assert, type, wipe = pairs, ipairs, assert, type, wipe
|
||||
local tgetn = table.getn
|
||||
local strfmt = string.format
|
||||
|
||||
-- WoW APIs
|
||||
local PlaySound = PlaySound
|
||||
local CreateFrame, UIParent = CreateFrame, UIParent
|
||||
local _G = AceCore._G
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: PanelTemplates_TabResize, PanelTemplates_SetDisabledTabState, PanelTemplates_SelectTab, PanelTemplates_DeselectTab
|
||||
|
||||
-- local upvalue storage used by BuildTabs
|
||||
local widths = {}
|
||||
local rowwidths = {}
|
||||
local rowends = {}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Support functions
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function UpdateTabLook(frame)
|
||||
if frame.disabled then
|
||||
PanelTemplates_SetDisabledTabState(frame)
|
||||
frame:SetAlpha(0.5)
|
||||
elseif frame.selected then
|
||||
PanelTemplates_SelectTab(frame)
|
||||
frame:SetAlpha(1)
|
||||
else
|
||||
PanelTemplates_DeselectTab(frame)
|
||||
frame:SetAlpha(0.5)
|
||||
end
|
||||
end
|
||||
|
||||
local function Tab_SetText(tab, text)
|
||||
tab:_SetText(text)
|
||||
local width = tab.obj.frame.width or tab.obj.frame:GetWidth() or 0
|
||||
PanelTemplates_TabResize(0, tab, nil, width)
|
||||
end
|
||||
|
||||
local function Tab_SetSelected(tab, selected)
|
||||
tab.selected = selected
|
||||
UpdateTabLook(tab)
|
||||
end
|
||||
|
||||
local function Tab_SetDisabled(tab, disabled)
|
||||
tab.disabled = disabled
|
||||
UpdateTabLook(tab)
|
||||
end
|
||||
|
||||
local function BuildTabsOnUpdate()
|
||||
local self = this.obj
|
||||
self:BuildTabs()
|
||||
this:SetScript("OnUpdate", nil)
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Scripts
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Tab_OnClick()
|
||||
if not (this.selected or this.disabled) then
|
||||
PlaySound("igCharacterInfoTab")
|
||||
this.obj:SelectTab(this.value)
|
||||
end
|
||||
end
|
||||
|
||||
local function Tab_OnEnter()
|
||||
local self = this.obj
|
||||
self:Fire("OnTabEnter", 2, self.tabs[this.id].value, this)
|
||||
end
|
||||
|
||||
local function Tab_OnLeave()
|
||||
local self = this.obj
|
||||
self:Fire("OnTabLeave", 2, self.tabs[this.id].value, this)
|
||||
end
|
||||
|
||||
local function Tab_OnShow()
|
||||
_G[this:GetName().."HighlightTexture"]:SetWidth(this:GetTextWidth() + 30)
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
self:SetTitle()
|
||||
end,
|
||||
|
||||
["OnRelease"] = function(self)
|
||||
self.status = nil
|
||||
for k in pairs(self.localstatus) do
|
||||
self.localstatus[k] = nil
|
||||
end
|
||||
self.tablist = nil
|
||||
for _, tab in pairs(self.tabs) do
|
||||
tab:Hide()
|
||||
end
|
||||
end,
|
||||
|
||||
["CreateTab"] = function(self, id)
|
||||
local tabname = strfmt("AceGUITabGroup%dTab%d", self.num, id)
|
||||
local tab = CreateFrame("Button", tabname, self.border, "TabButtonTemplate")
|
||||
-- Normal texture
|
||||
local texture = getglobal(tabname.."Left")
|
||||
texture:SetTexture("Interface\\ChatFrame\\ChatFrameTab")
|
||||
texture:ClearAllPoints()
|
||||
texture:SetPoint("BOTTOMLEFT", tab,"BOTTOMLEFT")
|
||||
texture:SetPoint("TOPLEFT", tab,"TOPLEFT")
|
||||
texture = getglobal(tabname.."Middle")
|
||||
texture:SetTexture("Interface\\ChatFrame\\ChatFrameTab")
|
||||
texture = getglobal(tabname.."Right")
|
||||
texture:SetTexture("Interface\\ChatFrame\\ChatFrameTab")
|
||||
-- Disabled texture
|
||||
texture = getglobal(tabname.."LeftDisabled")
|
||||
texture:SetTexture("Interface\\ChatFrame\\ChatFrameTab")
|
||||
texture:SetPoint("BOTTOMLEFT", tab,"BOTTOMLEFT")
|
||||
texture:SetPoint("TOPLEFT", tab,"TOPLEFT")
|
||||
texture = getglobal(tabname.."MiddleDisabled")
|
||||
texture:SetTexture("Interface\\ChatFrame\\ChatFrameTab")
|
||||
texture = getglobal(tabname.."RightDisabled")
|
||||
texture:SetTexture("Interface\\ChatFrame\\ChatFrameTab")
|
||||
|
||||
tab.obj = self
|
||||
tab.id = id
|
||||
|
||||
tab:SetScript("OnClick", Tab_OnClick)
|
||||
tab:SetScript("OnEnter", Tab_OnEnter)
|
||||
tab:SetScript("OnLeave", Tab_OnLeave)
|
||||
tab:SetScript("OnShow", Tab_OnShow)
|
||||
|
||||
tab._SetText = tab.SetText
|
||||
tab.SetText = Tab_SetText
|
||||
tab.SetSelected = Tab_SetSelected
|
||||
tab.SetDisabled = Tab_SetDisabled
|
||||
|
||||
return tab
|
||||
end,
|
||||
|
||||
["SetTitle"] = function(self, text)
|
||||
self.titletext:SetText(text or "")
|
||||
if text and text ~= "" then
|
||||
self.alignoffset = 25
|
||||
else
|
||||
self.alignoffset = 18
|
||||
end
|
||||
self:BuildTabs()
|
||||
end,
|
||||
|
||||
["SetStatusTable"] = function(self, status)
|
||||
assert(type(status) == "table")
|
||||
self.status = status
|
||||
end,
|
||||
|
||||
["SelectTab"] = function(self, value)
|
||||
local status = self.status or self.localstatus
|
||||
local found
|
||||
for i, v in ipairs(self.tabs) do
|
||||
if v.value == value then
|
||||
v:SetSelected(true)
|
||||
found = true
|
||||
else
|
||||
v:SetSelected(false)
|
||||
end
|
||||
end
|
||||
status.selected = value
|
||||
if found then
|
||||
self:Fire("OnGroupSelected",1,value)
|
||||
end
|
||||
end,
|
||||
|
||||
["SetTabs"] = function(self, tabs)
|
||||
self.tablist = tabs
|
||||
self:BuildTabs()
|
||||
end,
|
||||
|
||||
|
||||
["BuildTabs"] = function(self)
|
||||
local hastitle = (self.titletext:GetText() and self.titletext:GetText() ~= "")
|
||||
local status = self.status or self.localstatus
|
||||
local tablist = self.tablist
|
||||
local tabs = self.tabs
|
||||
|
||||
if not tablist then return end
|
||||
|
||||
local width = self.frame.width or self.frame:GetWidth() or 0
|
||||
|
||||
wipe(widths)
|
||||
wipe(rowwidths)
|
||||
wipe(rowends)
|
||||
|
||||
--Place Text into tabs and get thier initial width
|
||||
for i, v in ipairs(tablist) do
|
||||
local tab = tabs[i]
|
||||
if not tab then
|
||||
tab = self:CreateTab(i)
|
||||
tabs[i] = tab
|
||||
end
|
||||
|
||||
tab:Show()
|
||||
if type(v) == "table" then
|
||||
tab:SetText(v.text)
|
||||
tab:SetDisabled(v.disabled)
|
||||
tab.value = v.value
|
||||
elseif type(v) == "string" then
|
||||
tab:SetText(v)
|
||||
tab.value = v
|
||||
end
|
||||
|
||||
widths[i] = tab:GetWidth() - 6 --tabs are anchored 10 pixels from the right side of the previous one to reduce spacing, but add a fixed 4px padding for the text
|
||||
end
|
||||
|
||||
for i = tgetn(tablist)+1, tgetn(tabs), 1 do
|
||||
tabs[i]:Hide()
|
||||
end
|
||||
|
||||
--First pass, find the minimum number of rows needed to hold all tabs and the initial tab layout
|
||||
local numtabs = tgetn(tablist)
|
||||
local numrows = 1
|
||||
local usedwidth = 0
|
||||
|
||||
for i = 1, tgetn(tablist) do
|
||||
--If this is not the first tab of a row and there isn't room for it
|
||||
if usedwidth ~= 0 and (width - usedwidth - widths[i]) < 0 then
|
||||
rowwidths[numrows] = usedwidth + 10 --first tab in each row takes up an extra 10px
|
||||
rowends[numrows] = i - 1
|
||||
numrows = numrows + 1
|
||||
usedwidth = 0
|
||||
end
|
||||
usedwidth = usedwidth + widths[i]
|
||||
end
|
||||
rowwidths[numrows] = usedwidth + 10 --first tab in each row takes up an extra 10px
|
||||
rowends[numrows] = tgetn(tablist)
|
||||
|
||||
--Fix for single tabs being left on the last row, move a tab from the row above if applicable
|
||||
if numrows > 1 then
|
||||
--if the last row has only one tab
|
||||
if rowends[numrows-1] == numtabs-1 then
|
||||
--if there are more than 2 tabs in the 2nd last row
|
||||
if (numrows == 2 and rowends[numrows-1] > 2) or (rowends[numrows] - rowends[numrows-1] > 2) then
|
||||
--move 1 tab from the second last row to the last, if there is enough space
|
||||
if (rowwidths[numrows] + widths[numtabs-1]) <= width then
|
||||
rowends[numrows-1] = rowends[numrows-1] - 1
|
||||
rowwidths[numrows] = rowwidths[numrows] + widths[numtabs-1]
|
||||
rowwidths[numrows-1] = rowwidths[numrows-1] - widths[numtabs-1]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--anchor the rows as defined and resize tabs to fill thier row
|
||||
local starttab = 1
|
||||
for row, endtab in ipairs(rowends) do
|
||||
local first = true
|
||||
for tabno = starttab, endtab do
|
||||
local tab = tabs[tabno]
|
||||
tab:ClearAllPoints()
|
||||
if first then
|
||||
tab:SetPoint("TOPLEFT", self.frame, "TOPLEFT", 0, -(hastitle and 14 or 7)-(row-1)*20 )
|
||||
first = false
|
||||
else
|
||||
tab:SetPoint("LEFT", tabs[tabno-1], "RIGHT", -10, 0)
|
||||
end
|
||||
end
|
||||
|
||||
-- equal padding for each tab to fill the available width,
|
||||
-- if the used space is above 75% already
|
||||
-- the 18 pixel is the typical width of a scrollbar, so we can have a tab group inside a scrolling frame,
|
||||
-- and not have the tabs jump around funny when switching between tabs that need scrolling and those that don't
|
||||
local padding = 0
|
||||
if not (numrows == 1 and rowwidths[1] < width*0.75 - 18) then
|
||||
padding = (width - rowwidths[row]) / (endtab - starttab+1)
|
||||
end
|
||||
|
||||
for i = starttab, endtab do
|
||||
PanelTemplates_TabResize(padding + 4, tabs[i], nil, width)
|
||||
end
|
||||
starttab = endtab + 1
|
||||
end
|
||||
|
||||
self.borderoffset = (hastitle and 17 or 10)+((numrows)*20)+7
|
||||
self.border:SetPoint("TOPLEFT", 1, -self.borderoffset)
|
||||
end,
|
||||
|
||||
["OnWidthSet"] = function(self, width)
|
||||
local content = self.content
|
||||
local contentwidth = width - 60
|
||||
if contentwidth < 0 then
|
||||
contentwidth = 0
|
||||
end
|
||||
content:SetWidth(contentwidth)
|
||||
content.width = contentwidth
|
||||
self:BuildTabs(self)
|
||||
self.frame:SetScript("OnUpdate", BuildTabsOnUpdate)
|
||||
end,
|
||||
|
||||
["OnHeightSet"] = function(self, height)
|
||||
local content = self.content
|
||||
local contentheight = height - (self.borderoffset + 23)
|
||||
if contentheight < 0 then
|
||||
contentheight = 0
|
||||
end
|
||||
content:SetHeight(contentheight)
|
||||
content.height = contentheight
|
||||
end,
|
||||
|
||||
["LayoutFinished"] = function(self, width, height)
|
||||
if self.noAutoHeight then return end
|
||||
self:SetHeight((height or 0) + (self.borderoffset + 23))
|
||||
end
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local PaneBackdrop = {
|
||||
bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
|
||||
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
||||
tile = true, tileSize = 16, edgeSize = 16,
|
||||
insets = { left = 3, right = 3, top = 5, bottom = 3 }
|
||||
}
|
||||
|
||||
local function Constructor()
|
||||
local num = AceGUI:GetNextWidgetNum(Type)
|
||||
local frame = CreateFrame("Frame",nil,UIParent)
|
||||
frame:SetHeight(100)
|
||||
frame:SetWidth(100)
|
||||
frame:SetFrameStrata("FULLSCREEN_DIALOG")
|
||||
|
||||
local titletext = frame:CreateFontString(nil,"OVERLAY","GameFontNormal")
|
||||
titletext:SetPoint("TOPLEFT", 14, 0)
|
||||
titletext:SetPoint("TOPRIGHT", -14, 0)
|
||||
titletext:SetJustifyH("LEFT")
|
||||
titletext:SetHeight(18)
|
||||
titletext:SetText("")
|
||||
|
||||
local border = CreateFrame("Frame", nil, frame)
|
||||
border:SetPoint("TOPLEFT", 1, -27)
|
||||
border:SetPoint("BOTTOMRIGHT", -1, 3)
|
||||
border:SetBackdrop(PaneBackdrop)
|
||||
border:SetBackdropColor(0.1, 0.1, 0.1, 0.5)
|
||||
border:SetBackdropBorderColor(0.4, 0.4, 0.4)
|
||||
|
||||
local content = CreateFrame("Frame", nil, border)
|
||||
content:SetPoint("TOPLEFT", 10, -7)
|
||||
content:SetPoint("BOTTOMRIGHT", -10, 7)
|
||||
|
||||
local widget = {
|
||||
num = num,
|
||||
frame = frame,
|
||||
localstatus = {},
|
||||
alignoffset = 18,
|
||||
titletext = titletext,
|
||||
border = border,
|
||||
borderoffset = 27,
|
||||
tabs = {},
|
||||
content = content,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
|
||||
return AceGUI:RegisterAsContainer(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
@@ -0,0 +1,769 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
TreeGroup Container
|
||||
Container that uses a tree control to switch between groups.
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "TreeGroup", 40
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
local AceCore = LibStub("AceCore-3.0")
|
||||
local strsplit = AceCore.strsplit
|
||||
local _G = AceCore._G
|
||||
|
||||
-- Lua APIs
|
||||
local next, pairs, ipairs, assert, type = next, pairs, ipairs, assert, type
|
||||
local math_min, math_max, floor = math.min, math.max, floor
|
||||
local tgetn, tremove, unpack, tconcat = table.getn, table.remove, unpack, table.concat
|
||||
local strfmt = string.format
|
||||
|
||||
-- WoW APIs
|
||||
local CreateFrame, UIParent = CreateFrame, UIParent
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: GameTooltip, FONT_COLOR_CODE_CLOSE
|
||||
|
||||
-- Recycling functions
|
||||
local new, del
|
||||
do
|
||||
local pool = setmetatable({},{__mode='k'})
|
||||
function new()
|
||||
local t = next(pool)
|
||||
if t then
|
||||
pool[t] = nil
|
||||
return t
|
||||
else
|
||||
return {}
|
||||
end
|
||||
end
|
||||
function del(t)
|
||||
for k in pairs(t) do
|
||||
t[k] = nil
|
||||
end
|
||||
pool[t] = true
|
||||
end
|
||||
end
|
||||
|
||||
local DEFAULT_TREE_WIDTH = 175
|
||||
local DEFAULT_TREE_SIZABLE = true
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Support functions
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function GetButtonUniqueValue(line)
|
||||
local parent = line.parent
|
||||
if parent and parent.value then
|
||||
return GetButtonUniqueValue(parent).."\001"..line.value
|
||||
else
|
||||
return line.value
|
||||
end
|
||||
end
|
||||
|
||||
local function UpdateButton(button, treeline, selected, canExpand, isExpanded)
|
||||
local self = button.obj
|
||||
local toggle = button.toggle
|
||||
local frame = self.frame
|
||||
local text = treeline.text or ""
|
||||
local icon = treeline.icon
|
||||
local iconCoords = treeline.iconCoords
|
||||
local level = treeline.level
|
||||
local value = treeline.value
|
||||
local uniquevalue = treeline.uniquevalue
|
||||
local disabled = treeline.disabled
|
||||
|
||||
button.treeline = treeline
|
||||
button.value = value
|
||||
button.uniquevalue = uniquevalue
|
||||
if selected then
|
||||
button:LockHighlight()
|
||||
button.selected = true
|
||||
else
|
||||
button:UnlockHighlight()
|
||||
button.selected = false
|
||||
end
|
||||
local normalTexture = button:GetNormalTexture()
|
||||
local line = button.line
|
||||
button.level = level
|
||||
|
||||
if ( level == 1 ) then
|
||||
button.text:SetFontObject("GameFontNormal")
|
||||
button:SetHighlightFontObject("GameFontHighlight")
|
||||
button.text:SetPoint("LEFT", (icon and 16 or 0) + 8, 2)
|
||||
else
|
||||
button.text:SetFontObject("GameFontHighlightSmall")
|
||||
button:SetHighlightFontObject("GameFontHighlightSmall")
|
||||
button.text:SetPoint("LEFT", (icon and 16 or 0) + 8 * level, 2)
|
||||
end
|
||||
|
||||
if disabled then
|
||||
button:EnableMouse(false)
|
||||
button.text:SetText("|cff808080"..text..FONT_COLOR_CODE_CLOSE)
|
||||
else
|
||||
button.text:SetText(text)
|
||||
button:EnableMouse(true)
|
||||
end
|
||||
|
||||
if icon then
|
||||
button.icon:SetTexture(icon)
|
||||
button.icon:SetPoint("LEFT", 8 * level, (level == 1) and 0 or 1)
|
||||
else
|
||||
button.icon:SetTexture(nil)
|
||||
end
|
||||
|
||||
if iconCoords then
|
||||
button.icon:SetTexCoord(unpack(iconCoords))
|
||||
else
|
||||
button.icon:SetTexCoord(0, 1, 0, 1)
|
||||
end
|
||||
|
||||
if canExpand then
|
||||
if not isExpanded then
|
||||
toggle:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-UP")
|
||||
toggle:SetPushedTexture("Interface\\Buttons\\UI-PlusButton-DOWN")
|
||||
else
|
||||
toggle:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-UP")
|
||||
toggle:SetPushedTexture("Interface\\Buttons\\UI-MinusButton-DOWN")
|
||||
end
|
||||
toggle:Show()
|
||||
else
|
||||
toggle:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
local function ShouldDisplayLevel(tree)
|
||||
local result = false
|
||||
for k, v in ipairs(tree) do
|
||||
if v.children == nil and v.visible ~= false then
|
||||
result = true
|
||||
elseif v.children then
|
||||
result = result or ShouldDisplayLevel(v.children)
|
||||
end
|
||||
if result then return result end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function addLine(self, v, tree, level, parent)
|
||||
local line = new()
|
||||
line.value = v.value
|
||||
line.text = v.text
|
||||
line.icon = v.icon
|
||||
line.iconCoords = v.iconCoords
|
||||
line.disabled = v.disabled
|
||||
line.tree = tree
|
||||
line.level = level
|
||||
line.parent = parent
|
||||
line.visible = v.visible
|
||||
line.uniquevalue = GetButtonUniqueValue(line)
|
||||
if v.children then
|
||||
line.hasChildren = true
|
||||
else
|
||||
line.hasChildren = nil
|
||||
end
|
||||
tinsert(self.lines, line)
|
||||
return line
|
||||
end
|
||||
|
||||
--fire an update after one frame to catch the treeframes height
|
||||
local function FirstFrameUpdate()
|
||||
local self = this.obj
|
||||
this:SetScript("OnUpdate", nil)
|
||||
self:RefreshTree()
|
||||
end
|
||||
|
||||
local BuildUniqueValue
|
||||
do
|
||||
local args = {nil,nil,nil,nil,nil,nil,nil,nil,nil,nil}
|
||||
function BuildUniqueValue(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
|
||||
args[1] = a1
|
||||
args[2] = a2
|
||||
args[3] = a3
|
||||
args[4] = a4
|
||||
args[5] = a5
|
||||
args[6] = a6
|
||||
args[7] = a7
|
||||
args[8] = a8
|
||||
args[9] = a9
|
||||
args[10] = a10
|
||||
return tconcat(tmp, "\001", 1, tgetn(args))
|
||||
end
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Scripts
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Expand_OnClick()
|
||||
local button = this.button
|
||||
local self = button.obj
|
||||
local status = (self.status or self.localstatus).groups
|
||||
status[button.uniquevalue] = not status[button.uniquevalue]
|
||||
self:RefreshTree()
|
||||
end
|
||||
|
||||
local function Button_OnClick()
|
||||
local self = this.obj
|
||||
self:Fire("OnClick", 2, this.uniquevalue, this.selected)
|
||||
if not this.selected then
|
||||
self:SetSelected(this.uniquevalue)
|
||||
this.selected = true
|
||||
this:LockHighlight()
|
||||
self:RefreshTree()
|
||||
end
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
local function Button_OnDoubleClick()
|
||||
local self = this.obj
|
||||
local status = self.status or self.localstatus
|
||||
local status = (self.status or self.localstatus).groups
|
||||
status[this.uniquevalue] = not status[this.uniquevalue]
|
||||
self:RefreshTree()
|
||||
end
|
||||
|
||||
local function Button_OnEnter()
|
||||
local self = this.obj
|
||||
self:Fire("OnButtonEnter", 2, this.uniquevalue, this)
|
||||
|
||||
if self.enabletooltips then
|
||||
GameTooltip:SetOwner(this, "ANCHOR_NONE")
|
||||
GameTooltip:SetPoint("LEFT",this,"RIGHT")
|
||||
GameTooltip:SetText(this.text:GetText() or "", 1, .82, 0, true)
|
||||
|
||||
GameTooltip:Show()
|
||||
end
|
||||
end
|
||||
|
||||
local function Button_OnLeave()
|
||||
local self = this.obj
|
||||
self:Fire("OnButtonLeave", 2, this.uniquevalue, this)
|
||||
|
||||
if self.enabletooltips then
|
||||
GameTooltip:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
local function OnScrollValueChanged()
|
||||
if this.obj.noupdate then return end
|
||||
local self = this.obj
|
||||
local status = self.status or self.localstatus
|
||||
status.scrollvalue = floor(arg1 + 0.5)
|
||||
self:RefreshTree()
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
local function Tree_OnSizeChanged()
|
||||
this.obj:RefreshTree()
|
||||
end
|
||||
|
||||
local function Tree_OnMouseWheel()
|
||||
local self = this.obj
|
||||
if self.showscroll then
|
||||
local scrollbar = self.scrollbar
|
||||
local min, max = scrollbar:GetMinMaxValues()
|
||||
local value = scrollbar:GetValue()
|
||||
local newvalue = math_min(max,math_max(min,value - arg1))
|
||||
if value ~= newvalue then
|
||||
scrollbar:SetValue(newvalue)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function Dragger_OnLeave()
|
||||
this:SetBackdropColor(1, 1, 1, 0)
|
||||
end
|
||||
|
||||
local function Dragger_OnEnter()
|
||||
this:SetBackdropColor(1, 1, 1, 0.8)
|
||||
end
|
||||
|
||||
local function Dragger_OnMouseDown()
|
||||
local treeframe = this:GetParent()
|
||||
treeframe:StartSizing("RIGHT")
|
||||
end
|
||||
|
||||
local function Dragger_OnMouseUp()
|
||||
local treeframe = this:GetParent()
|
||||
local self = treeframe.obj
|
||||
local this = treeframe:GetParent()
|
||||
treeframe:StopMovingOrSizing()
|
||||
--treeframe:SetScript("OnUpdate", nil)
|
||||
treeframe:SetUserPlaced(false)
|
||||
--Without this :GetHeight will get stuck on the current height, causing the tree contents to not resize
|
||||
treeframe:SetHeight(0)
|
||||
treeframe:SetPoint("TOPLEFT", this, "TOPLEFT",0,0)
|
||||
treeframe:SetPoint("BOTTOMLEFT", this, "BOTTOMLEFT",0,0)
|
||||
|
||||
local status = self.status or self.localstatus
|
||||
status.treewidth = treeframe:GetWidth()
|
||||
|
||||
treeframe.obj:Fire("OnTreeResize", 1, treeframe:GetWidth())
|
||||
-- recalculate the content width
|
||||
treeframe.obj:OnWidthSet(status.fullwidth)
|
||||
-- update the layout of the content
|
||||
treeframe.obj:DoLayout()
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods
|
||||
do
|
||||
local select_args = {nil,nil,nil,nil,nil,nil,nil,nil,nil,nil}
|
||||
methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
self:SetTreeWidth(DEFAULT_TREE_WIDTH, DEFAULT_TREE_SIZABLE)
|
||||
self:EnableButtonTooltips(true)
|
||||
self.frame:SetScript("OnUpdate", FirstFrameUpdate)
|
||||
end,
|
||||
|
||||
["OnRelease"] = function(self)
|
||||
self.status = nil
|
||||
for k, v in pairs(self.localstatus) do
|
||||
if k == "groups" then
|
||||
for k2 in pairs(v) do
|
||||
v[k2] = nil
|
||||
end
|
||||
else
|
||||
self.localstatus[k] = nil
|
||||
end
|
||||
end
|
||||
self.localstatus.scrollvalue = 0
|
||||
self.localstatus.treewidth = DEFAULT_TREE_WIDTH
|
||||
self.localstatus.treesizable = DEFAULT_TREE_SIZABLE
|
||||
end,
|
||||
|
||||
["EnableButtonTooltips"] = function(self, enable)
|
||||
self.enabletooltips = enable
|
||||
end,
|
||||
|
||||
["CreateButton"] = function(self)
|
||||
local num = AceGUI:GetNextWidgetNum("TreeGroupButton")
|
||||
|
||||
local button = CreateFrame("Button", strfmt("AceGUI30TreeButton%d", num), self.treeframe)
|
||||
button.obj = self
|
||||
button:SetWidth(175)
|
||||
button:SetHeight(18)
|
||||
|
||||
local toggle = CreateFrame("Button", nil, button)
|
||||
toggle.obj = button
|
||||
button.toggle = toggle
|
||||
toggle:SetWidth(14)
|
||||
toggle:SetHeight(14)
|
||||
toggle:ClearAllPoints()
|
||||
toggle:SetPoint("TOPRIGHT", button, "TOPRIGHT", -6, -1)
|
||||
toggle:SetScript("OnClick", Button_OnClick)
|
||||
toggle:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-UP")
|
||||
toggle:SetPushedTexture("Interface\\Buttons\\UI-MinusButton-DOWN")
|
||||
toggle:SetHighlightTexture("Interface\\Buttons\\UI-PlusButton-Hilight", "ADD")
|
||||
|
||||
local text = button:CreateFontString()
|
||||
button.text = text
|
||||
text:SetFontObject(GameFontNormal)
|
||||
button:SetHighlightFontObject(GameFontHighlight)
|
||||
text:SetPoint("RIGHT", toggle, "LEFT", -2, 0);
|
||||
text:SetJustifyH("LEFT")
|
||||
|
||||
local highlight = button:CreateTexture(nil, "HIGHLIGHT");
|
||||
button.highlight = highlight
|
||||
highlight:SetTexture("Interface\\QuestFrame\\UI-QuestLogTitleHighlight")
|
||||
highlight:SetBlendMode("ADD")
|
||||
highlight:SetVertexColor(.196, .388, .8);
|
||||
highlight:ClearAllPoints()
|
||||
highlight:SetPoint("TOPLEFT",0,1)
|
||||
highlight:SetPoint("BOTTOMRIGHT",0,1)
|
||||
|
||||
local icon = button:CreateTexture(nil, "OVERLAY")
|
||||
icon:SetWidth(14)
|
||||
icon:SetHeight(14)
|
||||
button.icon = icon
|
||||
|
||||
button:SetScript("OnClick",Button_OnClick)
|
||||
button:SetScript("OnDoubleClick", Button_OnDoubleClick)
|
||||
button:SetScript("OnEnter",Button_OnEnter)
|
||||
button:SetScript("OnLeave",Button_OnLeave)
|
||||
|
||||
button.toggle.button = button
|
||||
button.toggle:SetScript("OnClick",Expand_OnClick)
|
||||
|
||||
button.text:SetHeight(14) -- Prevents text wrapping
|
||||
|
||||
return button
|
||||
end,
|
||||
|
||||
["SetStatusTable"] = function(self, status)
|
||||
assert(type(status) == "table")
|
||||
self.status = status
|
||||
if not status.groups then
|
||||
status.groups = {}
|
||||
end
|
||||
if not status.scrollvalue then
|
||||
status.scrollvalue = 0
|
||||
end
|
||||
if not status.treewidth then
|
||||
status.treewidth = DEFAULT_TREE_WIDTH
|
||||
end
|
||||
if status.treesizable == nil then
|
||||
status.treesizable = DEFAULT_TREE_SIZABLE
|
||||
end
|
||||
self:SetTreeWidth(status.treewidth,status.treesizable)
|
||||
self:RefreshTree()
|
||||
end,
|
||||
|
||||
--sets the tree to be displayed
|
||||
["SetTree"] = function(self, tree, filter)
|
||||
self.filter = filter
|
||||
if tree then
|
||||
assert(type(tree) == "table")
|
||||
end
|
||||
self.tree = tree
|
||||
self:RefreshTree()
|
||||
end,
|
||||
|
||||
["BuildLevel"] = function(self, tree, level, parent)
|
||||
local groups = (self.status or self.localstatus).groups
|
||||
local hasChildren = self.hasChildren
|
||||
|
||||
for i, v in ipairs(tree) do
|
||||
if v.children then
|
||||
if not self.filter or ShouldDisplayLevel(v.children) then
|
||||
local line = addLine(self, v, tree, level, parent)
|
||||
if groups[line.uniquevalue] then
|
||||
self:BuildLevel(v.children, level+1, line)
|
||||
end
|
||||
end
|
||||
elseif v.visible ~= false or not self.filter then
|
||||
addLine(self, v, tree, level, parent)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
["RefreshTree"] = function(self,scrollToSelection)
|
||||
local buttons = self.buttons
|
||||
local lines = self.lines
|
||||
|
||||
for i, v in ipairs(buttons) do
|
||||
v:Hide()
|
||||
end
|
||||
while lines[1] do
|
||||
local t = tremove(lines)
|
||||
for k in pairs(t) do
|
||||
t[k] = nil
|
||||
end
|
||||
del(t)
|
||||
end
|
||||
|
||||
if not self.tree then return end
|
||||
--Build the list of visible entries from the tree and status tables
|
||||
local status = self.status or self.localstatus
|
||||
local groupstatus = status.groups
|
||||
local tree = self.tree
|
||||
|
||||
local treeframe = self.treeframe
|
||||
|
||||
status.scrollToSelection = status.scrollToSelection or scrollToSelection -- needs to be cached in case the control hasn't been drawn yet (code bails out below)
|
||||
|
||||
self:BuildLevel(tree, 1)
|
||||
|
||||
local numlines = tgetn(lines)
|
||||
|
||||
local maxlines = (floor(((self.treeframe:GetHeight()or 0) - 20 ) / 18))
|
||||
if maxlines <= 0 then return end
|
||||
|
||||
local first, last
|
||||
|
||||
scrollToSelection = status.scrollToSelection
|
||||
status.scrollToSelection = nil
|
||||
|
||||
if numlines <= maxlines then
|
||||
--the whole tree fits in the frame
|
||||
status.scrollvalue = 0
|
||||
self:ShowScroll(false)
|
||||
first, last = 1, numlines
|
||||
else
|
||||
self:ShowScroll(true)
|
||||
--scrolling will be needed
|
||||
self.noupdate = true
|
||||
self.scrollbar:SetMinMaxValues(0, numlines - maxlines)
|
||||
--check if we are scrolled down too far
|
||||
if numlines - status.scrollvalue < maxlines then
|
||||
status.scrollvalue = numlines - maxlines
|
||||
end
|
||||
self.noupdate = nil
|
||||
first, last = status.scrollvalue+1, status.scrollvalue + maxlines
|
||||
--show selection?
|
||||
if scrollToSelection and status.selected then
|
||||
local show
|
||||
for i,line in ipairs(lines) do -- find the line number
|
||||
if line.uniquevalue==status.selected then
|
||||
show=i
|
||||
end
|
||||
end
|
||||
if not show then
|
||||
-- selection was deleted or something?
|
||||
elseif show>=first and show<=last then
|
||||
-- all good
|
||||
else
|
||||
-- scrolling needed!
|
||||
if show<first then
|
||||
status.scrollvalue = show-1
|
||||
else
|
||||
status.scrollvalue = show-maxlines
|
||||
end
|
||||
first, last = status.scrollvalue+1, status.scrollvalue + maxlines
|
||||
end
|
||||
end
|
||||
if self.scrollbar:GetValue() ~= status.scrollvalue then
|
||||
self.scrollbar:SetValue(status.scrollvalue)
|
||||
end
|
||||
end
|
||||
|
||||
local buttonnum = 1
|
||||
for i = first, last do
|
||||
local line = lines[i]
|
||||
local button = buttons[buttonnum]
|
||||
if not button then
|
||||
button = self:CreateButton()
|
||||
|
||||
buttons[buttonnum] = button
|
||||
button:SetParent(treeframe)
|
||||
button:SetFrameLevel(treeframe:GetFrameLevel()+1)
|
||||
button:ClearAllPoints()
|
||||
if buttonnum == 1 then
|
||||
if self.showscroll then
|
||||
button:SetPoint("TOPRIGHT", -22, -10)
|
||||
button:SetPoint("TOPLEFT", 0, -10)
|
||||
else
|
||||
button:SetPoint("TOPRIGHT", 0, -10)
|
||||
button:SetPoint("TOPLEFT", 0, -10)
|
||||
end
|
||||
else
|
||||
button:SetPoint("TOPRIGHT", buttons[buttonnum-1], "BOTTOMRIGHT",0,0)
|
||||
button:SetPoint("TOPLEFT", buttons[buttonnum-1], "BOTTOMLEFT",0,0)
|
||||
end
|
||||
end
|
||||
|
||||
UpdateButton(button, line, status.selected == line.uniquevalue, line.hasChildren, groupstatus[line.uniquevalue] )
|
||||
button:Show()
|
||||
buttonnum = buttonnum + 1
|
||||
end
|
||||
|
||||
end,
|
||||
|
||||
["SetSelected"] = function(self, value)
|
||||
local status = self.status or self.localstatus
|
||||
if status.selected ~= value then
|
||||
status.selected = value
|
||||
self:Fire("OnGroupSelected", 1, value)
|
||||
end
|
||||
end,
|
||||
|
||||
["Select"] = function(self, uniquevalue, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
|
||||
self.filter = false
|
||||
local status = self.status or self.localstatus
|
||||
local groups = status.groups
|
||||
select_args[1] = a1
|
||||
select_args[2] = a2
|
||||
select_args[3] = a3
|
||||
select_args[4] = a4
|
||||
select_args[5] = a5
|
||||
select_args[6] = a6
|
||||
select_args[7] = a7
|
||||
select_args[8] = a8
|
||||
select_args[9] = a9
|
||||
select_args[10] = a10
|
||||
for i = 1, tgetn(select_args) do
|
||||
groups[tconcat(select_args, "\001", 1, i)] = true
|
||||
end
|
||||
status.selected = uniquevalue
|
||||
self:RefreshTree(true)
|
||||
self:Fire("OnGroupSelected", 1, uniquevalue)
|
||||
end,
|
||||
|
||||
["SelectByPath"] = function(self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
|
||||
self:Select(BuildUniqueValue(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10), a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
|
||||
end,
|
||||
|
||||
["SelectByValue"] = function(self, uniquevalue)
|
||||
self:Select(uniquevalue, strsplit("\001", uniquevalue))
|
||||
end,
|
||||
|
||||
["ShowScroll"] = function(self, show)
|
||||
self.showscroll = show
|
||||
if show then
|
||||
self.scrollbar:Show()
|
||||
if self.buttons[1] then
|
||||
self.buttons[1]:SetPoint("TOPRIGHT", self.treeframe,"TOPRIGHT",-22,-10)
|
||||
end
|
||||
else
|
||||
self.scrollbar:Hide()
|
||||
if self.buttons[1] then
|
||||
self.buttons[1]:SetPoint("TOPRIGHT", self.treeframe,"TOPRIGHT",0,-10)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
["OnWidthSet"] = function(self, width)
|
||||
local content = self.content
|
||||
local treeframe = self.treeframe
|
||||
local status = self.status or self.localstatus
|
||||
status.fullwidth = width
|
||||
|
||||
local contentwidth = width - status.treewidth - 20
|
||||
if contentwidth < 0 then
|
||||
contentwidth = 0
|
||||
end
|
||||
content:SetWidth(contentwidth)
|
||||
content.width = contentwidth
|
||||
|
||||
local maxtreewidth = math_min(400, width - 50)
|
||||
|
||||
if maxtreewidth > 100 and status.treewidth > maxtreewidth then
|
||||
self:SetTreeWidth(maxtreewidth, status.treesizable)
|
||||
end
|
||||
treeframe:SetMaxResize(maxtreewidth, 1600)
|
||||
end,
|
||||
|
||||
["OnHeightSet"] = function(self, height)
|
||||
local content = self.content
|
||||
local contentheight = height - 20
|
||||
if contentheight < 0 then
|
||||
contentheight = 0
|
||||
end
|
||||
content:SetHeight(contentheight)
|
||||
content.height = contentheight
|
||||
end,
|
||||
|
||||
["SetTreeWidth"] = function(self, treewidth, resizable)
|
||||
if not resizable then
|
||||
if type(treewidth) == 'number' then
|
||||
resizable = false
|
||||
elseif type(treewidth) == 'boolean' then
|
||||
resizable = treewidth
|
||||
treewidth = DEFAULT_TREE_WIDTH
|
||||
else
|
||||
resizable = false
|
||||
treewidth = DEFAULT_TREE_WIDTH
|
||||
end
|
||||
end
|
||||
self.treeframe:SetWidth(treewidth)
|
||||
self.dragger:EnableMouse(resizable)
|
||||
|
||||
local status = self.status or self.localstatus
|
||||
status.treewidth = treewidth
|
||||
status.treesizable = resizable
|
||||
|
||||
-- recalculate the content width
|
||||
if status.fullwidth then
|
||||
self:OnWidthSet(status.fullwidth)
|
||||
end
|
||||
end,
|
||||
|
||||
["GetTreeWidth"] = function(self)
|
||||
local status = self.status or self.localstatus
|
||||
return status.treewidth or DEFAULT_TREE_WIDTH
|
||||
end,
|
||||
|
||||
["LayoutFinished"] = function(self, width, height)
|
||||
if self.noAutoHeight then return end
|
||||
self:SetHeight((height or 0) + 20)
|
||||
end
|
||||
}
|
||||
end -- method
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local PaneBackdrop = {
|
||||
bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
|
||||
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
||||
tile = true, tileSize = 16, edgeSize = 16,
|
||||
insets = { left = 3, right = 3, top = 5, bottom = 3 }
|
||||
}
|
||||
|
||||
local DraggerBackdrop = {
|
||||
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
|
||||
edgeFile = nil,
|
||||
tile = true, tileSize = 16, edgeSize = 0,
|
||||
insets = { left = 3, right = 3, top = 7, bottom = 7 }
|
||||
}
|
||||
|
||||
local function Constructor()
|
||||
local num = AceGUI:GetNextWidgetNum(Type)
|
||||
local frame = CreateFrame("Frame", nil, UIParent)
|
||||
|
||||
local treeframe = CreateFrame("Frame", nil, frame)
|
||||
treeframe:SetPoint("TOPLEFT", 0, 0)
|
||||
treeframe:SetPoint("BOTTOMLEFT", 0, 0)
|
||||
treeframe:SetWidth(DEFAULT_TREE_WIDTH)
|
||||
treeframe:EnableMouseWheel(true)
|
||||
treeframe:SetBackdrop(PaneBackdrop)
|
||||
treeframe:SetBackdropColor(0.1, 0.1, 0.1, 0.5)
|
||||
treeframe:SetBackdropBorderColor(0.4, 0.4, 0.4)
|
||||
treeframe:SetResizable(true)
|
||||
treeframe:SetMinResize(100, 1)
|
||||
treeframe:SetMaxResize(400, 1600)
|
||||
treeframe:SetScript("OnUpdate", FirstFrameUpdate)
|
||||
treeframe:SetScript("OnSizeChanged", Tree_OnSizeChanged)
|
||||
treeframe:SetScript("OnMouseWheel", Tree_OnMouseWheel)
|
||||
|
||||
local dragger = CreateFrame("Frame", nil, treeframe)
|
||||
dragger:SetWidth(8)
|
||||
dragger:SetPoint("TOP", treeframe, "TOPRIGHT")
|
||||
dragger:SetPoint("BOTTOM", treeframe, "BOTTOMRIGHT")
|
||||
dragger:SetBackdrop(DraggerBackdrop)
|
||||
dragger:SetBackdropColor(1, 1, 1, 0)
|
||||
dragger:SetScript("OnEnter", Dragger_OnEnter)
|
||||
dragger:SetScript("OnLeave", Dragger_OnLeave)
|
||||
dragger:SetScript("OnMouseDown", Dragger_OnMouseDown)
|
||||
dragger:SetScript("OnMouseUp", Dragger_OnMouseUp)
|
||||
|
||||
local scrollbar = CreateFrame("Slider", strfmt("AceConfigDialogTreeGroup%dScrollBar", num), treeframe, "UIPanelScrollBarTemplate")
|
||||
scrollbar:SetScript("OnValueChanged", nil)
|
||||
scrollbar:SetPoint("TOPRIGHT", -10, -26)
|
||||
scrollbar:SetPoint("BOTTOMRIGHT", -10, 26)
|
||||
scrollbar:SetMinMaxValues(0,0)
|
||||
scrollbar:SetValueStep(1)
|
||||
scrollbar:SetValue(0)
|
||||
scrollbar:SetWidth(16)
|
||||
scrollbar:SetScript("OnValueChanged", OnScrollValueChanged)
|
||||
|
||||
local scrollbg = scrollbar:CreateTexture(nil, "BACKGROUND")
|
||||
scrollbg:SetAllPoints(scrollbar)
|
||||
scrollbg:SetTexture(0,0,0,0.4)
|
||||
|
||||
local border = CreateFrame("Frame",nil,frame)
|
||||
border:SetPoint("TOPLEFT", treeframe, "TOPRIGHT")
|
||||
border:SetPoint("BOTTOMRIGHT", 0, 0)
|
||||
border:SetBackdrop(PaneBackdrop)
|
||||
border:SetBackdropColor(0.1, 0.1, 0.1, 0.5)
|
||||
border:SetBackdropBorderColor(0.4, 0.4, 0.4)
|
||||
|
||||
--Container Support
|
||||
local content = CreateFrame("Frame", nil, border)
|
||||
content:SetPoint("TOPLEFT", 10, -10)
|
||||
content:SetPoint("BOTTOMRIGHT", -10, 10)
|
||||
|
||||
local widget = {
|
||||
frame = frame,
|
||||
lines = {},
|
||||
levels = {},
|
||||
buttons = {},
|
||||
hasChildren = {},
|
||||
localstatus = { groups = {}, scrollvalue = 0 },
|
||||
filter = false,
|
||||
treeframe = treeframe,
|
||||
dragger = dragger,
|
||||
scrollbar = scrollbar,
|
||||
border = border,
|
||||
content = content,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
treeframe.obj, dragger.obj, scrollbar.obj = widget, widget, widget
|
||||
|
||||
return AceGUI:RegisterAsContainer(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
@@ -0,0 +1,331 @@
|
||||
local AceGUI = LibStub("AceGUI-3.0")
|
||||
|
||||
-- Lua APIs
|
||||
local pairs, assert, type = pairs, assert, type
|
||||
|
||||
-- WoW APIs
|
||||
local PlaySound = PlaySound
|
||||
local CreateFrame, UIParent = CreateFrame, UIParent
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: GameFontNormal
|
||||
|
||||
----------------
|
||||
-- Main Frame --
|
||||
----------------
|
||||
--[[
|
||||
Events :
|
||||
OnClose
|
||||
|
||||
]]
|
||||
do
|
||||
local Type = "Window"
|
||||
local Version = 4
|
||||
|
||||
local function frameOnClose()
|
||||
this.obj:Fire("OnClose")
|
||||
end
|
||||
|
||||
local function closeOnClick()
|
||||
PlaySound("gsTitleOptionExit")
|
||||
this.obj:Hide()
|
||||
end
|
||||
|
||||
local function frameOnMouseDown()
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
local function titleOnMouseDown()
|
||||
this:GetParent():StartMoving()
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
local function frameOnMouseUp()
|
||||
local frame = this:GetParent()
|
||||
frame:StopMovingOrSizing()
|
||||
local self = frame.obj
|
||||
local status = self.status or self.localstatus
|
||||
status.width = frame:GetWidth()
|
||||
status.height = frame:GetHeight()
|
||||
status.top = frame:GetTop()
|
||||
status.left = frame:GetLeft()
|
||||
end
|
||||
|
||||
local function sizerseOnMouseDown()
|
||||
this:GetParent():StartSizing("BOTTOMRIGHT")
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
local function sizersOnMouseDown()
|
||||
this:GetParent():StartSizing("BOTTOM")
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
local function sizereOnMouseDown()
|
||||
this:GetParent():StartSizing("RIGHT")
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
local function sizerOnMouseUp()
|
||||
this:GetParent():StopMovingOrSizing()
|
||||
end
|
||||
|
||||
local function SetTitle(self,title)
|
||||
self.titletext:SetText(title)
|
||||
end
|
||||
|
||||
local function SetStatusText(self,text)
|
||||
-- self.statustext:SetText(text)
|
||||
end
|
||||
|
||||
local function Hide(self)
|
||||
self.frame:Hide()
|
||||
end
|
||||
|
||||
local function Show(self)
|
||||
self.frame:Show()
|
||||
end
|
||||
|
||||
local function OnAcquire(self)
|
||||
self.frame:SetParent(UIParent)
|
||||
self.frame:SetFrameStrata("FULLSCREEN_DIALOG")
|
||||
self:ApplyStatus()
|
||||
self:EnableResize(true)
|
||||
self:Show()
|
||||
end
|
||||
|
||||
local function OnRelease(self)
|
||||
self.status = nil
|
||||
for k in pairs(self.localstatus) do
|
||||
self.localstatus[k] = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- called to set an external table to store status in
|
||||
local function SetStatusTable(self, status)
|
||||
assert(type(status) == "table")
|
||||
self.status = status
|
||||
self:ApplyStatus()
|
||||
end
|
||||
|
||||
local function ApplyStatus(self)
|
||||
local status = self.status or self.localstatus
|
||||
local frame = self.frame
|
||||
self:SetWidth(status.width or 700)
|
||||
self:SetHeight(status.height or 500)
|
||||
if status.top and status.left then
|
||||
frame:SetPoint("TOP",UIParent,"BOTTOM",0,status.top)
|
||||
frame:SetPoint("LEFT",UIParent,"LEFT",status.left,0)
|
||||
else
|
||||
frame:SetPoint("CENTER",UIParent,"CENTER")
|
||||
end
|
||||
end
|
||||
|
||||
local function OnWidthSet(self, width)
|
||||
local content = self.content
|
||||
local contentwidth = width - 34
|
||||
if contentwidth < 0 then
|
||||
contentwidth = 0
|
||||
end
|
||||
content:SetWidth(contentwidth)
|
||||
content.width = contentwidth
|
||||
end
|
||||
|
||||
|
||||
local function OnHeightSet(self, height)
|
||||
local content = self.content
|
||||
local contentheight = height - 57
|
||||
if contentheight < 0 then
|
||||
contentheight = 0
|
||||
end
|
||||
content:SetHeight(contentheight)
|
||||
content.height = contentheight
|
||||
end
|
||||
|
||||
local function EnableResize(self, state)
|
||||
local func = state and "Show" or "Hide"
|
||||
self.sizer_se[func](self.sizer_se)
|
||||
self.sizer_s[func](self.sizer_s)
|
||||
self.sizer_e[func](self.sizer_e)
|
||||
end
|
||||
|
||||
local function Constructor()
|
||||
local frame = CreateFrame("Frame",nil,UIParent)
|
||||
local self = {}
|
||||
self.type = "Window"
|
||||
|
||||
self.Hide = Hide
|
||||
self.Show = Show
|
||||
self.SetTitle = SetTitle
|
||||
self.OnRelease = OnRelease
|
||||
self.OnAcquire = OnAcquire
|
||||
self.SetStatusText = SetStatusText
|
||||
self.SetStatusTable = SetStatusTable
|
||||
self.ApplyStatus = ApplyStatus
|
||||
self.OnWidthSet = OnWidthSet
|
||||
self.OnHeightSet = OnHeightSet
|
||||
self.EnableResize = EnableResize
|
||||
|
||||
self.localstatus = {}
|
||||
|
||||
self.frame = frame
|
||||
frame.obj = self
|
||||
frame:SetWidth(700)
|
||||
frame:SetHeight(500)
|
||||
frame:SetPoint("CENTER",UIParent,"CENTER",0,0)
|
||||
frame:EnableMouse()
|
||||
frame:SetMovable(true)
|
||||
frame:SetResizable(true)
|
||||
frame:SetFrameStrata("FULLSCREEN_DIALOG")
|
||||
frame:SetScript("OnMouseDown", frameOnMouseDown)
|
||||
|
||||
frame:SetScript("OnHide",frameOnClose)
|
||||
frame:SetMinResize(240,240)
|
||||
frame:SetToplevel(true)
|
||||
|
||||
local titlebg = frame:CreateTexture(nil, "BACKGROUND")
|
||||
titlebg:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Title-Background]])
|
||||
titlebg:SetPoint("TOPLEFT", 9, -6)
|
||||
titlebg:SetPoint("BOTTOMRIGHT", frame, "TOPRIGHT", -28, -24)
|
||||
|
||||
local dialogbg = frame:CreateTexture(nil, "BACKGROUND")
|
||||
dialogbg:SetTexture([[Interface\Tooltips\UI-Tooltip-Background]])
|
||||
dialogbg:SetPoint("TOPLEFT", 8, -24)
|
||||
dialogbg:SetPoint("BOTTOMRIGHT", -6, 8)
|
||||
dialogbg:SetVertexColor(0, 0, 0, .75)
|
||||
|
||||
local topleft = frame:CreateTexture(nil, "BORDER")
|
||||
topleft:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
|
||||
topleft:SetWidth(64)
|
||||
topleft:SetHeight(64)
|
||||
topleft:SetPoint("TOPLEFT")
|
||||
topleft:SetTexCoord(0.501953125, 0.625, 0, 1)
|
||||
|
||||
local topright = frame:CreateTexture(nil, "BORDER")
|
||||
topright:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
|
||||
topright:SetWidth(64)
|
||||
topright:SetHeight(64)
|
||||
topright:SetPoint("TOPRIGHT")
|
||||
topright:SetTexCoord(0.625, 0.75, 0, 1)
|
||||
|
||||
local top = frame:CreateTexture(nil, "BORDER")
|
||||
top:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
|
||||
top:SetHeight(64)
|
||||
top:SetPoint("TOPLEFT", topleft, "TOPRIGHT")
|
||||
top:SetPoint("TOPRIGHT", topright, "TOPLEFT")
|
||||
top:SetTexCoord(0.25, 0.369140625, 0, 1)
|
||||
|
||||
local bottomleft = frame:CreateTexture(nil, "BORDER")
|
||||
bottomleft:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
|
||||
bottomleft:SetWidth(64)
|
||||
bottomleft:SetHeight(64)
|
||||
bottomleft:SetPoint("BOTTOMLEFT")
|
||||
bottomleft:SetTexCoord(0.751953125, 0.875, 0, 1)
|
||||
|
||||
local bottomright = frame:CreateTexture(nil, "BORDER")
|
||||
bottomright:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
|
||||
bottomright:SetWidth(64)
|
||||
bottomright:SetHeight(64)
|
||||
bottomright:SetPoint("BOTTOMRIGHT")
|
||||
bottomright:SetTexCoord(0.875, 1, 0, 1)
|
||||
|
||||
local bottom = frame:CreateTexture(nil, "BORDER")
|
||||
bottom:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
|
||||
bottom:SetHeight(64)
|
||||
bottom:SetPoint("BOTTOMLEFT", bottomleft, "BOTTOMRIGHT")
|
||||
bottom:SetPoint("BOTTOMRIGHT", bottomright, "BOTTOMLEFT")
|
||||
bottom:SetTexCoord(0.376953125, 0.498046875, 0, 1)
|
||||
|
||||
local left = frame:CreateTexture(nil, "BORDER")
|
||||
left:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
|
||||
left:SetWidth(64)
|
||||
left:SetPoint("TOPLEFT", topleft, "BOTTOMLEFT")
|
||||
left:SetPoint("BOTTOMLEFT", bottomleft, "TOPLEFT")
|
||||
left:SetTexCoord(0.001953125, 0.125, 0, 1)
|
||||
|
||||
local right = frame:CreateTexture(nil, "BORDER")
|
||||
right:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
|
||||
right:SetWidth(64)
|
||||
right:SetPoint("TOPRIGHT", topright, "BOTTOMRIGHT")
|
||||
right:SetPoint("BOTTOMRIGHT", bottomright, "TOPRIGHT")
|
||||
right:SetTexCoord(0.1171875, 0.2421875, 0, 1)
|
||||
|
||||
local close = CreateFrame("Button", nil, frame, "UIPanelCloseButton")
|
||||
close:SetPoint("TOPRIGHT", 2, 1)
|
||||
close:SetScript("OnClick", closeOnClick)
|
||||
self.closebutton = close
|
||||
close.obj = self
|
||||
|
||||
local titletext = frame:CreateFontString(nil, "ARTWORK")
|
||||
titletext:SetFontObject(GameFontNormal)
|
||||
titletext:SetPoint("TOPLEFT", 12, -8)
|
||||
titletext:SetPoint("TOPRIGHT", -32, -8)
|
||||
self.titletext = titletext
|
||||
|
||||
local title = CreateFrame("Button", nil, frame)
|
||||
title:SetPoint("TOPLEFT", titlebg)
|
||||
title:SetPoint("BOTTOMRIGHT", titlebg)
|
||||
title:EnableMouse()
|
||||
title:SetScript("OnMouseDown",titleOnMouseDown)
|
||||
title:SetScript("OnMouseUp", frameOnMouseUp)
|
||||
self.title = title
|
||||
|
||||
local sizer_se = CreateFrame("Frame",nil,frame)
|
||||
sizer_se:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",0,0)
|
||||
sizer_se:SetWidth(25)
|
||||
sizer_se:SetHeight(25)
|
||||
sizer_se:EnableMouse()
|
||||
sizer_se:SetScript("OnMouseDown",sizerseOnMouseDown)
|
||||
sizer_se:SetScript("OnMouseUp", sizerOnMouseUp)
|
||||
self.sizer_se = sizer_se
|
||||
|
||||
local line1 = sizer_se:CreateTexture(nil, "BACKGROUND")
|
||||
self.line1 = line1
|
||||
line1:SetWidth(14)
|
||||
line1:SetHeight(14)
|
||||
line1:SetPoint("BOTTOMRIGHT", -8, 8)
|
||||
line1:SetTexture("Interface\\Tooltips\\UI-Tooltip-Border")
|
||||
local x = 0.1 * 14/17
|
||||
line1:SetTexCoord(0.05 - x, 0.5, 0.05, 0.5 + x, 0.05, 0.5 - x, 0.5 + x, 0.5)
|
||||
|
||||
local line2 = sizer_se:CreateTexture(nil, "BACKGROUND")
|
||||
self.line2 = line2
|
||||
line2:SetWidth(8)
|
||||
line2:SetHeight(8)
|
||||
line2:SetPoint("BOTTOMRIGHT", -8, 8)
|
||||
line2:SetTexture("Interface\\Tooltips\\UI-Tooltip-Border")
|
||||
local x = 0.1 * 8/17
|
||||
line2:SetTexCoord(0.05 - x, 0.5, 0.05, 0.5 + x, 0.05, 0.5 - x, 0.5 + x, 0.5)
|
||||
|
||||
local sizer_s = CreateFrame("Frame",nil,frame)
|
||||
sizer_s:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",-25,0)
|
||||
sizer_s:SetPoint("BOTTOMLEFT",frame,"BOTTOMLEFT",0,0)
|
||||
sizer_s:SetHeight(25)
|
||||
sizer_s:EnableMouse()
|
||||
sizer_s:SetScript("OnMouseDown",sizersOnMouseDown)
|
||||
sizer_s:SetScript("OnMouseUp", sizerOnMouseUp)
|
||||
self.sizer_s = sizer_s
|
||||
|
||||
local sizer_e = CreateFrame("Frame",nil,frame)
|
||||
sizer_e:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",0,25)
|
||||
sizer_e:SetPoint("TOPRIGHT",frame,"TOPRIGHT",0,0)
|
||||
sizer_e:SetWidth(25)
|
||||
sizer_e:EnableMouse()
|
||||
sizer_e:SetScript("OnMouseDown",sizereOnMouseDown)
|
||||
sizer_e:SetScript("OnMouseUp", sizerOnMouseUp)
|
||||
self.sizer_e = sizer_e
|
||||
|
||||
--Container Support
|
||||
local content = CreateFrame("Frame",nil,frame)
|
||||
self.content = content
|
||||
content.obj = self
|
||||
content:SetPoint("TOPLEFT",frame,"TOPLEFT",12,-32)
|
||||
content:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",-12,13)
|
||||
|
||||
AceGUI:RegisterAsContainer(self)
|
||||
return self
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type,Constructor,Version)
|
||||
end
|
||||
@@ -0,0 +1,106 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Button Widget
|
||||
Graphical Button.
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "Button", 23
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
local AceCore = LibStub("AceCore-3.0")
|
||||
|
||||
-- Lua APIs
|
||||
local pairs = pairs
|
||||
|
||||
-- WoW APIs
|
||||
local _G = AceCore._G
|
||||
local PlaySound, CreateFrame, UIParent = PlaySound, CreateFrame, UIParent
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Scripts
|
||||
-------------------------------------------------------------------------------]]
|
||||
-- arg1 is the button for OnClick event
|
||||
local function Button_OnClick()
|
||||
AceGUI:ClearFocus()
|
||||
PlaySound("igMainMenuOption")
|
||||
this.obj:Fire("OnClick", 1, arg1)
|
||||
end
|
||||
|
||||
local function Control_OnEnter()
|
||||
this.obj:Fire("OnEnter")
|
||||
end
|
||||
|
||||
local function Control_OnLeave()
|
||||
this.obj:Fire("OnLeave")
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
-- restore default values
|
||||
self:SetHeight(24)
|
||||
self:SetWidth(200)
|
||||
self:SetDisabled(false)
|
||||
self:SetAutoWidth(false)
|
||||
self:SetText()
|
||||
end,
|
||||
|
||||
-- ["OnRelease"] = nil,
|
||||
|
||||
["SetText"] = function(self, text)
|
||||
self.text:SetText(text)
|
||||
if self.autoWidth then
|
||||
self:SetWidth(self.text:GetStringWidth() + 30)
|
||||
end
|
||||
end,
|
||||
|
||||
["SetAutoWidth"] = function(self, autoWidth)
|
||||
self.autoWidth = autoWidth
|
||||
if self.autoWidth then
|
||||
self:SetWidth(self.text:GetStringWidth() + 30)
|
||||
end
|
||||
end,
|
||||
|
||||
["SetDisabled"] = function(self, disabled)
|
||||
self.disabled = disabled
|
||||
if disabled then
|
||||
self.frame:Disable()
|
||||
else
|
||||
self.frame:Enable()
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Constructor()
|
||||
local name = "AceGUI30Button" .. AceGUI:GetNextWidgetNum(Type)
|
||||
local frame = CreateFrame("Button", name, UIParent, "UIPanelButtonTemplate2")
|
||||
frame:Hide()
|
||||
|
||||
frame:EnableMouse(true)
|
||||
frame:SetScript("OnClick", Button_OnClick)
|
||||
frame:SetScript("OnEnter", Control_OnEnter)
|
||||
frame:SetScript("OnLeave", Control_OnLeave)
|
||||
|
||||
local text = frame:GetFontString()
|
||||
text:ClearAllPoints()
|
||||
text:SetPoint("TOPLEFT", 15, -1)
|
||||
text:SetPoint("BOTTOMRIGHT", -15, 1)
|
||||
text:SetJustifyV("MIDDLE")
|
||||
|
||||
local widget = {
|
||||
text = text,
|
||||
frame = frame,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
|
||||
return AceGUI:RegisterAsWidget(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
@@ -0,0 +1,296 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Checkbox Widget
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "CheckBox", 22
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
-- Lua APIs
|
||||
local pairs = pairs
|
||||
|
||||
-- WoW APIs
|
||||
local PlaySound = PlaySound
|
||||
local CreateFrame, UIParent = CreateFrame, UIParent
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: SetDesaturation, GameFontHighlight
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Support functions
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function AlignImage(self)
|
||||
local img = self.image:GetTexture()
|
||||
self.text:ClearAllPoints()
|
||||
if not img then
|
||||
self.text:SetPoint("LEFT", self.checkbg, "RIGHT")
|
||||
self.text:SetPoint("RIGHT",0,0)
|
||||
else
|
||||
self.text:SetPoint("LEFT", self.image,"RIGHT", 1, 0)
|
||||
self.text:SetPoint("RIGHT",0,0)
|
||||
end
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Scripts
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Control_OnEnter()
|
||||
this.obj:Fire("OnEnter")
|
||||
end
|
||||
|
||||
local function Control_OnLeave()
|
||||
this.obj:Fire("OnLeave")
|
||||
end
|
||||
|
||||
local function CheckBox_OnMouseDown()
|
||||
local self = this.obj
|
||||
if not self.disabled then
|
||||
if self.image:GetTexture() then
|
||||
self.text:SetPoint("LEFT", self.image,"RIGHT", 2, -1)
|
||||
else
|
||||
self.text:SetPoint("LEFT", self.checkbg, "RIGHT", 1, -1)
|
||||
end
|
||||
end
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
local function CheckBox_OnMouseUp()
|
||||
|
||||
local self = this.obj
|
||||
if not self.disabled then
|
||||
self:ToggleChecked()
|
||||
|
||||
if self.checked then
|
||||
PlaySound("igMainMenuOptionCheckBoxOn")
|
||||
else -- for both nil and false (tristate)
|
||||
PlaySound("igMainMenuOptionCheckBoxOff")
|
||||
end
|
||||
|
||||
self:Fire("OnValueChanged", 1, self.checked)
|
||||
AlignImage(self)
|
||||
end
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
self:SetType()
|
||||
self:SetValue(false)
|
||||
self:SetTriState(nil)
|
||||
-- height is calculated from the width and required space for the description
|
||||
self:SetWidth(200)
|
||||
self:SetImage()
|
||||
self:SetDisabled(nil)
|
||||
self:SetDescription(nil)
|
||||
end,
|
||||
|
||||
-- ["OnRelease"] = nil,
|
||||
|
||||
["OnWidthSet"] = function(self, width)
|
||||
if self.desc then
|
||||
self.desc:SetWidth(width - 30)
|
||||
if self.desc:GetText() and self.desc:GetText() ~= "" then
|
||||
self:SetHeight(28 + self.desc:GetHeight())
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
["SetDisabled"] = function(self, disabled)
|
||||
self.disabled = disabled
|
||||
if disabled then
|
||||
self.frame:Disable()
|
||||
self.text:SetTextColor(0.5, 0.5, 0.5)
|
||||
SetDesaturation(self.check, true)
|
||||
if self.desc then
|
||||
self.desc:SetTextColor(0.5, 0.5, 0.5)
|
||||
end
|
||||
else
|
||||
self.frame:Enable()
|
||||
self.text:SetTextColor(1, 1, 1)
|
||||
if self.tristate and self.checked == nil then
|
||||
SetDesaturation(self.check, true)
|
||||
else
|
||||
SetDesaturation(self.check, false)
|
||||
end
|
||||
if self.desc then
|
||||
self.desc:SetTextColor(1, 1, 1)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
["SetValue"] = function(self,value)
|
||||
local check = self.check
|
||||
self.checked = value
|
||||
if value then
|
||||
SetDesaturation(self.check, false)
|
||||
self.check:Show()
|
||||
else
|
||||
--Nil is the unknown tristate value
|
||||
if self.tristate and value == nil then
|
||||
SetDesaturation(self.check, true)
|
||||
self.check:Show()
|
||||
else
|
||||
SetDesaturation(self.check, false)
|
||||
self.check:Hide()
|
||||
end
|
||||
end
|
||||
self:SetDisabled(self.disabled)
|
||||
end,
|
||||
|
||||
["GetValue"] = function(self)
|
||||
return self.checked
|
||||
end,
|
||||
|
||||
["SetTriState"] = function(self, enabled)
|
||||
self.tristate = enabled
|
||||
self:SetValue(self:GetValue())
|
||||
end,
|
||||
|
||||
["SetType"] = function(self, type)
|
||||
local checkbg = self.checkbg
|
||||
local check = self.check
|
||||
local highlight = self.highlight
|
||||
|
||||
local size
|
||||
if type == "radio" then
|
||||
size = 16
|
||||
checkbg:SetTexture("Interface\\Buttons\\UI-RadioButton")
|
||||
checkbg:SetTexCoord(0, 0.25, 0, 1)
|
||||
check:SetTexture("Interface\\Buttons\\UI-RadioButton")
|
||||
check:SetTexCoord(0.25, 0.5, 0, 1)
|
||||
check:SetBlendMode("ADD")
|
||||
highlight:SetTexture("Interface\\Buttons\\UI-RadioButton")
|
||||
highlight:SetTexCoord(0.5, 0.75, 0, 1)
|
||||
else
|
||||
size = 24
|
||||
checkbg:SetTexture("Interface\\Buttons\\UI-CheckBox-Up")
|
||||
checkbg:SetTexCoord(0, 1, 0, 1)
|
||||
check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
|
||||
check:SetTexCoord(0, 1, 0, 1)
|
||||
check:SetBlendMode("BLEND")
|
||||
highlight:SetTexture("Interface\\Buttons\\UI-CheckBox-Highlight")
|
||||
highlight:SetTexCoord(0, 1, 0, 1)
|
||||
end
|
||||
|
||||
checkbg:SetHeight(size)
|
||||
checkbg:SetWidth(size)
|
||||
end,
|
||||
|
||||
["ToggleChecked"] = function(self)
|
||||
local value = self:GetValue()
|
||||
if self.tristate then
|
||||
--cycle in true, nil, false order
|
||||
if value then
|
||||
self:SetValue(nil)
|
||||
elseif value == nil then
|
||||
self:SetValue(false)
|
||||
else
|
||||
self:SetValue(true)
|
||||
end
|
||||
else
|
||||
self:SetValue(not self:GetValue())
|
||||
end
|
||||
end,
|
||||
|
||||
["SetLabel"] = function(self, label)
|
||||
self.text:SetText(label)
|
||||
end,
|
||||
|
||||
["SetDescription"] = function(self, desc)
|
||||
if desc then
|
||||
if not self.desc then
|
||||
local desc = self.frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
|
||||
desc:ClearAllPoints()
|
||||
desc:SetPoint("TOPLEFT", self.checkbg, "TOPRIGHT", 5, -21)
|
||||
desc:SetWidth(self.frame.width - 30)
|
||||
desc:SetJustifyH("LEFT")
|
||||
desc:SetJustifyV("TOP")
|
||||
self.desc = desc
|
||||
end
|
||||
self.desc:Show()
|
||||
--self.text:SetFontObject(GameFontNormal)
|
||||
self.desc:SetText(desc)
|
||||
self:SetHeight(28 + self.desc:GetHeight())
|
||||
else
|
||||
if self.desc then
|
||||
self.desc:SetText("")
|
||||
self.desc:Hide()
|
||||
end
|
||||
--self.text:SetFontObject(GameFontHighlight)
|
||||
self:SetHeight(24)
|
||||
end
|
||||
end,
|
||||
|
||||
["SetImage"] = function(self, path, a1,a2,a3,a4,a5,a6,a7,a8)
|
||||
local image = self.image
|
||||
image:SetTexture(path)
|
||||
|
||||
if image:GetTexture() then
|
||||
if a4 or a8 then
|
||||
image:SetTexCoord(a1,a2,a3,a4,a5,a6,a7,a8)
|
||||
else
|
||||
image:SetTexCoord(0, 1, 0, 1)
|
||||
end
|
||||
end
|
||||
AlignImage(self)
|
||||
end
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Constructor()
|
||||
local frame = CreateFrame("Button", nil, UIParent)
|
||||
frame:Hide()
|
||||
|
||||
frame:EnableMouse(true)
|
||||
frame:SetScript("OnEnter", Control_OnEnter)
|
||||
frame:SetScript("OnLeave", Control_OnLeave)
|
||||
frame:SetScript("OnMouseDown", CheckBox_OnMouseDown)
|
||||
frame:SetScript("OnMouseUp", CheckBox_OnMouseUp)
|
||||
|
||||
local checkbg = frame:CreateTexture(nil, "ARTWORK")
|
||||
checkbg:SetWidth(24)
|
||||
checkbg:SetHeight(24)
|
||||
checkbg:SetPoint("TOPLEFT",0,0)
|
||||
checkbg:SetTexture("Interface\\Buttons\\UI-CheckBox-Up")
|
||||
|
||||
local check = frame:CreateTexture(nil, "OVERLAY")
|
||||
check:SetAllPoints(checkbg)
|
||||
check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
|
||||
|
||||
local text = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
|
||||
text:SetJustifyH("LEFT")
|
||||
text:SetHeight(18)
|
||||
text:SetPoint("LEFT", checkbg, "RIGHT")
|
||||
text:SetPoint("RIGHT",0,0)
|
||||
|
||||
local highlight = frame:CreateTexture(nil, "HIGHLIGHT")
|
||||
highlight:SetTexture("Interface\\Buttons\\UI-CheckBox-Highlight")
|
||||
highlight:SetBlendMode("ADD")
|
||||
highlight:SetAllPoints(checkbg)
|
||||
|
||||
local image = frame:CreateTexture(nil, "OVERLAY")
|
||||
image:SetHeight(16)
|
||||
image:SetWidth(16)
|
||||
image:SetPoint("LEFT", checkbg, "RIGHT", 1, 0)
|
||||
|
||||
local widget = {
|
||||
checkbg = checkbg,
|
||||
check = check,
|
||||
text = text,
|
||||
highlight = highlight,
|
||||
image = image,
|
||||
frame = frame,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
|
||||
return AceGUI:RegisterAsWidget(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
@@ -0,0 +1,187 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
ColorPicker Widget
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "ColorPicker", 23
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
-- Lua APIs
|
||||
local pairs = pairs
|
||||
|
||||
-- WoW APIs
|
||||
local CreateFrame, UIParent = CreateFrame, UIParent
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: ShowUIPanel, HideUIPanel, ColorPickerFrame, OpacitySliderFrame
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Support functions
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function ColorCallback(self, r, g, b, a, isAlpha)
|
||||
if not self.HasAlpha then
|
||||
a = 1
|
||||
end
|
||||
self:SetColor(r, g, b, a)
|
||||
if ColorPickerFrame:IsVisible() then
|
||||
--colorpicker is still open
|
||||
self:Fire("OnValueChanged", 4, r, g, b, a)
|
||||
else
|
||||
--colorpicker is closed, color callback is first, ignore it,
|
||||
--alpha callback is the final call after it closes so confirm now
|
||||
if isAlpha then
|
||||
self:Fire("OnValueConfirmed", 4, r, g, b, a)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Scripts
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Control_OnEnter()
|
||||
this.obj:Fire("OnEnter")
|
||||
end
|
||||
|
||||
local function Control_OnLeave()
|
||||
this.obj:Fire("OnLeave")
|
||||
end
|
||||
|
||||
local function ColorSwatch_OnClick()
|
||||
HideUIPanel(ColorPickerFrame)
|
||||
local self = this.obj
|
||||
if not self.disabled then
|
||||
ColorPickerFrame:SetFrameStrata("FULLSCREEN_DIALOG")
|
||||
ColorPickerFrame:SetClampedToScreen(true)
|
||||
|
||||
ColorPickerFrame.func = function()
|
||||
local r, g, b = ColorPickerFrame:GetColorRGB()
|
||||
local a = 1 - OpacitySliderFrame:GetValue()
|
||||
ColorCallback(self, r, g, b, a)
|
||||
end
|
||||
|
||||
ColorPickerFrame.hasOpacity = self.HasAlpha
|
||||
ColorPickerFrame.opacityFunc = function()
|
||||
local r, g, b = ColorPickerFrame:GetColorRGB()
|
||||
local a = 1 - OpacitySliderFrame:GetValue()
|
||||
ColorCallback(self, r, g, b, a, true)
|
||||
end
|
||||
|
||||
local r, g, b, a = self.r, self.g, self.b, self.a
|
||||
if self.HasAlpha then
|
||||
ColorPickerFrame.opacity = 1 - (a or 0)
|
||||
end
|
||||
ColorPickerFrame:SetColorRGB(r, g, b)
|
||||
|
||||
ColorPickerFrame.cancelFunc = function()
|
||||
ColorCallback(self, r, g, b, a, true)
|
||||
end
|
||||
|
||||
ShowUIPanel(ColorPickerFrame)
|
||||
end
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
self:SetHeight(24)
|
||||
self:SetWidth(200)
|
||||
self:SetHasAlpha(false)
|
||||
self:SetColor(0, 0, 0, 1)
|
||||
self:SetDisabled(nil)
|
||||
self:SetLabel(nil)
|
||||
end,
|
||||
|
||||
-- ["OnRelease"] = nil,
|
||||
|
||||
["SetLabel"] = function(self, text)
|
||||
self.text:SetText(text)
|
||||
end,
|
||||
|
||||
["SetColor"] = function(self, r, g, b, a)
|
||||
self.r = r
|
||||
self.g = g
|
||||
self.b = b
|
||||
self.a = a or 1
|
||||
self.colorSwatch:SetVertexColor(r, g, b, a)
|
||||
end,
|
||||
|
||||
["SetHasAlpha"] = function(self, HasAlpha)
|
||||
self.HasAlpha = HasAlpha
|
||||
end,
|
||||
|
||||
["SetDisabled"] = function(self, disabled)
|
||||
self.disabled = disabled
|
||||
if self.disabled then
|
||||
self.frame:Disable()
|
||||
self.text:SetTextColor(0.5, 0.5, 0.5)
|
||||
else
|
||||
self.frame:Enable()
|
||||
self.text:SetTextColor(1, 1, 1)
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Constructor()
|
||||
local frame = CreateFrame("Button", nil, UIParent)
|
||||
frame:Hide()
|
||||
|
||||
frame:EnableMouse(true)
|
||||
frame:SetScript("OnEnter", Control_OnEnter)
|
||||
frame:SetScript("OnLeave", Control_OnLeave)
|
||||
frame:SetScript("OnClick", ColorSwatch_OnClick)
|
||||
|
||||
local colorSwatch = frame:CreateTexture(nil, "OVERLAY")
|
||||
colorSwatch:SetWidth(19)
|
||||
colorSwatch:SetHeight(19)
|
||||
colorSwatch:SetTexture("Interface\\ChatFrame\\ChatFrameColorSwatch")
|
||||
colorSwatch:SetPoint("LEFT",0,0)
|
||||
|
||||
local texture = frame:CreateTexture(nil, "BACKGROUND")
|
||||
texture:SetWidth(16)
|
||||
texture:SetHeight(16)
|
||||
texture:SetTexture(1, 1, 1)
|
||||
texture:SetPoint("CENTER", colorSwatch)
|
||||
texture:Show()
|
||||
|
||||
local checkers = frame:CreateTexture(nil, "BACKGROUND")
|
||||
checkers:SetWidth(14)
|
||||
checkers:SetHeight(14)
|
||||
checkers:SetTexture("Tileset\\Generic\\Checkers")
|
||||
checkers:SetTexCoord(.25, 0, 0.5, .25)
|
||||
checkers:SetDesaturated(true)
|
||||
checkers:SetVertexColor(1, 1, 1, 0.75)
|
||||
checkers:SetPoint("CENTER", colorSwatch)
|
||||
checkers:Show()
|
||||
|
||||
local text = frame:CreateFontString(nil,"OVERLAY","GameFontHighlight")
|
||||
text:SetHeight(24)
|
||||
text:SetJustifyH("LEFT")
|
||||
text:SetTextColor(1, 1, 1)
|
||||
text:SetPoint("LEFT", colorSwatch, "RIGHT", 2, 0)
|
||||
text:SetPoint("RIGHT",0,0)
|
||||
|
||||
--local highlight = frame:CreateTexture(nil, "HIGHLIGHT")
|
||||
--highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight")
|
||||
--highlight:SetBlendMode("ADD")
|
||||
--highlight:SetAllPoints(frame)
|
||||
|
||||
local widget = {
|
||||
colorSwatch = colorSwatch,
|
||||
text = text,
|
||||
frame = frame,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
|
||||
return AceGUI:RegisterAsWidget(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
@@ -0,0 +1,457 @@
|
||||
--[[ $Id: AceGUIWidget-DropDown-Items.lua 1137 2016-05-15 10:57:36Z nevcairiel $ ]]--
|
||||
|
||||
local AceGUI = LibStub("AceGUI-3.0")
|
||||
|
||||
local IsLegion = false
|
||||
|
||||
-- Lua APIs
|
||||
local assert = assert
|
||||
local tgetn = table.getn
|
||||
|
||||
-- WoW APIs
|
||||
local PlaySound = PlaySound
|
||||
local CreateFrame = CreateFrame
|
||||
|
||||
local fixlevels = AceGUI.fixlevels
|
||||
local fixstrata = AceGUI.fixstrata
|
||||
|
||||
-- ItemBase is the base "class" for all dropdown items.
|
||||
-- Each item has to use ItemBase.Create(widgetType) to
|
||||
-- create an initial 'self' value.
|
||||
-- ItemBase will add common functions and ui event handlers.
|
||||
-- Be sure to keep basic usage when you override functions.
|
||||
|
||||
local ItemBase = {
|
||||
-- NOTE: The ItemBase version is added to each item's version number
|
||||
-- to ensure proper updates on ItemBase changes.
|
||||
-- Use at least 1000er steps.
|
||||
version = 1000,
|
||||
counter = 0,
|
||||
}
|
||||
|
||||
function ItemBase.Frame_OnEnter()
|
||||
local self = this.obj
|
||||
|
||||
if self.useHighlight then
|
||||
self.highlight:Show()
|
||||
end
|
||||
self:Fire("OnEnter")
|
||||
|
||||
if self.specialOnEnter then
|
||||
self.specialOnEnter(self)
|
||||
end
|
||||
end
|
||||
|
||||
function ItemBase.Frame_OnLeave()
|
||||
local self = this.obj
|
||||
|
||||
self.highlight:Hide()
|
||||
self:Fire("OnLeave")
|
||||
|
||||
if self.specialOnLeave then
|
||||
self.specialOnLeave(self)
|
||||
end
|
||||
end
|
||||
|
||||
-- exported, AceGUI callback
|
||||
function ItemBase.OnAcquire(self)
|
||||
self.frame:SetToplevel(true)
|
||||
self.frame:SetFrameStrata("FULLSCREEN_DIALOG")
|
||||
end
|
||||
|
||||
-- exported, AceGUI callback
|
||||
function ItemBase.OnRelease(self)
|
||||
self:SetDisabled(false)
|
||||
self.pullout = nil
|
||||
self.frame:SetParent(nil)
|
||||
self.frame:ClearAllPoints()
|
||||
self.frame:Hide()
|
||||
end
|
||||
|
||||
-- exported
|
||||
-- NOTE: this is called by a Dropdown-Pullout.
|
||||
-- Do not call this method directly
|
||||
function ItemBase.SetPullout(self, pullout)
|
||||
self.pullout = pullout
|
||||
|
||||
self.frame:SetParent(nil)
|
||||
local itemFrame = pullout.itemFrame
|
||||
self.frame:SetParent(itemFrame)
|
||||
self.parent = itemFrame
|
||||
fixlevels(itemFrame)
|
||||
end
|
||||
|
||||
-- exported
|
||||
function ItemBase.SetText(self, text)
|
||||
self.text:SetText(text or "")
|
||||
end
|
||||
|
||||
-- exported
|
||||
function ItemBase.GetText(self)
|
||||
return self.text:GetText()
|
||||
end
|
||||
|
||||
-- exported
|
||||
function ItemBase.SetPoint(self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
|
||||
self.frame:SetPoint(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
|
||||
end
|
||||
|
||||
-- exported
|
||||
function ItemBase.Show(self)
|
||||
self.frame:Show()
|
||||
end
|
||||
|
||||
-- exported
|
||||
function ItemBase.Hide(self)
|
||||
self.frame:Hide()
|
||||
end
|
||||
|
||||
-- exported
|
||||
function ItemBase.SetDisabled(self, disabled)
|
||||
self.disabled = disabled
|
||||
if disabled then
|
||||
self.useHighlight = false
|
||||
self.text:SetTextColor(.5, .5, .5)
|
||||
else
|
||||
self.useHighlight = true
|
||||
self.text:SetTextColor(1, 1, 1)
|
||||
end
|
||||
end
|
||||
|
||||
-- exported
|
||||
-- NOTE: this is called by a Dropdown-Pullout.
|
||||
-- Do not call this method directly
|
||||
function ItemBase.SetOnLeave(self, func)
|
||||
self.specialOnLeave = func
|
||||
end
|
||||
|
||||
-- exported
|
||||
-- NOTE: this is called by a Dropdown-Pullout.
|
||||
-- Do not call this method directly
|
||||
function ItemBase.SetOnEnter(self, func)
|
||||
self.specialOnEnter = func
|
||||
end
|
||||
|
||||
function ItemBase.Create(type)
|
||||
-- NOTE: Most of the following code is copied from AceGUI-3.0/Dropdown widget
|
||||
local count = AceGUI:GetNextWidgetNum(type)
|
||||
local frame = CreateFrame("Button", "AceGUI30DropDownItem"..count)
|
||||
local self = {}
|
||||
self.frame = frame
|
||||
frame.obj = self
|
||||
self.type = type
|
||||
|
||||
self.useHighlight = true
|
||||
|
||||
frame:SetHeight(17)
|
||||
frame:SetFrameStrata("FULLSCREEN_DIALOG")
|
||||
|
||||
local text = frame:CreateFontString(nil,"OVERLAY","GameFontNormalSmall")
|
||||
text:SetTextColor(1,1,1)
|
||||
text:SetJustifyH("LEFT")
|
||||
text:SetPoint("TOPLEFT",frame,"TOPLEFT",18,0)
|
||||
text:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",-8,0)
|
||||
self.text = text
|
||||
|
||||
local highlight = frame:CreateTexture(nil, "OVERLAY")
|
||||
highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight")
|
||||
highlight:SetBlendMode("ADD")
|
||||
highlight:SetHeight(14)
|
||||
highlight:ClearAllPoints()
|
||||
highlight:SetPoint("RIGHT",frame,"RIGHT",-3,0)
|
||||
highlight:SetPoint("LEFT",frame,"LEFT",5,0)
|
||||
highlight:Hide()
|
||||
self.highlight = highlight
|
||||
|
||||
local check = frame:CreateTexture("OVERLAY")
|
||||
check:SetWidth(16)
|
||||
check:SetHeight(16)
|
||||
check:SetPoint("LEFT",frame,"LEFT",3,-1)
|
||||
check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
|
||||
check:Hide()
|
||||
self.check = check
|
||||
|
||||
local sub = frame:CreateTexture("OVERLAY")
|
||||
sub:SetWidth(16)
|
||||
sub:SetHeight(16)
|
||||
sub:SetPoint("RIGHT",frame,"RIGHT",-3,-1)
|
||||
sub:SetTexture("Interface\\ChatFrame\\ChatFrameExpandArrow")
|
||||
sub:Hide()
|
||||
self.sub = sub
|
||||
|
||||
frame:SetScript("OnEnter", ItemBase.Frame_OnEnter)
|
||||
frame:SetScript("OnLeave", ItemBase.Frame_OnLeave)
|
||||
|
||||
self.OnAcquire = ItemBase.OnAcquire
|
||||
self.OnRelease = ItemBase.OnRelease
|
||||
|
||||
self.SetPullout = ItemBase.SetPullout
|
||||
self.GetText = ItemBase.GetText
|
||||
self.SetText = ItemBase.SetText
|
||||
self.SetDisabled = ItemBase.SetDisabled
|
||||
|
||||
self.SetPoint = ItemBase.SetPoint
|
||||
self.Show = ItemBase.Show
|
||||
self.Hide = ItemBase.Hide
|
||||
|
||||
self.SetOnLeave = ItemBase.SetOnLeave
|
||||
self.SetOnEnter = ItemBase.SetOnEnter
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
-- Register a dummy LibStub library to retrieve the ItemBase, so other addons can use it.
|
||||
local IBLib = LibStub:NewLibrary("AceGUI-3.0-DropDown-ItemBase", ItemBase.version)
|
||||
if IBLib then
|
||||
IBLib.GetItemBase = function() return ItemBase end
|
||||
end
|
||||
|
||||
--[[
|
||||
Template for items:
|
||||
|
||||
-- Item:
|
||||
--
|
||||
do
|
||||
local widgetType = "Dropdown-Item-"
|
||||
local widgetVersion = 1
|
||||
|
||||
local function Constructor()
|
||||
local self = ItemBase.Create(widgetType)
|
||||
|
||||
AceGUI:RegisterAsWidget(self)
|
||||
return self
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion + ItemBase.version)
|
||||
end
|
||||
--]]
|
||||
|
||||
-- Item: Header
|
||||
-- A single text entry.
|
||||
-- Special: Different text color and no highlight
|
||||
do
|
||||
local widgetType = "Dropdown-Item-Header"
|
||||
local widgetVersion = 1
|
||||
|
||||
local function OnEnter(this)
|
||||
local self = this.obj
|
||||
self:Fire("OnEnter")
|
||||
|
||||
if self.specialOnEnter then
|
||||
self.specialOnEnter(self)
|
||||
end
|
||||
end
|
||||
|
||||
local function OnLeave()
|
||||
local self = this.obj
|
||||
self:Fire("OnLeave")
|
||||
|
||||
if self.specialOnLeave then
|
||||
self.specialOnLeave(self)
|
||||
end
|
||||
end
|
||||
|
||||
-- exported, override
|
||||
local function SetDisabled(self, disabled)
|
||||
ItemBase.SetDisabled(self, disabled)
|
||||
if not disabled then
|
||||
self.text:SetTextColor(1, 1, 0)
|
||||
end
|
||||
end
|
||||
|
||||
local function Constructor()
|
||||
local self = ItemBase.Create(widgetType)
|
||||
|
||||
self.SetDisabled = SetDisabled
|
||||
|
||||
self.frame:SetScript("OnEnter", OnEnter)
|
||||
self.frame:SetScript("OnLeave", OnLeave)
|
||||
|
||||
self.text:SetTextColor(1, 1, 0)
|
||||
|
||||
AceGUI:RegisterAsWidget(self)
|
||||
return self
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion + ItemBase.version)
|
||||
end
|
||||
|
||||
-- Item: Execute
|
||||
-- A simple button
|
||||
do
|
||||
local widgetType = "Dropdown-Item-Execute"
|
||||
local widgetVersion = 1
|
||||
|
||||
local function Frame_OnClick(this, button)
|
||||
local self = this.obj
|
||||
if self.disabled then return end
|
||||
self:Fire("OnClick")
|
||||
if self.pullout then
|
||||
self.pullout:Close()
|
||||
end
|
||||
end
|
||||
|
||||
local function Constructor()
|
||||
local self = ItemBase.Create(widgetType)
|
||||
|
||||
self.frame:SetScript("OnClick", Frame_OnClick)
|
||||
|
||||
AceGUI:RegisterAsWidget(self)
|
||||
return self
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion + ItemBase.version)
|
||||
end
|
||||
|
||||
-- Item: Toggle
|
||||
-- Some sort of checkbox for dropdown menus.
|
||||
-- Does not close the pullout on click.
|
||||
do
|
||||
local widgetType = "Dropdown-Item-Toggle"
|
||||
local widgetVersion = 3
|
||||
|
||||
local function UpdateToggle(self)
|
||||
if self.value then
|
||||
self.check:Show()
|
||||
else
|
||||
self.check:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
local function OnRelease(self)
|
||||
ItemBase.OnRelease(self)
|
||||
self:SetValue(nil)
|
||||
end
|
||||
|
||||
local function Frame_OnClick()
|
||||
local self = this.obj
|
||||
if self.disabled then return end
|
||||
self.value = not self.value
|
||||
if self.value then
|
||||
PlaySound("igMainMenuOptionCheckBoxOn")
|
||||
else
|
||||
PlaySound("igMainMenuOptionCheckBoxOff")
|
||||
end
|
||||
UpdateToggle(self)
|
||||
self:Fire("OnValueChanged", 1, self.value)
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function SetValue(self, value)
|
||||
self.value = value
|
||||
UpdateToggle(self)
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function GetValue(self)
|
||||
return self.value
|
||||
end
|
||||
|
||||
local function Constructor()
|
||||
local self = ItemBase.Create(widgetType)
|
||||
|
||||
self.frame:SetScript("OnClick", Frame_OnClick)
|
||||
|
||||
self.SetValue = SetValue
|
||||
self.GetValue = GetValue
|
||||
self.OnRelease = OnRelease
|
||||
|
||||
AceGUI:RegisterAsWidget(self)
|
||||
return self
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion + ItemBase.version)
|
||||
end
|
||||
|
||||
-- Item: Menu
|
||||
-- Shows a submenu on mouse over
|
||||
-- Does not close the pullout on click
|
||||
do
|
||||
local widgetType = "Dropdown-Item-Menu"
|
||||
local widgetVersion = 2
|
||||
|
||||
local function OnEnter()
|
||||
local self = this.obj
|
||||
self:Fire("OnEnter")
|
||||
|
||||
if self.specialOnEnter then
|
||||
self.specialOnEnter(self)
|
||||
end
|
||||
|
||||
self.highlight:Show()
|
||||
|
||||
if not self.disabled and self.submenu then
|
||||
self.submenu:Open("TOPLEFT", self.frame, "TOPRIGHT", self.pullout:GetRightBorderWidth(), 0, self.frame:GetFrameLevel() + 100)
|
||||
end
|
||||
end
|
||||
|
||||
local function OnHide()
|
||||
local self = this.obj
|
||||
if self.submenu then
|
||||
self.submenu:Close()
|
||||
end
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function SetMenu(self, menu)
|
||||
assert(menu.type == "Dropdown-Pullout")
|
||||
self.submenu = menu
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function CloseMenu(self)
|
||||
self.submenu:Close()
|
||||
end
|
||||
|
||||
local function Constructor()
|
||||
local self = ItemBase.Create(widgetType)
|
||||
|
||||
self.sub:Show()
|
||||
|
||||
self.frame:SetScript("OnEnter", OnEnter)
|
||||
self.frame:SetScript("OnHide", OnHide)
|
||||
|
||||
self.SetMenu = SetMenu
|
||||
self.CloseMenu = CloseMenu
|
||||
|
||||
AceGUI:RegisterAsWidget(self)
|
||||
return self
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion + ItemBase.version)
|
||||
end
|
||||
|
||||
-- Item: Separator
|
||||
-- A single line to separate items
|
||||
do
|
||||
local widgetType = "Dropdown-Item-Separator"
|
||||
local widgetVersion = 2
|
||||
|
||||
-- exported, override
|
||||
local function SetDisabled(self, disabled)
|
||||
ItemBase.SetDisabled(self, disabled)
|
||||
self.useHighlight = false
|
||||
end
|
||||
|
||||
local function Constructor()
|
||||
local self = ItemBase.Create(widgetType)
|
||||
|
||||
self.SetDisabled = SetDisabled
|
||||
|
||||
local line = self.frame:CreateTexture(nil, "OVERLAY")
|
||||
line:SetHeight(1)
|
||||
line:SetTexture(.5, .5, .5)
|
||||
|
||||
line:SetPoint("LEFT", self.frame, "LEFT", 10, 0)
|
||||
line:SetPoint("RIGHT", self.frame, "RIGHT", -10, 0)
|
||||
|
||||
self.text:Hide()
|
||||
|
||||
self.useHighlight = false
|
||||
|
||||
AceGUI:RegisterAsWidget(self)
|
||||
return self
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion + ItemBase.version)
|
||||
end
|
||||
@@ -0,0 +1,726 @@
|
||||
--[[ $Id: AceGUIWidget-DropDown.lua 1116 2014-10-12 08:15:46Z nevcairiel $ ]]--
|
||||
local AceGUI = LibStub("AceGUI-3.0")
|
||||
|
||||
local AceCore = LibStub("AceCore-3.0")
|
||||
|
||||
-- Lua APIs
|
||||
local min, max, floor = math.min, math.max, math.floor
|
||||
local pairs, ipairs, type = pairs, ipairs, type
|
||||
local tsort, tinsert, tgetn, tsetn = table.sort, table.insert, table.getn, table.setn
|
||||
|
||||
-- WoW APIs
|
||||
local PlaySound = PlaySound
|
||||
local UIParent, CreateFrame = UIParent, CreateFrame
|
||||
local _G = AceCore._G
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: CLOSE
|
||||
|
||||
local fixlevels = AceGUI.fixlevels
|
||||
local fixstrata = AceGUI.fixstrata
|
||||
|
||||
do
|
||||
local widgetType = "Dropdown-Pullout"
|
||||
local widgetVersion = 3
|
||||
|
||||
--[[ Static data ]]--
|
||||
|
||||
local backdrop = {
|
||||
bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
|
||||
edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
|
||||
edgeSize = 32,
|
||||
tileSize = 32,
|
||||
tile = true,
|
||||
insets = { left = 11, right = 12, top = 12, bottom = 11 },
|
||||
}
|
||||
local sliderBackdrop = {
|
||||
bgFile = "Interface\\Buttons\\UI-SliderBar-Background",
|
||||
edgeFile = "Interface\\Buttons\\UI-SliderBar-Border",
|
||||
tile = true, tileSize = 8, edgeSize = 8,
|
||||
insets = { left = 3, right = 3, top = 3, bottom = 3 }
|
||||
}
|
||||
|
||||
local defaultWidth = 200
|
||||
local defaultMaxHeight = 600
|
||||
|
||||
--[[ UI Event Handlers ]]--
|
||||
|
||||
-- HACK: This should be no part of the pullout, but there
|
||||
-- is no other 'clean' way to response to any item-OnEnter
|
||||
-- Used to close Submenus when an other item is entered
|
||||
local function OnEnter(item)
|
||||
local self = item.pullout
|
||||
for k, v in ipairs(self.items) do
|
||||
if v.CloseMenu and v ~= item then
|
||||
v:CloseMenu()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- See the note in Constructor() for each scroll related function
|
||||
local function OnMouseWheel()
|
||||
this.obj:MoveScroll(arg1)
|
||||
end
|
||||
|
||||
local function OnScrollValueChanged()
|
||||
this.obj:SetScroll(arg1)
|
||||
end
|
||||
|
||||
local function OnSizeChanged()
|
||||
this.obj:FixScroll()
|
||||
end
|
||||
|
||||
--[[ Exported methods ]]--
|
||||
|
||||
-- exported
|
||||
local function SetScroll(self, value)
|
||||
local status = self.scrollStatus
|
||||
local frame, child = self.scrollFrame, self.itemFrame
|
||||
local height, viewheight = frame:GetHeight(), child:GetHeight()
|
||||
|
||||
local offset
|
||||
if height > viewheight then
|
||||
offset = 0
|
||||
else
|
||||
offset = floor((viewheight - height) / 1000 * value)
|
||||
end
|
||||
child:ClearAllPoints()
|
||||
child:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, offset)
|
||||
child:SetPoint("TOPRIGHT", frame, "TOPRIGHT", self.slider:IsShown() and -12 or 0, offset)
|
||||
status.offset = offset
|
||||
status.scrollvalue = value
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function MoveScroll(self, value)
|
||||
local status = self.scrollStatus
|
||||
local frame, child = self.scrollFrame, self.itemFrame
|
||||
local height, viewheight = frame:GetHeight(), child:GetHeight()
|
||||
|
||||
if height > viewheight then
|
||||
self.slider:Hide()
|
||||
else
|
||||
self.slider:Show()
|
||||
local diff = height - viewheight
|
||||
local delta = 1
|
||||
if value < 0 then
|
||||
delta = -1
|
||||
end
|
||||
self.slider:SetValue(min(max(status.scrollvalue + delta*(1000/(diff/45)),0), 1000))
|
||||
end
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function FixScroll(self)
|
||||
local status = self.scrollStatus
|
||||
local frame, child = self.scrollFrame, self.itemFrame
|
||||
local height, viewheight = frame:GetHeight(), child:GetHeight()
|
||||
local offset = status.offset or 0
|
||||
|
||||
if viewheight < height then
|
||||
self.slider:Hide()
|
||||
child:SetPoint("TOPRIGHT", frame, "TOPRIGHT", 0, offset)
|
||||
self.slider:SetValue(0)
|
||||
else
|
||||
self.slider:Show()
|
||||
local value = (offset / (viewheight - height) * 1000)
|
||||
if value > 1000 then value = 1000 end
|
||||
self.slider:SetValue(value)
|
||||
self:SetScroll(value)
|
||||
if value < 1000 then
|
||||
child:ClearAllPoints()
|
||||
child:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, offset)
|
||||
child:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -12, offset)
|
||||
status.offset = offset
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- exported, AceGUI callback
|
||||
local function OnAcquire(self)
|
||||
self.frame:SetParent(UIParent)
|
||||
--self.itemFrame:SetToplevel(true)
|
||||
end
|
||||
|
||||
-- exported, AceGUI callback
|
||||
local function OnRelease(self)
|
||||
self:Clear()
|
||||
self.frame:ClearAllPoints()
|
||||
self.frame:Hide()
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function AddItem(self, item)
|
||||
tinsert(self.items, item)
|
||||
|
||||
local h = tgetn(self.items) * 16
|
||||
self.itemFrame:SetHeight(h)
|
||||
self.frame:SetHeight(min(h + 34, self.maxHeight)) -- +34: 20 for scrollFrame placement (10 offset) and +14 for item placement
|
||||
|
||||
item.frame:SetPoint("LEFT", self.itemFrame, "LEFT")
|
||||
item.frame:SetPoint("RIGHT", self.itemFrame, "RIGHT")
|
||||
|
||||
item:SetPullout(self)
|
||||
item:SetOnEnter(OnEnter)
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function Open(self, point, relFrame, relPoint, x, y)
|
||||
local items = self.items
|
||||
local frame = self.frame
|
||||
local itemFrame = self.itemFrame
|
||||
|
||||
frame:SetPoint(point, relFrame, relPoint, x, y)
|
||||
|
||||
|
||||
local height = 8
|
||||
for i, item in pairs(items) do
|
||||
if i == 1 then
|
||||
item:SetPoint("TOP", itemFrame, "TOP", 0, -2)
|
||||
else
|
||||
item:SetPoint("TOP", items[i-1].frame, "BOTTOM", 0, 1)
|
||||
end
|
||||
|
||||
item:Show()
|
||||
|
||||
height = height + 16
|
||||
end
|
||||
itemFrame:SetHeight(height)
|
||||
fixstrata("TOOLTIP", frame)
|
||||
frame:Show()
|
||||
self:Fire("OnOpen")
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function Close(self)
|
||||
self.frame:Hide()
|
||||
self:Fire("OnClose")
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function Clear(self)
|
||||
local items = self.items
|
||||
for i, item in pairs(items) do
|
||||
AceGUI:Release(item)
|
||||
items[i] = nil
|
||||
end
|
||||
tsetn(items,0)
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function IterateItems(self)
|
||||
return ipairs(self.items)
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function SetHideOnLeave(self, val)
|
||||
self.hideOnLeave = val
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function SetMaxHeight(self, height)
|
||||
self.maxHeight = height or defaultMaxHeight
|
||||
if self.frame:GetHeight() > height then
|
||||
self.frame:SetHeight(height)
|
||||
elseif (self.itemFrame:GetHeight() + 34) < height then
|
||||
self.frame:SetHeight(self.itemFrame:GetHeight() + 34) -- see :AddItem
|
||||
end
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function GetRightBorderWidth(self)
|
||||
return 6 + (self.slider:IsShown() and 12 or 0)
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function GetLeftBorderWidth(self)
|
||||
return 6
|
||||
end
|
||||
|
||||
--[[ Constructor ]]--
|
||||
|
||||
local function Constructor()
|
||||
local count = AceGUI:GetNextWidgetNum(widgetType)
|
||||
local frame = CreateFrame("Frame", "AceGUI30Pullout"..count, UIParent)
|
||||
local self = {}
|
||||
self.count = count
|
||||
self.type = widgetType
|
||||
self.frame = frame
|
||||
frame.obj = self
|
||||
|
||||
self.OnAcquire = OnAcquire
|
||||
self.OnRelease = OnRelease
|
||||
|
||||
self.AddItem = AddItem
|
||||
self.Open = Open
|
||||
self.Close = Close
|
||||
self.Clear = Clear
|
||||
self.IterateItems = IterateItems
|
||||
self.SetHideOnLeave = SetHideOnLeave
|
||||
|
||||
self.SetScroll = SetScroll
|
||||
self.MoveScroll = MoveScroll
|
||||
self.FixScroll = FixScroll
|
||||
|
||||
self.SetMaxHeight = SetMaxHeight
|
||||
self.GetRightBorderWidth = GetRightBorderWidth
|
||||
self.GetLeftBorderWidth = GetLeftBorderWidth
|
||||
|
||||
self.items = {}
|
||||
|
||||
self.scrollStatus = {
|
||||
scrollvalue = 0,
|
||||
}
|
||||
|
||||
self.maxHeight = defaultMaxHeight
|
||||
|
||||
frame:SetBackdrop(backdrop)
|
||||
frame:SetBackdropColor(0, 0, 0)
|
||||
frame:SetFrameStrata("FULLSCREEN_DIALOG")
|
||||
frame:SetClampedToScreen(true)
|
||||
frame:SetWidth(defaultWidth)
|
||||
frame:SetHeight(self.maxHeight)
|
||||
--frame:SetToplevel(true)
|
||||
|
||||
-- NOTE: The whole scroll frame code is copied from the AceGUI-3.0 widget ScrollFrame
|
||||
local scrollFrame = CreateFrame("ScrollFrame", nil, frame)
|
||||
local itemFrame = CreateFrame("Frame", nil, scrollFrame)
|
||||
|
||||
self.scrollFrame = scrollFrame
|
||||
self.itemFrame = itemFrame
|
||||
|
||||
scrollFrame.obj = self
|
||||
itemFrame.obj = self
|
||||
|
||||
local slider = CreateFrame("Slider", "AceGUI30PulloutScrollbar"..count, scrollFrame)
|
||||
slider:SetOrientation("VERTICAL")
|
||||
slider:SetHitRectInsets(0, 0, -10, 0)
|
||||
slider:SetBackdrop(sliderBackdrop)
|
||||
slider:SetWidth(8)
|
||||
slider:SetThumbTexture("Interface\\Buttons\\UI-SliderBar-Button-Vertical")
|
||||
slider:SetFrameStrata("FULLSCREEN_DIALOG")
|
||||
self.slider = slider
|
||||
slider.obj = self
|
||||
|
||||
scrollFrame:SetScrollChild(itemFrame)
|
||||
scrollFrame:SetPoint("TOPLEFT", frame, "TOPLEFT", 6, -12)
|
||||
scrollFrame:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -6, 12)
|
||||
scrollFrame:EnableMouseWheel(true)
|
||||
scrollFrame:SetScript("OnMouseWheel", OnMouseWheel)
|
||||
scrollFrame:SetScript("OnSizeChanged", OnSizeChanged)
|
||||
scrollFrame:SetToplevel(true)
|
||||
scrollFrame:SetFrameStrata("FULLSCREEN_DIALOG")
|
||||
|
||||
itemFrame:SetPoint("TOPLEFT", scrollFrame, "TOPLEFT", 0, 0)
|
||||
itemFrame:SetPoint("TOPRIGHT", scrollFrame, "TOPRIGHT", -12, 0)
|
||||
itemFrame:SetHeight(400)
|
||||
itemFrame:SetToplevel(true)
|
||||
itemFrame:SetFrameStrata("FULLSCREEN_DIALOG")
|
||||
|
||||
slider:SetPoint("TOPLEFT", scrollFrame, "TOPRIGHT", -16, 0)
|
||||
slider:SetPoint("BOTTOMLEFT", scrollFrame, "BOTTOMRIGHT", -16, 0)
|
||||
slider:SetScript("OnValueChanged", OnScrollValueChanged)
|
||||
slider:SetMinMaxValues(0, 1000)
|
||||
slider:SetValueStep(1)
|
||||
slider:SetValue(0)
|
||||
|
||||
scrollFrame:Show()
|
||||
itemFrame:Show()
|
||||
slider:Hide()
|
||||
|
||||
self:FixScroll()
|
||||
|
||||
AceGUI:RegisterAsWidget(self)
|
||||
return self
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion)
|
||||
end
|
||||
|
||||
do
|
||||
local widgetType = "Dropdown"
|
||||
local widgetVersion = 30
|
||||
|
||||
--[[ Static data ]]--
|
||||
|
||||
--[[ UI event handler ]]--
|
||||
|
||||
local function Control_OnEnter()
|
||||
this.obj.button:LockHighlight()
|
||||
this.obj:Fire("OnEnter")
|
||||
end
|
||||
|
||||
local function Control_OnLeave()
|
||||
this.obj.button:UnlockHighlight()
|
||||
this.obj:Fire("OnLeave")
|
||||
end
|
||||
|
||||
local function Dropdown_OnHide()
|
||||
local self = this.obj
|
||||
if self.open then
|
||||
self.pullout:Close()
|
||||
end
|
||||
end
|
||||
|
||||
local function Dropdown_TogglePullout()
|
||||
local self = this.obj
|
||||
PlaySound("igMainMenuOptionCheckBoxOn") -- missleading name, but the Blizzard code uses this sound
|
||||
if self.open then
|
||||
self.open = nil
|
||||
self.pullout:Close()
|
||||
AceGUI:ClearFocus()
|
||||
else
|
||||
self.open = true
|
||||
self.pullout:SetWidth(self.pulloutWidth or self.frame:GetWidth())
|
||||
self.pullout:Open("TOPLEFT", self.frame, "BOTTOMLEFT", 0, self.label:IsShown() and -2 or 0)
|
||||
AceGUI:SetFocus(self)
|
||||
end
|
||||
end
|
||||
|
||||
local function OnPulloutOpen(this)
|
||||
local self = this.userdata.obj
|
||||
local value = self.value
|
||||
|
||||
if not self.multiselect then
|
||||
for i, item in this:IterateItems() do
|
||||
item:SetValue(item.userdata.value == value)
|
||||
end
|
||||
end
|
||||
|
||||
self.open = true
|
||||
self:Fire("OnOpened")
|
||||
end
|
||||
|
||||
local function OnPulloutClose(this)
|
||||
local self = this.userdata.obj
|
||||
self.open = nil
|
||||
self:Fire("OnClosed")
|
||||
end
|
||||
|
||||
local function ShowMultiText(self)
|
||||
local text
|
||||
for i, widget in self.pullout:IterateItems() do
|
||||
if widget.type == "Dropdown-Item-Toggle" then
|
||||
if widget:GetValue() then
|
||||
if text then
|
||||
text = text..", "..widget:GetText()
|
||||
else
|
||||
text = widget:GetText()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
self:SetText(text)
|
||||
end
|
||||
|
||||
local function OnItemValueChanged(this, event, _, checked)
|
||||
local self = this.userdata.obj
|
||||
|
||||
if self.multiselect then
|
||||
self:Fire("OnValueChanged", 2, this.userdata.value, checked)
|
||||
ShowMultiText(self)
|
||||
else
|
||||
if checked then
|
||||
self:SetValue(this.userdata.value)
|
||||
self:Fire("OnValueChanged", 1, this.userdata.value)
|
||||
this:SetValue(false)
|
||||
else
|
||||
self:SetValue(nil)
|
||||
self:Fire("OnValueChanged", 1, nil)
|
||||
this:SetValue(true)
|
||||
end
|
||||
if self.open then
|
||||
self.pullout:Close()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[ Exported methods ]]--
|
||||
|
||||
-- exported, AceGUI callback
|
||||
local function OnAcquire(self)
|
||||
local pullout = AceGUI:Create("Dropdown-Pullout")
|
||||
self.pullout = pullout
|
||||
pullout.userdata.obj = self
|
||||
pullout:SetCallback("OnClose", OnPulloutClose)
|
||||
pullout:SetCallback("OnOpen", OnPulloutOpen)
|
||||
self.pullout.frame:SetFrameLevel(self.frame:GetFrameLevel() + 1)
|
||||
local frame = self.pullout.frame
|
||||
fixlevels(frame)
|
||||
|
||||
self:SetHeight(44)
|
||||
self:SetWidth(200)
|
||||
self:SetLabel()
|
||||
self:SetPulloutWidth(nil)
|
||||
end
|
||||
|
||||
-- exported, AceGUI callback
|
||||
local function OnRelease(self)
|
||||
if self.open then
|
||||
self.pullout:Close()
|
||||
end
|
||||
AceGUI:Release(self.pullout)
|
||||
self.pullout = nil
|
||||
|
||||
self:SetText("")
|
||||
self:SetDisabled(false)
|
||||
self:SetMultiselect(false)
|
||||
|
||||
self.value = nil
|
||||
self.list = nil
|
||||
self.open = nil
|
||||
self.hasClose = nil
|
||||
|
||||
self.frame:ClearAllPoints()
|
||||
self.frame:Hide()
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function SetDisabled(self, disabled)
|
||||
self.disabled = disabled
|
||||
if disabled then
|
||||
self.text:SetTextColor(0.5,0.5,0.5)
|
||||
self.button:Disable()
|
||||
self.button_cover:Disable()
|
||||
self.label:SetTextColor(0.5,0.5,0.5)
|
||||
else
|
||||
self.button:Enable()
|
||||
self.button_cover:Enable()
|
||||
self.label:SetTextColor(1,.82,0)
|
||||
self.text:SetTextColor(1,1,1)
|
||||
end
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function ClearFocus(self)
|
||||
if self.open then
|
||||
self.pullout:Close()
|
||||
end
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function SetText(self, text)
|
||||
self.text:SetText(text or "")
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function SetLabel(self, text)
|
||||
if text and text ~= "" then
|
||||
self.label:SetText(text)
|
||||
self.label:Show()
|
||||
self.dropdown:SetPoint("TOPLEFT",self.frame,"TOPLEFT",-15,-14)
|
||||
self:SetHeight(40)
|
||||
self.alignoffset = 26
|
||||
else
|
||||
self.label:SetText("")
|
||||
self.label:Hide()
|
||||
self.dropdown:SetPoint("TOPLEFT",self.frame,"TOPLEFT",-15,0)
|
||||
self:SetHeight(26)
|
||||
self.alignoffset = 12
|
||||
end
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function SetValue(self, value)
|
||||
if self.list then
|
||||
self:SetText(self.list[value] or "")
|
||||
end
|
||||
self.value = value
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function GetValue(self)
|
||||
return self.value
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function SetItemValue(self, item, value)
|
||||
if not self.multiselect then return end
|
||||
for i, widget in self.pullout:IterateItems() do
|
||||
if widget.userdata.value == item then
|
||||
if widget.SetValue then
|
||||
widget:SetValue(value)
|
||||
end
|
||||
end
|
||||
end
|
||||
ShowMultiText(self)
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function SetItemDisabled(self, item, disabled)
|
||||
for i, widget in self.pullout:IterateItems() do
|
||||
if widget.userdata.value == item then
|
||||
widget:SetDisabled(disabled)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function AddListItem(self, value, text, itemType)
|
||||
if not itemType then itemType = "Dropdown-Item-Toggle" end
|
||||
local exists = AceGUI:GetWidgetVersion(itemType)
|
||||
if not exists then error(("The given item type, %q, does not exist within AceGUI-3.0"):format(tostring(itemType)), 2) end
|
||||
|
||||
local item = AceGUI:Create(itemType)
|
||||
item:SetText(text)
|
||||
item.userdata.obj = self
|
||||
item.userdata.value = value
|
||||
item:SetCallback("OnValueChanged", OnItemValueChanged)
|
||||
self.pullout:AddItem(item)
|
||||
end
|
||||
|
||||
local function AddCloseButton(self)
|
||||
if not self.hasClose then
|
||||
local close = AceGUI:Create("Dropdown-Item-Execute")
|
||||
close:SetText(CLOSE)
|
||||
self.pullout:AddItem(close)
|
||||
self.hasClose = true
|
||||
end
|
||||
end
|
||||
|
||||
-- exported
|
||||
local sortlist = {}
|
||||
local function SetList(self, list, order, itemType)
|
||||
self.list = list
|
||||
self.pullout:Clear()
|
||||
self.hasClose = nil
|
||||
if not list then return end
|
||||
|
||||
if type(order) ~= "table" then
|
||||
for v in pairs(list) do
|
||||
tinsert(sortlist, v)
|
||||
end
|
||||
tsort(sortlist)
|
||||
|
||||
for i, key in ipairs(sortlist) do
|
||||
AddListItem(self, key, list[key], itemType)
|
||||
sortlist[i] = nil
|
||||
end
|
||||
tsetn(sortlist,0)
|
||||
else
|
||||
for i, key in ipairs(order) do
|
||||
AddListItem(self, key, list[key], itemType)
|
||||
end
|
||||
end
|
||||
if self.multiselect then
|
||||
ShowMultiText(self)
|
||||
AddCloseButton(self)
|
||||
end
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function AddItem(self, value, text, itemType)
|
||||
if self.list then
|
||||
self.list[value] = text
|
||||
AddListItem(self, value, text, itemType)
|
||||
end
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function SetMultiselect(self, multi)
|
||||
self.multiselect = multi
|
||||
if multi then
|
||||
ShowMultiText(self)
|
||||
AddCloseButton(self)
|
||||
end
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function GetMultiselect(self)
|
||||
return self.multiselect
|
||||
end
|
||||
|
||||
local function SetPulloutWidth(self, width)
|
||||
self.pulloutWidth = width
|
||||
end
|
||||
|
||||
--[[ Constructor ]]--
|
||||
|
||||
local function Constructor()
|
||||
local count = AceGUI:GetNextWidgetNum(widgetType)
|
||||
local frame = CreateFrame("Frame", nil, UIParent)
|
||||
local dropdown = CreateFrame("Frame", "AceGUI30DropDown"..count, frame, "UIDropDownMenuTemplate")
|
||||
|
||||
local self = {}
|
||||
self.type = widgetType
|
||||
self.frame = frame
|
||||
self.dropdown = dropdown
|
||||
self.count = count
|
||||
frame.obj = self
|
||||
dropdown.obj = self
|
||||
|
||||
self.OnRelease = OnRelease
|
||||
self.OnAcquire = OnAcquire
|
||||
|
||||
self.ClearFocus = ClearFocus
|
||||
|
||||
self.SetText = SetText
|
||||
self.SetValue = SetValue
|
||||
self.GetValue = GetValue
|
||||
self.SetList = SetList
|
||||
self.SetLabel = SetLabel
|
||||
self.SetDisabled = SetDisabled
|
||||
self.AddItem = AddItem
|
||||
self.SetMultiselect = SetMultiselect
|
||||
self.GetMultiselect = GetMultiselect
|
||||
self.SetItemValue = SetItemValue
|
||||
self.SetItemDisabled = SetItemDisabled
|
||||
self.SetPulloutWidth = SetPulloutWidth
|
||||
|
||||
self.alignoffset = 26
|
||||
|
||||
frame:SetScript("OnHide",Dropdown_OnHide)
|
||||
|
||||
dropdown:ClearAllPoints()
|
||||
dropdown:SetPoint("TOPLEFT",frame,"TOPLEFT",-15,0)
|
||||
dropdown:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",17,0)
|
||||
dropdown:SetScript("OnHide", nil)
|
||||
|
||||
local left = _G[dropdown:GetName() .. "Left"]
|
||||
local middle = _G[dropdown:GetName() .. "Middle"]
|
||||
local right = _G[dropdown:GetName() .. "Right"]
|
||||
|
||||
middle:ClearAllPoints()
|
||||
right:ClearAllPoints()
|
||||
|
||||
middle:SetPoint("LEFT", left, "RIGHT", 0, 0)
|
||||
middle:SetPoint("RIGHT", right, "LEFT", 0, 0)
|
||||
right:SetPoint("TOPRIGHT", dropdown, "TOPRIGHT", 0, 17)
|
||||
|
||||
local button = _G[dropdown:GetName() .. "Button"]
|
||||
self.button = button
|
||||
button.obj = self
|
||||
button:SetScript("OnEnter",Control_OnEnter)
|
||||
button:SetScript("OnLeave",Control_OnLeave)
|
||||
button:SetScript("OnClick",Dropdown_TogglePullout)
|
||||
|
||||
local button_cover = CreateFrame("BUTTON",nil,self.frame)
|
||||
self.button_cover = button_cover
|
||||
button_cover.obj = self
|
||||
button_cover:SetPoint("TOPLEFT",self.frame,"BOTTOMLEFT",0,25)
|
||||
button_cover:SetPoint("BOTTOMRIGHT",self.frame,"BOTTOMRIGHT")
|
||||
button_cover:SetScript("OnEnter",Control_OnEnter)
|
||||
button_cover:SetScript("OnLeave",Control_OnLeave)
|
||||
button_cover:SetScript("OnClick",Dropdown_TogglePullout)
|
||||
|
||||
local text = _G[dropdown:GetName() .. "Text"]
|
||||
self.text = text
|
||||
text.obj = self
|
||||
text:ClearAllPoints()
|
||||
text:SetPoint("RIGHT", right, "RIGHT" ,-43, 2)
|
||||
text:SetPoint("LEFT", left, "LEFT", 25, 2)
|
||||
|
||||
local label = frame:CreateFontString(nil,"OVERLAY","GameFontNormalSmall")
|
||||
label:SetPoint("TOPLEFT",frame,"TOPLEFT",0,0)
|
||||
label:SetPoint("TOPRIGHT",frame,"TOPRIGHT",0,0)
|
||||
label:SetJustifyH("LEFT")
|
||||
label:SetHeight(18)
|
||||
label:Hide()
|
||||
self.label = label
|
||||
|
||||
AceGUI:RegisterAsWidget(self)
|
||||
return self
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion)
|
||||
end
|
||||
@@ -0,0 +1,367 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
EditBox Widget
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "EditBox", 26
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
local AceCore = LibStub("AceCore-3.0")
|
||||
local hooksecurefunc = AceCore.hooksecurefunc
|
||||
local _G = AceCore._G
|
||||
local GetCursorInfo = _G.GetCursorInfo
|
||||
|
||||
-- Lua APIs
|
||||
local tostring, pairs = tostring, pairs
|
||||
|
||||
-- WoW APIs
|
||||
local PlaySound = PlaySound
|
||||
local GetCursorInfo, ClearCursor, GetSpellInfo = GetCursorInfo, ClearCursor, GetSpellInfo
|
||||
local CreateFrame, UIParent = CreateFrame, UIParent
|
||||
local strlen = string.len
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: AceGUIEditBoxInsertLink, ChatFontNormal, OKAY
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Support functions
|
||||
-------------------------------------------------------------------------------]]
|
||||
if not AceGUIEditBoxInsertLink then
|
||||
-- upgradeable hook
|
||||
hooksecurefunc("BankFrameItemButtonGeneric_OnClick",
|
||||
function(button)
|
||||
if button == "LeftButton" and IsShiftKeyDown() and not this.isBag then
|
||||
return _G.AceGUIEditBoxInsertLink(GetContainerItemLink(BANK_CONTAINER, this:GetID()))
|
||||
end
|
||||
end)
|
||||
hooksecurefunc("ContainerFrameItemButton_OnClick",
|
||||
function(button, ignoreModifiers)
|
||||
if button == "LeftButton" and IsShiftKeyDown() and not ignoreModifiers then
|
||||
return _G.AceGUIEditBoxInsertLink(GetContainerItemLink(this:GetParent():GetID(), this:GetID()))
|
||||
end
|
||||
end)
|
||||
|
||||
hooksecurefunc("KeyRingItemButton_OnClick",
|
||||
function(button)
|
||||
if button == "LeftButton" and IsShiftKeyDown() and not this.isBag then
|
||||
return _G.AceGUIEditBoxInsertLink(GetContainerItemLink(KEYRING_CONTAINER, this:GetID()))
|
||||
end
|
||||
end)
|
||||
hooksecurefunc("LootFrameItem_OnClick",
|
||||
function(button)
|
||||
if button == "LeftButton" and IsShiftKeyDown() then
|
||||
return _G.AceGUIEditBoxInsertLink(GetLootSlotLink(this.slot))
|
||||
end
|
||||
end)
|
||||
hooksecurefunc("SetItemRef",
|
||||
function(link, text, button)
|
||||
if IsShiftKeyDown() then
|
||||
if strsub(link,1,6) == "player" then
|
||||
local name = strsub(link,8)
|
||||
if name and (strlen(name) > 0) then
|
||||
return _G.AceGUIEditBoxInsertLink(name)
|
||||
end
|
||||
else
|
||||
return _G.AceGUIEditBoxInsertLink(text)
|
||||
end
|
||||
end
|
||||
end)
|
||||
hooksecurefunc("MerchantItemButton_OnClick",
|
||||
function(button, ignoreModifiers)
|
||||
if MerchantFrame.selectedTab == 1 and button == "LeftButton" and IsShiftKeyDown() and not ignoreModifiers then
|
||||
return _G.AceGUIEditBoxInsertLink(GetMerchantItemLink(this:GetID()))
|
||||
end
|
||||
end)
|
||||
hooksecurefunc("PaperDollItemSlotButton_OnClick",
|
||||
function(button, ignoreModifiers)
|
||||
if button == "LeftButton" and IsShiftKeyDown() and not ignoreModifiers then
|
||||
return _G.AceGUIEditBoxInsertLink(GetInventoryItemLink("player", this:GetID()))
|
||||
end
|
||||
end)
|
||||
hooksecurefunc("QuestItem_OnClick",
|
||||
function()
|
||||
if IsShiftKeyDown() and this.rewardType ~= "spell" then
|
||||
return _G.AceGUIEditBoxInsertLink(GetQuestItemLink(this.type, this:GetID()))
|
||||
end
|
||||
end)
|
||||
hooksecurefunc("QuestRewardItem_OnClick",
|
||||
function()
|
||||
if IsShiftKeyDown() and this.rewardType ~= "spell" then
|
||||
return _G.AceGUIEditBoxInsertLink(GetQuestItemLink(this.type, this:GetID()))
|
||||
end
|
||||
end)
|
||||
hooksecurefunc("QuestLogTitleButton_OnClick",
|
||||
function(button)
|
||||
if IsShiftKeyDown() and (not this.isHeader) then
|
||||
return _G.AceGUIEditBoxInsertLink(gsub(this:GetText(), " *(.*)", "%1"))
|
||||
end
|
||||
end)
|
||||
hooksecurefunc("QuestLogRewardItem_OnClick",
|
||||
function()
|
||||
if IsShiftKeyDown() and this.rewardType ~= "spell" then
|
||||
return _G.AceGUIEditBoxInsertLink(GetQuestLogItemLink(this.type, this:GetID()))
|
||||
end
|
||||
end)
|
||||
hooksecurefunc("SpellButton_OnClick",
|
||||
function(drag)
|
||||
local id = SpellBook_GetSpellID(this:GetID())
|
||||
if id <= MAX_SPELLS and (not drag) and IsShiftKeyDown() then
|
||||
local spellName, subSpellName = GetSpellName(id, SpellBookFrame.bookType)
|
||||
if spellName and not IsSpellPassive(id, SpellBookFrame.bookType) then
|
||||
if subSpellName and (strlen(subSpellName) > 0) then
|
||||
_G.AceGUIEditBoxInsertLink(spellName.."("..subSpellName..")");
|
||||
else
|
||||
_G.AceGUIEditBoxInsertLink(spellName);
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
function _G.AceGUIEditBoxInsertLink(text)
|
||||
for i = 1, AceGUI:GetWidgetCount(Type) do
|
||||
local editbox = _G["AceGUI-3.0EditBox"..i]
|
||||
if editbox and editbox:IsVisible() and editbox.hasfocus then
|
||||
editbox:Insert(text)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function ShowButton(self)
|
||||
if not self.disablebutton then
|
||||
self.button:Show()
|
||||
self.editbox:SetTextInsets(0, 20, 3, 3)
|
||||
end
|
||||
end
|
||||
|
||||
local function HideButton(self)
|
||||
self.button:Hide()
|
||||
self.editbox:SetTextInsets(0, 0, 3, 3)
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Scripts
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Control_OnEnter()
|
||||
this.obj:Fire("OnEnter")
|
||||
end
|
||||
|
||||
local function Control_OnLeave()
|
||||
this.obj:Fire("OnLeave")
|
||||
end
|
||||
|
||||
local function Frame_OnShowFocus()
|
||||
this.obj.editbox:SetFocus()
|
||||
this:SetScript("OnShow", nil)
|
||||
end
|
||||
|
||||
local function EditBox_OnEscapePressed()
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
local function EditBox_OnEnterPressed()
|
||||
local self = this.obj
|
||||
local value = this:GetText()
|
||||
local cancel = self:Fire("OnEnterPressed", 1, value)
|
||||
if not cancel then
|
||||
PlaySound("igMainMenuOptionCheckBoxOn")
|
||||
HideButton(self)
|
||||
end
|
||||
end
|
||||
|
||||
local function EditBox_OnReceiveDrag()
|
||||
if not GetCursorInfo then return end
|
||||
local self = this.obj
|
||||
local type, id, info = GetCursorInfo()
|
||||
if type == "item" then
|
||||
self:SetText(info)
|
||||
self:Fire("OnEnterPressed", 1, info)
|
||||
ClearCursor()
|
||||
elseif type == "spell" then
|
||||
local spell, rank = GetSpellName(id, info)
|
||||
if rank ~= "" then spell = spell.."("..rank..")" end
|
||||
self:SetText(spell)
|
||||
self:Fire("OnEnterPressed", 1, spell)
|
||||
ClearCursor()
|
||||
elseif type == "macro" then
|
||||
local name = GetMacroInfo(id)
|
||||
self:SetText(name)
|
||||
self:Fire("OnEnterPressed", 1, name)
|
||||
ClearCursor()
|
||||
end
|
||||
HideButton(self)
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
|
||||
local function EditBox_OnTextChanged()
|
||||
local self = this.obj
|
||||
local value = this:GetText()
|
||||
if tostring(value) ~= tostring(self.lasttext) then
|
||||
self:Fire("OnTextChanged", 1, value)
|
||||
self.lasttext = value
|
||||
ShowButton(self)
|
||||
end
|
||||
end
|
||||
|
||||
local function EditBox_OnFocusGained()
|
||||
this.hasfocus = true
|
||||
AceGUI:SetFocus(this.obj)
|
||||
end
|
||||
|
||||
local function EditBox_OnFocusLost()
|
||||
this.hasfocus = nil
|
||||
end
|
||||
|
||||
local function Button_OnClick()
|
||||
local editbox = this.obj.editbox
|
||||
editbox:ClearFocus()
|
||||
this = editbox -- Ace3v: this is kinda hack here
|
||||
EditBox_OnEnterPressed()
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
-- height is controlled by SetLabel
|
||||
self:SetWidth(200)
|
||||
self:SetDisabled(false)
|
||||
self:SetLabel()
|
||||
self:SetText()
|
||||
self:DisableButton(false)
|
||||
self:SetMaxLetters(0)
|
||||
end,
|
||||
|
||||
["OnRelease"] = function(self)
|
||||
self:ClearFocus()
|
||||
end,
|
||||
|
||||
["SetDisabled"] = function(self, disabled)
|
||||
self.disabled = disabled
|
||||
if disabled then
|
||||
self.editbox:EnableMouse(false)
|
||||
self.editbox:ClearFocus()
|
||||
self.editbox:SetTextColor(0.5,0.5,0.5)
|
||||
self.label:SetTextColor(0.5,0.5,0.5)
|
||||
else
|
||||
self.editbox:EnableMouse(true)
|
||||
self.editbox:SetTextColor(1,1,1)
|
||||
self.label:SetTextColor(1,.82,0)
|
||||
end
|
||||
end,
|
||||
|
||||
["SetText"] = function(self, text)
|
||||
self.lasttext = text or ""
|
||||
self.editbox:SetText(text or "")
|
||||
self.editbox:HighlightText(0)
|
||||
HideButton(self)
|
||||
end,
|
||||
|
||||
["GetText"] = function(self, text)
|
||||
return self.editbox:GetText()
|
||||
end,
|
||||
|
||||
["SetLabel"] = function(self, text)
|
||||
if text and text ~= "" then
|
||||
self.label:SetText(text)
|
||||
self.label:Show()
|
||||
self.editbox:SetPoint("TOPLEFT",self.frame,"TOPLEFT",7,-18)
|
||||
self:SetHeight(44)
|
||||
self.alignoffset = 30
|
||||
else
|
||||
self.label:SetText("")
|
||||
self.label:Hide()
|
||||
self.editbox:SetPoint("TOPLEFT",self.frame,"TOPLEFT",7,0)
|
||||
self:SetHeight(26)
|
||||
self.alignoffset = 12
|
||||
end
|
||||
end,
|
||||
|
||||
["DisableButton"] = function(self, disabled)
|
||||
self.disablebutton = disabled
|
||||
if disabled then
|
||||
HideButton(self)
|
||||
end
|
||||
end,
|
||||
|
||||
["SetMaxLetters"] = function (self, num)
|
||||
self.editbox:SetMaxLetters(num or 0)
|
||||
end,
|
||||
|
||||
["ClearFocus"] = function(self)
|
||||
self.editbox:ClearFocus()
|
||||
self.frame:SetScript("OnShow", nil)
|
||||
end,
|
||||
|
||||
["SetFocus"] = function(self)
|
||||
self.editbox:SetFocus()
|
||||
if not self.frame:IsShown() then
|
||||
self.frame:SetScript("OnShow", Frame_OnShowFocus)
|
||||
end
|
||||
end,
|
||||
|
||||
["HighlightText"] = function(self, from, to)
|
||||
self.editbox:HighlightText(from, to)
|
||||
end
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Constructor()
|
||||
local num = AceGUI:GetNextWidgetNum(Type)
|
||||
local frame = CreateFrame("Frame", nil, UIParent)
|
||||
frame:Hide()
|
||||
|
||||
local editbox = CreateFrame("EditBox", "AceGUI-3.0EditBox"..num, frame, "InputBoxTemplate")
|
||||
editbox:SetAutoFocus(false)
|
||||
editbox:SetFontObject(ChatFontNormal)
|
||||
editbox:SetScript("OnEnter", Control_OnEnter)
|
||||
editbox:SetScript("OnLeave", Control_OnLeave)
|
||||
editbox:SetScript("OnEscapePressed", EditBox_OnEscapePressed)
|
||||
editbox:SetScript("OnEnterPressed", EditBox_OnEnterPressed)
|
||||
editbox:SetScript("OnTextChanged", EditBox_OnTextChanged)
|
||||
editbox:SetScript("OnReceiveDrag", EditBox_OnReceiveDrag)
|
||||
editbox:SetScript("OnMouseDown", EditBox_OnReceiveDrag)
|
||||
editbox:SetScript("OnEditFocusGained", EditBox_OnFocusGained)
|
||||
editbox:SetScript("OnEditFocusLost", EditBox_OnFocusLost)
|
||||
editbox:SetTextInsets(0, 0, 3, 3)
|
||||
editbox:SetMaxLetters(256)
|
||||
editbox:SetPoint("BOTTOMLEFT", 6, 0)
|
||||
editbox:SetPoint("BOTTOMRIGHT", 0, 0)
|
||||
editbox:SetHeight(19)
|
||||
|
||||
local label = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
|
||||
label:SetPoint("TOPLEFT", 0, -2)
|
||||
label:SetPoint("TOPRIGHT", 0, -2)
|
||||
label:SetJustifyH("LEFT")
|
||||
label:SetHeight(18)
|
||||
|
||||
local button = CreateFrame("Button", nil, editbox, "UIPanelButtonTemplate")
|
||||
button:SetWidth(40)
|
||||
button:SetHeight(20)
|
||||
button:SetPoint("RIGHT", -2, 0)
|
||||
button:SetText(OKAY)
|
||||
button:SetScript("OnClick", Button_OnClick)
|
||||
button:Hide()
|
||||
|
||||
local widget = {
|
||||
alignoffset = 30,
|
||||
editbox = editbox,
|
||||
label = label,
|
||||
button = button,
|
||||
frame = frame,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
editbox.obj, button.obj = widget, widget
|
||||
|
||||
return AceGUI:RegisterAsWidget(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
@@ -0,0 +1,78 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Heading Widget
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "Heading", 20
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
-- Lua APIs
|
||||
local pairs = pairs
|
||||
|
||||
-- WoW APIs
|
||||
local CreateFrame, UIParent = CreateFrame, UIParent
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
self:SetText()
|
||||
self:SetFullWidth()
|
||||
self:SetHeight(18)
|
||||
end,
|
||||
|
||||
-- ["OnRelease"] = nil,
|
||||
|
||||
["SetText"] = function(self, text)
|
||||
self.label:SetText(text or "")
|
||||
if text and text ~= "" then
|
||||
self.left:SetPoint("RIGHT", self.label, "LEFT", -5, 0)
|
||||
self.right:Show()
|
||||
else
|
||||
self.left:SetPoint("RIGHT", -3, 0)
|
||||
self.right:Hide()
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Constructor()
|
||||
local frame = CreateFrame("Frame", nil, UIParent)
|
||||
frame:Hide()
|
||||
|
||||
local label = frame:CreateFontString(nil, "BACKGROUND", "GameFontNormal")
|
||||
label:SetPoint("TOP",0,0)
|
||||
label:SetPoint("BOTTOM",0,0)
|
||||
label:SetJustifyH("CENTER")
|
||||
|
||||
local left = frame:CreateTexture(nil, "BACKGROUND")
|
||||
left:SetHeight(8)
|
||||
left:SetPoint("LEFT", 3, 0)
|
||||
left:SetPoint("RIGHT", label, "LEFT", -5, 0)
|
||||
left:SetTexture("Interface\\Tooltips\\UI-Tooltip-Border")
|
||||
left:SetTexCoord(0.81, 0.94, 0.5, 1)
|
||||
|
||||
local right = frame:CreateTexture(nil, "BACKGROUND")
|
||||
right:SetHeight(8)
|
||||
right:SetPoint("RIGHT", -3, 0)
|
||||
right:SetPoint("LEFT", label, "RIGHT", 5, 0)
|
||||
right:SetTexture("Interface\\Tooltips\\UI-Tooltip-Border")
|
||||
right:SetTexCoord(0.81, 0.94, 0.5, 1)
|
||||
|
||||
local widget = {
|
||||
label = label,
|
||||
left = left,
|
||||
right = right,
|
||||
frame = frame,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
|
||||
return AceGUI:RegisterAsWidget(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
@@ -0,0 +1,139 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Icon Widget
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "Icon", 21
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
-- Lua APIs
|
||||
local pairs, print = pairs, print
|
||||
|
||||
-- WoW APIs
|
||||
local CreateFrame, UIParent = CreateFrame, UIParent
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Scripts
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Control_OnEnter()
|
||||
this.obj:Fire("OnEnter")
|
||||
end
|
||||
|
||||
local function Control_OnLeave()
|
||||
this.obj:Fire("OnLeave")
|
||||
end
|
||||
|
||||
local function Button_OnClick()
|
||||
this.obj:Fire("OnClick", 1, arg1)
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
self:SetHeight(110)
|
||||
self:SetWidth(110)
|
||||
self:SetLabel()
|
||||
self:SetImage(nil)
|
||||
self:SetImageSize(64, 64)
|
||||
self:SetDisabled(false)
|
||||
end,
|
||||
|
||||
-- ["OnRelease"] = nil,
|
||||
|
||||
["SetLabel"] = function(self, text)
|
||||
if text and text ~= "" then
|
||||
self.label:Show()
|
||||
self.label:SetText(text)
|
||||
self:SetHeight(self.image:GetHeight() + 25)
|
||||
else
|
||||
self.label:Hide()
|
||||
self:SetHeight(self.image:GetHeight() + 10)
|
||||
end
|
||||
end,
|
||||
|
||||
["SetImage"] = function(self, path, a1,a2,a3,a4,a5,a6,a7,a8)
|
||||
local image = self.image
|
||||
image:SetTexture(path)
|
||||
|
||||
if image:GetTexture() then
|
||||
if a4 or a8 then
|
||||
image:SetTexCoord(a1,a2,a3,a4,a5,a6,a7,a8)
|
||||
else
|
||||
image:SetTexCoord(0, 1, 0, 1)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
["SetImageSize"] = function(self, width, height)
|
||||
self.image:SetWidth(width)
|
||||
self.image:SetHeight(height)
|
||||
--self.frame:SetWidth(width + 30)
|
||||
if self.label:IsShown() then
|
||||
self:SetHeight(height + 25)
|
||||
else
|
||||
self:SetHeight(height + 10)
|
||||
end
|
||||
end,
|
||||
|
||||
["SetDisabled"] = function(self, disabled)
|
||||
self.disabled = disabled
|
||||
if disabled then
|
||||
self.frame:Disable()
|
||||
self.label:SetTextColor(0.5, 0.5, 0.5)
|
||||
self.image:SetVertexColor(0.5, 0.5, 0.5, 0.5)
|
||||
else
|
||||
self.frame:Enable()
|
||||
self.label:SetTextColor(1, 1, 1)
|
||||
self.image:SetVertexColor(1, 1, 1, 1)
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Constructor()
|
||||
local frame = CreateFrame("Button", nil, UIParent)
|
||||
frame:Hide()
|
||||
|
||||
frame:EnableMouse(true)
|
||||
frame:SetScript("OnEnter", Control_OnEnter)
|
||||
frame:SetScript("OnLeave", Control_OnLeave)
|
||||
frame:SetScript("OnClick", Button_OnClick)
|
||||
|
||||
local label = frame:CreateFontString(nil, "BACKGROUND", "GameFontHighlight")
|
||||
label:SetPoint("BOTTOMLEFT")
|
||||
label:SetPoint("BOTTOMRIGHT")
|
||||
label:SetJustifyH("CENTER")
|
||||
label:SetJustifyV("TOP")
|
||||
label:SetHeight(18)
|
||||
|
||||
local image = frame:CreateTexture(nil, "BACKGROUND")
|
||||
image:SetWidth(64)
|
||||
image:SetHeight(64)
|
||||
image:SetPoint("TOP", 0, -5)
|
||||
|
||||
local highlight = frame:CreateTexture(nil, "HIGHLIGHT")
|
||||
highlight:SetAllPoints(image)
|
||||
highlight:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-Tab-Highlight")
|
||||
highlight:SetTexCoord(0, 1, 0.23, 0.77)
|
||||
highlight:SetBlendMode("ADD")
|
||||
|
||||
local widget = {
|
||||
label = label,
|
||||
image = image,
|
||||
frame = frame,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
|
||||
widget.SetText = function(self,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) print("AceGUI-3.0-Icon: SetText is deprecated! Use SetLabel instead!"); self:SetLabel(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) end
|
||||
|
||||
return AceGUI:RegisterAsWidget(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
@@ -0,0 +1,100 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
InteractiveLabel Widget
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "InteractiveLabel", 20
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
-- Lua APIs
|
||||
local pairs = pairs
|
||||
|
||||
-- WoW APIs
|
||||
local CreateFrame, UIParent = CreateFrame, UIParent
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: GameFontHighlightSmall
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Scripts
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Control_OnEnter()
|
||||
this.obj:Fire("OnEnter")
|
||||
end
|
||||
|
||||
local function Control_OnLeave()
|
||||
this.obj:Fire("OnLeave")
|
||||
end
|
||||
|
||||
local function Label_OnClick()
|
||||
this.obj:Fire("OnClick", 1, arg1)
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
self:LabelOnAcquire()
|
||||
self:SetHighlight()
|
||||
self:SetHighlightTexCoord()
|
||||
self:SetDisabled(false)
|
||||
end,
|
||||
|
||||
-- ["OnRelease"] = nil,
|
||||
|
||||
["SetHighlight"] = function(self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
|
||||
self.highlight:SetTexture(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
|
||||
end,
|
||||
|
||||
["SetHighlightTexCoord"] = function(self, a1,a2,a3,a4,a5,a6,a7,a8)
|
||||
if a4 or a8 then
|
||||
self.highlight:SetTexCoord(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
|
||||
else
|
||||
self.highlight:SetTexCoord(0, 1, 0, 1)
|
||||
end
|
||||
end,
|
||||
|
||||
["SetDisabled"] = function(self,disabled)
|
||||
self.disabled = disabled
|
||||
if disabled then
|
||||
self.frame:EnableMouse(false)
|
||||
self.label:SetTextColor(0.5, 0.5, 0.5)
|
||||
else
|
||||
self.frame:EnableMouse(true)
|
||||
self.label:SetTextColor(1, 1, 1)
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Constructor()
|
||||
-- create a Label type that we will hijack
|
||||
local label = AceGUI:Create("Label")
|
||||
|
||||
local frame = label.frame
|
||||
frame:EnableMouse(true)
|
||||
frame:SetScript("OnEnter", Control_OnEnter)
|
||||
frame:SetScript("OnLeave", Control_OnLeave)
|
||||
frame:SetScript("OnMouseDown", Label_OnClick)
|
||||
|
||||
local highlight = frame:CreateTexture(nil, "HIGHLIGHT")
|
||||
highlight:SetTexture(nil)
|
||||
highlight:SetAllPoints()
|
||||
highlight:SetBlendMode("ADD")
|
||||
|
||||
label.highlight = highlight
|
||||
label.type = Type
|
||||
label.LabelOnAcquire = label.OnAcquire
|
||||
for method, func in pairs(methods) do
|
||||
label[method] = func
|
||||
end
|
||||
|
||||
return label
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
|
||||
@@ -0,0 +1,259 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Keybinding Widget
|
||||
Set Keybindings in the Config UI.
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "Keybinding", 25
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
-- Lua APIs
|
||||
local pairs = pairs
|
||||
|
||||
-- WoW APIs
|
||||
local IsShiftKeyDown, IsControlKeyDown, IsAltKeyDown = IsShiftKeyDown, IsControlKeyDown, IsAltKeyDown
|
||||
local CreateFrame, UIParent = CreateFrame, UIParent
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: NOT_BOUND
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Scripts
|
||||
-------------------------------------------------------------------------------]]
|
||||
|
||||
local function Control_OnEnter()
|
||||
this.obj:Fire("OnEnter")
|
||||
end
|
||||
|
||||
local function Control_OnLeave()
|
||||
this.obj:Fire("OnLeave")
|
||||
end
|
||||
|
||||
local function Keybinding_OnHide()
|
||||
local self = this.obj
|
||||
this:EnableKeyboard(false)
|
||||
this:EnableMouseWheel(false)
|
||||
self.msgframe:Hide()
|
||||
this:UnlockHighlight()
|
||||
self.waitingForKey = nil
|
||||
end
|
||||
|
||||
local ignoreKeys = {
|
||||
["BUTTON1"] = true, ["BUTTON2"] = true,
|
||||
["UNKNOWN"] = true,
|
||||
["SHIFT"] = true, ["CTRL"] = true, ["ALT"] = true,
|
||||
}
|
||||
local function Keybinding_OnKeyDown()
|
||||
local self = this.obj
|
||||
if self.waitingForKey then
|
||||
local keyPressed = arg1
|
||||
if keyPressed == "ESCAPE" then
|
||||
keyPressed = ""
|
||||
else
|
||||
if ignoreKeys[keyPressed] then return end
|
||||
if IsShiftKeyDown() then
|
||||
keyPressed = "SHIFT-"..keyPressed
|
||||
end
|
||||
if IsControlKeyDown() then
|
||||
keyPressed = "CTRL-"..keyPressed
|
||||
end
|
||||
if IsAltKeyDown() then
|
||||
keyPressed = "ALT-"..keyPressed
|
||||
end
|
||||
end
|
||||
|
||||
this:EnableKeyboard(false)
|
||||
this:EnableMouseWheel(false)
|
||||
self.msgframe:Hide()
|
||||
this:UnlockHighlight()
|
||||
self.waitingForKey = nil
|
||||
|
||||
if not self.disabled then
|
||||
self:SetKey(keyPressed)
|
||||
self:Fire("OnKeyChanged", 1, keyPressed)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function Keybinding_OnMouseDown()
|
||||
getglobal(this:GetName().."Left"):SetTexture("Interface\\Buttons\\UI-Panel-Button-Down");
|
||||
getglobal(this:GetName().."Middle"):SetTexture("Interface\\Buttons\\UI-Panel-Button-Down");
|
||||
getglobal(this:GetName().."Right"):SetTexture("Interface\\Buttons\\UI-Panel-Button-Down");
|
||||
end
|
||||
|
||||
local function Keybinding_OnMouseUp()
|
||||
getglobal(this:GetName().."Left"):SetTexture("Interface\\Buttons\\UI-Panel-Button-Up");
|
||||
getglobal(this:GetName().."Middle"):SetTexture("Interface\\Buttons\\UI-Panel-Button-Up");
|
||||
getglobal(this:GetName().."Right"):SetTexture("Interface\\Buttons\\UI-Panel-Button-Up");
|
||||
local self = this.obj
|
||||
if MouseIsOver(this) and not self.disabled then
|
||||
if self.waitingForKey then
|
||||
if arg1 ~= "LeftButton" and arg1 ~= "RightButton" then
|
||||
Keybinding_OnKeyDown()
|
||||
end
|
||||
this:EnableKeyboard(false)
|
||||
this:EnableMouseWheel(false)
|
||||
self.msgframe:Hide()
|
||||
this:UnlockHighlight()
|
||||
self.waitingForKey = nil
|
||||
else
|
||||
this:EnableKeyboard(true)
|
||||
this:EnableMouseWheel(true)
|
||||
self.msgframe:Show()
|
||||
this:LockHighlight()
|
||||
self.waitingForKey = true
|
||||
end
|
||||
end
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
local function Keybinding_OnMouseWheel()
|
||||
if arg1 >= 0 then
|
||||
arg1 = "MOUSEWHEELUP"
|
||||
else
|
||||
arg1 = "MOUSEWHEELDOWN"
|
||||
end
|
||||
Keybinding_OnKeyDown()
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
self:SetWidth(200)
|
||||
self:SetLabel("")
|
||||
self:SetKey("")
|
||||
self.waitingForKey = nil
|
||||
self.msgframe:Hide()
|
||||
self:SetDisabled(false)
|
||||
self.button:EnableKeyboard(false)
|
||||
self.button:EnableMouseWheel(false)
|
||||
end,
|
||||
|
||||
-- ["OnRelease"] = nil,
|
||||
|
||||
["SetDisabled"] = function(self, disabled)
|
||||
self.disabled = disabled
|
||||
if disabled then
|
||||
self.button:Disable()
|
||||
self.label:SetTextColor(0.5,0.5,0.5)
|
||||
else
|
||||
self.button:Enable()
|
||||
self.label:SetTextColor(1,1,1)
|
||||
end
|
||||
end,
|
||||
|
||||
["SetKey"] = function(self, key)
|
||||
if (key or "") == "" then
|
||||
self.button:SetText(NOT_BOUND)
|
||||
self.text:SetFontObject("GameFontNormal")
|
||||
else
|
||||
self.button:SetText(key)
|
||||
self.text:SetFontObject("GameFontHighlight")
|
||||
end
|
||||
end,
|
||||
|
||||
["GetKey"] = function(self)
|
||||
local key = self.button:GetText()
|
||||
if key == NOT_BOUND then
|
||||
key = nil
|
||||
end
|
||||
return key
|
||||
end,
|
||||
|
||||
["SetLabel"] = function(self, label)
|
||||
self.label:SetText(label or "")
|
||||
if (label or "") == "" then
|
||||
self.alignoffset = nil
|
||||
self:SetHeight(24)
|
||||
else
|
||||
self.alignoffset = 30
|
||||
self:SetHeight(44)
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
|
||||
local ControlBackdrop = {
|
||||
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
|
||||
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
||||
tile = true, tileSize = 16, edgeSize = 16,
|
||||
insets = { left = 3, right = 3, top = 3, bottom = 3 }
|
||||
}
|
||||
|
||||
local function keybindingMsgFixWidth()
|
||||
this:SetWidth(this.msg:GetWidth() + 10)
|
||||
this:SetScript("OnUpdate", nil)
|
||||
end
|
||||
|
||||
local function Constructor()
|
||||
local name = "AceGUI30KeybindingButton" .. AceGUI:GetNextWidgetNum(Type)
|
||||
|
||||
local frame = CreateFrame("Frame", nil, UIParent)
|
||||
local button = CreateFrame("Button", name, frame, "UIPanelButtonTemplate2")
|
||||
|
||||
button:EnableMouse(true)
|
||||
button:EnableMouseWheel(false)
|
||||
button:SetScript("OnEnter", Control_OnEnter)
|
||||
button:SetScript("OnLeave", Control_OnLeave)
|
||||
|
||||
button:SetScript("OnKeyDown", Keybinding_OnKeyDown)
|
||||
button:RegisterForClicks("AnyDown","AnyUp")
|
||||
-- Ace3v: RegisterForClicks means OnClick will not be triggered, so use OnKeyDown and OnKeyUp
|
||||
button:SetScript("OnMouseDown", Keybinding_OnMouseDown)
|
||||
button:SetScript("OnMouseUp", Keybinding_OnMouseUp)
|
||||
button:SetScript("OnMouseWheel", Keybinding_OnMouseWheel)
|
||||
button:SetScript("OnHide", Keybinding_OnHide)
|
||||
button:SetPoint("BOTTOMLEFT",0,0)
|
||||
button:SetPoint("BOTTOMRIGHT",0,0)
|
||||
button:SetHeight(24)
|
||||
button:EnableKeyboard(false)
|
||||
|
||||
local text = button:GetFontString()
|
||||
text:SetPoint("LEFT", 7, 0)
|
||||
text:SetPoint("RIGHT", -7, 0)
|
||||
|
||||
local label = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
|
||||
label:SetPoint("TOPLEFT",0,0)
|
||||
label:SetPoint("TOPRIGHT",0,0)
|
||||
label:SetJustifyH("CENTER")
|
||||
label:SetHeight(18)
|
||||
|
||||
local msgframe = CreateFrame("Frame", nil, UIParent)
|
||||
msgframe:SetHeight(30)
|
||||
msgframe:SetBackdrop(ControlBackdrop)
|
||||
msgframe:SetBackdropColor(0,0,0)
|
||||
msgframe:SetFrameStrata("FULLSCREEN_DIALOG")
|
||||
msgframe:SetFrameLevel(1000)
|
||||
msgframe:SetToplevel(true)
|
||||
|
||||
local msg = msgframe:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
||||
msg:SetText("Press a key to bind, ESC to clear the binding or click the button again to cancel.")
|
||||
msgframe.msg = msg
|
||||
msg:SetPoint("TOPLEFT", 5, -5)
|
||||
msgframe:SetScript("OnUpdate", keybindingMsgFixWidth)
|
||||
msgframe:SetPoint("BOTTOM", button, "TOP")
|
||||
msgframe:Hide()
|
||||
|
||||
local widget = {
|
||||
button = button,
|
||||
label = label,
|
||||
msgframe = msgframe,
|
||||
frame = frame,
|
||||
alignoffset = 30,
|
||||
type = Type,
|
||||
text = text
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
button.obj = widget
|
||||
|
||||
return AceGUI:RegisterAsWidget(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
@@ -0,0 +1,165 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Label Widget
|
||||
Displays text and optionally an icon.
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "Label", 23
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
-- Lua APIs
|
||||
local max, pairs = math.max, pairs
|
||||
|
||||
-- WoW APIs
|
||||
local CreateFrame, UIParent = CreateFrame, UIParent
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: GameFontHighlightSmall
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Support functions
|
||||
-------------------------------------------------------------------------------]]
|
||||
|
||||
local function UpdateImageAnchor(self)
|
||||
if self.resizing then return end
|
||||
local frame = self.frame
|
||||
local width = frame.width or frame:GetWidth() or 0
|
||||
local image = self.image
|
||||
local label = self.label
|
||||
local height
|
||||
|
||||
label:ClearAllPoints()
|
||||
image:ClearAllPoints()
|
||||
|
||||
if self.imageshown then
|
||||
local imagewidth = image:GetWidth()
|
||||
if (width - imagewidth) < 200 or (label:GetText() or "") == "" then
|
||||
-- image goes on top centered when less than 200 width for the text, or if there is no text
|
||||
image:SetPoint("TOP",0,0)
|
||||
label:SetPoint("TOP", image, "BOTTOM")
|
||||
label:SetPoint("LEFT",0,0)
|
||||
label:SetWidth(width)
|
||||
height = image:GetHeight() + label:GetHeight()
|
||||
else
|
||||
-- image on the left
|
||||
image:SetPoint("TOPLEFT",0,0)
|
||||
if image:GetHeight() > label:GetHeight() then
|
||||
label:SetPoint("LEFT", image, "RIGHT", 4, 0)
|
||||
else
|
||||
label:SetPoint("TOPLEFT", image, "TOPRIGHT", 4, 0)
|
||||
end
|
||||
label:SetWidth(width - imagewidth - 4)
|
||||
height = max(image:GetHeight(), label:GetHeight())
|
||||
end
|
||||
else
|
||||
-- no image shown
|
||||
label:SetPoint("TOPLEFT",0,0)
|
||||
label:SetWidth(width)
|
||||
height = label:GetHeight()
|
||||
end
|
||||
|
||||
self.resizing = true
|
||||
frame:SetHeight(height)
|
||||
frame.height = height
|
||||
self.resizing = nil
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
-- set the flag to stop constant size updates
|
||||
self.resizing = true
|
||||
-- height is set dynamically by the text and image size
|
||||
self:SetWidth(200)
|
||||
self:SetText()
|
||||
self:SetImage(nil)
|
||||
self:SetImageSize(16, 16)
|
||||
self:SetColor()
|
||||
self:SetFontObject()
|
||||
|
||||
-- reset the flag
|
||||
self.resizing = nil
|
||||
-- run the update explicitly
|
||||
UpdateImageAnchor(self)
|
||||
end,
|
||||
|
||||
-- ["OnRelease"] = nil,
|
||||
|
||||
["OnWidthSet"] = function(self, width)
|
||||
UpdateImageAnchor(self)
|
||||
end,
|
||||
|
||||
["SetText"] = function(self, text)
|
||||
self.label:SetText(text)
|
||||
UpdateImageAnchor(self)
|
||||
end,
|
||||
|
||||
["SetColor"] = function(self, r, g, b)
|
||||
if not (r and g and b) then
|
||||
r, g, b = 1, 1, 1
|
||||
end
|
||||
self.label:SetVertexColor(r, g, b)
|
||||
end,
|
||||
|
||||
["SetImage"] = function(self, path, a1,a2,a3,a4,a5,a6,a7,a8)
|
||||
local image = self.image
|
||||
image:SetTexture(path)
|
||||
|
||||
if image:GetTexture() then
|
||||
self.imageshown = true
|
||||
if a4 or a8 then
|
||||
image:SetTexCoord(a1,a2,a3,a4,a5,a6,a7,a8)
|
||||
else
|
||||
image:SetTexCoord(0, 1, 0, 1)
|
||||
end
|
||||
else
|
||||
self.imageshown = nil
|
||||
end
|
||||
UpdateImageAnchor(self)
|
||||
end,
|
||||
|
||||
["SetFont"] = function(self, font, height, flags)
|
||||
self.label:SetFont(font, height, flags)
|
||||
end,
|
||||
|
||||
["SetFontObject"] = function(self, font)
|
||||
self:SetFont((font or GameFontHighlightSmall):GetFont())
|
||||
end,
|
||||
|
||||
["SetImageSize"] = function(self, width, height)
|
||||
self.image:SetWidth(width)
|
||||
self.image:SetHeight(height)
|
||||
UpdateImageAnchor(self)
|
||||
end,
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Constructor()
|
||||
local frame = CreateFrame("Frame", nil, UIParent)
|
||||
frame:Hide()
|
||||
|
||||
local label = frame:CreateFontString(nil, "BACKGROUND", "GameFontHighlightSmall")
|
||||
label:SetJustifyH("LEFT")
|
||||
label:SetJustifyV("TOP")
|
||||
|
||||
local image = frame:CreateTexture(nil, "BACKGROUND")
|
||||
|
||||
-- create widget
|
||||
local widget = {
|
||||
label = label,
|
||||
image = image,
|
||||
frame = frame,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
|
||||
return AceGUI:RegisterAsWidget(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
@@ -0,0 +1,475 @@
|
||||
local Type, Version = "MultiLineEditBox", 28
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
local AceCore = LibStub("AceCore-3.0")
|
||||
local hooksecurefunc = AceCore.hooksecurefunc
|
||||
|
||||
-- Lua APIs
|
||||
local strfmt = string.format
|
||||
local pairs = pairs
|
||||
|
||||
-- WoW APIs
|
||||
local GetCursorInfo, GetSpellInfo, ClearCursor = GetCursorInfo, GetSpellInfo, ClearCursor
|
||||
local CreateFrame, UIParent = CreateFrame, UIParent
|
||||
local _G = AceCore._G
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: ACCEPT, ChatFontNormal
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Support functions
|
||||
-------------------------------------------------------------------------------]]
|
||||
if not AceGUIMultiLineEditBoxInsertLink then
|
||||
-- upgradeable hook
|
||||
hooksecurefunc("BankFrameItemButtonGeneric_OnClick",
|
||||
function(button)
|
||||
if button == "LeftButton" and IsShiftKeyDown() and not this.isBag then
|
||||
return _G.AceGUIMultiLineEditBoxInsertLink(GetContainerItemLink(BANK_CONTAINER, this:GetID()))
|
||||
end
|
||||
end)
|
||||
hooksecurefunc("ContainerFrameItemButton_OnClick",
|
||||
function(button, ignoreModifiers)
|
||||
if button == "LeftButton" and IsShiftKeyDown() and not ignoreModifiers then
|
||||
return _G.AceGUIMultiLineEditBoxInsertLink(GetContainerItemLink(this:GetParent():GetID(), this:GetID()))
|
||||
end
|
||||
end)
|
||||
|
||||
hooksecurefunc("KeyRingItemButton_OnClick",
|
||||
function(button)
|
||||
if button == "LeftButton" and IsShiftKeyDown() and not this.isBag then
|
||||
return _G.AceGUIMultiLineEditBoxInsertLink(GetContainerItemLink(KEYRING_CONTAINER, this:GetID()))
|
||||
end
|
||||
end)
|
||||
hooksecurefunc("LootFrameItem_OnClick",
|
||||
function(button)
|
||||
if button == "LeftButton" and IsShiftKeyDown() then
|
||||
return _G.AceGUIMultiLineEditBoxInsertLink(GetLootSlotLink(this.slot))
|
||||
end
|
||||
end)
|
||||
hooksecurefunc("SetItemRef",
|
||||
function(link, text, button)
|
||||
if IsShiftKeyDown() then
|
||||
if strsub(link,1,6) == "player" then
|
||||
local name = strsub(link,8)
|
||||
if name and (strlen(name) > 0) then
|
||||
return _G.AceGUIMultiLineEditBoxInsertLink(name)
|
||||
end
|
||||
else
|
||||
return _G.AceGUIMultiLineEditBoxInsertLink(text)
|
||||
end
|
||||
end
|
||||
end)
|
||||
hooksecurefunc("MerchantItemButton_OnClick",
|
||||
function(button, ignoreModifiers)
|
||||
if MerchantFrame.selectedTab == 1 and button == "LeftButton" and IsShiftKeyDown() and not ignoreModifiers then
|
||||
return _G.AceGUIMultiLineEditBoxInsertLink(GetMerchantItemLink(this:GetID()))
|
||||
end
|
||||
end)
|
||||
hooksecurefunc("PaperDollItemSlotButton_OnClick",
|
||||
function(button, ignoreModifiers)
|
||||
if button == "LeftButton" and IsShiftKeyDown() and not ignoreModifiers then
|
||||
return _G.AceGUIMultiLineEditBoxInsertLink(GetInventoryItemLink("player", this:GetID()))
|
||||
end
|
||||
end)
|
||||
hooksecurefunc("QuestItem_OnClick",
|
||||
function()
|
||||
if IsShiftKeyDown() and this.rewardType ~= "spell" then
|
||||
return _G.AceGUIMultiLineEditBoxInsertLink(GetQuestItemLink(this.type, this:GetID()))
|
||||
end
|
||||
end)
|
||||
hooksecurefunc("QuestRewardItem_OnClick",
|
||||
function()
|
||||
if IsShiftKeyDown() and this.rewardType ~= "spell" then
|
||||
return _G.AceGUIMultiLineEditBoxInsertLink(GetQuestItemLink(this.type, this:GetID()))
|
||||
end
|
||||
end)
|
||||
hooksecurefunc("QuestLogTitleButton_OnClick",
|
||||
function(button)
|
||||
if IsShiftKeyDown() and (not this.isHeader) then
|
||||
return _G.AceGUIMultiLineEditBoxInsertLink(gsub(this:GetText(), " *(.*)", "%1"))
|
||||
end
|
||||
end)
|
||||
hooksecurefunc("QuestLogRewardItem_OnClick",
|
||||
function()
|
||||
if IsShiftKeyDown() and this.rewardType ~= "spell" then
|
||||
return _G.AceGUIMultiLineEditBoxInsertLink(GetQuestLogItemLink(this.type, this:GetID()))
|
||||
end
|
||||
end)
|
||||
hooksecurefunc("SpellButton_OnClick",
|
||||
function(drag)
|
||||
local id = SpellBook_GetSpellID(this:GetID())
|
||||
if id <= MAX_SPELLS and (not drag) and IsShiftKeyDown() then
|
||||
local spellName, subSpellName = GetSpellName(id, SpellBookFrame.bookType)
|
||||
if spellName and not IsSpellPassive(id, SpellBookFrame.bookType) then
|
||||
if subSpellName and (strlen(subSpellName) > 0) then
|
||||
_G.AceGUIMultiLineEditBoxInsertLink(spellName.."("..subSpellName..")");
|
||||
else
|
||||
_G.AceGUIMultiLineEditBoxInsertLink(spellName);
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
function _G.AceGUIMultiLineEditBoxInsertLink(text)
|
||||
for i = 1, AceGUI:GetWidgetCount(Type) do
|
||||
local editbox = _G[strfmt("MultiLineEditBox%uEdit",i)]
|
||||
if editbox and editbox:IsVisible() and editbox.hasfocus then
|
||||
editbox:Insert(text)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function Layout(self)
|
||||
self:SetHeight(self.numlines * 14 + (self.disablebutton and 19 or 41) + self.labelHeight)
|
||||
|
||||
if self.labelHeight == 0 then
|
||||
self.scrollBar:SetPoint("TOP", self.frame, "TOP", 0, -23)
|
||||
else
|
||||
self.scrollBar:SetPoint("TOP", self.label, "BOTTOM", 0, -19)
|
||||
end
|
||||
|
||||
if self.disablebutton then
|
||||
self.scrollBar:SetPoint("BOTTOM", self.frame, "BOTTOM", 0, 21)
|
||||
self.scrollBG:SetPoint("BOTTOMLEFT", 0, 4)
|
||||
else
|
||||
self.scrollBar:SetPoint("BOTTOM", self.button, "TOP", 0, 18)
|
||||
self.scrollBG:SetPoint("BOTTOMLEFT", self.button, "TOPLEFT")
|
||||
end
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Scripts
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function OnClick() -- Button
|
||||
local self = this.obj
|
||||
self.editBox:ClearFocus()
|
||||
if not self:Fire("OnEnterPressed", 1, self.editBox:GetText()) then
|
||||
self.button:Disable()
|
||||
end
|
||||
end
|
||||
|
||||
local function OnCursorChanged() -- EditBox
|
||||
|
||||
local self, y = this.obj.scrollFrame, -arg2
|
||||
local offset = self:GetVerticalScroll()
|
||||
if y < offset then
|
||||
self:SetVerticalScroll(y)
|
||||
else
|
||||
y = y + arg4 - self:GetHeight()
|
||||
if y > offset then
|
||||
self:SetVerticalScroll(y)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function OnEditFocusLost() -- EditBox
|
||||
this.hasfocus = nil
|
||||
this:HighlightText(0, 0)
|
||||
this.obj:Fire("OnEditFocusLost")
|
||||
end
|
||||
|
||||
local function OnEnter() -- EditBox / ScrollFrame
|
||||
local self = this.obj
|
||||
if not self.entered then
|
||||
self.entered = true
|
||||
self:Fire("OnEnter")
|
||||
end
|
||||
end
|
||||
|
||||
local function OnLeave() -- EditBox / ScrollFrame
|
||||
local self = this.obj
|
||||
if self.entered then
|
||||
self.entered = nil
|
||||
self:Fire("OnLeave")
|
||||
end
|
||||
end
|
||||
|
||||
local function OnMouseUp() -- ScrollFrame
|
||||
local self = this.obj.editBox
|
||||
self:SetFocus()
|
||||
local n = self:GetNumLetters()
|
||||
self:HighlightText(n,n)
|
||||
end
|
||||
|
||||
local function OnReceiveDrag() -- EditBox / ScrollFrame
|
||||
if not GetCursorInfo then return end
|
||||
local type, id, info = GetCursorInfo()
|
||||
if type == "spell" then
|
||||
local spell, rank = GetSpellName(id, info)
|
||||
if rank ~= "" then spell = spell.."("..rank..")" end
|
||||
info = spell
|
||||
elseif type ~= "item" then
|
||||
return
|
||||
end
|
||||
ClearCursor()
|
||||
local self = this.obj
|
||||
local editBox = self.editBox
|
||||
if not this.hasfocus then
|
||||
this.hasfocus = true
|
||||
editBox:SetFocus()
|
||||
local n = editBox:GetNumLetters()
|
||||
editBox:HighlightText(n,n)
|
||||
end
|
||||
editBox:Insert(info)
|
||||
self.button:Enable()
|
||||
end
|
||||
|
||||
local function OnSizeChanged() -- ScrollFrame
|
||||
this.obj.editBox:SetWidth(arg1)
|
||||
end
|
||||
|
||||
local function OnTextChanged() -- EditBox
|
||||
local self = this.obj
|
||||
local value = this:GetText()
|
||||
if tostring(value) ~= tostring(self.lasttext) then
|
||||
self:Fire("OnTextChanged", 1, value)
|
||||
self.lasttext = value
|
||||
self.button:Enable()
|
||||
end
|
||||
end
|
||||
|
||||
local function OnTextSet() -- EditBox
|
||||
this:HighlightText(0, 0)
|
||||
this.obj.button:Disable()
|
||||
end
|
||||
|
||||
local function OnVerticalScroll() -- ScrollFrame
|
||||
local self = this.obj
|
||||
local editBox = self.editBox
|
||||
editBox:SetHitRectInsets(0, 0, arg1, editBox:GetHeight() - arg1 - this:GetHeight())
|
||||
|
||||
self.scrollFrame:SetScrollChild(self.editBox)
|
||||
self.editBox:SetPoint("TOPLEFT",0,arg1)
|
||||
self.editBox:SetPoint("TOPRIGHT",0,arg1)
|
||||
end
|
||||
|
||||
local function OnShowFocus()
|
||||
this.obj.editBox:SetFocus()
|
||||
this:SetScript("OnShow", nil)
|
||||
end
|
||||
|
||||
local function OnEditFocusGained()
|
||||
this.hasfocus = true
|
||||
AceGUI:SetFocus(this.obj)
|
||||
this.obj:Fire("OnEditFocusGained")
|
||||
end
|
||||
|
||||
local function OnEscapePressed() -- EditBox
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
self.editBox:SetText("")
|
||||
self:SetDisabled(false)
|
||||
self:SetWidth(200)
|
||||
self:DisableButton(false)
|
||||
self:SetNumLines()
|
||||
self.entered = nil
|
||||
self:SetMaxLetters(0)
|
||||
end,
|
||||
|
||||
["OnRelease"] = function(self)
|
||||
self:ClearFocus()
|
||||
end,
|
||||
|
||||
["SetDisabled"] = function(self, disabled)
|
||||
local editBox = self.editBox
|
||||
if disabled then
|
||||
editBox:ClearFocus()
|
||||
editBox:EnableMouse(false)
|
||||
editBox:SetTextColor(0.5, 0.5, 0.5)
|
||||
self.label:SetTextColor(0.5, 0.5, 0.5)
|
||||
self.scrollFrame:EnableMouse(false)
|
||||
self.button:Disable()
|
||||
else
|
||||
editBox:EnableMouse(true)
|
||||
editBox:SetTextColor(1, 1, 1)
|
||||
self.label:SetTextColor(1, 0.82, 0)
|
||||
self.scrollFrame:EnableMouse(true)
|
||||
end
|
||||
end,
|
||||
|
||||
["SetLabel"] = function(self, text)
|
||||
if text and text ~= "" then
|
||||
self.label:SetText(text)
|
||||
if self.labelHeight ~= 10 then
|
||||
self.labelHeight = 10
|
||||
self.label:Show()
|
||||
end
|
||||
elseif self.labelHeight ~= 0 then
|
||||
self.labelHeight = 0
|
||||
self.label:Hide()
|
||||
end
|
||||
Layout(self)
|
||||
end,
|
||||
|
||||
["SetNumLines"] = function(self, value)
|
||||
if not value or value < 4 then
|
||||
value = 4
|
||||
end
|
||||
self.numlines = value
|
||||
Layout(self)
|
||||
end,
|
||||
|
||||
["SetText"] = function(self, text)
|
||||
self.lasttext = text or ""
|
||||
self.editBox:SetText(text or "")
|
||||
self.editBox:HighlightText(0)
|
||||
self.button:Disable()
|
||||
end,
|
||||
|
||||
["GetText"] = function(self)
|
||||
return self.editBox:GetText()
|
||||
end,
|
||||
|
||||
["SetMaxLetters"] = function (self, num)
|
||||
self.editBox:SetMaxLetters(num or 0)
|
||||
end,
|
||||
|
||||
["DisableButton"] = function(self, disabled)
|
||||
self.disablebutton = disabled
|
||||
if disabled then
|
||||
self.button:Hide()
|
||||
else
|
||||
self.button:Show()
|
||||
end
|
||||
Layout(self)
|
||||
end,
|
||||
|
||||
["ClearFocus"] = function(self)
|
||||
self.editBox:ClearFocus()
|
||||
self.frame:SetScript("OnShow", nil)
|
||||
end,
|
||||
|
||||
["SetFocus"] = function(self)
|
||||
self.editBox:SetFocus()
|
||||
if not self.frame:IsShown() then
|
||||
self.frame:SetScript("OnShow", OnShowFocus)
|
||||
end
|
||||
end,
|
||||
|
||||
["HighlightText"] = function(self, from, to)
|
||||
self.editBox:HighlightText(from, to)
|
||||
end,
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local backdrop = {
|
||||
bgFile = [[Interface\Tooltips\UI-Tooltip-Background]],
|
||||
edgeFile = [[Interface\Tooltips\UI-Tooltip-Border]], edgeSize = 16,
|
||||
insets = { left = 4, right = 3, top = 4, bottom = 3 }
|
||||
}
|
||||
|
||||
local function Constructor()
|
||||
local frame = CreateFrame("Frame", nil, UIParent)
|
||||
frame:Hide()
|
||||
|
||||
local widgetNum = AceGUI:GetNextWidgetNum(Type)
|
||||
|
||||
local label = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
|
||||
label:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, -4)
|
||||
label:SetPoint("TOPRIGHT", frame, "TOPRIGHT", 0, -4)
|
||||
label:SetJustifyH("LEFT")
|
||||
label:SetText(ACCEPT)
|
||||
label:SetHeight(10)
|
||||
|
||||
local button = CreateFrame("Button", strfmt("%s%dButton", Type, widgetNum), frame, "UIPanelButtonTemplate")
|
||||
button:SetPoint("BOTTOMLEFT", 0, 4)
|
||||
button:SetHeight(22)
|
||||
button:SetWidth(label:GetStringWidth() + 24)
|
||||
button:SetText(ACCEPT)
|
||||
button:SetScript("OnClick", OnClick)
|
||||
button:Disable()
|
||||
|
||||
local text = button:GetFontString()
|
||||
text:ClearAllPoints()
|
||||
text:SetPoint("TOPLEFT", button, "TOPLEFT", 5, -5)
|
||||
text:SetPoint("BOTTOMRIGHT", button, "BOTTOMRIGHT", -5, 1)
|
||||
text:SetJustifyV("MIDDLE")
|
||||
|
||||
local scrollBG = CreateFrame("Frame", nil, frame)
|
||||
scrollBG:SetBackdrop(backdrop)
|
||||
scrollBG:SetBackdropColor(0, 0, 0)
|
||||
scrollBG:SetBackdropBorderColor(0.4, 0.4, 0.4)
|
||||
|
||||
local scrollFrame = CreateFrame("ScrollFrame", strfmt("%s%dScrollFrame", Type, widgetNum), frame, "UIPanelScrollFrameTemplate")
|
||||
|
||||
local scrollBar = _G[scrollFrame:GetName() .. "ScrollBar"]
|
||||
scrollBar:ClearAllPoints()
|
||||
scrollBar:SetPoint("TOP", label, "BOTTOM", 0, -19)
|
||||
scrollBar:SetPoint("BOTTOM", button, "TOP", 0, 18)
|
||||
scrollBar:SetPoint("RIGHT", frame, "RIGHT")
|
||||
|
||||
scrollBG:SetPoint("TOPRIGHT", scrollBar, "TOPLEFT", 0, 19)
|
||||
scrollBG:SetPoint("BOTTOMLEFT", button, "TOPLEFT")
|
||||
|
||||
scrollFrame:SetPoint("TOPLEFT", scrollBG, "TOPLEFT", 5, -6)
|
||||
scrollFrame:SetPoint("BOTTOMRIGHT", scrollBG, "BOTTOMRIGHT", -4, 4)
|
||||
scrollFrame:SetScript("OnEnter", OnEnter)
|
||||
scrollFrame:SetScript("OnLeave", OnLeave)
|
||||
scrollFrame:SetScript("OnMouseUp", OnMouseUp)
|
||||
scrollFrame:SetScript("OnReceiveDrag", OnReceiveDrag)
|
||||
scrollFrame:SetScript("OnSizeChanged", OnSizeChanged)
|
||||
local old = scrollFrame:GetScript("OnVerticalScroll");
|
||||
if old then
|
||||
scrollFrame:SetScript("OnVerticalScroll", function()
|
||||
old()
|
||||
OnVerticalScroll()
|
||||
end)
|
||||
else
|
||||
scrollFrame:SetScript("OnVerticalScroll", OnVerticalScroll)
|
||||
end
|
||||
|
||||
local editBox = CreateFrame("EditBox", strfmt("%s%dEdit", Type, widgetNum), scrollFrame)
|
||||
editBox:SetFontObject(ChatFontNormal)
|
||||
editBox:SetMultiLine(true)
|
||||
editBox:EnableMouse(true)
|
||||
editBox:SetAutoFocus(false)
|
||||
--editBox:SetCountInvisibleLetters(false)
|
||||
editBox:SetScript("OnCursorChanged", OnCursorChanged)
|
||||
editBox:SetScript("OnEditFocusLost", OnEditFocusLost)
|
||||
editBox:SetScript("OnEnter", OnEnter)
|
||||
editBox:SetScript("OnEscapePressed", OnEscapePressed)
|
||||
editBox:SetScript("OnLeave", OnLeave)
|
||||
editBox:SetScript("OnMouseDown", OnReceiveDrag)
|
||||
editBox:SetScript("OnReceiveDrag", OnReceiveDrag)
|
||||
editBox:SetScript("OnTextChanged", OnTextChanged)
|
||||
editBox:SetScript("OnTextSet", OnTextSet)
|
||||
editBox:SetScript("OnEditFocusGained", OnEditFocusGained)
|
||||
|
||||
-- Ace3v: the orders are important here
|
||||
scrollFrame:SetScrollChild(editBox)
|
||||
editBox:SetPoint("TOPLEFT",0,0)
|
||||
editBox:SetPoint("TOPRIGHT",0,0)
|
||||
|
||||
local widget = {
|
||||
button = button,
|
||||
editBox = editBox,
|
||||
frame = frame,
|
||||
label = label,
|
||||
labelHeight = 10,
|
||||
numlines = 4,
|
||||
scrollBar = scrollBar,
|
||||
scrollBG = scrollBG,
|
||||
scrollFrame = scrollFrame,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
button.obj, editBox.obj, scrollFrame.obj = widget, widget, widget
|
||||
|
||||
return AceGUI:RegisterAsWidget(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
@@ -0,0 +1,312 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Slider Widget
|
||||
Graphical Slider, like, for Range values.
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "Slider", 22
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
-- Lua APIs
|
||||
local min, max, floor = math.min, math.max, math.floor
|
||||
local tonumber, pairs = tonumber, pairs
|
||||
|
||||
-- WoW APIs
|
||||
local PlaySound = PlaySound
|
||||
local CreateFrame, UIParent = CreateFrame, UIParent
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: GameFontHighlightSmall
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Support functions
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function DisplayValue(self, value)
|
||||
if self.valueLabels and self.valueLabels[value] then
|
||||
return self.valueLabels[value]
|
||||
end
|
||||
return value
|
||||
end
|
||||
|
||||
local function UpdateText(self)
|
||||
local value = self.value or 0
|
||||
if self.valueLabels and self.valueLabels[value] then
|
||||
self.editbox:SetText(self.valueLabels[value])
|
||||
elseif self.ispercent then
|
||||
self.editbox:SetText(("%s%%"):format(floor(value * 1000 + 0.5) / 10))
|
||||
else
|
||||
self.editbox:SetText(floor(value * 100 + 0.5) / 100)
|
||||
end
|
||||
end
|
||||
|
||||
local function UpdateLabels(self)
|
||||
local min, max = (self.min or 0), (self.max or 100)
|
||||
if self.valueLabels then
|
||||
self.lowtext:SetText(DisplayValue(self, min))
|
||||
self.hightext:SetText(DisplayValue(self, max))
|
||||
elseif self.ispercent then
|
||||
self.lowtext:SetFormattedText("%s%%", (min * 100))
|
||||
self.hightext:SetFormattedText("%s%%", (max * 100))
|
||||
else
|
||||
self.lowtext:SetText(min)
|
||||
self.hightext:SetText(max)
|
||||
end
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Scripts
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Control_OnEnter()
|
||||
this.obj:Fire("OnEnter")
|
||||
end
|
||||
|
||||
local function Control_OnLeave()
|
||||
this.obj:Fire("OnLeave")
|
||||
end
|
||||
|
||||
local function Frame_OnMouseDown()
|
||||
this.obj.slider:EnableMouseWheel(true)
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
local function Slider_OnValueChanged()
|
||||
local self = this.obj
|
||||
if not this.setup then
|
||||
local newvalue = this:GetValue()
|
||||
if self.step and self.step > 0 then
|
||||
local min_value = self.min or 0
|
||||
newvalue = floor((newvalue - min_value) / self.step + 0.5) * self.step + min_value
|
||||
end
|
||||
if newvalue ~= self.value and not self.disabled then
|
||||
self.value = newvalue
|
||||
self:Fire("OnValueChanged", 1, newvalue)
|
||||
end
|
||||
if self.value then
|
||||
UpdateText(self)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function Slider_OnMouseUp()
|
||||
local self = this.obj
|
||||
self:Fire("OnMouseUp", 1, self.value)
|
||||
end
|
||||
|
||||
local function Slider_OnMouseWheel()
|
||||
local self = this.obj
|
||||
if not self.disabled then
|
||||
local value = self.value
|
||||
if arg1 > 0 then
|
||||
value = min(value + (self.step or 1), self.max)
|
||||
else
|
||||
value = max(value - (self.step or 1), self.min)
|
||||
end
|
||||
self.slider:SetValue(value)
|
||||
end
|
||||
end
|
||||
|
||||
local function EditBox_OnEscapePressed()
|
||||
this:ClearFocus()
|
||||
end
|
||||
|
||||
local function EditBox_OnEnterPressed()
|
||||
local self = this.obj
|
||||
local value = this:GetText()
|
||||
if self.valueLabels then
|
||||
local typed=value
|
||||
value=tonumber(value)
|
||||
if not value then
|
||||
for sliderValue,label in pairs(self.valueLabels) do
|
||||
if tostring(label)==typed then value=sliderValue break end
|
||||
end
|
||||
end
|
||||
elseif self.ispercent then
|
||||
value = value:gsub('%%', '')
|
||||
value = tonumber(value) / 100
|
||||
else
|
||||
value = tonumber(value)
|
||||
end
|
||||
|
||||
if value then
|
||||
PlaySound("igMainMenuOptionCheckBoxOn")
|
||||
self.slider:SetValue(value)
|
||||
self:Fire("OnMouseUp", 1, value)
|
||||
end
|
||||
end
|
||||
|
||||
local function EditBox_OnEnter()
|
||||
this:SetBackdropBorderColor(0.5, 0.5, 0.5, 1)
|
||||
end
|
||||
|
||||
local function EditBox_OnLeave()
|
||||
this:SetBackdropBorderColor(0.3, 0.3, 0.3, 0.8)
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
self:SetWidth(200)
|
||||
self:SetHeight(44)
|
||||
self:SetDisabled(false)
|
||||
self:SetValueLabels(nil)
|
||||
self:SetIsPercent(nil)
|
||||
self:SetSliderValues(0,100,1)
|
||||
self:SetValue(0)
|
||||
self.slider:EnableMouseWheel(false)
|
||||
end,
|
||||
|
||||
-- ["OnRelease"] = nil,
|
||||
|
||||
["SetDisabled"] = function(self, disabled)
|
||||
self.disabled = disabled
|
||||
if disabled then
|
||||
self.slider:EnableMouse(false)
|
||||
self.label:SetTextColor(.5, .5, .5)
|
||||
self.hightext:SetTextColor(.5, .5, .5)
|
||||
self.lowtext:SetTextColor(.5, .5, .5)
|
||||
--self.valuetext:SetTextColor(.5, .5, .5)
|
||||
self.editbox:SetTextColor(.5, .5, .5)
|
||||
self.editbox:EnableMouse(false)
|
||||
self.editbox:ClearFocus()
|
||||
else
|
||||
self.slider:EnableMouse(true)
|
||||
self.label:SetTextColor(1, .82, 0)
|
||||
self.hightext:SetTextColor(1, 1, 1)
|
||||
self.lowtext:SetTextColor(1, 1, 1)
|
||||
--self.valuetext:SetTextColor(1, 1, 1)
|
||||
self.editbox:SetTextColor(1, 1, 1)
|
||||
self.editbox:EnableMouse(true)
|
||||
end
|
||||
end,
|
||||
|
||||
["SetValue"] = function(self, value)
|
||||
self.slider.setup = true
|
||||
self.slider:SetValue(value)
|
||||
self.value = value
|
||||
UpdateText(self)
|
||||
self.slider.setup = nil
|
||||
end,
|
||||
|
||||
["GetValue"] = function(self)
|
||||
return self.value
|
||||
end,
|
||||
|
||||
["SetLabel"] = function(self, text)
|
||||
self.label:SetText(text)
|
||||
end,
|
||||
|
||||
["SetSliderValues"] = function(self, min, max, step)
|
||||
local frame = self.slider
|
||||
frame.setup = true
|
||||
self.min = min
|
||||
self.max = max
|
||||
self.step = step
|
||||
frame:SetMinMaxValues(min or 0,max or 100)
|
||||
UpdateLabels(self)
|
||||
frame:SetValueStep(step or 1)
|
||||
if self.value then
|
||||
frame:SetValue(self.value)
|
||||
end
|
||||
frame.setup = nil
|
||||
end,
|
||||
|
||||
["SetValueLabels"] = function(self, labels)
|
||||
self.valueLabels = labels
|
||||
UpdateLabels(self)
|
||||
UpdateText(self)
|
||||
end,
|
||||
|
||||
["SetIsPercent"] = function(self, value)
|
||||
self.ispercent = value
|
||||
UpdateLabels(self)
|
||||
UpdateText(self)
|
||||
end
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local SliderBackdrop = {
|
||||
bgFile = "Interface\\Buttons\\UI-SliderBar-Background",
|
||||
edgeFile = "Interface\\Buttons\\UI-SliderBar-Border",
|
||||
tile = true, tileSize = 8, edgeSize = 8,
|
||||
insets = { left = 3, right = 3, top = 6, bottom = 6 }
|
||||
}
|
||||
|
||||
local ManualBackdrop = {
|
||||
bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
|
||||
edgeFile = "Interface\\ChatFrame\\ChatFrameBackground",
|
||||
tile = true, edgeSize = 1, tileSize = 5,
|
||||
}
|
||||
|
||||
local function Constructor()
|
||||
local frame = CreateFrame("Frame", nil, UIParent)
|
||||
|
||||
frame:EnableMouse(true)
|
||||
frame:SetScript("OnMouseDown", Frame_OnMouseDown)
|
||||
|
||||
local label = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
||||
label:SetPoint("TOPLEFT",0,0)
|
||||
label:SetPoint("TOPRIGHT",0,0)
|
||||
label:SetJustifyH("CENTER",0,0)
|
||||
label:SetHeight(15)
|
||||
|
||||
local slider = CreateFrame("Slider", nil, frame)
|
||||
slider:SetOrientation("HORIZONTAL")
|
||||
slider:SetHeight(15)
|
||||
slider:SetHitRectInsets(0, 0, -10, 0)
|
||||
slider:SetBackdrop(SliderBackdrop)
|
||||
slider:SetThumbTexture("Interface\\Buttons\\UI-SliderBar-Button-Horizontal")
|
||||
slider:SetPoint("TOP", label, "BOTTOM")
|
||||
slider:SetPoint("LEFT", 3, 0)
|
||||
slider:SetPoint("RIGHT", -3, 0)
|
||||
slider:SetValue(0)
|
||||
slider:SetScript("OnValueChanged",Slider_OnValueChanged)
|
||||
slider:SetScript("OnEnter", Control_OnEnter)
|
||||
slider:SetScript("OnLeave", Control_OnLeave)
|
||||
slider:SetScript("OnMouseUp", Slider_OnMouseUp)
|
||||
slider:SetScript("OnMouseWheel", Slider_OnMouseWheel)
|
||||
|
||||
local lowtext = slider:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
|
||||
lowtext:SetPoint("TOPLEFT", slider, "BOTTOMLEFT", 2, 3)
|
||||
|
||||
local hightext = slider:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
|
||||
hightext:SetPoint("TOPRIGHT", slider, "BOTTOMRIGHT", -2, 3)
|
||||
|
||||
local editbox = CreateFrame("EditBox", nil, frame)
|
||||
editbox:SetAutoFocus(false)
|
||||
editbox:SetFontObject(GameFontHighlightSmall)
|
||||
editbox:SetPoint("TOP", slider, "BOTTOM")
|
||||
editbox:SetHeight(14)
|
||||
editbox:SetWidth(70)
|
||||
editbox:SetJustifyH("CENTER")
|
||||
editbox:EnableMouse(true)
|
||||
editbox:SetBackdrop(ManualBackdrop)
|
||||
editbox:SetBackdropColor(0, 0, 0, 0.5)
|
||||
editbox:SetBackdropBorderColor(0.3, 0.3, 0.30, 0.80)
|
||||
editbox:SetScript("OnEnter", EditBox_OnEnter)
|
||||
editbox:SetScript("OnLeave", EditBox_OnLeave)
|
||||
editbox:SetScript("OnEnterPressed", EditBox_OnEnterPressed)
|
||||
editbox:SetScript("OnEscapePressed", EditBox_OnEscapePressed)
|
||||
|
||||
local widget = {
|
||||
label = label,
|
||||
slider = slider,
|
||||
lowtext = lowtext,
|
||||
hightext = hightext,
|
||||
editbox = editbox,
|
||||
alignoffset = 25,
|
||||
frame = frame,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
slider.obj, editbox.obj = widget, widget
|
||||
|
||||
return AceGUI:RegisterAsWidget(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type,Constructor,Version)
|
||||
@@ -0,0 +1,14 @@
|
||||
<Ui xmlns="http://www.blizzard.com/wow/ui/">
|
||||
<Script file="AceGUIContainer-Frame.lua"/>
|
||||
<Script file="AceGUIContainer-InlineGroup.lua"/>
|
||||
<Script file="AceGUIContainer-ScrollFrame.lua"/>
|
||||
<Script file="AceGUIContainer-SimpleGroup.lua"/>
|
||||
<Script file="AceGUIContainer-TabGroup.lua"/>
|
||||
<Script file="AceGUIWidget-Button.lua"/>
|
||||
<Script file="AceGUIWidget-CheckBox.lua"/>
|
||||
<Script file="AceGUIWidget-DropDown.lua"/>
|
||||
<Script file="AceGUIWidget-DropDown-Items.lua"/>
|
||||
<Script file="AceGUIWidget-Heading.lua"/>
|
||||
<Script file="AceGUIWidget-Label.lua"/>
|
||||
<Script file="AceGUIWidget-Slider.lua"/>
|
||||
</Ui>
|
||||
@@ -0,0 +1,252 @@
|
||||
--[[ Questie CallbackHandler-1.0 API, Lua 5.0 syntax compatibility ]]
|
||||
-- Original Questie foundation: CallbackHandler-1.0 r1131 / MINOR 6.
|
||||
-- Turtle 1.12 Lua 5.0 supports vararg declarations but consumes them through
|
||||
-- the implicit 'arg' table rather than Lua 5.1's '...' expression.
|
||||
local MAJOR, MINOR = "CallbackHandler-1.0", 6
|
||||
local CallbackHandler = LibStub:NewLibrary(MAJOR, MINOR)
|
||||
|
||||
if not CallbackHandler then return end
|
||||
|
||||
local meta = {__index = function(tbl, key) tbl[key] = {} return tbl[key] end}
|
||||
|
||||
local tconcat = table.concat
|
||||
local assert, error, loadstring = assert, error, loadstring
|
||||
local setmetatable, rawset, rawget = setmetatable, rawset, rawget
|
||||
local next, pairs, type, tostring = next, pairs, type, tostring
|
||||
local unpack = unpack
|
||||
local xpcall = xpcall
|
||||
|
||||
local function errorhandler(err)
|
||||
return geterrorhandler()(err)
|
||||
end
|
||||
|
||||
-- Same Questie dispatcher strategy, emitted with fixed named arguments so the
|
||||
-- generated source contains no Lua 5.1 vararg expressions.
|
||||
local function CreateDispatcher(argCount)
|
||||
local args={}
|
||||
local oldargs={}
|
||||
for i=1,argCount do
|
||||
args[i]="arg"..i
|
||||
oldargs[i]="old_arg"..i
|
||||
end
|
||||
|
||||
local argList=tconcat(args,", ")
|
||||
local oldArgList=tconcat(oldargs,", ")
|
||||
local dispatchSignature="handlers"
|
||||
if argCount>0 then dispatchSignature=dispatchSignature..", "..argList end
|
||||
|
||||
local saveOld
|
||||
local assignArgs
|
||||
local restoreOld
|
||||
|
||||
if argCount>0 then
|
||||
saveOld="local old_CALL_ARGS = CALL_ARGS"
|
||||
assignArgs="CALL_ARGS = {"..argList.."}"
|
||||
restoreOld="CALL_ARGS = old_CALL_ARGS"
|
||||
else
|
||||
saveOld="local old_CALL_ARGS = CALL_ARGS"
|
||||
assignArgs="CALL_ARGS = {}"
|
||||
restoreOld="CALL_ARGS = old_CALL_ARGS"
|
||||
end
|
||||
|
||||
local code=[[
|
||||
return function(next, xpcall, eh, unpack)
|
||||
local method
|
||||
local CALL_ARGS = {}
|
||||
|
||||
local function call()
|
||||
method(unpack(CALL_ARGS, 1, CALL_ARGS.n or table.getn(CALL_ARGS)))
|
||||
end
|
||||
|
||||
local function dispatch(DISPATCH_SIGNATURE)
|
||||
local index
|
||||
index, method = next(handlers)
|
||||
if not method then return end
|
||||
|
||||
SAVE_OLD
|
||||
ASSIGN_ARGS
|
||||
CALL_ARGS.n = ARG_COUNT
|
||||
|
||||
repeat
|
||||
xpcall(call, eh)
|
||||
index, method = next(handlers, index)
|
||||
until not method
|
||||
|
||||
RESTORE_OLD
|
||||
end
|
||||
|
||||
return dispatch
|
||||
end
|
||||
]]
|
||||
|
||||
code=string.gsub(code,"DISPATCH_SIGNATURE",dispatchSignature)
|
||||
code=string.gsub(code,"SAVE_OLD",saveOld)
|
||||
code=string.gsub(code,"ASSIGN_ARGS",assignArgs)
|
||||
code=string.gsub(code,"RESTORE_OLD",restoreOld)
|
||||
code=string.gsub(code,"ARG_COUNT",tostring(argCount))
|
||||
|
||||
local chunk=assert(loadstring(code,"safecall Dispatcher["..argCount.."]"))
|
||||
local factory=chunk()
|
||||
return factory(next,xpcall,errorhandler,unpack)
|
||||
end
|
||||
|
||||
local Dispatchers=setmetatable({},{
|
||||
__index=function(self,argCount)
|
||||
local dispatcher=CreateDispatcher(argCount)
|
||||
rawset(self,argCount,dispatcher)
|
||||
return dispatcher
|
||||
end
|
||||
})
|
||||
|
||||
function CallbackHandler:New(target, RegisterName, UnregisterName, UnregisterAllName)
|
||||
RegisterName=RegisterName or "RegisterCallback"
|
||||
UnregisterName=UnregisterName or "UnregisterCallback"
|
||||
if UnregisterAllName==nil then
|
||||
UnregisterAllName="UnregisterAllCallbacks"
|
||||
end
|
||||
|
||||
local events=setmetatable({},meta)
|
||||
local registry={recurse=0,events=events}
|
||||
|
||||
function registry:Fire(eventname, ...)
|
||||
if not rawget(events,eventname) or not next(events[eventname]) then return end
|
||||
|
||||
local oldrecurse=registry.recurse
|
||||
registry.recurse=oldrecurse+1
|
||||
|
||||
local count=arg.n or table.getn(arg)
|
||||
local callargs={eventname}
|
||||
callargs.n=count+1
|
||||
for i=1,count do callargs[i+1]=arg[i] end
|
||||
Dispatchers[count+1](events[eventname],unpack(callargs,1,callargs.n))
|
||||
|
||||
registry.recurse=oldrecurse
|
||||
|
||||
if registry.insertQueue and oldrecurse==0 then
|
||||
for queuedEvent,callbacks in pairs(registry.insertQueue) do
|
||||
local first=not rawget(events,queuedEvent) or not next(events[queuedEvent])
|
||||
for self,func in pairs(callbacks) do
|
||||
events[queuedEvent][self]=func
|
||||
if first and registry.OnUsed then
|
||||
registry.OnUsed(registry,target,queuedEvent)
|
||||
first=nil
|
||||
end
|
||||
end
|
||||
end
|
||||
registry.insertQueue=nil
|
||||
end
|
||||
end
|
||||
|
||||
target[RegisterName]=function(self,eventname,method,...)
|
||||
if type(eventname)~="string" then
|
||||
error("Usage: "..RegisterName.."(eventname, method[, arg]): 'eventname' - string expected.",2)
|
||||
end
|
||||
|
||||
method=method or eventname
|
||||
local first=not rawget(events,eventname) or not next(events[eventname])
|
||||
|
||||
if type(method)~="string" and type(method)~="function" then
|
||||
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - string or function expected.",2)
|
||||
end
|
||||
|
||||
local regfunc
|
||||
local optionalCount=arg.n or table.getn(arg)
|
||||
|
||||
if type(method)=="string" then
|
||||
if type(self)~="table" then
|
||||
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): self was not a table?",2)
|
||||
elseif self==target then
|
||||
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): do not use Library:"..RegisterName.."(), use your own 'self'",2)
|
||||
elseif type(self[method])~="function" then
|
||||
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - method '"..tostring(method).."' not found on self.",2)
|
||||
end
|
||||
|
||||
if optionalCount>=1 then
|
||||
local extra=arg[1]
|
||||
regfunc=function(...)
|
||||
self[method](self,extra,unpack(arg,1,arg.n or table.getn(arg)))
|
||||
end
|
||||
else
|
||||
regfunc=function(...)
|
||||
self[method](self,unpack(arg,1,arg.n or table.getn(arg)))
|
||||
end
|
||||
end
|
||||
else
|
||||
if type(self)~="table" and type(self)~="string" and type(self)~="thread" then
|
||||
error("Usage: "..RegisterName.."(self or \"addonId\", eventname, method): 'self or addonId': table or string or thread expected.",2)
|
||||
end
|
||||
|
||||
if optionalCount>=1 then
|
||||
local extra=arg[1]
|
||||
regfunc=function(...)
|
||||
method(extra,unpack(arg,1,arg.n or table.getn(arg)))
|
||||
end
|
||||
else
|
||||
regfunc=method
|
||||
end
|
||||
end
|
||||
|
||||
if events[eventname][self] or registry.recurse<1 then
|
||||
events[eventname][self]=regfunc
|
||||
if registry.OnUsed and first then
|
||||
registry.OnUsed(registry,target,eventname)
|
||||
end
|
||||
else
|
||||
registry.insertQueue=registry.insertQueue or setmetatable({},meta)
|
||||
registry.insertQueue[eventname][self]=regfunc
|
||||
end
|
||||
end
|
||||
|
||||
target[UnregisterName]=function(self,eventname)
|
||||
if not self or self==target then
|
||||
error("Usage: "..UnregisterName.."(eventname): bad 'self'",2)
|
||||
end
|
||||
if type(eventname)~="string" then
|
||||
error("Usage: "..UnregisterName.."(eventname): 'eventname' - string expected.",2)
|
||||
end
|
||||
|
||||
if rawget(events,eventname) and events[eventname][self] then
|
||||
events[eventname][self]=nil
|
||||
if registry.OnUnused and not next(events[eventname]) then
|
||||
registry.OnUnused(registry,target,eventname)
|
||||
end
|
||||
end
|
||||
|
||||
if registry.insertQueue and rawget(registry.insertQueue,eventname) and registry.insertQueue[eventname][self] then
|
||||
registry.insertQueue[eventname][self]=nil
|
||||
end
|
||||
end
|
||||
|
||||
if UnregisterAllName then
|
||||
target[UnregisterAllName]=function(...)
|
||||
local count=arg.n or table.getn(arg)
|
||||
if count<1 then
|
||||
error("Usage: "..UnregisterAllName.."([whatFor]): missing 'self' or \"addonId\" to unregister events for.",2)
|
||||
end
|
||||
if count==1 and arg[1]==target then
|
||||
error("Usage: "..UnregisterAllName.."([whatFor]): supply a meaningful 'self' or \"addonId\"",2)
|
||||
end
|
||||
|
||||
for i=1,count do
|
||||
local self=arg[i]
|
||||
|
||||
if registry.insertQueue then
|
||||
for eventname,callbacks in pairs(registry.insertQueue) do
|
||||
if callbacks[self] then callbacks[self]=nil end
|
||||
end
|
||||
end
|
||||
|
||||
for eventname,callbacks in pairs(events) do
|
||||
if callbacks[self] then
|
||||
callbacks[self]=nil
|
||||
if registry.OnUnused and not next(callbacks) then
|
||||
registry.OnUnused(registry,target,eventname)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return registry
|
||||
end
|
||||
@@ -0,0 +1,4 @@
|
||||
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
|
||||
..\FrameXML\UI.xsd">
|
||||
<Script file="CallbackHandler-1.0.lua"/>
|
||||
</Ui>
|
||||
@@ -0,0 +1,30 @@
|
||||
-- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info
|
||||
-- LibStub is hereby placed in the Public Domain Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke
|
||||
local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS!
|
||||
local LibStub = _G[LIBSTUB_MAJOR]
|
||||
|
||||
if not LibStub or LibStub.minor < LIBSTUB_MINOR then
|
||||
LibStub = LibStub or {libs = {}, minors = {} }
|
||||
_G[LIBSTUB_MAJOR] = LibStub
|
||||
LibStub.minor = LIBSTUB_MINOR
|
||||
|
||||
function LibStub:NewLibrary(major, minor)
|
||||
assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
|
||||
minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.")
|
||||
|
||||
local oldminor = self.minors[major]
|
||||
if oldminor and oldminor >= minor then return nil end
|
||||
self.minors[major], self.libs[major] = minor, self.libs[major] or {}
|
||||
return self.libs[major], oldminor
|
||||
end
|
||||
|
||||
function LibStub:GetLibrary(major, silent)
|
||||
if not self.libs[major] and not silent then
|
||||
error(("Cannot find a library instance of %q."):format(tostring(major)), 2)
|
||||
end
|
||||
return self.libs[major], self.minors[major]
|
||||
end
|
||||
|
||||
function LibStub:IterateLibraries() return pairs(self.libs) end
|
||||
setmetatable(LibStub, { __call = LibStub.GetLibrary })
|
||||
end
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user