1
0
Bifurcation 0

Abandoning the idea of separating the collection system from the core for the moment. It is looking a bit harder than anticipated for the moment. I will revisit this later.

Cette révision appartient à :
Nathanial.C.Jones 2012-01-02 01:34:49 +00:00
Parent 476acd7eb7
révision ec57f73384
26 fichiers modifiés avec 25 ajouts et 3790 suppressions

Voir le fichier

@ -1,36 +0,0 @@
## Interface: 40300
## Title: QuestHelper Collector
## Author: zorbathut, smariot, vipersniper, nesher, nconantj
## Notes: Collects data for QuestHelper
## Version: 4.0.1.$svnversion$
## SavedVariables: QuestHelper_Collector
## X-Website: http://www.quest-helper.com/
# Basic utilities used for miscellaneous things, also creates the QH frame
utility.lua
# oh shut up
collect_notifier.lua
collect_achievement.lua
collect_lzw.lua
collect_traveled.lua
collect_location.lua
collect_zone.lua
collect_hearth.lua
collect_merger.lua
collect_monster.lua
collect_item.lua
collect_object.lua
collect_loot.lua
collect_patterns.lua
collect_flight.lua
collect_util.lua
collect_quest.lua
collect_equip.lua
collect_spec.lua
collect_bitstream.lua
collect_upgrade.lua
collect_merchant.lua
collect_warp.lua
collect.lua

Voir le fichier

