2012-01-01 04:01:18 +01:00
local GetTime = QuestHelper_GetTime
2010-11-08 14:28:59 +01:00
QuestHelper_File [ " collect_quest.lua " ] = " 4.0.1.$svnversion$ "
2010-10-24 23:17:33 +02:00
QuestHelper_Loadtime [ " collect_quest.lua " ] = GetTime ( )
local debug_output = false
if QuestHelper_File [ " collect_quest.lua " ] == " Development Version " then debug_output = true end
local IsMonsterGUID
local GetMonsterType
local GetQuestType
local GetItemType
local GetLoc
local GetSpecBolus
local QHCQ
local deebey
local function RegisterQuestData ( category , location , GetQuestLogWhateverInfo )
local index = 1
local localspot
while true do
local ilink = GetQuestLogItemLink ( category , index )
if not ilink then break end
if not localspot then if not location [ " items_ " .. category ] then location [ " items_ " .. category ] = { } end localspot = location [ " items_ " .. category ] end
local name , tex , num , qual , usa = GetQuestLogWhateverInfo ( index )
localspot [ GetItemType ( ilink ) ] = num
--QuestHelper:TextOut(string.format("%s:%d - %d %s %s", category, index, num, tostring(ilink), tostring(name)))
index = index + 1
end
end
local complete_suffix = string.gsub ( string.gsub ( string.gsub ( ERR_QUEST_OBJECTIVE_COMPLETE_S , " %%s " , " " ) , " %) " , " %%) " ) , " %( " , " %%( " )
function pin ( )
QuestHelper : TextOut ( " ^.*: (%d+)/(%d+)( " .. complete_suffix .. " )?$ " )
end
-- qlookup[questname][objectivename] = {{qid = qid, objid = objid}}
local qlookups = { }
local function ScanQuests ( )
local selected
local index = 1
local dbx = { }
qlookups = { }
while true do
if not GetQuestLogTitle ( index ) then break end
local qlink = GetQuestLink ( index )
if qlink then
--QuestHelper:TextOut(qlink)
--QuestHelper:TextOut(string.gsub(qlink, "|", "||"))
local id , level = GetQuestType ( qlink )
local title , _ , tag , groupcount , _ , _ , _ , daily = GetQuestLogTitle ( index )
if not qlookups [ title ] then qlookups [ title ] = { } end -- gronk
--QuestHelper:TextOut(string.format("%s - %d %d", qlink, id, level))
if not QHCQ [ id ] then
--if true then
if not selected then selected = GetQuestLogSelection ( ) end
SelectQuestLogEntry ( index )
QHCQ [ id ] = { }
QHCQ [ id ] . level = level
RegisterQuestData ( " reward " , QHCQ [ id ] , GetQuestLogRewardInfo )
RegisterQuestData ( " choice " , QHCQ [ id ] , GetQuestLogChoiceInfo )
--QuestHelper:TextOut(string.format("%d", GetNumQuestLeaderBoards(index)))
2011-01-22 03:44:34 +01:00
if not QHCQ [ id ] [ " criteria " ] then QHCQ [ id ] [ " criteria " ] = { } end
2011-01-22 02:45:43 +01:00
2010-10-24 23:17:33 +02:00
for i = 1 , GetNumQuestLeaderBoards ( index ) do
2011-01-22 02:45:43 +01:00
local desc , typ = GetQuestLogLeaderBoard ( i , index )
local criterion = { text = desc , type = typ }
2011-01-22 03:44:34 +01:00
QHCQ [ id ] [ " criteria " ] [ tostring ( i ) ] = criterion
2011-01-22 02:45:43 +01:00
--QHCQ[id][string.format("criteria_%d_text", i)] = desc
--QHCQ[id][string.format("criteria_%d_type", i)] = type
2010-10-24 23:17:33 +02:00
--QuestHelper:TextOut(string.format("%s, %s", desc, type))
end
QHCQ [ id ] . name = title
QHCQ [ id ] . tag = tag
QHCQ [ id ] . groupcount = ( groupcount or - 1 )
QHCQ [ id ] . daily = ( not not daily )
if GetQuestLogSpecialItemInfo then
local typ = GetQuestLogSpecialItemInfo ( index )
if typ then typ = GetItemType ( typ ) end
QHCQ [ id ] . special_item = typ or false
end
end
dbx [ id ] = { }
--QuestHelper:TextOut(string.format("%d", GetNumQuestLeaderBoards(index)))
for i = 1 , GetNumQuestLeaderBoards ( index ) do
local desc , typ , done = GetQuestLogLeaderBoard ( i , index )
-- Some quests have faulty objectives where there is literally NO information... Ignore those objectives.
if desc and typ ~= " log " then
if not qlookups [ title ] [ desc ] then qlookups [ title ] [ desc ] = { } end
table.insert ( qlookups [ title ] [ desc ] , { qid = id , obj = i } )
-- If we wanted to parse everything here, we'd do something very complicated.
-- Fundamentally, we don't. We only care if numeric values change or if something goes from "not done" to "done".
-- Luckily, the patterns are identical in all cases for this (I think.)
local have , needed = string.match ( desc , " ^.*: (%d+)/(%d+)$ " )
have = tonumber ( have )
needed = tonumber ( needed )
--[[QuestHelper:TextOut(desc)
QuestHelper : TextOut ( " ^.*: (%d+)/(%d+)( " .. complete_suffix .. " )?$ " )
QuestHelper : TextOut ( string.gsub ( desc , complete_suffix , " " ) )
QuestHelper : TextOut ( string.format ( " %s %s " , tostring ( have ) , tostring ( needed ) ) ) ] ]
if not have or not needed then
have = done and 1 or 0
needed = 1 -- okay so we don't really use this unless we're debugging, shut up >:(
end
dbx [ id ] [ i ] = have
end
end
end
index = index + 1
end
if selected then SelectQuestLogEntry ( selected ) end -- abort abort bzzt bzzt bzzt awoooooooga dive, dive, dive
return dbx
end
local eventy = { }
local function Looted ( message )
local ltype = GetItemType ( message , true )
2010-10-25 02:11:00 +02:00
-- Oddly, we get an ltype that has a nil value once in a while, so we ignore it and return.
-- Only seems to occur when rolling for something.
if ltype == nil then return end
-- Just in case...
if type ( ltype ) ~= " number " then
error ( string.format ( " Expected a number but got a %s. " , type ( ltype ) ) .. " The value is: " .. ltype )
end
2012-01-01 03:22:56 +01:00
table.insert ( eventy , { time = GetTime ( ) , event = { type = " item " , value = ltype } } )
2010-10-24 23:17:33 +02:00
--if debug_output then QuestHelper:TextOut(string.format("Added event %s", string.format("I%di", ltype))) end
end
2011-07-06 13:46:30 +02:00
local function Combat ( _ , event , _ , _ , _ , _ , _ , guid )
2010-10-24 23:17:33 +02:00
if event ~= " UNIT_DIED " then return end
if not IsMonsterGUID ( guid ) then return end
local mtype = GetMonsterType ( guid , true )
2012-01-01 03:22:56 +01:00
table.insert ( eventy , { time = GetTime ( ) , event = { type = " monster " , value = mtype } } )
2010-10-24 23:17:33 +02:00
--if debug_output then QuestHelper:TextOut(string.format("Added event %s", string.format("M%dm", mtype))) end
end
local changed = false
local first = true
local function Init ( )
first = true
end
local function LogChanged ( )
changed = true
end
local function WatchUpdate ( ) -- we're currently ignoring the ID of the quest that was updated for simplicity's sake.
changed = true
end
local function AppendMember ( tab , key , dat )
2011-01-21 02:06:11 +01:00
if not tab [ key ] then tab [ key ] = { } end
table.insert ( tab [ key ] , dat )
--tab[key] = (tab[key] or "") .. dat
2010-10-24 23:17:33 +02:00
end
local function StartOrEnd ( se , id )
local targuid = UnitGUID ( " target " )
2011-01-21 02:06:11 +01:00
local chunk = { }
2010-10-24 23:17:33 +02:00
if targuid and IsMonsterGUID ( targuid ) then
2011-01-21 02:06:11 +01:00
chunk.m = GetMonsterType ( targuid )
2010-10-24 23:17:33 +02:00
end
2011-01-21 02:06:11 +01:00
chunk.loc = GetLoc ( )
chunk.spec = GetSpecBolus ( )
2010-10-24 23:17:33 +02:00
2011-01-21 02:06:11 +01:00
if not QHCQ [ id ] [ se ] then QHCQ [ id ] [ se ] = { } end
table.insert ( QHCQ [ id ] [ se ] , chunk )
--AppendMember(QHCQ[id], se, chunk)
--AppendMember(QHCQ[id], se .. "_spec", GetSpecBolus())
2010-10-24 23:17:33 +02:00
end
local abandoncomplete = " "
local abandoncomplete_timestamp = nil
local GetQuestReward_Orig = GetQuestReward
GetQuestReward = function ( ... )
abandoncomplete = " complete "
2012-01-01 03:22:56 +01:00
abandoncomplete_timestamp = GetTime ( )
2010-10-24 23:17:33 +02:00
GetQuestReward_Orig ( ... )
end
local AbandonQuest_Orig = AbandonQuest
AbandonQuest = function ( )
abandoncomplete = " abandon "
2012-01-01 03:22:56 +01:00
abandoncomplete_timestamp = GetTime ( )
2010-10-24 23:17:33 +02:00
AbandonQuest_Orig ( )
end
local function UpdateQuests ( )
do -- this should once and for all fix this issue
local foverride = true
for _ , _ in pairs ( deebey ) do
foverride = false
end
if UnitLevel ( " player " ) == 1 then
foverride = false
end
if foverride then foverride = true end
end
if first then deebey = ScanQuests ( ) first = false end
if not changed then return end
changed = false
2012-01-01 03:22:56 +01:00
local tim = GetTime ( )
2010-10-24 23:17:33 +02:00
local noobey = ScanQuests ( )
local traverse = { }
local dsize , nsize = QuestHelper : TableSize ( deebey ) , QuestHelper : TableSize ( noobey )
for k , _ in pairs ( deebey ) do traverse [ k ] = true end
for k , _ in pairs ( noobey ) do traverse [ k ] = true end
--[[
if QuestHelper : TableSize ( deebey ) ~= QuestHelper : TableSize ( noobey ) then
QuestHelper : TextOut ( string.format ( " %d %d " , QuestHelper : TableSize ( deebey ) , QuestHelper : TableSize ( noobey ) ) )
end ] ]
2012-01-01 03:22:56 +01:00
while # eventy > 0 and eventy [ 1 ] . time < GetTime ( ) - 1 do table.remove ( eventy , 1 ) end -- slurp
2010-10-24 23:17:33 +02:00
local token
local debugtok
local diffs = 0
for k , _ in pairs ( traverse ) do
if not deebey [ k ] then
-- Quest was acquired
if debug_output then QuestHelper : TextOut ( string.format ( " Acquired! Questid %d " , k ) ) end
StartOrEnd ( " start " , k )
diffs = diffs + 1
elseif not noobey [ k ] then
-- Quest was dropped or completed
2012-01-01 03:22:56 +01:00
if abandoncomplete == " complete " and abandoncomplete_timestamp + 30 >= GetTime ( ) then
2010-10-24 23:17:33 +02:00
if debug_output then QuestHelper : TextOut ( string.format ( " Completed! Questid %d " , k ) ) end
StartOrEnd ( " end " , k )
abandoncomplete = " "
else
if debug_output then QuestHelper : TextOut ( string.format ( " Dropped! Questid %d " , k ) ) end
end
diffs = diffs + 1
else
QuestHelper : Assert ( # deebey [ k ] == # noobey [ k ] , string.format ( " %d vs %d, %d " , # deebey [ k ] , # noobey [ k ] , k ) )
for i = 1 , # deebey [ k ] do
if noobey [ k ] [ i ] > deebey [ k ] [ i ] then
if not token then
2011-01-21 02:06:11 +01:00
token = { }
token [ " events " ] = { }
2011-01-21 02:51:15 +01:00
for k , v in pairs ( eventy ) do table.insert ( token.events , v.event ) end
2010-10-24 23:17:33 +02:00
debugtok = token
2011-01-21 02:06:11 +01:00
token [ " loc " ] = GetLoc ( )
--token = token .. "(" .. GetLoc() .. ")"
2010-10-24 23:17:33 +02:00
end
local ttok = token
if noobey [ k ] [ i ] - 1 ~= deebey [ k ] [ i ] then
2011-01-21 02:06:11 +01:00
--ttok = string.format("C%dc", noobey[k][i] - deebey[k][i]) .. ttok
if not ttok [ " Cdc " ] then ttok [ " Cdc " ] = { } end
table.insert ( ttok [ " Cdc " ] , noobey [ k ] [ i ] - deebey [ k ] [ i ] )
2010-10-24 23:17:33 +02:00
end
2011-01-22 02:45:43 +01:00
if not QHCQ [ k ] [ " criteria " ] then QHCQ [ k ] [ " criteria " ] = { } end
2010-10-24 23:17:33 +02:00
2011-01-22 02:45:43 +01:00
if not QHCQ [ k ] [ " criteria " ] [ tostring ( i ) ] then QHCQ [ k ] [ " criteria " ] [ tostring ( i ) ] = { } end
if not QHCQ [ k ] [ " criteria " ] [ tostring ( i ) ] [ " satisfied " ] then QHCQ [ k ] [ " criteria " ] [ tostring ( i ) ] [ " satisfied " ] = { } end
table.insert ( QHCQ [ k ] [ " criteria " ] [ tostring ( i ) ] [ " satisfied " ] , ttok )
2011-01-21 02:06:11 +01:00
--AppendMember(QHCQ[k], string.format("criteria_%d_satisfied", i), ttok)
2010-10-24 23:17:33 +02:00
if debug_output then QuestHelper : TextOut ( string.format ( " Updated! Questid %d item %d count %d tok %s " , k , i , noobey [ k ] [ i ] - deebey [ k ] [ i ] , debugtok ) ) end
diffs = diffs + 1
end
end
end
end
deebey = noobey
--QuestHelper: Assert(diffs <= 5, string.format("excessive quest diffs - delta is %d, went from %d to %d", diffs, dsize, nsize))
2012-01-01 03:22:56 +01:00
--QuestHelper:TextOut(string.format("done in %f", GetTime() - tim))
2010-10-24 23:17:33 +02:00
end
local enable_quest_hints = GetBuildInfo ( ) : match ( " 0%.1%..* " ) or ( GetBuildInfo ( ) : match ( " 3%..* " ) and not GetBuildInfo ( ) : match ( " 3%.0%..* " ) )
QH_filter_hints = false
local function MouseoverUnit ( )
QH_filter_hints = false
if not enable_quest_hints then return end
if GameTooltip : GetUnit ( ) and UnitExists ( " mouseover " ) and UnitIsVisible ( " mouseover " ) and not UnitIsPlayer ( " mouseover " ) and not UnitPlayerControlled ( " mouseover " ) then
local guid = UnitGUID ( " mouseover " )
if not IsMonsterGUID ( guid ) then return end
guid = GetMonsterType ( guid )
if GetQuestLogSpecialItemInfo then
for _ , v in pairs ( qlookups ) do
for _ , block in pairs ( v ) do
for _ , tv in ipairs ( block ) do
2011-01-22 02:45:43 +01:00
if not QHCQ [ tv.qid ] [ " criteria " ] then QHCQ [ tv.qid ] [ " criteria " ] = { } end
if not QHCQ [ tv.qid ] [ " criteria " ] [ tostring ( tv.obj ) ] then QHCQ [ tv.qid ] [ " criteria " ] [ tostring ( tv.obj ) ] = { } end
2012-01-01 04:10:17 +01:00
if not QHCQ [ tv.qid ] [ " criteria " ] [ tostring ( tv.obj ) ] [ " monster " ] then QHCQ [ tv.qid ] [ " criteria " ] [ tostring ( tv.obj ) ] [ " monster " ] = { } end
2011-01-22 02:45:43 +01:00
if not QHCQ [ tv.qid ] [ " criteria " ] [ tostring ( tv.obj ) ] [ " monster " ] [ " true " ] then
QHCQ [ tv.qid ] [ " criteria " ] [ tostring ( tv.obj ) ] [ " monster " ] [ " true " ] = { }
QHCQ [ tv.qid ] [ " criteria " ] [ tostring ( tv.obj ) ] [ " monster " ] [ " false " ] = { }
2010-10-24 23:17:33 +02:00
end
2011-01-22 02:45:43 +01:00
QHCQ [ tv.qid ] [ " criteria " ] [ tostring ( tv.obj ) ] [ " monster " ] [ " false " ] [ guid ] = ( QHCQ [ tv.qid ] [ " criteria " ] [ tostring ( tv.obj ) ] [ " monster " ] [ " false " ] [ guid ] or 0 ) + 1
2010-10-24 23:17:33 +02:00
end
end
end
local line = 2
local qs
local qe
while _G [ " GameTooltipTextLeft " .. line ] and _G [ " GameTooltipTextLeft " .. line ] : IsShown ( ) do
local r , g , b , a = _G [ " GameTooltipTextLeft " .. line ] : GetTextColor ( )
r , g , b , a = math.floor ( r * 255 + 0.5 ) , math.floor ( g * 255 + 0.5 ) , math.floor ( b * 255 + 0.5 ) , math.floor ( a * 255 + 0.5 )
--print(r, g, b, a)
if r == 255 and g == 210 and b == 0 and a == 255 then
if not qs then qs = line end
else
if qs and not qe then qe = line end
end
line = line + 1
end
if qs and not qe then qe = line end
if qe then qe = qe - 1 end
if qs and qe then
local cquest = nil
QH_filter_hints = true
for i = qs , qe do
local lin = _G [ " GameTooltipTextLeft " .. i ] : GetText ( )
if cquest and cquest [ lin ] then
local titem_block = cquest [ lin ]
for _ , titem in pairs ( titem_block ) do
2011-01-22 02:45:43 +01:00
local tv = titem
QHCQ [ tv.qid ] [ " criteria " ] [ tostring ( tv.obj ) ] [ " monster " ] [ " false " ] [ guid ] = ( QHCQ [ tv.qid ] [ " criteria " ] [ tostring ( tv.obj ) ] [ " monster " ] [ " false " ] [ guid ] or 0 ) - 1
QHCQ [ tv.qid ] [ " criteria " ] [ tostring ( tv.obj ) ] [ " monster " ] [ " false " ] [ guid ] = ( QHCQ [ tv.qid ] [ " criteria " ] [ tostring ( tv.obj ) ] [ " monster " ] [ " true " ] [ guid ] or 0 ) + 1
2010-10-24 23:17:33 +02:00
end
elseif qlookups [ lin ] then
cquest = qlookups [ lin ]
else
QH_filter_hints = false
--QuestHelper: Assert()
end
end
end
end
end
end
2012-09-26 01:52:08 +02:00
function QH_Collect_Quest_FactionChange ( QHCData )
2010-10-24 23:17:33 +02:00
if not QHCData.quest then QHCData.quest = { } end
QHCQ = QHCData.quest
2012-09-26 01:52:08 +02:00
end
function QH_Collect_Quest_Init ( QHCData , API )
QH_Collect_Quest_FactionChange ( QHCData )
2010-10-24 23:17:33 +02:00
GetQuestType = API.Utility_GetQuestType
GetItemType = API.Utility_GetItemType
IsMonsterGUID = API.Utility_IsMonsterGUID
GetMonsterType = API.Utility_GetMonsterType
GetSpecBolus = API.Utility_GetSpecBolus
QuestHelper : Assert ( GetQuestType )
QuestHelper : Assert ( GetItemType )
QuestHelper : Assert ( IsMonsterGUID )
QuestHelper : Assert ( GetMonsterType )
QuestHelper : Assert ( GetSpecBolus )
GetLoc = API.Callback_LocationBolusCurrent
QuestHelper : Assert ( GetLoc )
deebey = ScanQuests ( )
QH_Event ( " UNIT_QUEST_LOG_CHANGED " , LogChanged )
QH_Event ( " QUEST_LOG_UPDATE " , UpdateQuests )
QH_Event ( " QUEST_WATCH_UPDATE " , WatchUpdate )
QH_Event ( " CHAT_MSG_LOOT " , Looted )
QH_Event ( " COMBAT_LOG_EVENT_UNFILTERED " , Combat )
API.Registrar_TooltipHook ( MouseoverUnit )
-- Here's a pile of events that seem to trigger during startup that also don't seem like would trigger while questing.
-- We'll lose a few quest updates from this, but that's OK.
QH_Event ( " PLAYER_ENTERING_WORLD " , Init )
QH_Event ( " UNIT_MODEL_CHANGED " , Init )
QH_Event ( " GUILDBANK_UPDATE_WITHDRAWMONEY " , Init )
QH_Event ( " UPDATE_TICKET " , Init )
end