@ -1,308 +0,0 @@
local GetTime = QuestHelperCollector_GetTime
QuestHelper_File["collect.lua"] = "4.0.1.$svnversion$"
QuestHelper_Loadtime["collect.lua"] = GetTime()
local --[[ static ]] MINSVNVERSION = 185
local --[[ static ]] PURGEDEV = false
local debug_output = false
if QuestHelper_File["collect.lua"] == "Development Version" then debug_output = true end
local QuestHelper_Collector_Version_Current = 8
QuestHelper_Collector = {}
QuestHelper_Collector_Version = QuestHelper_Collector_Version_Current
local OnUpdateRegistrar = {}
local TooltipRegistrar = {}
local function OnUpdateHookRegistrar(func)
QuestHelper: Assert(func)
table.insert(OnUpdateRegistrar, func)
end
local suppress = false
-- real tooltips don't use this function
local SetTextScript = GameTooltip.SetText
GameTooltip.SetText = function (...)
suppress = true
SetTextScript(...)
suppress = false
end
local function CollectTooltippery(self)
if not self then self = GameTooltip end
for k, v in pairs(TooltipRegistrar) do
v(self)
end
-- anything past here is not my fault
end
local ottsu = GameTooltip:GetScript("OnTooltipSetUnit")
QH_Hook(GameTooltip, "OnTooltipSetUnit", function (self, ...)
CollectTooltippery(self)
if ottsu then return QH_Hook_NotMyFault(ottsu, self, ...) end
end, "collection OnTooltipSetUnit")
local ottsi = GameTooltip:GetScript("OnTooltipSetItem")
QH_Hook(GameTooltip, "OnTooltipSetItem", function (self, ...)
CollectTooltippery(self)
if ottsi then return QH_Hook_NotMyFault(ottsi, self, ...) end
end, "collection OnTooltipSetItem")
local ottsh = GameTooltip:GetScript("OnShow")
QH_Hook(GameTooltip, "OnShow", function (self, ...)
CollectTooltippery(self)
if ottsh then return QH_Hook_NotMyFault(ottsh, self, ...) end
end, "collection OnShow")
local function TooltipHookRegistrar(func)
QuestHelper: Assert(func)
table.insert(TooltipRegistrar, func)
end
local API = {
Registrar_OnUpdateHook = OnUpdateHookRegistrar,
Registrar_TooltipHook = TooltipHookRegistrar,
Callback_Location_Raw = function () return QuestHelper:Location_RawRetrieve() end,
Callback_Location_Absolute = function () return QuestHelper:Location_AbsoluteRetrieve() end,
}
-- We do these early, because some things that aren't in collect may rely on these. Yes I realize that avoiding this was one of my main goals in the separate collect system, shut up go away I hate you (in all seriousness: crunch mode + lazy = some nasty bits.)
-- TODO: Make a common collect/mainmodule system, then rely on that better.
QH_Collect_Util_Init(nil, API) -- Some may actually add their own functions to the API, and should go first. There's no real formalized order, I just know which depend on others, and it's heavily asserted so it will break if it goes in the wrong order.
QH_Collect_Merger_Init(nil, API)
QH_Collect_Bitstream_Init(nil, API)
QH_Collect_Location_Init(nil, API)
QH_Collect_Patterns_Init(nil, API)
QH_Collect_Notifier_Init(nil, API)
QH_Collect_Spec_Init(nil, API)
QH_Collect_LZW_Init(nil, API)
local CompressCollection
function QH_Collector_Init()
-- Dunno why, but these statements cause the 1% issue.
--[[
QH_Collector_UpgradeAll(QuestHelper_Collector)
for _, v in pairs(QuestHelper_Collector) do
if not v.modified then v.modified = time() - 7 * 24 * 60 * 60 end -- eugh. Yeah, we set it to be a week ago. It's pretty grim.
end
--]]
QuestHelper_Collector_Version = QuestHelper_Collector_Version_Current
local svnversion = "$svnversion$"
local buildInfo, locale, faction = GetBuildInfo(), GetLocale(), QuestHelper:PlayerFaction()
local altfaction = ""
if faction == ALLIANCE then
altfaction = "Alliance"
else
altfaction = "Horde"
end
local realm = GetRealmName()
local remove_sigs = {}
for k, v in pairs(QuestHelper_Collector) do
local sig = k:match("^(%d)a$") or k:match("^(%d)b$") or k:match("^(%d)r$")
if sig then
if tonumber(sig) < MINSVNVERSION then
table.insert(remove_sigs, sig)
end
elseif k ~= svnversion then
table.insert(remove_sigs, k)
elseif k == "$svnversion\$" and PURGEDEV then
table.insert(remove_sigs, k)
end
end
for _, v in ipairs(remove_sigs) do
QuestHelper_Collector[v] = nil
end
if not QuestHelper_Collector.created then
QuestHelper_Collector.created = time();
end
-- Swap buildInfo and svnversion once first alteration is complete.
-- Perhaps move locale out of the "signature"
if not QuestHelper_Collector[svnversion] then
QuestHelper_Collector[svnversion] = {}
end
if not QuestHelper_Collector[svnversion][realm] then
QuestHelper_Collector[svnversion][realm] = {}
end
if not QuestHelper_Collector[svnversion][realm][buildInfo] then
QuestHelper_Collector[svnversion][realm][buildInfo] = {}
end
if not QuestHelper_Collector[svnversion][realm][buildInfo][locale] then
QuestHelper_Collector[svnversion][realm][buildInfo][locale] = {}
end
if not QuestHelper_Collector[svnversion][realm][buildInfo][locale][altfaction] then
QuestHelper_Collector[svnversion][realm][buildInfo][locale][altfaction] = {}
end
--if not QuestHelper_Collector[sig] or QuestHelper_Collector[sig].compressed then QuestHelper_Collector[sig] = {version = QuestHelper_Collector_Version} end -- fuckin' bullshit, man
local QHCData = QuestHelper_Collector[svnversion][realm][buildInfo][locale][altfaction]
QuestHelper: Assert(not QHCData.compressed)
QHCData.modified = time()
QH_Collect_Achievement_Init(QHCData, API)
QH_Collect_Traveled_Init(QHCData, API)
QH_Collect_Zone_Init(QHCData, API)
QH_Collect_Hearth_Init(QHCData, API)
QH_Collect_Monster_Init(QHCData, API)
QH_Collect_Item_Init(QHCData, API)
QH_Collect_Object_Init(QHCData, API)
QH_Collect_Flight_Init(QHCData, API)
QH_Collect_Quest_Init(QHCData, API)
QH_Collect_Warp_Init(QHCData, API)
QH_Collect_Loot_Init(QHCData, API)
QH_Collect_Equip_Init(QHCData, API)
QH_Collect_Merchant_Init(QHCData, API)
if false then -- this will be disabled in most public releases, or set to a very rare probabalistic thing
if not QHCData.routing_dump then QHCData.routing_dump = {} end
local nt = {}
table.insert(QHCData.routing_dump, nt)
QH_Collect_Routing_Dump = nt
end
--[[ NOPE DO NOT DO THIS! IT'LL MESS UP THE NEW SYSTEM.
do -- Clean some stuff up!
local obliterate = {}
for k, v in pairs(QuestHelper_Collector) do
if not v.modified or v.modified + 30 * 24 * 60 * 60 < GetTime() then
table.insert(obliterate, k)
end
end
for _, v in ipairs(obliterate) do
QuestHelper_Collector[v] = nil
end
end
--]]
-- So, why do we delay it?
-- It's simple. People are gonna update to this version, and then they're going to look at the memory usage. Then they will panic because omg this version uses so much more memory, I bet that will somehow hurt my framerates in a way which is not adequately explained!
-- So instead, we just wait half an hour before compressing. Compression will still get done, and I won't have to deal with panicked comments about how bloated QH has gotten.
-- addendum: yeah naturally I'm getting all sorts of panicked comments about how bloated qh has gotten, sigh
--API.Utility_Notifier(GetTime() + (debug_output and 0 or (30 * 60)), function() CompressCollection(QHCData, QuestHelper_Collector[sig_altfaction], API.Utility_Merger, API.Utility_LZW.Compress) end)
end
QH_OnUpdate(function ()
local tstart = GetTime()
for _, v in pairs(OnUpdateRegistrar) do
v()
end
QH_Timeslice_Increment(GetTime() - tstart, "collect_update")
end)
--- I've tossed the compression stuff down here just 'cause I don't feel like making an entire file for it (even though I probably should.)
local noncompressible = {
modified = true,
version = true,
}
local squarify
local seritem
local serializers = {
["nil"] = function(item, add)
add("nil")
end,
["number"] = function(item, add)
add(tostring(item))
end,
["string"] = function(item, add)
add(string.format("%q", item))
end,
["boolean"] = function(item, add)
add(item and "true" or "false")
end,
["table"] = function(item, add)
add("{")
local first = true
for k, v in pairs(item) do
if not first then add(",") end
first = false
add("[")
seritem(k, add)
add("]=")
seritem(v, add)
end
add("}")
end,
}
seritem = function(item, add)
QH_Timeslice_Yield()
serializers[type(item)](item, add)
end
local function DoCompress(item, merger, comp)
if debug_output then QuestHelper: TextOut("Item condensing") end
local ts = GetTime()
local target = {}
for k, v in pairs(item) do
if not noncompressible[k] then
target[k] = v
end
end
local mg = {}
seritem(target, function(dat) merger.Add(mg, dat) end)
local tg = merger.Finish(mg)
if debug_output then QuestHelper: TextOut(string.format("Item condensed to %d bytes, %f taken so far", #tg, GetTime() - ts)) end
mg = nil
local cmp = {}
local cmptot = 0
local doublecheck = ""
for chunk = 1, #tg, 1048576 do
local fragment = tg:sub(chunk, chunk + 1048575)
doublecheck = doublecheck .. fragment
local ite = comp(fragment, 256, 8)
cmptot = cmptot + #ite
table.insert(cmp, ite)
end
QuestHelper: Assert(doublecheck == tg)
if #cmp == 1 then cmp = cmp[1] end
for k, v in pairs(target) do
if not noncompressible[k] then
item[k] = nil
end
end
item.compressed = cmp
if debug_output then QuestHelper: TextOut(string.format("Item compressed to %d bytes in %d shards (previously %d), %f taken", cmptot, type(cmp) == "table" and #cmp or 1, #tg, GetTime() - ts)) end
end
CompressCollection = function(active, active2, merger, comp)
for _, v in pairs(QuestHelper_Collector) do
if v ~= active and v ~= active2 and not v.compressed then
QH_Timeslice_Add(function ()
DoCompress(v, merger, comp)
CompressCollection(active, active2, merger, comp)
end, "compress")
break
end
end
end

Voir le fichier

@ -1,75 +0,0 @@
local GetTime = QuestHelperCollector_GetTime
QuestHelper_File["collect_achievement.lua"] = "4.0.1.$svnversion$"
QuestHelper_Loadtime["collect_achievement.lua"] = GetTime()
local QHCA
local GetLoc
local Merger
local cloc
local function ScanAchievements(oldADB, newADB)
--QuestHelper:TextOut("scanach")
local changes = 0
for k, v in pairs(newADB.achievements) do
if v.complete ~= oldADB.achievements[k].complete then
changes = changes + 1
end
end
for k, v in pairs(newADB.criteria) do
if v.complete and not oldADB.criteria[k].complete then
changes = changes + 1
end
end
if changes < 10 then -- if someone gets 10 criteria at once, well, I guess that's just what happens
for k, v in pairs(newADB.achievements) do
if v.complete ~= oldADB.achievements[k].complete then
QuestHelper: Assert(v.complete and not oldADB.achievements[k].complete)
if not QHCA[k] then QHCA[k] = {} end
if not QHCA[k].achieved then QHCA[k].achieved = {} end
table.insert(QHCA[k].achieved, cloc)
--QHCA[k].achieved = (QHCA[k].achieved or "") .. cloc
--QuestHelper:TextOut(string.format("Achievement complete, %s", select(2, GetAchievementInfo(k))))
end
end
for k, v in pairs(newADB.criteria) do
if v.complete and not oldADB.criteria[k].complete then -- Note that it's possible for objectives to be "uncompleted" when it's things like "do a bunch of shit in one run of this battleground" (see: isle of conquest)
--QuestHelper:TextOut(string.format("Criteria complete, %d", k))
--QuestHelper:TextOut(string.format("Criteria complete, %s", select(1, GetAchievementCriteriaInfo(k))))
if not QHCA[k] then QHCA[k] = {} end
if not QHCA[k].parent then QHCA[k].parent = v.parent end
if not QHCA[k].achieved then QHCA[k].achieved = {} end
table.insert(QHCA[k].achieved, cloc)
--QHCA[v.parent][k] = (QHCA[v.parent][k] or "") .. cloc
elseif v.progress > oldADB.criteria[k].progress then
--QuestHelper:TextOut(string.format("Criteria progress, %d", k))
--QuestHelper:TextOut(string.format("Criteria progress, %s", select(1, GetAchievementCriteriaInfo(k))))
end
end
end
end
function SetCloc()
cloc = GetLoc() -- yoink
end
function QH_Collect_Achievement_Init(QHCData, API)
if not QHCData.achievement then QHCData.achievement = {} end
QHCA = QHCData.achievement
GetLoc = API.Callback_LocationBolusCurrent
QuestHelper: Assert(GetLoc)
Merger = API.Utility_Merger
QuestHelper: Assert(Merger)
QH_AchievementManagerRegister(ScanAchievements)
QH_AchievementManagerRegister_Prescan(SetCloc)
QH_AchievementManager_Init()
end

Voir le fichier

@ -1,56 +0,0 @@
local GetTime = QuestHelperCollector_GetTime
QuestHelper_File["collect_bitstream.lua"] = "4.0.1.$svnversion$"
QuestHelper_Loadtime["collect_bitstream.lua"] = GetTime()
local Merger
local function Output(outbits)
return {
r = {},
cbits = 0,
cval = 0,
append = function (self, value, bits)
self.cbits = self.cbits + bits
self.cval = bit.lshift(self.cval, bits)
self.cval = self.cval + value
while self.cbits >= outbits do
Merger.Add(self.r, strchar(bit.rshift(self.cval, self.cbits - outbits)))
self.cbits = self.cbits - outbits
self.cval = bit.band(self.cval, bit.lshift(1, self.cbits) - 1)
end
end,
finish = function (self)
if self.cbits > 0 then self:append(0, outbits - self.cbits) end
return Merger.Finish(self.r)
end,
}
end
local function Input(indata, outbits)
return {
cbits = 0,
cval = 0,
coffset = 1,
depend = function (self, bits)
while self.cbits < bits do
self.cbits = self.cbits + outbits
self.cval = bit.lshift(self.cval, outbits) + strbyte(indata, self.coffset)
self.coffset = self.coffset + 1
end
local rv = bit.rshift(self.cval, self.cbits - bits)
self.cbits = self.cbits - bits;
self.cval = bit.band(self.cval, bit.lshift(1, self.cbits) - 1)
return rv
end,
}
end
function QH_Collect_Bitstream_Init(_, API)
Merger = API.Utility_Merger
QuestHelper: Assert(Merger)
API.Utility_Bitstream = {Input = Input, Output = Output}
end

Voir le fichier

@ -1,134 +0,0 @@
local GetTime = QuestHelperCollector_GetTime
QuestHelper_File["collect_equip.lua"] = "4.0.1.$svnversion$"
QuestHelper_Loadtime["collect_equip.lua"] = GetTime()
local debug_output = false
if QuestHelper_File["collect_equip.lua"] == "Development Version" then debug_output = true end
local GetItemType
local Notifier
local GetSpecBolus
local Patterns
local QHCI
-- why does this need to exist
local invloc_lookup_proto = {
INVTYPE_HEAD = {"HeadSlot"},
INVTYPE_NECK = {"NeckSlot"},
INVTYPE_SHOULDER = {"ShoulderSlot"},
INVTYPE_CHEST = {"ChestSlot"},
INVTYPE_ROBE = {"ChestSlot"},
INVTYPE_WAIST = {"WaistSlot"},
INVTYPE_LEGS = {"LegsSlot"},
INVTYPE_FEET = {"FeetSlot"},
INVTYPE_WRIST = {"WristSlot"},
INVTYPE_HAND = {"HandsSlot"},
INVTYPE_FINGER = {"Finger0Slot", "Finger1Slot"},
INVTYPE_TRINKET = {"Trinket0Slot", "Trinket1Slot"},
INVTYPE_CLOAK = {"BackSlot"},
INVTYPE_WEAPON = {"MainHandSlot", "SecondaryHandSlot"},
INVTYPE_SHIELD = {"SecondaryHandSlot"},
INVTYPE_2HWEAPON = {"MainHandSlot"},
INVTYPE_WEAPONMAINHAND = {"MainHandSlot"},
INVTYPE_WEAPONOFFHAND = {"SecondaryHandSlot"},
INVTYPE_HOLDABLE = {"RangedSlot"},
INVTYPE_RANGED = {"RangedSlot"},
INVTYPE_THROWN = {"RangedSlot"},
INVTYPE_RANGEDRIGHT = {"RangedSlot"},
INVTYPE_RELIC = {"RangedSlot"},
}
local invloc_lookup = {}
for k, v in pairs(invloc_lookup_proto) do
local temp = {}
for _, tv in pairs(v) do
table.insert(temp, (GetInventorySlotInfo(tv)))
end
invloc_lookup[k] = temp
end
local function Recheck(item, location, competing)
local replaced_item = nil
local confused = false
for i, v in pairs(invloc_lookup[location]) do
if competing[i] then
local ilink = GetInventoryItemLink("player", v)
if ilink then
local itype = GetItemType(ilink)
local eqtext = nil
if itype == item then
replaced_item = competing[i]
elseif itype == competing[i] then
else
confused = true
end
end
end
end
if confused then
if debug_output then QuestHelper:TextOut(string.format("Confused about %s", GetItemInfo(item))) end
return
end
if not QHCI[item] then QHCI[item] = {} end
if replaced_item then
if debug_output then QuestHelper:TextOut(string.format("Equipped %s over %s", GetItemInfo(item), GetItemInfo(replaced))) end
if not QHCI[item].equip_yes then QHCI[item].equip_yes = {} end
table.insert(QHCI[item].equip_yes, { replaced = replaced_item, spec = GetSpecBolus() })
else
for _, v in pairs(competing) do
if debug_output then QuestHelper:TextOut(string.format("Did not equip %s over %s", GetItemInfo(item), GetItemInfo(v))) end
if not QHCI[item].equip_no then QHCI[item].equip_no = {} end
table.insert(QHCI[item].equip_no, { item = v, spec = GetSpecBolus() })
end
end
end
local function Looted(message)
item = string.match(message, Patterns.LOOT_ITEM_PUSHED_SELF)
if not item then item = string.match(message, Patterns.LOOT_ITEM_SELF) end
if not item then return end
local item = GetItemType(message, true)
local name, _, quality, ilvl, min, itype, isubtype, _, equiploc, _ = GetItemInfo(item)
if name and IsEquippableItem(item) and min <= UnitLevel("player") and invloc_lookup[equiploc] then -- The level comparison may be redundant
local competing = {}
local nonempty = false
for i, v in pairs(invloc_lookup[equiploc]) do
local litem = GetInventoryItemLink("player", v)
if litem then litem = GetItemType(litem) end
if litem and litem ~= item then competing[i] = litem nonempty = true end
end
if not nonempty then return end -- congratulations you are better than nothing, we do not care
Notifier(GetTime() + 5 * 60, function () Recheck(item, equiploc, competing) end)
end
end
function QH_Collect_Equip_Init(QHCData, API)
if not QHCData.item then QHCData.item = {} end
QHCI = QHCData.item
Patterns = API.Patterns
QuestHelper: Assert(Patterns)
API.Patterns_Register("LOOT_ITEM_PUSHED_SELF", "|c.*|r")
API.Patterns_Register("LOOT_ITEM_SELF", "|c.*|r")
QH_Event("CHAT_MSG_LOOT", Looted)
GetItemType = API.Utility_GetItemType
Notifier = API.Utility_Notifier
GetSpecBolus = API.Utility_GetSpecBolus
QuestHelper: Assert(GetItemType)
QuestHelper: Assert(Notifier)
QuestHelper: Assert(GetSpecBolus)
end

Voir le fichier

@ -1,114 +0,0 @@
local GetTime = QuestHelperCollector_GetTime
QuestHelper_File["collect_flight.lua"] = "4.0.1.$svnversion$"
QuestHelper_Loadtime["collect_flight.lua"] = GetTime()
local debug_output = false
if QuestHelper_File["collect_flight.lua"] == "Development Version" then debug_output = true end
local QHCFM
local QHCFT
local IsMonsterGUID
local GetMonsterType
local function GetRoute(currentname, endnode)
local path = currentname .. "@@" .. TaxiNodeName(endnode)
local links = GetNumRoutes(endnode)
if links > 50 then -- links is apparently sometimes 999998. Why? I could not say. It is a mystery. Hopefully this will show up in the datafiles and I'll be able to debug it.
if (TaxiNodeGetType(endnode) == "NONE") then
return path, TaxiNodeName(endnode) .. " not currently in use."
else
return path, string.format("@@@ WACKYLAND %s %d @@@", TaxiNodeGetType(endnode), links)
end
end
local route = ""
for j = 1, links - 1 do -- Why only the first n-1 links? Why not all? Research.
if #route > 0 then route = route .. "," end
route = route .. string.format("(%f,%f)", TaxiGetDestX(endnode, j), TaxiGetDestY(endnode, j))
end
return path, route
end
local function GetCurrentname()
QuestHelper: Assert(NumTaxiNodes() < 150, tostring(NumTaxiNodes())) -- hmm what
for i = 1, NumTaxiNodes() do if TaxiNodeGetType(i) == "CURRENT" then return TaxiNodeName(i) end end
end
local path, route
local start_time
local phase = "IDLE"
local real_TakeTaxiNode = TakeTaxiNode
TakeTaxiNode = function(id)
path, route = GetRoute(GetCurrentname(), id)
phase = "PENDING"
start_time = GetTime()
real_TakeTaxiNode(id)
end
local function TaximapOpened()
-- Figure out who we have targeted and what our location name is
local currentname = GetCurrentname()
if not currentname then return end -- must not actually have opened the map
QuestHelper: Assert(NumTaxiNodes() < 100)
for i = 1, NumTaxiNodes() do
local name, type = TaxiNodeName(i), TaxiNodeGetType(i)
if not QHCFM[name] then QHCFM[name] = {} end
QHCFM[name].x, QHCFM[name].y = TaxiNodePosition(i)
if type == "CURRENT" then
local guid = UnitGUID("target")
if guid and IsMonsterGUID(guid) then QHCFM[name].master = GetMonsterType(guid) end
end
if type ~= "CURRENT" then
local path, route = GetRoute(currentname, i)
if not QHCFT[path] then QHCFT[path] = {} end
if not QHCFT[path][route] then QHCFT[path][route] = {} end
end
end
end
local function OnUpdate()
if UnitOnTaxi("player") then
if phase == "PENDING" then
start_time = GetTime()
phase = "FLYING"
end
else
if phase == "PENDING" then
if GetTime() > start_time + 5 then -- something has gone wrong, abort
phase = "IDLE"
path, route, start_time = nil, nil, nil
end
elseif phase == "FLYING" then
-- yaay
QHCFT[path][route].time = (QHCFT[path][route].time or 0) + (GetTime() - start_time)
QHCFT[path][route].count = (QHCFT[path][route].count or 0) + 1
phase = "IDLE"
path, route, start_time = nil, nil, nil
end
end
end
function QH_Collect_Flight_Init(QHCData, API)
if not QHCData.flight_master then QHCData.flight_master = {} end
if not QHCData.flight_times then QHCData.flight_times = {} end
QHCFM, QHCFT = QHCData.flight_master, QHCData.flight_times
IsMonsterGUID = API.Utility_IsMonsterGUID
GetMonsterType = API.Utility_GetMonsterType
QuestHelper: Assert(IsMonsterGUID)
QuestHelper: Assert(GetMonsterType)
QH_Event("TAXIMAP_OPENED", TaximapOpened)
API.Registrar_OnUpdateHook(OnUpdate)
end

Voir le fichier

@ -1,54 +0,0 @@
local GetTime = QuestHelperCollector_GetTime
QuestHelper_File["collect_hearth.lua"] = "4.0.1.$svnversion$"
QuestHelper_Loadtime["collect_hearth.lua"] = GetTime()
local debug_output = false
if QuestHelper_File["collect_hearth.lua"] == "Development Version" then debug_output = true end
local QHCZ
local GetLoc
local Merger
local last_hearth = 0
local function OnZoneChanged()
local start, cd, _ = GetItemCooldown(6948)
if last_hearth + 1800 < GetTime() and cd == 1800 then
last_hearth = start
local home = GetBindLocation()
if not QHCZ[home] then QHCZ[home] = {} end
QHCZ[home].Landing = GetLoc()
end
end
local GetMonsterType
local function OnConfirmBinder(...)
local new_home = ...
if not QHCZ[new_home] then QHCZ[new_home] = {} end
if not QHCZ[new_home].Innkeeper then QHCZ[new_home].Innkeeper = {} end
QHCZ[new_home].Innkeeper.ID = GetMonsterType(UnitGUID("target"))
end
function QH_Collect_Hearth_Init(QHCData, API)
if not QHCData.hearth then QHCData.hearth = {} end
QHCZ = QHCData.hearth
QH_Event("ZONE_CHANGED", OnZoneChanged)
QH_Event("ZONE_CHANGED_INDOORS", OnZoneChanged)
QH_Event("ZONE_CHANGED_NEW_AREA", OnZoneChanged)
QH_Event("CONFIRM_BINDER", OnConfirmBinder)
--API.Registrar_OnUpdateHook(OnUpdate)
GetLoc = API.Callback_LocationBolusCurrent
QuestHelper: Assert(GetLoc)
Merger = API.Utility_Merger
QuestHelper: Assert(Merger)
GetMonsterType = API.Utility_GetMonsterType
QuestHelper: Assert(GetMonsterType)
end

Voir le fichier

@ -1,63 +0,0 @@
local GetTime = QuestHelperCollector_GetTime
QuestHelper_File["collect_item.lua"] = "4.0.1.$svnversion$"
QuestHelper_Loadtime["collect_item.lua"] = GetTime()
local debug_output = false
if QuestHelper_File["collect_item.lua"] == "Development Version" then debug_output = true end
local GetItemType
local QHCI
-- We could probably snag data from other locations as well, but at the moment, we're not.
local function Tooltipy(self)
if not self.GetItem then return end -- ughhhh, inventoryonpar
local _, ilink = self:GetItem()
if not ilink then return end
local id = GetItemType(ilink)
if not QHCI[id] then QHCI[id] = {} end
local item = QHCI[id]
local name, _, quality, ilvl, min, itype, isubtype, _, equiploc, _ = GetItemInfo(id)
if name then
item.name = name
item.quality = quality
item.ilevel = ilvl
item.minlevel = min
item.type = itype -- Was originally type/subtype, but we can do that during processing. Might want to eventually have it separated, so we separate here.
item.subtype = isubtype
local loc = string.match(equiploc, "INVTYPE_(.*)")
if loc then
item.equiplocation = loc
else
item.equiplocation = nil
end
local lines = GameTooltip:NumLines()
local openable = false
for i = 2, lines do
if _G["GameTooltipTextLeft" .. tostring(i)]:GetText() == ITEM_OPENABLE then
openable = true
end
end
openable = "open_" .. (openable and "yes" or "no")
item[openable] = (item[openable] or 0) + 1 -- so we're going to add a lot to this if the user keeps whipping their mouse over it. I'll live.
end
end
function QH_Collect_Item_Init(QHCData, API)
if not QHCData.item then QHCData.item = {} end
QHCI = QHCData.item
API.Registrar_TooltipHook(Tooltipy)
GetItemType = API.Utility_GetItemType
QuestHelper: Assert(GetItemType)
end

Voir le fichier

@ -1,49 +0,0 @@
local GetTime = QuestHelperCollector_GetTime
QuestHelper_File["collect_location.lua"] = "4.0.1.$svnversion$"
QuestHelper_Loadtime["collect_location.lua"] = GetTime()
-- little endian two's complement
local function signed(c)
QuestHelper: Assert(not c or c >= -127 and c < 127)
if not c then c = -128 end
if c < 0 then c = c + 256 end
return c
--return strchar(c)
end
local function float(c)
-- if not c then c = -128 end
-- QuestHelper: Assert( c >= -128, string.format("c is too small. It is %s.", tostring(c)))
-- QuestHelper: Assert( c < 128, string.format("c is too big. It is %s.", tostring(c)))
local ret = tostring(c):gsub(",",".") -- eliminate issues with locales that use a comma as the decimal separator.
return ret
end
local function BolusizeLocation(delayed, c, z, x, y, dl, mid, mf, f)
-- c and z are *signed* integers that fit within an 8-bit int.
-- x and y are floating-point values, generally between 0 and 1. We'll dedicate 24 bits to the fractional part, largely because we can.
-- Overall we're using a weird 11 bytes on this. Meh.
-- Also, any nil values are being turned into MIN_WHATEVER.
local float_x = float(x)
local float_y = float(y)
local loc = {}
loc["delayed"] = (delayed and 1 or 0)
loc["c"] = c
loc["z"] = z
loc["x"] = float_x
loc["y"] = float_y
loc["dungeonLevel"] = dl
loc["mapid"] = mid
loc["mapfile"] = mf
loc["facing"] = f
return loc;
--return string.format("%s,%s,%s,%s,%s", signed(delayed and 1 or 0), signed(c), signed(z), float_x, float_y)
--return signed(delayed and 1 or 0) .. signed(c) .. signed(z) .. float_x .. float_y
end
-- This merely provides another API function
function QH_Collect_Location_Init(_, API)
API.Callback_LocationBolus = BolusizeLocation -- Yeah. *Bolusize*. You heard me.
API.Callback_LocationBolusCurrent = function () return BolusizeLocation(API.Callback_Location_Raw()) end -- This is just a convenience function, really
end

Voir le fichier

@ -1,649 +0,0 @@
local GetTime = QuestHelperCollector_GetTime
QuestHelper_File["collect_loot.lua"] = "4.0.1.$svnversion$"
QuestHelper_Loadtime["collect_loot.lua"] = GetTime()
local debug_output = false
if QuestHelper_File["collect_loot.lua"] == "Development Version" then debug_output = true end
local QHC
local PseudoIDs = {
["gold"] = -1,
}
local GetMonsterUID
local GetMonsterType
local GetItemType
local GetLoc
local Patterns
local members = {}
local members_count = 0
local members_refs = {} -- "raid6" and the like
local function MembersUpdate()
-- We want to keep track of exactly who is in a group with this player, so we can watch for combat messages involving them, so we can see who's been tapped, so we can record the right deaths, so we can know who the player should be able to loot.
-- I hate my life.
-- >:(
local alone = false
--QuestHelper:TextOut("MU start")
members = {} -- we burn a table every time this updates, but whatever
members_count = 0
if GetNumRaidMembers() > 0 then
-- we is in a raid
for i = 1, 40 do
local ite = string.format("raid%d", i)
local gud = UnitGUID(ite)
if gud then
members[gud] = true
table.insert(members_refs, ite)
--QuestHelper:TextOut(string.format("raid member %s added", UnitName(ite)))
end
end
elseif GetNumPartyMembers() > 0 then
-- we is in a party
for i = 1, 4 do
local ite = string.format("party%d", i)
local gud = UnitGUID(ite)
if gud then
members[gud] = true
table.insert(members_refs, ite)
--QuestHelper:TextOut(string.format("party member %s added", UnitName(ite)))
end
end
members[UnitGUID("player")] = true
table.insert(members_refs, "player")
--QuestHelper:TextOut(string.format("player %s added", UnitName("player")))
else
-- we is alone ;.;
if UnitGUID("player") then members[UnitGUID("player")] = true end -- it's possible that we haven't logged in entirely yet
table.insert(members_refs, "player")
--QuestHelper:TextOut(string.format("player %s added as %s", UnitName("player"), tostring(UnitGUID("player"))))
alone = true
end
if GetLootMethod() == "master" and not alone then members = {} members_refs = {} end -- We're not going to bother trying to deal with master loot right now - it's just too different and I just don't care enough.
for _, _ in pairs(members) do members_count = members_count + 1 end -- lulz
end
local MS_TAPPED_US = 1
local MS_TAPPED_US_TRIVIAL = 2
local MS_TAPPED_OTHER = 3
local MS_TAPPED_LOOTABLE = 4
local MS_TAPPED_LOOTABLE_TRIVIAL = 5
local MS_TAPPED_LOOTED = 6
local last_cleanup = GetTime()
local monsterstate = {}
local monsterrefresh = {}
local monstertimeout = {}
-- This all does something quite horrible.
-- Some monsters don't become lootable when they're killed and didn't drop anything. We need to record this so we can get real numbers for them.
-- Unfortunately, we can't just record when "something" is killed. We have to record when "our group" killed it, so we know that there *was* a chance of looting it.
-- As such, we need to check for monster deaths that the player may never have actually targeted. It gets, to put it mildly, grim, and unfortunately we'll never be able to solve it entirely.
-- Worse, we need to *not* record item drops for things that we never actually "saw" but that were lootable anyway, because if we do, we bias the results towards positive (i.e. if we AOE ten monsters down, and two of them drop, and we loot those, that's 2/2 if we record the drops, and 0/0 if we don't, while what we really want is 2/10. 0/0 is at least "not wrong".)
-- On top of this, we want to avoid looting "discarded items", but unfortunately there's no real good way to determine this. Welp.
local last_scan = 0
-- Here's a little bottleneck - we're going to try to only do one scan per second. Fingers crossed.
local function CombatLogEvent(_, event, sourceguid, _, _, destguid, _, _, _, spellname)
-- There's many things that are handled here.
-- First, if there's any damage messages coming either to or from a party member, we check to see if that monster is tapped by us. If it's tapped, we cache the value for 15 seconds, expiring entirely in 30.
-- Second, there's the Death message. If it's tapped by us, increases the kill count by 1/partymembers and changes its state to lootable.
if event ~= "UNIT_DIED" then
if last_scan > GetTime() then return end -- welp
-- Something has been attacked by something, maybe.
if not string.find(event, "_DAMAGE$") then return end -- We only care about something punching something else.
local target, source
if members[sourceguid] then
source = sourceguid
target = destguid
elseif members[destguid] then
source = targetguid
target = sourceguid
end -- If one of the items is in our party, the other is our target.
if not target then return end -- If we don't have a target, then nobody is in our party, and we don't care.
if monsterrefresh[target] and monsterrefresh[target] > GetTime() then return end -- we already have fresh data, so we're good
-- Now comes the tricky part. We can't just look at the target because we're not allowed to target by GUID. So we iterate through all the party/raid members and hope *someone* has it targeted. Luckily, we can stop once we find someone who does.
local targ
for _, v in pairs(members_refs) do
targ = v .. "target" if UnitGUID(targ) == target then break end
targ = nil
end
last_scan = GetTime() + 1
if not targ then
--monsterrefresh[target] = GetTime() + 5
--monstertimeout[target] = GetTime() + 5
return
end -- Well, nobody seems to be targeting it. That's . . . odd, and annoying. We were thinking of tossing on a 5-second timeout. But we didn't, because we decided the global one-second lockout might help. So we'll do that for now.
-- Okay. So we know who's targeting it. Now, let's see who has it tapped, if anyone.
if not UnitIsTapped(targ) then
-- Great. Nobody is. That is just *great*. Look how exuberant I feel at this moment. You know what? 5-second timeout.
monsterstate[target] = nil
monsterrefresh[target] = GetTime() + 5
monstertimeout[target] = GetTime() + 5
--if debug_output then QuestHelper:TextOut(string.format("Monster ignorified")) end
else
-- We know someone is, so we're going to set up our caching . . .
monsterrefresh[target] = GetTime() + 15
monstertimeout[target] = GetTime() + 30
monsterstate[target] = (UnitIsTappedByPlayer(targ)) and (not UnitIsTrivial(targ) and MS_TAPPED_US or MS_TAPPED_US_TRIVIAL) or MS_TAPPED_OTHER -- and figure out if it's us. Or if it's trivial. We somewhat-ignore it if it's trivial, since it's much less likely to be looted and that could throw off our numbers
--if debug_output then QuestHelper:TextOut(string.format("Monster %s set to %d, %s, %s", target, monsterstate[target], tostring(UnitIsTappedByPlayer(targ)), tostring(UnitIsTrivial(targ)))) end
end
-- DONE
else
-- It's dead. Hooray!
if monsterstate[destguid] and monstertimeout[destguid] > GetTime() and (monsterstate[destguid] == MS_TAPPED_US or monsterstate[destguid] == MS_TAPPED_US_TRIVIAL) and members_count > 0 then -- yaaay
local type = GetMonsterType(destguid)
if not QHC.monster[type] then QHC.monster[type] = {} end
if monsterstate[destguid] == MS_TAPPED_US then
QHC.monster[type].kills = (QHC.monster[type].kills or 0) + 1 / members_count -- Hopefully, most people loot their kills. Divide by members_count 'cause there's a 1/members chance that we get to loot. We'll flag the loot count some other way if it was a trivial monster.
end
monsterstate[destguid] = (monsterstate[destguid] == MS_TAPPED_US and MS_TAPPED_LOOTABLE or MS_TAPPED_LOOTABLE_TRIVIAL)
monsterrefresh[destguid] = GetTime() + 600
monstertimeout[destguid] = GetTime() + 600
--QuestHelper:TextOut(string.format("Tapped monster %s slain, set to lootable", destguid))
else
monsterstate[destguid] = nil
monsterrefresh[destguid] = nil
monstertimeout[destguid] = nil
--QuestHelper:TextOut(string.format("Untapped monster %s slain, cleared", destguid))
end
end
end
local skintypes = {}
skintypes[UNIT_SKINNABLE_ROCK] = "mine"
skintypes[UNIT_SKINNABLE_HERB] = "herb"
skintypes[UNIT_SKINNABLE_BOLTS] = "eng"
skintypes[UNIT_SKINNABLE_LEATHER] = "skin"
local function SkinnableflagsTooltipy(self, ...)
--QuestHelper:TextOut("tooltipy")
if UnitExists("mouseover") and UnitIsVisible("mouseover") and not UnitIsPlayer("mouseover") and not UnitPlayerControlled("mouseover") and UnitIsDead("mouseover") then
local guid = UnitGUID("mouseover")
--QuestHelper:TextOut("critar")
if not monsterstate[guid] or monsterstate[guid] ~= MS_TAPPED_LOOTED or monsterrefresh[guid] > GetTime() then return end
--QuestHelper:TextOut("runin")
local cid = GetMonsterType(guid)
local skintype = nil
local lines = GameTooltip:NumLines()
for i = 3, lines do
--QuestHelper:TextOut(_G["GameTooltipTextLeft" .. tostring(i)]:GetText())
local skeen = skintypes[_G["GameTooltipTextLeft" .. tostring(i)]:GetText()]
if skeen then QuestHelper: Assert(not skintype) skintype = skeen end
end
if not QHC.monster[cid] then QHC.monster[cid] = {} end
local qhci = QHC.monster[cid]
for _, v in pairs(skintypes) do
if v == skintype then
--QuestHelper:TextOut(v .. "_yes")
qhci[v .. "_yes"] = (qhci[v .. "_yes"] or 0) + 1
else
--QuestHelper:TextOut(v .. "_no")
qhci[v .. "_no"] = (qhci[v .. "_no"] or 0) + 1
end
end
end
end
-- Logic behind this module:
-- Watch for the spell to be sent
-- Watch for it to start
-- Check out the combat log and see what GUID we get
-- If the GUID is null, we're targeting an object, otherwise, we're targeting a critter
-- Wait for spell to succeed
-- If anything doesn't synch up, or the spell is interrupted, nil out all these items.
-- We've got a little special case for pickpocketing, because people often use macros, so we detect that case specifically.
local PP_PHASE_IDLE
local PP_PHASE_SENT
local PP_PHASE_COMPLETE
local pickpocket_phase = PP_PHASE_IDLE
local pickpocket_target
local pickpocket_otarget_guid
local pickpocket_timestamp
local pickpocket_name = GetSpellInfo(921) -- this is the pickpocket spell ID
local function pp_reset()
pickpocket_target, pickpocket_otarget_guid, pickpocket_timestamp, pickpocket_phase = nil, nil, nil, PP_PHASE_IDLE
end
pp_reset()
local function PPSent(player, spell, _, target)
if player ~= "player" then return end
if spell ~= pickpocket_name then return end
if UnitName("target") ~= target then return end -- DENY
pickpocket_timestamp, pickpocket_target, pickpocket_otarget_guid, pickpocket_phase = GetTime(), target, UnitGUID("target"), PP_PHASE_SENT
end
local function PPSucceed(player, spell, rank)
if player ~= "player" then return end
if spell ~= pickpocket_name then return end
if pickpocket_phase ~= PP_PHASE_SENT and (not pickpocket_otarget_guid or last_timestamp + 1 < GetTime()) then
pp_reset()
return
end
pickpocket_timestamp, pickpocket_phase = GetTime(), PP_PHASE_COMPLETE
end
-- This segment deals with openable containers
local touched_itemid
local touched_timestamp
local function ItemLock(bag, slot)
if not bag or not slot then return end -- probably changing equipment
local _, _, locked = GetContainerItemInfo(bag, slot)
--QuestHelper:TextOut(string.format("trying lock %s", tostring(locked)))
if locked then
touched_itemid = GetItemType(GetContainerItemLink(bag, slot))
--[[QuestHelper:TextOut(string.format("trying lock %s", tostring(touched_itemid)))
QuestHelper:TextOut(string.format("trying lock %s", tostring(type(touched_itemid))))
QuestHelper:TextOut(string.format("trying lock %s", tostring(QHC.item[touched_itemid].open_yes)))
QuestHelper:TextOut(string.format("trying lock %s", tostring(QHC.item[touched_itemid].open_no)))]]
touched_timestamp = GetTime()
if not QHC.item[touched_itemid] or (QHC.item[touched_itemid].open_yes or 0) <= (QHC.item[touched_itemid].open_no or 0) then
touched_itemid = nil
touched_timestamp = nil
end
else
touched_itemid = nil
touched_timestamp = nil
end
end
-- Here's the segment for longer spells. There aren't any instant spells we currently care about, besides pickpocketing. This will probably change eventually (arrows in the DK starting zone?)
local LAST_PHASE_IDLE = 0
local LAST_PHASE_SENT = 1
local LAST_PHASE_START = 2
local LAST_PHASE_COMBATLOG = 3
local LAST_PHASE_COMPLETE = 4
local last_phase = LAST_PHASE_IDLE
local last_spell
local last_rank
local last_target
local last_target_guid
local last_otarget
local last_otarget_guid
local last_timestamp
local last_succeed = false
local last_succeed_trade = GetTime()
local gathereffects = {}
gathereffects[GetSpellInfo(51306)] = {token = "eng", noclog = true}
gathereffects[GetSpellInfo(32606)] = {token = "mine"}
gathereffects[GetSpellInfo(2366)] = {token = "herb"}
gathereffects[GetSpellInfo(8613)] = {token = "skin"}
gathereffects[GetSpellInfo(21248)] = {token = "open", noclog = true}
gathereffects[GetSpellInfo(30427)] = {token = "extract", noclog = true} -- not a loot window, so it won't really work, but hey
gathereffects[GetSpellInfo(13262)] = {token = "de", noclog = true, ignore = true}
gathereffects[GetSpellInfo(31252)] = {token = "prospect", noclog = true, ignore = true}
gathereffects[GetSpellInfo(51005)] = {token = "mill", noclog = true, ignore = true}
local function normalize_spell(spell)
for k in pairs(gathereffects) do
if spell:find(k) then return k end
end
return spell
end
local function last_reset()
last_timestamp, last_spell, last_rank, last_target, last_target_guid, last_otarget, last_otarget_guid, last_succeed, last_phase = nil, nil, nil, nil, nil, nil, false, LAST_PHASE_IDLE
end
last_reset()
-- This all doesn't work with instant spells. Luckily, I don't care about instant spells (yet).
local function SpellSent(player, spell, rank, target)
if player ~= "player" then return end
spell = normalize_spell(spell)
last_timestamp, last_spell, last_rank, last_target, last_target_guid, last_otarget, last_otarget_guid, last_succeed, last_phase = GetTime(), spell, rank, target, nil, UnitName("target"), UnitGUID("target"), false, LAST_PHASE_SENT
if last_otarget and last_otarget ~= last_target then last_reset() return end
--QuestHelper:TextOut(string.format("ss %s", spell))
end
local function SpellStart(player, spell, rank)
if player ~= "player" then return end
spell = normalize_spell(spell)
if spell ~= last_spell or rank ~= last_rank or last_target_guid or last_phase ~= LAST_PHASE_SENT or last_timestamp + 1 < GetTime() then
last_reset()
else
--QuestHelper:TextOut(string.format("sst %s", spell))
last_timestamp, last_phase = GetTime(), LAST_PHASE_START
end
end
local function SpellCombatLog(_, event, sourceguid, _, _, destguid, _, _, _, spellname)
if event ~= "SPELL_CAST_START" then return end
if sourceguid ~= UnitGUID("player") then return end
spellname = normalize_spell(spellname)
--QuestHelper:TextOut(string.format("cle_ss enter %s %s %s %s", tostring(spellname ~= last_spell), tostring(not last_target), tostring(not not last_target_guid), tostring(last_timestamp + 1 < GetTime())))
if spellname ~= last_spell or not last_target or last_target_guid or last_timestamp + 1 < GetTime() then
last_reset()
return
end
--QuestHelper:TextOut("cle_ss enter")
if last_phase ~= LAST_PHASE_START then
last_reset()
return
end
--QuestHelper:TextOut(string.format("cesst %s", spellname))
last_timestamp, last_target_guid, last_phase = GetTime(), destguid, LAST_PHASE_COMBATLOG
if last_target_guid == "0x0000000000000000" then last_target_guid = nil end
if last_target_guid and last_target_guid ~= last_otarget_guid then last_reset() return end
end
local function SpellSucceed(player, spell, rank)
if player ~= "player" then return end
spell = normalize_spell(spell)
if gathereffects[spell] then last_succeed_trade = GetTime() end
--QuestHelper:TextOut(string.format("sscu enter %s %s %s %s %s", tostring(last_spell), tostring(last_target), tostring(last_rank), tostring(spell), tostring(rank)))
if not last_spell or not last_target or last_spell ~= spell or last_rank ~= rank then
last_reset()
return
end
--QuestHelper:TextOut("sscu enter")
if gathereffects[spell] and gathereffects[spell].noclog then
if last_phase ~= LAST_PHASE_START or last_timestamp + 10 < GetTime() then
last_reset()
return
end
else
if last_phase ~= LAST_PHASE_COMBATLOG or last_timestamp + 10 < GetTime() then
last_reset()
return
end
end
--QuestHelper:TextOut(string.format("sscu %s, %d, %s, %s", spell, last_phase, tostring(last_phase == LAST_PHASE_SENT), tostring((last_phase == LAST_PHASE_SENT) and LAST_PHASE_SHORT_SUCCEEDED)))
last_timestamp, last_succeed, last_phase = GetTime(), true, LAST_PHASE_COMPLETE
--QuestHelper:TextOut(string.format("last_phase %d", last_phase))
--[[if last_phase == LAST_PHASE_COMPLETE then
QuestHelper:TextOut(string.format("spell succeeded, casting %s %s on %s/%s", last_spell, last_rank, tostring(last_target), tostring(last_target_guid)))
end]]
end
local function SpellInterrupt(player, spell, rank)
if player ~= "player" then return end
-- I don't care what they were casting, they're certainly not doing it now
--QuestHelper:TextOut(string.format("si %s", spell))
last_reset()
end
local function LootOpened()
local targetguid = UnitGUID("target")
-- We're cleaning up the monster charts here, on the theory that if someone is looting, they're okay with a tiny lag spike.
if last_cleanup + 300 < GetTime() then
local cleanup = {}
for k, v in pairs(monstertimeout) do
if v < GetTime() then table.insert(cleanup, k) end
end
for _, v in pairs(cleanup) do
monsterstate[v] = nil
monsterrefresh[v] = nil
monstertimeout[v] = nil
end
end
-- First off, we try to figure out where the hell these items came from.
local ltype = nil
local spot = nil
local prefix = nil
if IsFishingLoot() then
-- yaaaaay
--if debug_output then QuestHelper:TextOut("Fishing loot") end
local loc = GetLoc()
if not QHC.fishing then QHC.fishing = {} end
ltype = QHC.fishing
spot = {}
spot.loc = loc
prefix = "fish"
elseif pickpocket_phase == PP_PHASE_COMPLETE and pickpocket_timestamp and pickpocket_timestamp + 1 > GetTime() and targetguid == pickpocket_otarget_guid then
--if debug_output then QuestHelper:TextOut(string.format("Pickpocketing from %s/%s", pickpocket_target, UnitName("target"), targetguid)) end
local mid = GetMonsterType(targetguid)
if not QHC.monster[mid] then QHC.monster[mid] = {} end
spot = QHC.monster[mid]
prefix = "rob"
elseif last_phase == LAST_PHASE_COMPLETE and gathereffects[last_spell] and last_timestamp + 1 > GetTime() then
local beef = string.format("%s/%s %s/%s", tostring(last_target), tostring(last_target_guid), tostring(last_otarget), tostring(last_otarget_guid))
if gathereffects[last_spell].ignore then return end
prefix = gathereffects[last_spell].token
-- this one is sort of grim actually
-- If we have an last_otarget_guid, it's the right one, and it's a monster
-- If we don't, use last_target, and it's an object
-- This is probably going to be buggy. Welp.
if last_otarget_guid then
if debug_output then QuestHelper:TextOut(string.format("%s from monster %s", gathereffects[last_spell].token, beef)) end
local mid = GetMonsterType(last_otarget_guid)
if not QHC.monster[mid] then QHC.monster[mid] = {} end
spot = QHC.monster[mid]
else
if debug_output then QuestHelper:TextOut(string.format("%s from object %s", gathereffects[last_spell].token, beef)) end
if not QHC.object[last_target] then QHC.object[last_target] = {} end
spot = QHC.object[last_target]
end
elseif touched_timestamp and touched_timestamp + 1 > GetTime() then
-- Opening a container, possibly
--if debug_output then QuestHelper:TextOut(string.format("Opening container %d", touched_itemid)) end
if not QHC.item[touched_itemid] then QHC.item[touched_itemid] = {} end
spot = QHC.item[touched_itemid]
prefix = "open"
elseif targetguid and (monsterstate[targetguid] == MS_TAPPED_LOOTABLE or monsterstate[targetguid] == MS_TAPPED_LOOTABLE_TRIVIAL) and monstertimeout[targetguid] > GetTime() and (not pickpocket_timestamp or pickpocket_timestamp + 5 < GetTime()) and (not last_timestamp or last_timestamp + 5 < GetTime()) and (last_succeed_trade + 5 < GetTime()) then -- haha holy shit
-- Monster is lootable, so we loot the monster. Should we check to see if it's dead first? Probably.
--if debug_output then QuestHelper:TextOut(string.format("%s from %s/%s", (monsterstate[targetguid] == MS_TAPPED_LOOTABLE and "Monsterloot" or "Trivial monsterloot"), UnitName("target"), targetguid)) end
local mid = GetMonsterType(targetguid)
if not QHC.monster[mid] then QHC.monster[mid] = {} end
spot = QHC.monster[mid]
if monsterstate[targetguid] == MS_TAPPED_LOOTABLE then
prefix = "loot"
elseif monsterstate[targetguid] == MS_TAPPED_LOOTABLE_TRIVIAL then
prefix = "loot_trivial" -- might be a better way to do this, but we'll see
end
monsterstate[targetguid] = MS_TAPPED_LOOTED
monstertimeout[targetguid] = GetTime() + 300
monsterrefresh[targetguid] = GetTime() + 2
else
--if debug_output then QuestHelper:TextOut("Who knows") end -- ugh
local loc = GetLoc()
if not QHC.worldloot then QHC.worldloot = {} end
ltype = QHC.worldloot
spot = {}
spot.loc = loc
prefix = "loot"
end
local items = {}
items[PseudoIDs["gold"]] = 0
for i = 1, GetNumLootItems() do
tex, name, quant, qual, locked = GetLootSlotInfo(i)
link = GetLootSlotLink(i)
local curr = LootSlotIsCurrency(i)
local coin = LootSlotIsCoin(i)
local itm = LootSlotIsItem(i)
if quant == 0 then
-- moneys
local tot = 0
local _, _, gold = string.find(name, Patterns.GOLD_AMOUNT)
local _, _, silver = string.find(name, Patterns.SILVER_AMOUNT)
local _, _, copper = string.find(name, Patterns.COPPER_AMOUNT)
tot = (tonumber(gold) or 0) * 10000 + (tonumber(silver) or 0) * 100 + (tonumber(copper) or 0) * 1
items[PseudoIDs["gold"]] = tot
else
if curr then
if not QHC.PseudoIDs[name] then
QHC.PseudoIDsMin = QHC.PseudoIDsMin - 1
QHC.PseudoIDs[name] = QHC.PseudoIDsMin
end
items[QHC.PseudoIDs[name]] = (items[QHC.PseudoIDs[name]] or 0) + quant
else
if not link and not name then
local msg = "Texture is " .. tostring(tex) .. " with a quantity of " .. tostring(quant) .. ", a quality of " .. qual .. "."
if coin then
QuestHelper:Assert(false, "Loot slot " .. tostring(i) .. " is coin. " .. msg)
elseif itm then
QuestHelper:Assert(false, "Loot slot " .. tostring(i) .. " is item. " .. msg)
else
QuestHelper_ErrorCatcher_ExplicitError(false, "Loot slot " .. tostring(i) .. " is ???. " .. msg)
--QuestHelper:Assert(false, "Loot slot " .. tostring(i) .. " is ???. " .. msg)
end
elseif not link then
QuestHelper:Assert(link, "Need more info on '" .. name .. "'x" .. tostring(quant) .. ".")
elseif not name then
QuestHelper:Assert(name, "Need more info on '" .. link .. "'x" .. tostring(quant) .. ".")
end
local itype = GetItemType(link)
items[itype] = (items[itype] or 0) + quant
end
end
end
if not spot[prefix] then spot[prefix] = {} end
spot[prefix]["count"] = (spot[prefix]["count"] or 0) + 1
if not spot[prefix]["loot"] then spot[prefix]["loot"] = {} end
local pt = spot[prefix]["loot"]
for k, v in pairs(items) do
if v > 0 then pt[k] = (pt[k] or 0) + v end
end
if ltype then table.insert(ltype, spot) end
end
function QH_Collect_Loot_Init(QHCData, API)
QHC = QHCData
if not QHC.monster then QHC.monster = {} end
if not QHC.worldloot then QHC.worldloot = {} end
if not QHC.fishing then QHC.fishing = {} end
if not QHC.item then QHC.item = {} end
if not QHC.PseudoIDs then
QHC.PseudoIDs = PseudoIDs
QHC.PseudoIDsMin = -1
end
QH_Event("PLAYER_ENTERING_WORLD", MembersUpdate)
QH_Event("RAID_ROSTER_UPDATE", MembersUpdate)
QH_Event("PARTY_MEMBERS_CHANGED", MembersUpdate)
QH_Event("COMBAT_LOG_EVENT_UNFILTERED", CombatLogEvent)
QH_Event("UPDATE_MOUSEOVER_UNIT", SkinnableflagsTooltipy)
QH_Event("UNIT_SPELLCAST_SENT", PPSent)
QH_Event("UNIT_SPELLCAST_SUCCEEDED", PPSucceed)
QH_Event("ITEM_LOCK_CHANGED", ItemLock)
QH_Event("UNIT_SPELLCAST_SENT", SpellSent)
QH_Event("UNIT_SPELLCAST_START", SpellStart)
QH_Event("COMBAT_LOG_EVENT_UNFILTERED", SpellCombatLog)
QH_Event("UNIT_SPELLCAST_SUCCEEDED", SpellSucceed)
QH_Event("UNIT_SPELLCAST_INTERRUPTED", SpellInterrupt)
QH_Event("LOOT_OPENED", LootOpened)
MembersUpdate() -- to get self, probably won't work but hey
GetMonsterUID = API.Utility_GetMonsterUID
GetMonsterType = API.Utility_GetMonsterType
GetItemType = API.Utility_GetItemType
QuestHelper: Assert(GetMonsterUID)
QuestHelper: Assert(GetMonsterType)
QuestHelper: Assert(GetItemType)
Patterns = API.Patterns
API.Patterns_RegisterNumber("GOLD_AMOUNT")
API.Patterns_RegisterNumber("SILVER_AMOUNT")
API.Patterns_RegisterNumber("COPPER_AMOUNT")
GetLoc = API.Callback_LocationBolusCurrent
QuestHelper: Assert(GetLoc)
-- What I want to know is whether it was tagged by me or my group when dead
-- Check target-of-each-groupmember? Once we see him tapped once, and by us, it's probably sufficient.
-- Notes:
--[[
COMBAT_LOG_EVENT_UNFILTERED arg2 UNIT_DIED, PLAYER_TARGET_CHANGED, LOOT_OPENED, (LOOT_CLOSED, [LOOT_SLOT_CLEARED, ITEM_PUSH, CHAT_MSG_LOOT]), PLAYER_TARGET_CHANGED, SPELLCAST_SENT, SPELLCAST_START, SUCCEEDED/INTERRUPTED, STOP, LOOT_OPENED (etc)
ITEM_PUSH can happen after LOOT_CLOSED, but it still happens.
Between LOOT_OPENED and LOOT_CLOSED, the lootable target is still targeted. Unsure what happens when looting items. LOOT_CLOSED triggers first if we target someone else.
ITEM_PUSH happens, then CHAT_MSG_LOOT. CHAT_MSG_LOOT includes quite a lot of potentially useful arguments.
PLAYER_TARGET_CHANGED before either looting or skinning.
SPELLCAST_SENT, SPELLCAST_START, SUCCEEDED/INTERRUPTED, STOP in that order. Arg4 on SENT seems to be the target's name. Arg4 on the others appears to be a unique identifier.
When started, we target the right thing. After that, we don't seem to. Check the combat log.
]]
end

Voir le fichier

@ -1,338 +0,0 @@
local GetTime = QuestHelperCollector_GetTime
QuestHelper_File["collect_lzw.lua"] = "4.0.1.$svnversion$"
QuestHelper_Loadtime["collect_lzw.lua"] = GetTime()
local Merger
local Bitstream
local function cleanup(tab)
for _, v in pairs(tab) do
QuestHelper:ReleaseTable(v)
end
QuestHelper:ReleaseTable(tab)
end
local function QH_LZW_Decompress(input, tokens, outbits, inputstatic)
local d = QuestHelper:CreateTable("lzw")
local i
for i = 0, tokens-1 do
d[i] = QuestHelper:CreateTable("lzw")
d[i][0] = string.char(i)
end
local dsize = tokens + 1 -- we use the "tokens" value as an EOF marker
if inputstatic then
local used = QuestHelper:CreateTable("lzw")
for _, v in ipairs(inputstatic) do
for i = #v, 2, -1 do
local subi = v:sub(1, i)
if not used[subi] then
used[subi] = true
d[bit.mod(dsize, tokens)][math.floor(dsize / tokens)] = subi
dsize = dsize + 1
else
break
end
end
end
QuestHelper:ReleaseTable(used)
end
local bits = 1
local nextbits = 2
while nextbits < dsize do bits = bits + 1; nextbits = nextbits * 2 end
local i = Bitstream.Input(input, outbits)
local rv = {}
local idlect = 0
local tok = i:depend(bits)
if tok == tokens then cleanup(d) return "" end -- Okay. There's nothing. We get it.
Merger.Add(rv, d[bit.mod(tok, tokens)][math.floor(tok / tokens)])
local w = d[bit.mod(tok, tokens)][math.floor(tok / tokens)]
while true do
if idlect == 25 then
QH_Timeslice_Yield()
idlect = 0
else
idlect = idlect + 1
end
dsize = dsize + 1 -- We haven't actually added the next element yet. However, we could in theory include it in the stream, so we need to adjust the number of bits properly.
if dsize > nextbits then
bits = bits + 1
nextbits = nextbits * 2
end
tok = i:depend(bits)
if tok == tokens then break end -- we're done!
local entry
if d[bit.mod(tok, tokens)][math.floor(tok / tokens)] then
entry = d[bit.mod(tok, tokens)][math.floor(tok / tokens)]
elseif tok == dsize - 1 then
entry = w .. w:sub(1, 1)
else
QuestHelper: Assert(false, "faaaail")
end
Merger.Add(rv, entry)
d[bit.mod(dsize - 1, tokens)][math.floor((dsize - 1) / tokens)] = w .. entry:sub(1, 1) -- Naturally, we're writing to one *less* than dsize, since we already incremented.
w = entry
end
cleanup(d)
return Merger.Finish(rv)
end
local function QH_LZW_Compress(input, tokens, outbits, inputstatic)
-- shared init code
local d = {}
local i
for i = 0, tokens-1 do
d[string.char(i)] = {[""] = i}
end
local dsize = tokens + 1 -- we use the "tokens" value as an EOF marker
if inputstatic then
for _, v in ipairs(inputstatic) do
local da = d[v:sub(1, 1)]
for i = #v, 2, -1 do
local b = v:sub(2, i)
if not da[b] then
da[b] = dsize
dsize = dsize + 1
else
break
end
end
end
end
local bits = 1
local nextbits = 2
while nextbits < dsize do bits = bits + 1; nextbits = nextbits * 2 end
local r = Bitstream.Output(outbits)
local idlect = 0
local w = ""
for ci = 1, #input do
if idlect == 100 then
QH_Timeslice_Yield()
idlect = 0
else
idlect = idlect + 1
end
local c = input:sub(ci, ci)
local wcp = w .. c
if d[wcp:sub(1, 1)][wcp:sub(2)] then
w = wcp
else
r:append(d[w:sub(1, 1)][w:sub(2)], bits)
d[wcp:sub(1, 1)][wcp:sub(2)] = dsize
dsize = dsize + 1
if dsize > nextbits then
bits = bits + 1
nextbits = nextbits * 2
end
w = c
end
end
if w ~= "" then
r:append(d[w:sub(1, 1)][w:sub(2)], bits)
dsize = dsize + 1 -- Our decompressor doesn't realize we're ending here, so it will have added a table entry for that last token. Sigh.
if dsize > nextbits then
bits = bits + 1
nextbits = nextbits * 2
end
end
r:append(tokens, bits)
local rst = r:finish()
QuestHelper: Assert(QH_LZW_Decompress(rst, tokens, outbits, inputstatic) == input) -- yay
return rst
end
local function mdict(inputdict)
local idc = QuestHelper:CreateTable("lzw mdict")
for i = 1, #inputdict do if math.fmod(i, 100) == 0 then QH_Timeslice_Yield() end idc[inputdict:sub(i, i)] = strchar(i - 1) end
return idc
end
local function dictize(idcl, stt)
local im = QuestHelper:CreateTable("lzw dictize")
for i = 1, #stt do
local subl = idcl[stt:sub(i, i)]
QuestHelper: Assert(subl)
Merger.Add(im, subl)
end
local result = Merger.Finish(im)
QuestHelper:ReleaseTable(im)
return result
end
local function QH_LZW_Prepare(inputdict, inputstatic)
QuestHelper: Assert(inputdict and inputstatic)
local idc = mdict(inputdict)
local inpstat = {}
local ct = 0
for _, v in ipairs(inputstatic) do
ct = ct + 1
if ct == 10 then QH_Timeslice_Yield() ct = 0 end
table.insert(inpstat, dictize(idc, v))
end
return idc, #inputdict, inpstat
end
local function QH_LZW_Compress_Dicts_Prepared(input, idprepped, idpreppedsize, outputdict, isprepped)
input = dictize(idprepped, input)
local bits, dsize = 1, 2
if not outputdict then bits = 8 else while dsize < #outputdict do bits = bits + 1 ; dsize = dsize * 2 end end
QuestHelper: Assert(not outputdict or #outputdict == dsize)
local comp = QH_LZW_Compress(input, idpreppedsize, bits, isprepped)
if outputdict then
local origcomp = comp
local im = {}
for i = 1, #origcomp do Merger.Add(im, outputdict:sub(strbyte(origcomp:sub(i, i)) + 1)) end
comp = Merger.Finish(im)
end
return comp
end
local function QH_LZW_Compress_Dicts(input, inputdict, outputdict, inputstatic)
local inproc = input
local inpstat = inputstatic
if inputdict then
local idc = mdict(inputdict)
inproc = dictize(idc, input)
if inputstatic then
inpstat = {}
for _, v in ipairs(inputstatic) do
table.insert(inpstat, dictize(idc, v))
end
end
QuestHelper:ReleaseTable(idc)
end
local bits, dsize = 1, 2
if not outputdict then bits = 8 else while dsize < #outputdict do bits = bits + 1 ; dsize = dsize * 2 end end
QuestHelper: Assert(not outputdict or #outputdict == dsize)
local comp = QH_LZW_Compress(inproc, inputdict and #inputdict or 256, bits, inpstat)
if outputdict then
local origcomp = comp
local im = {}
for i = 1, #origcomp do Merger.Add(im, outputdict:sub(strbyte(origcomp:sub(i, i)) + 1)) end
comp = Merger.Finish(im)
end
return comp
end
local function QH_LZW_Decompress_Dicts_Prepared(compressed, inputdict, outputdict, ispreppred) -- this is kind of backwards - we assume that "outputdict" is the dictionary that "compressed" is encoded in
QuestHelper: Assert(not outputdict)
QuestHelper: Assert(inputdict)
local decomp = QH_LZW_Decompress(compressed, #inputdict, 8, ispreppred)
local ov = {}
for i = 1, #decomp do
Merger.Add(ov, inputdict:sub(decomp:byte(i) + 1, decomp:byte(i) + 1))
end
return Merger.Finish(ov)
end
local function QH_LZW_Decompress_Dicts(compressed, inputdict, outputdict, inputstatic) -- this is kind of backwards - we assume that "outputdict" is the dictionary that "compressed" is encoded in
QuestHelper: Assert(not outputdict)
QuestHelper: Assert(inputdict)
local inpstat = inputstatic
if inputdict and inputstatic then
local idc = mdict(inputdict)
inpstat = {}
for _, v in ipairs(inputstatic) do
table.insert(inpstat, dictize(idc, v))
end
QuestHelper:ReleaseTable(idc)
end
local decomp = QH_LZW_Decompress(compressed, #inputdict, 8, inpstat)
local ov = {}
for i = 1, #decomp do
Merger.Add(ov, inputdict:sub(decomp:byte(i) + 1, decomp:byte(i) + 1))
end
return Merger.Finish(ov)
end
QH_LZW_Prepare_Arghhacky = QH_LZW_Prepare -- need to rig up a better mechanism for this really
QH_LZW_Decompress_Dicts_Arghhacky = QH_LZW_Decompress_Dicts -- need to rig up a better mechanism for this really
QH_LZW_Decompress_Dicts_Prepared_Arghhacky = QH_LZW_Decompress_Dicts_Prepared -- need to rig up a better mechanism for this really
function QH_Collect_LZW_Init(_, API)
Merger = API.Utility_Merger
QuestHelper: Assert(Merger)
Bitstream = API.Utility_Bitstream
QuestHelper: Assert(Bitstream)
API.Utility_LZW = {Compress = QH_LZW_Compress, Decompress = QH_LZW_Decompress, Compress_Dicts = QH_LZW_Compress_Dicts, Decompress_Dicts = QH_LZW_Decompress_Dicts, Prepare = QH_LZW_Prepare, Compress_Dicts_Prepared = QH_LZW_Compress_Dicts_Prepared, Decompress_Dicts_Prepared = QH_LZW_Decompress_Dicts_Prepared}
end
-- old debug code :)
--[[
print("hello")
QH_LZW_Compress("TOBEORNOTTOBEORTOBEORNOT", 256, 8)
]]
--[[
QuestHelper:TextOut("lulz")
local inq = "ABABABABA"
local alpha = 253
local bits = 7
str = QH_LZW_Compress(inq, alpha, bits)
tvr = ""
for i = 1, #str do
tvr = tvr .. string.format("%d ", strbyte(str, i))
end
QuestHelper:TextOut(tvr)
ret = QH_LZW_Decompress(str, alpha, bits)
QuestHelper:TextOut(ret)
QuestHelper: Assert(inq == ret)
]]

Voir le fichier

@ -1,82 +0,0 @@
local GetTime = QuestHelperCollector_GetTime
QuestHelper_File["collect_merchant.lua"] = "4.0.1.$svnversion$"
QuestHelper_Loadtime["collect_merchant.lua"] = GetTime()
-- http://www.penny-arcade.com/comic/2005/01/05/
local debug_output = false
if QuestHelper_File["collect_merchant.lua"] == "Development Version" then debug_output = true end
local QHCM
local IsMonsterGUID
local GetMonsterType
local GetItemType
local function AddChatType(typ)
local target = UnitGUID("target")
if not target then return end
if not IsMonsterGUID(target) then return end
target = GetMonsterType(target)
if not QHCM[target] then QHCM[target] = {} end
QHCM[target]["chat_" .. typ] = (QHCM[target]["chat_" .. typ] or 0) + 1
return QHCM[target]
end
local function MerchantShow()
local ct = GetMerchantNumItems()
for i = 1, ct do if not GetMerchantItemLink(i) then return end end -- We want to make sure it's cached, otherwise we'll return wonky data. Technically this biases things away from "yes he's a shopkeeper", but honestly, it doesn't matter that much.
targ = AddChatType("shop")
if not targ then return end -- welllllp
local ct = GetMerchantNumItems()
--QuestHelper:TextOut(string.format("nitems %d", ct))
for i = 1, ct do
local itemid = GetMerchantItemLink(i)
QuestHelper: Assert(itemid)
itemid = GetItemType(itemid)
local _, _, price, quant, avail, _, _ = GetMerchantItemInfo(i)
local dstr = {}
dstr.quant = quant
dstr.avail = avail
dstr.price = price
--if debug_output then QuestHelper:TextOut(dstr) end
if not targ.shop then targ.shop = {} end
if not targ.shop[itemid] then
targ.shop[itemid] = dstr
end
targ.shop[itemid].count = (targ.shop[itemid].count or 0) + 1
end
end
local function GossipShow()
AddChatType("talk")
end
local function QuestGreeting()
AddChatType("quest")
end
function QH_Collect_Merchant_Init(QHCData, API)
if not QHCData.monster then QHCData.monster = {} end
QHCM = QHCData.monster
QH_Event("MERCHANT_SHOW", MerchantShow)
QH_Event("GOSSIP_SHOW", GossipShow)
QH_Event("QUEST_GREETING", QuestGreeting)
IsMonsterGUID = API.Utility_IsMonsterGUID
GetMonsterType = API.Utility_GetMonsterType
GetItemType = API.Utility_GetItemType
QuestHelper: Assert(IsMonsterGUID)
QuestHelper: Assert(GetMonsterType)
QuestHelper: Assert(GetItemType)
end

Voir le fichier

@ -1,27 +0,0 @@
local GetTime = QuestHelperCollector_GetTime
QuestHelper_File["collect_merger.lua"] = "4.0.1.$svnversion$"
QuestHelper_Loadtime["collect_merger.lua"] = GetTime()
local function Add(self, data, stoprepeat) -- NOTE: if you're getting errors about adding tables, you probably did Merger:Add instead of Merger.Add
if stoprepeat and #self > 0 and string.sub(self[#self], -#data) == data then return end
table.insert(self, data)
for i = #self - 1, 1, -1 do
if string.len(self[i]) > string.len(self[i + 1]) then break end
self[i] = self[i] .. table.remove(self, i + 1)
end
end
local function Finish(self, data)
for i = #self - 1, 1, -1 do
self[i] = self[i] .. table.remove(self)
end
return self[1] or ""
end
QH_Merger_Add = Add
QH_Merger_Finish = Finish
function QH_Collect_Merger_Init(_, API)
API.Utility_Merger = {Add = Add, Finish = Finish}
end

Voir le fichier

@ -1,138 +0,0 @@
local GetTime = QuestHelperCollector_GetTime
QuestHelper_File["collect_monster.lua"] = "4.0.1.$svnversion$"
QuestHelper_Loadtime["collect_monster.lua"] = GetTime()
local debug_output = false
if QuestHelper_File["collect_monster.lua"] == "Development Version" then debug_output = true end
local QHCM
local GetLoc
local Merger
local Patterns
local IsMonsterGUID
local GetMonsterUID
local GetMonsterType
local logon = GetTime() -- Because I'm incredibly paranoid, I'm waiting fifteen minutes after logon to assume they're not drunk.
local drunk_logon = true
local drunk_message = false
local function SystemMessage(arg, arg2, arg3)
if strfind(arg, Patterns["DRUNK_MESSAGE_SELF2"]) or strfind(arg, Patterns["DRUNK_MESSAGE_SELF3"]) or strfind(arg, Patterns["DRUNK_MESSAGE_SELF4"]) or strfind(arg, Patterns["DRUNK_MESSAGE_ITEM_SELF2"]) or strfind(arg, Patterns["DRUNK_MESSAGE_ITEM_SELF3"]) or strfind(arg, Patterns["DRUNK_MESSAGE_ITEM_SELF4"]) then
drunk_message = true
elseif strfind(arg, Patterns["DRUNK_MESSAGE_SELF1"]) or strfind(arg, Patterns["DRUNK_MESSAGE_ITEM_SELF1"]) then
drunk_message = false
end
end
local InteractDistances = {28, 11, 10, 0} -- There's actually a 4, but it's also 28 and it's kind of handy to be able to do it this way.
local recentlySeenCritters = {} -- We try not to repeatedly record critters frequently.
-- Kind of a nasty system here, built for efficiency and simplicity. All newly-seen critters go into Recent. When Recent reaches a certain size (100?) everything in NextTrash is deleted and NextTrash is replaced with Recent. Badabing, badaboom.
local recentlySeenCritters_NextTrash = {}
local recentlySeenCritters_Recent = {}
local function AccumulateFrequency(target, name, data)
if not target[name] then target[name] = {} end
target[name][data] = (target[name][data] or 0) + 1
--local key = name .. "_" .. tostring(data)
--target[key] = (target[key] or 0) + 1
end
local function MouseoverUnit()
if logon and logon + 60 * 15 < GetTime() then
logon = nil
drunk_logon = false
end
-- First off, we see if it's "interesting".
-- The original code for this filtered out critters. I don't, because critters are cute, and rare.
if 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 -- pet that isn't controlled by a player? NPC pet? It's kind of unclear, but I'm getting some, so, FIXED
local creatureid = GetMonsterUID(guid)
if not recentlySeenCritters[creatureid] then
recentlySeenCritters_Recent[creatureid] = true
recentlySeenCritters[creatureid] = true
-- register the critter here
local cid = GetMonsterType(guid)
if not QHCM[cid] then QHCM[cid] = {} end
local critter = QHCM[cid]
if cid < 30621 or cid > 30625 then AccumulateFrequency(critter, "name", UnitName("mouseover")) end -- The exceptions are for Herald Volasj's minions, which are named after your partymembers.
AccumulateFrequency(critter, "reaction", UnitReaction("mouseover", "player"))
if not drunk_logon and not drunk_message then
AccumulateFrequency(critter, "level", UnitLevel("mouseover"))
end
local minrange = InteractDistances[1]
local maxrange = 255
-- Now we try to derive a bound for how far away it is
for i = #InteractDistances - 1, 1, -1 do
if CheckInteractDistance("mouseover", i) then
minrange = InteractDistances[i + 1]
maxrange = InteractDistances[i]
break
end
end
QuestHelper: Assert(minrange >= 0 and minrange < 256 and maxrange >= 0 and maxrange < 256)
local data = {}
data.loc = GetLoc()
data.minrange = minrange
data.maxrange = maxrange
if not critter.encounters then critter.encounters = {} end
table.insert(critter.encounters, data)
--Merger.Add(critter, string.format("(%s %s %s),", GetLoc(), tostring(minrange), tostring(maxrange))) --strchar(minrange, maxrange))
if #recentlySeenCritters_Recent >= 100 then
for k, v in recentlySeenCritters_NextTrash do
recentlySeenCritters[v] = nil
end
recentlySeenCritters_NextTrash = recentlySeenCritters_Recent
recentlySeenCritters_Recent = {} -- BAM, garbage collection!
end
end
end
end
function QH_Collect_Monster_Init(QHCData, API)
if not QHCData.monster then QHCData.monster = {} end
QHCM = QHCData.monster
QH_Event("UPDATE_MOUSEOVER_UNIT", MouseoverUnit)
QH_Event("CHAT_MSG_SYSTEM", SystemMessage)
Patterns = API.Patterns
QuestHelper: Assert(Patterns)
API.Patterns_Register("DRUNK_MESSAGE_SELF1", "|c.*|r")
API.Patterns_Register("DRUNK_MESSAGE_SELF2", "|c.*|r")
API.Patterns_Register("DRUNK_MESSAGE_SELF3", "|c.*|r")
API.Patterns_Register("DRUNK_MESSAGE_SELF4", "|c.*|r")
API.Patterns_Register("DRUNK_MESSAGE_ITEM_SELF1", "|c.*|r")
API.Patterns_Register("DRUNK_MESSAGE_ITEM_SELF2", "|c.*|r")
API.Patterns_Register("DRUNK_MESSAGE_ITEM_SELF3", "|c.*|r")
API.Patterns_Register("DRUNK_MESSAGE_ITEM_SELF4", "|c.*|r")
GetLoc = API.Callback_LocationBolusCurrent
QuestHelper: Assert(GetLoc)
Merger = API.Utility_Merger
QuestHelper: Assert(Merger)
IsMonsterGUID = API.Utility_IsMonsterGUID
GetMonsterUID = API.Utility_GetMonsterUID
GetMonsterType = API.Utility_GetMonsterType
QuestHelper: Assert(IsMonsterGUID)
QuestHelper: Assert(GetMonsterUID)
QuestHelper: Assert(GetMonsterType)
end

Voir le fichier

@ -1,29 +0,0 @@
local GetTime = QuestHelperCollector_GetTime
QuestHelper_File["collect_notifier.lua"] = "4.0.1.$svnversion$"
QuestHelper_Loadtime["collect_notifier.lua"] = GetTime()
local NotificationsPending = {}
local function OnUpdate()
while #NotificationsPending > 0 and GetTime() >= NotificationsPending[1].time do
NotificationsPending[1].func()
table.remove(NotificationsPending, 1) -- okay okay n^2 deal with it
end
end
local function AddItem(time, func)
QuestHelper: Assert(time)
QuestHelper: Assert(func)
table.insert(NotificationsPending, {time = time, func = func})
table.sort(NotificationsPending, function (a, b) return a.time < b.time end) -- haha who cares about efficiency anyway, NOT ME that is for certain
end
function QH_Collect_Notifier_Init(_, API)
API.Utility_Notifier = AddItem
API.Registrar_OnUpdateHook(OnUpdate)
end
-- grrrr
QH_AddNotifier = AddItem

Voir le fichier

@ -1,109 +0,0 @@
local GetTime = QuestHelperCollector_GetTime
QuestHelper_File["collect_object.lua"] = "4.0.1.$svnversion$"
QuestHelper_Loadtime["collect_object.lua"] = GetTime()
local debug_output = false
if QuestHelper_File["collect_object.lua"] == "Development Version" then debug_output = true end
local QHCO
local GetLoc
local Merger
local Patterns
local minetypes = {
mine = UNIT_SKINNABLE_ROCK,
herb = UNIT_SKINNABLE_HERB,
eng = UNIT_SKINNABLE_BOLTS,
skin = UNIT_SKINNABLE_LEATHER,
}
local function Tooltipy(self)
-- objects are a bitch since they have no unique ID or any standard way to detect them (that I know of).
-- So we kind of guess at it.
if self:GetAnchorType() == "ANCHOR_NONE" then -- Theoretically this function no longer exists as of 2010-12-14.
if self:GetItem() or self:GetUnit() or self:GetSpell() then return end
-- rglrglrglrglrglrgl
local skintype = nil
local lines = GameTooltip:NumLines()
if not skintype then
local cline = 2
-- the painful process of checking to see if it might be a game object
-- first, look for a "requires" line
if not (_G["GameTooltipTextLeft" .. cline] and _G["GameTooltipTextLeft" .. cline]:IsShown()) then return end
do
local gt = _G["GameTooltipTextLeft" .. cline]:GetText()
if string.match(gt, Patterns.LOCKED_WITH_ITEM) or string.match(gt, Patterns.LOCKED_WITH_SPELL) or string.match(gt, Patterns.LOCKED_WITH_SPELL_KNOWN) then cline = cline + 1 end
end
if not (_G["GameTooltipTextLeft" .. cline] and _G["GameTooltipTextLeft" .. cline]:IsShown()) then return end
local r, g, b, a = _G["GameTooltipTextLeft" .. cline]: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)
if not (r == 255 and g == 210 and b == 0 and a == 255) then return end -- not a quest item, which I guess we care about
cline = cline + 1
if not (_G["GameTooltipTextLeft" .. cline] and _G["GameTooltipTextLeft" .. cline]:IsShown()) then return end
local r, g, b, a = _G["GameTooltipTextLeft" .. cline]: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)
if not (r == 255 and g == 255 and b == 255 and a == 255) or not _G["GameTooltipTextLeft" .. cline]:GetText():match("^ - ") then return end -- not a quest item, which I guess we care about
-- alright good enough
end
local name = _G["GameTooltipTextLeft1"]:GetText()
if string.match(name, Patterns.CORPSE_TOOLTIP) then return end -- no corpses plzkthx
if debug_output then QuestHelper:TextOut("Parsing " .. name) end
if not QHCO[name] then QHCO[name] = {} end
local qhci = QHCO[name]
-- We have no unique identifier, so I'm just going to record every position we see. That said, I wonder if it's a good idea to add a cooldown.
-- Obviously, we also have no possible range data, so, welp.
local loc = GetLoc()
local contained = false
for _, v in pairs(qhci) do
if v.delayed then
if v.delayed == loc.delayed and
v.c == loc.c and v.z == loc.z and
v.x == loc.x and v.y == loc.y then
contained = true
break
end
end
end
if not contained then table.insert(qhci, loc) end
--Merger.Add(qhci, "(" .. GetLoc() .. ")", true)
end
end
function QH_Collect_Object_Init(QHCData, API)
if not QHCData.object then QHCData.object = {} end
QHCO = QHCData.object
API.Registrar_TooltipHook(Tooltipy)
Patterns = API.Patterns
QuestHelper: Assert(Patterns)
API.Patterns_Register("CORPSE_TOOLTIP", "[^%s]+")
API.Patterns_Register("LOCKED_WITH_ITEM", "[^%s]+")
API.Patterns_Register("LOCKED_WITH_SPELL", "[^%s]+")
API.Patterns_Register("LOCKED_WITH_SPELL_KNOWN", "[^%s]+")
GetLoc = API.Callback_LocationBolusCurrent
QuestHelper: Assert(GetLoc)
Merger = API.Utility_Merger
QuestHelper: Assert(Merger)
end

Voir le fichier

@ -1,21 +0,0 @@
local GetTime = QuestHelperCollector_GetTime
QuestHelper_File["collect_patterns.lua"] = "4.0.1.$svnversion$"
QuestHelper_Loadtime["collect_patterns.lua"] = GetTime()
local patterns = {}
function MakePattern(label, newpat)
if not newpat then newpat = ".*" end
if not patterns[label] then patterns[label] = "^" .. string.gsub(_G[label], "%%s", newpat) .. "$" end
end
function MakeNumberSnag(label)
if not patterns[label] then patterns[label] = string.gsub(_G[label], "%%d", "([0-9,.]+)") end
end
function QH_Collect_Patterns_Init(QHCData, API)
API.Patterns = patterns
API.Patterns_Register = MakePattern
API.Patterns_RegisterNumber = MakeNumberSnag
end

Voir le fichier

@ -1,439 +0,0 @@
local GetTime = QuestHelperCollector_GetTime
QuestHelper_File["collect_quest.lua"] = "4.0.1.$svnversion$"
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)))
if not QHCQ[id]["criteria"] then QHCQ[id]["criteria"] = {} end
for i = 1, GetNumQuestLeaderBoards(index) do
local desc, typ = GetQuestLogLeaderBoard(i, index)
local criterion = { text = desc, type = typ }
QHCQ[id]["criteria"][tostring(i)] = criterion
--QHCQ[id][string.format("criteria_%d_text", i)] = desc
--QHCQ[id][string.format("criteria_%d_type", i)] = type
--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)
-- 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
table.insert(eventy, {time = GetTime(), event = {type = "item", value = ltype}})
--if debug_output then QuestHelper:TextOut(string.format("Added event %s", string.format("I%di", ltype))) end
end
local function Combat(_, event, _, _, _, _, _, guid)
if event ~= "UNIT_DIED" then return end
if not IsMonsterGUID(guid) then return end
local mtype = GetMonsterType(guid, true)
table.insert(eventy, {time = GetTime(), event = { type = "monster", value = mtype}})
--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)
if not tab[key] then tab[key] = {} end
table.insert(tab[key], dat)
--tab[key] = (tab[key] or "") .. dat
end
local function StartOrEnd(se, id)
local targuid = UnitGUID("target")
local chunk = {}
if targuid and IsMonsterGUID(targuid) then
chunk.m = GetMonsterType(targuid)
end
chunk.loc = GetLoc()
chunk.spec = GetSpecBolus()
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())
end
local abandoncomplete = ""
local abandoncomplete_timestamp = nil
local GetQuestReward_Orig = GetQuestReward
GetQuestReward = function (...)
abandoncomplete = "complete"
abandoncomplete_timestamp = GetTime()
GetQuestReward_Orig(...)
end
local AbandonQuest_Orig = AbandonQuest
AbandonQuest = function ()
abandoncomplete = "abandon"
abandoncomplete_timestamp = GetTime()
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
local tim = GetTime()
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]]
while #eventy > 0 and eventy[1].time < GetTime() - 1 do table.remove(eventy, 1) end -- slurp
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
if abandoncomplete == "complete" and abandoncomplete_timestamp + 30 >= GetTime() then
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
token = {}
token["events"] = {}
for k, v in pairs(eventy) do table.insert(token.events, v.event) end
debugtok = token
token["loc"] = GetLoc()
--token = token .. "(" .. GetLoc() .. ")"
end
local ttok = token
if noobey[k][i] - 1 ~= deebey[k][i] then
--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])
end
if not QHCQ[k]["criteria"] then QHCQ[k]["criteria"] = {} end
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)
--AppendMember(QHCQ[k], string.format("criteria_%d_satisfied", i), ttok)
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))
--QuestHelper:TextOut(string.format("done in %f", GetTime() - tim))
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
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
if not QHCQ[tv.qid]["criteria"][tostring(tv.obj)]["monster"] then QHCQ[tv.qid]["criteria"][tostring(tv.obj)]["monster"] = {} end
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"] = {}
end
QHCQ[tv.qid]["criteria"][tostring(tv.obj)]["monster"]["false"][guid] = (QHCQ[tv.qid]["criteria"][tostring(tv.obj)]["monster"]["false"][guid] or 0) + 1
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
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
end
elseif qlookups[lin] then
cquest = qlookups[lin]
else
QH_filter_hints = false
--QuestHelper: Assert()
end
end
end
end
end
end
function QH_Collect_Quest_Init(QHCData, API)
if not QHCData.quest then QHCData.quest = {} end
QHCQ = QHCData.quest
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

Voir le fichier

@ -1,75 +0,0 @@
local GetTime = QuestHelperCollector_GetTime
QuestHelper_File["collect_spec.lua"] = "4.0.1.$svnversion$"
QuestHelper_Loadtime["collect_spec.lua"] = GetTime()
local Bitstream
local classlookup = {
["DEATHKNIGHT"] = "K",
["DRUID"] = "D",
["HUNTER"] = "H",
["MAGE"] = "M",
["PALADIN"] = "N",
["PRIEST"] = "P",
["ROGUE"] = "R",
["SHAMAN"] = "S",
["WARLOCK"] = "L",
["WARRIOR"] = "W"
};
local racelookup = {
["Draenei"] = "R",
["Gnome"] = "G",
["Dwarf"] = "D",
["Human"] = "H",
["NightElf"] = "E",
["Worgen"] = "W",
["Orc"] = "O",
["Troll"] = "T",
["Tauren"] = "N",
["Undead"] = "U",
["BloodElf"] = "B",
["Goblin"] = "L"
-- lol i spelled nub
}
local function GetSpecBolus()
local _, id = UnitClass("player")
local level = UnitLevel("player")
local _, race = UnitRace("player")
--[[ assert(racelookup[race]) ]]
--local bso = Bitstream.Output(8)
local talents = {}
local points = (GetUnspentTalentPoints() or 0)
local talents_learned = false
for t = 1, GetNumTalentTabs() do -- come on. Is this ever not going to be 3? Seriously? Perhaps someday, but not as of Cat.
local _, tab, _, _, p, _, _, yn = GetTalentTabInfo(t)
p = p or 0
talents_learned = true
talents[tab] = {}
for ta = 1, GetNumTalents(t) do
local talent, _, _, _, rank, _ = GetTalentInfo(t, ta)
if talent then talents[tab][talent] = rank end
end
end
local spec = {}
spec.talents = talents
spec.class = id
spec.race = race
spec.level = level
--return string.format("(2%s,%s,%02d)", classlookup[id], racelookup[race] or "", level) .. talstr
return spec
end
function QH_Collect_Spec_Init(_, API)
Bitstream = API.Utility_Bitstream
QuestHelper: Assert(Bitstream)
API.Utility_GetSpecBolus = GetSpecBolus
end

Voir le fichier

@ -1,220 +0,0 @@
local GetTime = QuestHelperCollector_GetTime
QuestHelper_File["collect_traveled.lua"] = "4.0.1.$svnversion$"
QuestHelper_Loadtime["collect_traveled.lua"] = GetTime()
local debug_output = false
if QuestHelper_File["collect_traveled.lua"] == "Development Version" then debug_output = true end
--[[
Meaningful symbols it generates:
%d,%d,%d,%d|COMPRESSED
First four values: continent ID as per client, X coordinate in yards as per client via Astrolabe, Y coordinate in yards as per client via Astrolabe, faction ID (Alliance/Horde)
Compressed data is complicated lzw'ed hideousness.
Version number is probably contained in the |, I'll change that when I need to change meaning.
User is assumed to start facing right, all turns are 90 degrees.
Allowed values, post-lookup-table listed below, are:
^ - forward
< - turn left and move forward
> - turn right and move forward
v - turn around and move forward
C - combo indicator, each one indicates that another next UDLR is part of a single move (the toggles are zero-time anyway)
S - swim toggle
X - taxi toggle
M - mount toggle
Y - flying mount toggle
D - dead/ghost toggle
]]
local QHCT
local Merger
local LZW
local Bolus
local cc, cx, cy, cd = nil, nil, nil, nil
local flags = {}
local nx, ny = nil, nil
local function round(x) return math.floor(x + 0.5) end
local function dist(x, y) return math.abs(x) + math.abs(y) end -- fuck it, manhattan distance
-- ++ is turning right
local dx = {1, 0, -1, 0}
local dy = {0, 1, 0, -1}
local function InitWorking()
QHCT.working = {}
QHCT.working.prefix = {}
end
local function AddDataPrefix(data)
table.insert(QHCT.working.prefix, data)
--QHCT.working.prefix = QHCT.working.prefix .. data
end
local function AddData(data)
table.insert(QHCT.working, data)
--Merger.Add(QHCT.working, data)
end
local function FinishData()
return Merger.Finish(QHCT.working)
end
local function TestDirection(nd, kar)
if nd < 1 then nd = nd + 4 end
if nd > 4 then nd = nd - 4 end
if dist(cx + dx[nd] - nx , cy + dy[nd] - ny) < dist(cx - nx, cy - ny) then
AddData(kar)
cd = nd
cx = cx + dx[cd]
cy = cy + dy[cd]
return true
else
return false
end
end
local function CompressAndComplete(ki)
--QuestHelper:TextOut(string.format("%d tokens", #QHCT.compressing[ki].data))
local tim = GetTime()
local lzwed = LZW.Compress_Dicts(QHCT.compressing[ki].data, "^<>vCSXMYD")
if debug_output then
QuestHelper:TextOut(string.format("%d tokens: compressed to %d in %f", #QHCT.compressing[ki].data, #lzwed, GetTime() - tim))
end
if not QHCT.done then QHCT.done = {} end
table.insert(QHCT.done, QHCT.compressing[ki].prefix .. lzwed)
QHCT.compressing[ki] = nil
end
local function CompressFromKey(ki)
QH_Timeslice_Add(function () CompressAndComplete(ki) end, "lzw")
end
local function CompileData()
local data = FinishData()
local prefix = QHCT.working.prefix
InitWorking()
if #data > 0 then
if not QHCT.compressing then QHCT.compressing = {} end
local ki = GetTime()
while QHCT.compressing[ki] do ki = ki + 1 end -- if this ever triggers, I'm shocked
QHCT.compressing[ki] = {data = data, prefix = prefix}
CompressFromKey(ki)
end
end
local function AppendFlag(flagval, flagid)
flagval = not not flagval
flags[flagid] = not not flags[flagid]
if flagval ~= flags[flagid] then
if debug_output then
--QuestHelper:TextOut(string.format("Status toggle %s", flagid))
end
flags[flagid] = flagval
AddData(flagid)
end
end
local function QH_Collect_Traveled_Point(c, x, y, rc, rz)
if not c or not x or not y then return end
nx, ny = round(x), round(y)
if c ~= cc or dist(nx - cx, ny - cy) > 10 then
if debug_output then
QuestHelper:TextOut(string.format("finishing thanks to differences, %s,%s,%s vs %s,%s,%s (%s)", tostring(cc), tostring(cx), tostring(cy), tostring(c), tostring(nx), tostring(ny), cc and tostring(dist(nx - cx, ny - cy)) or "lol"))
end
CompileData()
cc, cx, cy, cd = c, nx, ny, 1
swim, mount, flying, taxi = false, false, false, false
local b = Bolus(c, x, y, rc, rz)
b.faction = QuestHelper:PlayerFaction()
AddDataPrefix(Bolus(c, x, y, rc, rz) .. strchar(tostring(QuestHelper:PlayerFaction()))) -- The playerfaction can be removed, as it's now encoded in the collection shard. Not removing it for compatibility reasons.
end
AppendFlag(IsMounted(), 'M')
AppendFlag(IsFlying(), 'Y')
AppendFlag(IsSwimming(), 'S')
AppendFlag(UnitOnTaxi("player"), 'X')
AppendFlag(UnitIsDeadOrGhost("player"), 'D')
for x = 1, dist(nx - cx, ny - cy) - 1 do
AddData('C')
end
-- first we go forward as much as is reasonable
while TestDirection(cd, '^') do end
if TestDirection(cd + 1, '>') then -- if we can go right, we do so, then we go forward again
while TestDirection(cd, '^') do end
-- In theory, if the original spot was back-and-to-the-right of us, we could need to go right *again* and then forward *again*. So we do.
if TestDirection(cd + 1, '>') then
while TestDirection(cd, '^') do end
end
elseif TestDirection(cd - 1, '<') then -- the same logic applies for left.
while TestDirection(cd, '^') do end
if TestDirection(cd - 1, '<') then
while TestDirection(cd, '^') do end
end
else
-- And we also test back, just in case.
if TestDirection(cd + 2, 'v') then
while TestDirection(cd, '^') do end
end
end
QuestHelper: Assert(cx == nx and cy == ny)
-- Done!
end
local GetRawLocation
local function OnUpdate()
QH_Collect_Traveled_Point(GetRawLocation())
end
function QH_Collect_Traveled_Init(QHCData, API)
-- We're actually just going to disable this for now.
--[[
Merger = API.Utility_Merger
QuestHelper: Assert(Merger) -- I need to get rid of this stupid space hack someday
LZW = API.Utility_LZW
QuestHelper: Assert(LZW)
Bolus = API.Callback_LocationBolus
QuestHelper: Assert(Bolus)
if not QHCData.traveled then QHCData.traveled = {} end
QHCT = QHCData.traveled
if not QHCT.working then InitWorking() end
if QHCT.compressing then for k, v in pairs(QHCT.compressing) do
CompressFromKey(k)
end end
GetRawLocation = API.Callback_RawLocation
API.Registrar_OnUpdateHook(OnUpdate)]]
end
--[[
function hackeryflush()
CompileData()
cc = nil
end
]]

Voir le fichier

@ -1,103 +0,0 @@
local GetTime = QuestHelperCollector_GetTime
QuestHelper_File["collect_upgrade.lua"] = "4.0.1.$svnversion$"
QuestHelper_Loadtime["collect_upgrade.lua"] = GetTime()
function QH_Collector_Upgrade(chunk)
QuestHelper: Assert(not chunk.compressed)
if chunk.version == 1 then
-- We basically just want to clobber all our old route data, it's not worth storing - it's all good data, it's just that we don't want to preserve relics of the old location system.
chunk.traveled = nil
chunk.version = 2
end
if chunk.version == 2 then
-- Originally I split the zones based on locale. Later I just split everything based on locale. Discarding old data rather than doing the gymnastics needed to preserve it.
-- This is turning into a routine. :D
chunk.zone = nil
chunk.version = 3
end
if chunk.version == 3 then
-- Screwed up the item collection code in instances. Obliterate old data, try again.
if chunk.item then
for id, dat in pairs(chunk.item) do
dat.equip_no = nil
dat.equip_yes = nil
end
end
chunk.version = 4
end
if chunk.version == 4 then
-- Munged the shops rather badly. Whoopsydaisy.
if chunk.monster then
local nv = {}
for id, dat in pairs(chunk.monster) do
if type(dat) == "table" then
nv[id] = dat
end
end
chunk.monster = nv
end
chunk.version = 5
end
if chunk.version == 5 then
-- Horrible things involving objects. Let's preserve what we can.
if chunk.object then
local new_obj = {}
for k, v in pairs(chunk.object) do
local keep = false
for tk, _ in pairs(v) do
if type(tk) == "string" and tk:match("[a-z]+_loot") then
keep = true
break
end
end
if keep then new_obj[k] = v end
end
chunk.object = new_obj
end
chunk.version = 6
end
if chunk.version == 6 then
-- I just screwed this up really
-- Note that a few versions back (I'll have to check which) the standard bolus format changed. Since I can't actually *fix* it, I'm just ignoring it, but there's an implicit format change in there. I'll catch it and deal with it in the processing system.
chunk.warp = nil
chunk.routing_dump = nil -- and this shouldn't have been getting dumped anyway
chunk.version = 7
end
if chunk.version == 7 then
-- botched the achievement code, fixed the achievement code (maybe?)
chunk.achievement = nil
chunk.version = 8
end
end
function QH_Collector_UpgradeAll(Collector)
-- So, I screwed up the compression code, and there's no way to know what version was compressed . . . except that we thankfully didn't change the version number on that change. Any untagged compression will therefore be the version number that this was loaded with.
for _, v in pairs(Collector) do
--[[ QuestHelper:Assert(type(v) == "table") ]]
if not v.version then
QuestHelper: Assert(QuestHelper_Collector_Version) -- This is going to fail somehow. I just know it. Seriously, this right here will be proof that, today, the gods hate me.
v.version = QuestHelper_Collector_Version
end
if not v.compressed then
QH_Collector_Upgrade(v)
end
end
end

Voir le fichier

@ -1,53 +0,0 @@
local GetTime = QuestHelperCollector_GetTime
QuestHelper_File["collect_util.lua"] = "4.0.1.$svnversion$"
QuestHelper_Loadtime["collect_util.lua"] = GetTime()
local function IsMonsterGUID(guid)
QuestHelper: Assert(strlen(guid) == 18, "guid len " .. guid) -- 64 bits, plus the 0x prefix
QuestHelper: Assert(guid:sub(1, 2) == "0x", "guid 0x-prefix " .. guid)
return guid:sub(5, 5) == "3" or guid:sub(5, 5) == "5"
end
local function GetMonsterUID(guid)
QuestHelper: Assert(strlen(guid) == 18, "guid len " .. guid) -- 64 bits, plus the 0x prefix
QuestHelper: Assert(guid:sub(1, 2) == "0x", "guid 0x-prefix " .. guid)
QuestHelper: Assert(guid:sub(5, 5) == "3" or guid:sub(5, 5) == "5", "guid 3-prefix " .. guid) -- It *shouldn't* be a player or a pet by the time we've gotten here. If so, something's gone wrong.
return guid:sub(9, 18) -- here's our actual identifier
end
local function GetMonsterType(guid)
QuestHelper: Assert(strlen(guid) == 18, "guid len " .. guid) -- 64 bits, plus the 0x prefix
QuestHelper: Assert(guid:sub(1, 2) == "0x", "guid 0x-prefix " .. guid)
QuestHelper: Assert(guid:sub(5, 5) == "3" or guid:sub(5, 5) == "5", "guid 3-prefix " .. guid) -- It *shouldn't* be a player or a pet by the time we've gotten here. If so, something's gone wrong.
if GetBuildInfo():sub(1, 3) == "3.2" then
return tonumber(guid:sub(9, 12), 16) -- here's our actual identifier
else
return tonumber(guid:sub(7, 10), 16) -- 3.3 and in the future, including 0.3.0
end
end
local function GetItemType(link, vague)
QuestHelper:Assert(link, "Item did not have a link! Say WHAT?")
local result = tonumber(string.match(link,
(vague and "" or "^") .. "|cff%x%x%x%x%x%x|Hitem:(%d+):[%d:-]+|h%[[^%]]*%]|h|r".. (vague and "" or "$")
))
QuestHelper:Assert(result, "Item does not have a type ('" .. link .. "')")
return result
end
local function GetQuestType(link)
return tonumber(string.match(link,
"^|cff%x%x%x%x%x%x|Hquest:(%d+):[%d-]+|h%[[^%]]*%]|h|r$"
)), tonumber(string.match(link,
"^|cff%x%x%x%x%x%x|Hquest:%d+:([%d-]+)|h%[[^%]]*%]|h|r$"
))
end
function QH_Collect_Util_Init(_, API)
API.Utility_IsMonsterGUID = IsMonsterGUID
API.Utility_GetMonsterUID = GetMonsterUID
API.Utility_GetMonsterType = GetMonsterType
API.Utility_GetItemType = GetItemType
API.Utility_GetQuestType = GetQuestType
end

Voir le fichier

@ -1,74 +0,0 @@
local GetTime = QuestHelperCollector_GetTime
QuestHelper_File["collect_warp.lua"] = "4.0.1.$svnversion$"
QuestHelper_Loadtime["collect_warp.lua"] = GetTime()
local debug_output = false
if QuestHelper_File["collect_warp.lua"] == "Development Version" then debug_output = true end
local QHCW
local GetLoc
local Merger
local RawLocation
local lastloc_bolus
local last_delayed, last_rc, last_rz, last_rx, last_ry
local last_valid
local last_warp = 0
local function valid(d, rc, rz, rx, ry)
return not d and rc and rz and rx and ry
end
local function OnUpdate()
local bolus = GetLoc()
local now_delayed, now_rc, now_rz, now_rx, now_ry = RawLocation()
local now_valid = valid(RawLocation())
if last_valid and now_valid then
local leapy = false
if last_rc ~= now_rc or last_rz ~= now_rz then
leapy = true
else
local dx, dy = last_rx - now_rx, last_ry - now_ry
dx, dy = dx * dx, dy * dy
if dx + dy > 0.01 * 0.01 then
leapy = true
end
end
if leapy then
if debug_output then QuestHelper:TextOut("Warpy!") end
end
if last_warp + 10 < GetTime() and leapy then
if debug_output then QuestHelper:TextOut("REAL Warpy!") end
local warpy = { last = lastloc_bolus, current = bolus }
table.insert(QHCW, warpy)
--Merger.Add(QHCW, "(" .. lastloc_bolus .. ")(" .. bolus .. ")")
last_warp = GetTime()
end
end
lastloc_bolus = bolus
last_delayed, last_rc, last_rz, last_rx, last_ry, last_valid = now_delayed, now_rc, now_rz, now_rx, now_ry, now_valid
end
function QH_Collect_Warp_Init(QHCData, API)
if not QHCData.warp then QHCData.warp = {} end
QHCW = QHCData.warp
API.Registrar_OnUpdateHook(OnUpdate)
GetLoc = API.Callback_LocationBolusCurrent
QuestHelper: Assert(GetLoc)
RawLocation = API.Callback_Location_Raw
QuestHelper: Assert(RawLocation)
Merger = API.Utility_Merger
QuestHelper: Assert(Merger)
end

Voir le fichier

@ -1,65 +0,0 @@
local GetTime = QuestHelperCollector_GetTime
QuestHelper_File["collect_zone.lua"] = "4.0.1.$svnversion$"
QuestHelper_Loadtime["collect_zone.lua"] = GetTime()
local debug_output = false
if QuestHelper_File["collect_zone.lua"] == "Development Version" then debug_output = true end
local QHCZ
local GetLoc
local Merger
local function DoZoneUpdate(label, debugverbose)
local zname = string.format("%s@@%s@@%s", GetZoneText(), GetRealZoneText(), GetSubZoneText()) -- I don't *think* any zones will have a @@ in them :D
if zname == "@@@@" then return end -- denied
if not QHCZ[zname] then QHCZ[zname] = {} end
if not QHCZ[zname][label] then QHCZ[zname][label] = {} end
local znl = QHCZ[zname][label]
if debugverbose and debug_output then
--QuestHelper:TextOut("zoneupdate " .. zname .. " type " .. label)
end
QHCZ[zname].mapname = GetMapInfo()
local loc = GetLoc()
if loc.delayed == 128 and loc.c == 0 and loc.z == 0 and loc.x == -128 and loc.y == -128 then return end
--if loc == "€\000\000\000€\000\000\000€€€" then return end -- this is kind of the "null value"
local found = false
-- Commented out, 'cause this module isn't really loaded anymore. I'll remove it after the next commit.
--Merger.Add(znl, loc, true)
end
local function OnEvent()
DoZoneUpdate("border", true)
end
local lastupdate = 0
local function OnUpdate()
if lastupdate + 15 <= GetTime() then
DoZoneUpdate("update")
lastupdate = GetTime()
end
end
function QH_Collect_Zone_Init(QHCData, API)
do return end -- we really don't need this anymore
if not QHCData.zone then QHCData.zone = {} end
QHCZ = QHCData.zone
QH_Event("ZONE_CHANGED", OnEvent)
QH_Event("ZONE_CHANGED_INDOORS", OnEvent)
QH_Event("ZONE_CHANGED_NEW_AREA", OnEvent)
--API.Registrar_OnUpdateHook(OnUpdate)
GetLoc = API.Callback_LocationBolusCurrent
QuestHelper: Assert(GetLoc)
Merger = API.Utility_Merger
QuestHelper: Assert(Merger)
end

Voir le fichier

@ -1,454 +0,0 @@
function QuestHelperCollector_GetTime()
return debugprofilestop() / 1000
end
local GetTime = QuestHelperCollector_GetTime
QuestHelper_File["utility.lua"] = "4.0.1.$svnversion$"
QuestHelper_Loadtime["utility.lua"] = GetTime()
QuestHelper = CreateFrame("Frame", "QuestHelper", nil)
--[[ static ]] ALLIANCE = 1
--[[ static ]] HORDE = 2
local default_colour_theme =
{message_prefix={0.4, 0.78, 1},
message={1, 0.6, 0.2},
tooltip={1, 0.8, 0.5},
message_highlight={0.73, 1, 0.84},
menu_text={1, 1, 1},
menu_text_highlight={0, 0, 0},
menu={0, 0, 0},
menu_highlight={0.3, 0.5, 0.7},
menu_title_text={1, 1, 1},
menu_title_text_highlight={1, 1, 1},
menu_title={0, 0.2, 0.6},
menu_title_highlight={0.1, 0.4, 0.8}}
local xmas_colour_theme =
{message_prefix={0.0, 0.7, 0.0},
message={0.2, 1, 0.2},
tooltip={0.4, 1, 0.4},
message_highlight={1, 0.3, 0.1},
menu_text={1, 1, 1},
menu_text_highlight={0, 0, 0},
menu={0.2, 0, 0},
menu_highlight={1, 0.3, 0.3},
menu_title_text={0.8, 1, 0.8},
menu_title_text_highlight={1, 1, 1},
menu_title={0.2, 0.6, 0.2},
menu_title_highlight={0.4, 0.7, 0.4}}
function QuestHelper:GetColourTheme()
if date("%b%d") == "Dec25" then
return xmas_colour_theme
end
return default_colour_theme
end
QuestHelper.nop = function () end -- Who wouldn't want a function that does nothing?
function QuestHelper:HashString(text)
-- Computes an Adler-32 checksum.
local a, b = 1, 0
for i=1,string.len(text) do
a = (a+string.byte(text,i))%65521
b = (b+a)%65521
end
return b*65536+a
end
function QuestHelper:CreateUID(length)
local result = ""
local characters = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
for k = 1, (math.floor(GetTime() % 1000) + 5) do math.random() end -- it's sort of like seeding. only worse.
local base = GetUnitName("player")..":"..GetRealmName()..":"..math.random(0, 2147483647)..":"..GetTime()..":"..time()
for c = 1,(length or 32) do
local pos = 1+math.floor(self:HashString(result..base..math.random(0, 2147483647))%string.len(characters))
result = result .. string.sub(characters, pos, pos)
end
return result
end
function QuestHelper:ZoneSanity()
local sane = true
for c in pairs(self.Astrolabe:GetMapVirtualContinents()) do
local pz = self.Astrolabe:GetMapVirtualZones(c)
pz[0] = true
for z in pairs(pz) do
local name
if z == 0 then
name = self.Astrolabe:GetMapVirtualContinents()[c]
else
name = self.Astrolabe:GetMapVirtualZones(c)[z]
end
--[[ assert(name) ]]
-- c,z should be equal to name, unless c = 5 and z = 0, in which case it should be equal to name .. " Continent"
if QuestHelper_Zones[c][z] ~= name then
sane = false
QuestHelper_ErrorCatcher_ExplicitError(false, string.format("'%s' has the wrong ID (should be %d,%d).", name, c, z))
--QuestHelper:TextOut(string.format("'%s' has the wrong ID (should be %d,%d).", name, c, z))
end
local pair = QuestHelper_ZoneLookup[name]
if not pair then
sane = false
QuestHelper_ErrorCatcher_ExplicitError(false, string.format("ZoneLookup['%s'] is missing data. PANIC!", name))
elseif c ~= pair[1] or z ~= pair[2] then
sane = false
QuestHelper_ErrorCatcher_ExplicitError(false, string.format("ZoneLookup['%s'] maps to wrong pair. It should be (%d, %d) but is (%d, %d)", name, c, z, pair[1], pair[2]))
--QuestHelper:TextOut("ZoneLookup['"..name.."'] maps to wrong pair.")
end
local index = QuestHelper_IndexLookup[name]
if QuestHelper_ZoneLookup[index] ~= pair then
sane = false
QuestHelper_ErrorCatcher_ExplicitError(false, "ZoneLookup['"..name.."'] isn't equal to ZoneLookup["..index.."] they are "..tostring(QuestHelper_ZoneLookup[name]).." and "..tostring(QuestHelper_ZoneLookup[index])..", respectively.")
--QuestHelper:TextOut("ZoneLookup['"..name.."'] isn't equal to ZoneLookup["..index.."] they are "..tostring(QuestHelper_ZoneLookup[name]).." and "..tostring(QuestHelper_ZoneLookup[index])..", respectively.")
end
if not index or QuestHelper_NameLookup[index] ~= name then
sane = false
QuestHelper_ErrorCatcher_ExplicitError(false, "NameLookup["..(index or "???").."] doesn't equal '"..name.."', it is "..tostring(QuestHelper_NameLookup[index]))
--QuestHelper:TextOut("NameLookup["..(index or "???").."] doesn't equal '"..name.."', it is "..tostring(QuestHelper_NameLookup[index]))
end
end
end
return sane
end
function QuestHelper:TextOut(text)
local theme = self:GetColourTheme()
DEFAULT_CHAT_FRAME:AddMessage(string.format("|cff%2x%2x%2xQuestHelper: |r%s", theme.message_prefix[1]*255,
theme.message_prefix[2]*255,
theme.message_prefix[3]*255, text),
theme.message[1],
theme.message[2],
theme.message[3])
end
function QuestHelper:Error(what)
--DEFAULT_CHAT_FRAME:AddMessage("QuestHelper Error: "..(what or "Unknown").."\n"..debugstack(2), 1,.5,0)
QuestHelper_ErrorCatcher_ExplicitError(true, what or "Unknown", nil, nil)
error((what or "") .. " Abort!")
end
function QuestHelper:HighlightText(text)
local theme = self:GetColourTheme()
return string.format("|cff%2x%2x%2x%s|r", theme.message_highlight[1]*255,
theme.message_highlight[2]*255,
theme.message_highlight[3]*255, text)
end
function QuestHelper:GetUnitID(unit)
local id = UnitGUID(unit)
if id then
return (string.sub(id, 5, 5) == "3") and tonumber(string.sub(id, 6, 12), 16) or nil
end
return nil
end
function QuestHelper:GetQuestID(index)
return tonumber(select(3, string.find(GetQuestLink(index), "|Hquest:(%d+):")))
end
-- For future reference:
-- Hearthstone = 6948
-- Rune of Teleportation = 17031
-- Rune of Portals = 17032
function QuestHelper:CountItem(item_id)
local count = 0
for bag = 0,NUM_BAG_SLOTS do
for slot = 1,GetContainerNumSlots(bag) do
local link = GetContainerItemLink(bag, slot)
if link and string.find(link, string.format("|Hitem:%d:", item_id)) then
count = count + (select(2, GetContainerItemInfo(bag, slot)) or 0)
end
end
end
return count
end
function QuestHelper:ItemCooldown(item_id)
local now = GetTime()
local cooldown = nil
for bag = 0,NUM_BAG_SLOTS do
for slot = 1,GetContainerNumSlots(bag) do
local link = GetContainerItemLink(bag, slot)
if link and string.find(link, string.format("|Hitem:%d:", item_id)) then
local s, d, e = GetContainerItemCooldown(bag, slot)
if e then
if cooldown then
cooldown = math.min(cooldown, math.max(0, d-now+s))
else
cooldown = math.max(0, d-now+s)
end
else
return 0
end
end
end
end
return cooldown
end
function QuestHelper:TimeString(seconds)
if not seconds then
--self:AppendNotificationError("2008-10-8 nil-timestring") -- we're just going to do away with this entirely, the fact is that a lot of this is going to be ripped to shreds soon anyway
return "(unknown)"
end
local seconds = math.ceil(seconds)
local h, m, s = math.floor(seconds/(60*60)), math.floor(seconds/60)%60, seconds%60
if h > 0 then
return string.format("|cffffffff%d|r:|cffffffff%02d|r:|cffffffff%02d|r", h, m, s)
else
return string.format("|cffffffff%d|r:|cffffffff%02d|r", m, s)
end
end
function QuestHelper:ProgressString(str, pct)
if pct > 1 then
return string.format("|cff00ff00%s|r", str)
elseif pct < 0 then
return string.format("|cffff0000%s|r", str)
elseif pct > 0.5 then
return string.format("|cff%2xff00%s|r", 510-pct*510, str)
else
return string.format("|cffff%2x00%s|r", pct*510, str)
end
end
function QuestHelper:PercentString(pct)
if pct > 1 then
return string.format("|cff00ff00%.1f%%|r", pct*100)
elseif pct < 0 then
return string.format("|cffff0000%.1f%%|r", pct*100)
elseif pct > 0.5 then
return string.format("|cff%2xff00%.1f%%|r", 510-pct*510, pct*100)
else
return string.format("|cffff%2x00%.1f%%|r", pct*510, pct*100)
end
end
function QuestHelper:PlayerPosition()
return self.i, self.x, self.y
end
function QuestHelper:UnitPosition(unit)
local c, z, x, y = self.Astrolabe:GetUnitPosition(unit,true)
if c then
if z == 0 then
SetMapToCurrentZone()
z = GetCurrentMapZone()
if z ~= 0 then
x, y = self.Astrolabe:TranslateWorldMapPosition(c, 0, x, y, c, z)
end
end
return QuestHelper_IndexLookup[c][z], x, y
else
return self:PlayerPosition()
end
end
function QuestHelper:PlayerFaction()
return UnitFactionGroup("player") == "Alliance" and ALLIANCE or HORDE
end
function QuestHelper:LocationString(i, x, y)
return ("[|cffffffff%s|r:|cffffffff%d,%.3f,%.3f|r]"):format(QuestHelper_NameLookup[i] or "nil", i or -7777, x or -7777, y or -7777)
end
function QuestHelper:Location_RawString(delayed, c, z, x, y)
return ("[|cffffffff%s/%s,%s,%s,%s|r]"):format(delayed and "D" or "c", c and string.format("%d", c) or tostring(c), z and string.format("%d", z) or tostring(z), x and string.format("%.3f", x) or tostring(x), y and string.format("%.3f", y) or tostring(y))
end
function QuestHelper:Location_AbsoluteString(delayed, c, x, y)
return ("[|cffffffff%s/%s,%s,%s|r]"):format(delayed and "D" or "c", c and string.format("%d", c) or tostring(c), x and string.format("%.3f", x) or tostring(x), y and string.format("%.3f", y) or tostring(y))
end
function QuestHelper:Distance(i1, x1, y1, i2, x2, y2)
local p1, p2 = QuestHelper_ZoneLookup[i1], QuestHelper_ZoneLookup[i2]
return self.Astrolabe:ComputeDistance(p1[1], p1[2], x1, y1, p2[1], p2[2], x2, y2) or 10000
end
function QuestHelper:AppendPosition(list, index, x, y, w, min_dist)
if not x or not y or (x == 0 and y == 0) or x <= -0.1 or y <= -0.1 or x >= 1.1 or y >= 1.1 then
local nc, nz, nx, ny = self.Astrolabe:GetCurrentPlayerPosition()
--self:AppendNotificationError("2008-10-6 nil-position", string.format("nilposition, %s %s %s %s vs %s %s", tostring(nc), tostring(nz), tostring(nx), tostring(ny), tostring(x), tostring(y))) -- We're just not worrying about this too much anymore. Slash and burn.
return list -- This isn't a real position.
end
local closest, distance = nil, 0
w = w or 1
min_dist = min_dist or 200
for i, p in ipairs(list) do
if index == p[1] then
local d = self:Distance(index, x, y, p[1], p[2], p[3])
if not closest or d < distance then
closest, distance = i, d
end
end
end
if closest and distance < min_dist then
local p = list[closest]
p[2] = (p[2]*p[4]+x*w)/(p[4]+w)
p[3] = (p[3]*p[4]+y*w)/(p[4]+w)
p[4] = p[4]+w
else
table.insert(list, {index, x, y, w})
end
return list
end
function QuestHelper:PositionListDistance(list, index, x, y)
local closest, distance = nil, 0
for i, p in ipairs(list) do
local d = self:Distance(index, x, y, p[1], p[2], p[3])
if not closest or d < distance then
closest, distance = p, d
end
end
if closest then
return distance, closest[1], closest[2], closest[3]
end
end
function QuestHelper:PositionListDistance2(list, i1, x1, y1, i2, x2, y2)
local closest, bd1, bd2, bdt = nil, 0, 0, 0
for i, p in ipairs(list) do
local d1 = self:Distance(i1, x1, y1, p[1], p[2], p[3])
local d2 = self:Distance(i2, x2, y2, p[1], p[2], p[3])
local t = d1+d2
if not closest or t < bdt then
closest, bd1, bd2, bdt = p, d1, d2, t
end
end
if closest then
return d1, d2, closest[1], closest[2], closest[3]
end
end
function QuestHelper:MergePositions(list1, list2)
for i, p in ipairs(list2) do
self:AppendPosition(list1, unpack(p))
end
end
function QuestHelper:MergeDrops(list1, list2)
for element, count in pairs(list2) do
list1[element] = (list1[element] or 0) + count
end
end
function QuestHelper: Assert(a, b) -- the space exists so the anti-assert script doesn't find it :D
if not a then
QuestHelper:Error(b or "Assertion Failed")
end
end
function QuestHelper:StringizeTable(a)
if not a then return "nil" end
acu = tostring(self.recycle_tabletyping[a])..": "
for i,v in pairs(a) do acu = acu.."["..tostring(i)..","..tostring(v).."] " end
return acu
end
function QuestHelper:StringizeTableDouble(a)
if not a then return "nil" end
acu = tostring(self.recycle_tabletyping[a])..": "
for i,v in pairs(a) do acu = acu.."["..self:StringizeTable(i)..","..self:StringizeTable(v).."] " end
return acu
end
function QuestHelper:StringizeRecursive(a, d)
if not a then return "nil" end
if d <= 0 or type(a) ~= "table" then return tostring(a) end
acu = tostring(self.recycle_tabletyping[a])..": "
for i,v in pairs(a) do acu = acu.."["..self:StringizeRecursive(i, d - 1)..","..self:StringizeRecursive(v, d - 1).."] " end
return acu
end
function QuestHelper:TableSize(tbl)
local count = 0
for k, v in pairs(tbl) do
count = count + 1
end
return count
end
function QuestHelper:IsWrath()
--return GetBuildInfo():sub(1,1) == '3' or GetBuildInfo() == "0.0.2" -- come on
return true -- this had better be true :D
end
function QuestHelper:IsWrath32()
return tonumber(GetBuildInfo():sub(3,3)) >= 2
end
function QuestHelper:AppendNotificationError(type, data)
local terror = QuestHelper_ErrorPackage(2)
terror.data = data
QuestHelper_ErrorCatcher_RegisterError(type, terror)
end
function QuestHelper.CreateLoadingCounter()
return {
MakeSubcategory = function(self, weight)
QuestHelper: Assert(not self.percentage)
if not self.weighting then self.weighting = {} end
local subcat = QuestHelper:CreateLoadingCounter()
table.insert(self.weighting, {weight = weight, item = subcat})
return subcat
end,
SetPercentage = function(self, percent)
QuestHelper: Assert(not self.weighting)
self.percentage = percent
end,
GetPercentage = function(self)
if self.percentage then return self.percentage end
if not self.weighting then return 0 end
local total_weight = 0
local total_value = 0
for _, v in ipairs(self.weighting) do
total_weight = total_weight + v.weight
total_value = total_value + v.weight * v.item:GetPercentage()
end
return total_value / total_weight
end
}
end
local msgid = 0
function QH_fixedmessage(text)
local msgtext = "QH_MSG_" .. msgid
StaticPopupDialogs[msgtext] = {
text = text,
button1 = OKAY,
OnAccept = function(self)
end,
timeout = 0,
whileDead = 1,
hideOnEscape = 1
}
StaticPopup_Show(msgtext)
end

Voir le fichier

@ -8,9 +8,9 @@
## Notes-esMX: Calcula la mejor ruta a seguir para usted.
## Notes-koKR: 노선에 대한 계산을 수행합니다.
## Version: 4.0.1.$svnversion$
## Dependencies: QHData-base, QHCollector
## Dependencies: QHData-base
## OptionalDeps: Cartographer_Waypoints, TomTom, Cartographer_InstanceMaps, !Swatter, tekticles, UnicodeFont, ClearFont2
## SavedVariables: QuestHelper_Pref QuestHelper_UID QuestHelper_SaveDate QuestHelper_Errors QuestHelper_Collector_Version QHDB_Export
## SavedVariables: QuestHelper_Pref QuestHelper_UID QuestHelper_SaveDate QuestHelper_Errors QuestHelper_Collector QuestHelper_Collector_Version QHDB_Export
## SavedVariablesPerCharacter: QuestHelper_KnownFlightRoutes QuestHelper_Home QuestHelper_CharVersion QuestHelper_Flight_Updates
## X-Website: http://www.quest-helper.com/
## X-Embeds: AstrolabeQH, ChatThrottleLib
@ -98,7 +98,7 @@ lang\zhcn.lua
lang\zhtw.lua
# oh shut up
#collect_notifier.lua
collect_notifier.lua
# Memory management, depends on nothing, calls nothing. I don't mention when things depend on this - it's not as extensively used as it used to be, but it's still under basic-utilities.
recycle.lua
@ -179,28 +179,28 @@ objtips.lua
textviewer.lua
help.lua
#collect_achievement.lua
#collect_lzw.lua
#collect_traveled.lua
#collect_location.lua
#collect_zone.lua
#collect_hearth.lua
#collect_merger.lua
#collect_monster.lua
#collect_item.lua
#collect_object.lua
#collect_loot.lua
#collect_patterns.lua
#collect_flight.lua
#collect_util.lua
#collect_quest.lua
#collect_equip.lua
#collect_spec.lua
#collect_bitstream.lua
#collect_upgrade.lua
#collect_merchant.lua
#collect_warp.lua
#collect.lua
collect_achievement.lua
collect_lzw.lua
collect_traveled.lua
collect_location.lua
collect_zone.lua
collect_hearth.lua
collect_merger.lua
collect_monster.lua
collect_item.lua
collect_object.lua
collect_loot.lua
collect_patterns.lua
collect_flight.lua
collect_util.lua
collect_quest.lua
collect_equip.lua
collect_spec.lua
collect_bitstream.lua
collect_upgrade.lua
collect_merchant.lua
collect_warp.lua
collect.lua
cartographer.lua
tomtom.lua