1 QuestHelper_File
["nag.lua"] = "Development Version"
2 QuestHelper_Loadtime
["nag.lua"] = GetTime()
4 local function FindStaticQuest(faction
, level
, name
, hash
)
5 local data
= QuestHelper_StaticData
[QuestHelper
.locale
]
6 data
= data
and data
.quest
7 data
= data
and data
[faction
]
8 data
= data
and data
[level
]
9 data
= data
and data
[name
]
10 if data
and data
.hash
and data
.hash
~= hash
then
11 data
= data
.alt
and data
.alt
[hash
]
16 local function FindStaticObjective(cat
, name
)
17 local data
= QuestHelper_StaticData
[QuestHelper
.locale
]
18 data
= data
and data
.objective
19 data
= data
and data
[cat
]
20 return data
and data
[name
]
23 local function ListUpdated(list
, static
, compare
, weight
)
24 if not list
then return false end
25 if not static
then return true end
33 for _
, b
in ipairs(static
) do
34 high
= math
.max(high
, weight(b
))
37 for _
, a
in ipairs(list
) do
40 for _
, b
in ipairs(static
) do
41 if weight(a
) < high
*0.2 or compare(a
, b
) then
47 if not found
then return true end
52 local function PositionWeight(a
)
56 local function PositionCompare(a
, b
)
57 return a
[1] == b
[1] and
58 (a
[2]-b
[2])*(a
[2]-b
[2])+(a
[3]-b
[3])*(a
[3]-b
[3]) < 0.05*0.05
61 local function VendorCompare(a
, b
)
65 local function VendorWeight(a
)
69 local function PositionListUpdated(list
, static
)
70 return ListUpdated(list
, static
, PositionCompare
, PositionWeight
)
73 local function VendorListUpdated(list
, static
)
74 return ListUpdated(list
, static
, VendorCompare
, VendorWeight
)
77 local function DropListUpdated(list
, static
)
78 if not list
then return false end
79 if not static
then return next(list
, nil) ~= nil end
82 for name
in pairs(list
) do
83 local monster_obj
= FindStaticObjective("monster", name
)
84 if monster_obj
and monster_obj
.looted
and monster_obj
.looted
> 0 then
85 high
= math
.max(high
, (static
[name
] or 0)/monster_obj
.looted
)
89 for name
, v
in pairs(list
) do
90 local monster_obj1
= QuestHelper
:GetObjective("monster", name
)
91 local monster_obj2
= FindStaticObjective("monster", name
)
93 local looted
= math
.ceil((monster_obj1
.o
.looted
or 0)+((monster_obj2
and monster_obj2
.looted
) or 0))
95 v
= math
.max(1, math
.floor(v
))/looted
96 if v
> high
*0.2 and not static
[name
] then return true end
102 local function DropListMass(list
)
103 if not list
then return 0 end
105 for item
, count
in pairs(list
) do
111 local function PositionListMass(list
)
112 if not list
then return 0 end
114 for _
, pos
in ipairs(list
) do
120 local function CompareStaticQuest(info
, faction
, level
, name
, hash
, data
, verbose
)
121 local static
= FindStaticQuest(faction
, level
, name
, hash
)
124 if data
.finish
or data
.pos
then
125 if verbose
then QuestHelper
:TextOut("Quest "..QuestHelper
:HighlightText(name
).." was missing.") end
126 info
.new
.quest
= (info
.new
.quest
or 0) + 1
131 local updated
= false
133 if data
.finish
and data
.finish
~= static
.finish
then
134 if verbose
then QuestHelper
:TextOut("Quest "..QuestHelper
:HighlightText(name
).." was missing finish NPC "..QuestHelper
:HighlightText(data
.finish
)..".") end
136 elseif not static
.finish
and PositionListUpdated(data
.pos
, static
.pos
) then
137 if verbose
then QuestHelper
:TextOut("Quest "..QuestHelper
:HighlightText(name
).." was missing finish location.") end
139 elseif data
.item
then
140 for item_name
, item
in pairs(data
.item
) do
141 local static_item
= (static
.item
and static
.item
[item_name
]) or FindStaticObjective("item", item_name
)
143 if not static_item
then
144 if verbose
then QuestHelper
:TextOut("Quest "..QuestHelper
:HighlightText(name
).." was missing item "..QuestHelper
:HighlightText(item_name
)..".") end
147 elseif item
.drop
then
148 if DropListUpdated(item
.drop
, static_item
.drop
) then
149 if DropListMass(item
.drop
) > PositionListMass(static_item
.pos
) then
150 if verbose
then QuestHelper
:TextOut("Quest "..QuestHelper
:HighlightText(name
).." was missing drop for item "..QuestHelper
:HighlightText(item_name
)..".") end
155 elseif item
.pos
and not static_item
.drop
and PositionListUpdated(item
.pos
, static_item
.pos
) then
156 if verbose
then QuestHelper
:TextOut("Quest "..QuestHelper
:HighlightText(name
).." was missing position for item "..QuestHelper
:HighlightText(item_name
)..".") end
164 info
.update
.quest
= (info
.update
.quest
or 0)+1
168 local function CompareStaticObjective(info
, cat
, name
, data
, verbose
)
170 local static
= FindStaticObjective(cat
, name
)
172 if data
.pos
or data
.drop
or data
.vendor
then
173 if verbose
then QuestHelper
:TextOut(string.gsub(cat
, "^(.)", string.upper
).." "..QuestHelper
:HighlightText(name
).." was missing.") end
174 info
.new
[cat
.."_obj"] = (info
.new
[cat
.."_obj"] or 0)+1
179 local updated
= false
182 updated
= VendorListUpdated(data
.vendor
, static
.vendor
)
183 if updated
and verbose
then QuestHelper
:TextOut(string.gsub(cat
, "^(.)", string.upper
).." "..QuestHelper
:HighlightText(name
).." was missing vendor.") end
184 elseif data
.drop
and not static
.vendor
then
185 updated
= DropListUpdated(data
.drop
, static
.drop
) and DropListMass(data
.drop
) > PositionListMass(static
.pos
)
186 if updated
and verbose
then QuestHelper
:TextOut(string.gsub(cat
, "^(.)", string.upper
).." "..QuestHelper
:HighlightText(name
).." was missing monster drop.") end
187 elseif data
.pos
and not static
.vendor
and not static
.drop
then
188 if updated
and verbose
then QuestHelper
:TextOut(Qstring
.gsub(cat
, "^(.)", string.upper
).." "..QuestHelper
:HighlightText(name
).." was missing position.") end
189 updated
= PositionListUpdated(data
.pos
, static
.pos
)
193 info
.update
[cat
.."_obj"] = (info
.update
[cat
.."_obj"] or 0)+1
198 function QuestHelper
:Nag(cmd
)
199 do return end -- BZZT
201 local verbose
, local_only
= false, true
203 if QuestHelper_IsPolluted() then
204 self
:TextOut(QHFormat("NAG_POLLUTED"))
209 if string.find(cmd
, "verbose") then verbose
= true end
210 if string.find(cmd
, "all") then local_only
= false end
219 for version
, data
in pairs(QuestHelper_Quests
) do
220 for faction
, level_list
in pairs(data
) do
221 if not local_only
or faction
== self
.faction
then
222 for level
, name_list
in pairs(level_list
) do
223 for name
, data
in pairs(name_list
) do
224 CompareStaticQuest(info
, faction
, level
, name
, data
.hash
, data
, verbose
)
226 for hash
, data
in pairs(data
.alt
) do
227 CompareStaticQuest(info
, faction
, level
, name
, hash
, data
, verbose
)
236 for version
, data
in pairs(QuestHelper_Objectives
) do
237 for cat
, name_list
in pairs(data
) do
238 for name
, obj
in pairs(name_list
) do
239 CompareStaticObjective(info
, cat
, name
, obj
, verbose
)
244 for version
, data
in pairs(QuestHelper_FlightInstructors
) do
245 for faction
, location_list
in pairs(data
) do
246 if not local_only
or faction
== self
.faction
then
247 for location
, npc
in pairs(location_list
) do
248 local data
= QuestHelper_StaticData
[self
.locale
]
249 data
= data
and data
.flight_instructors
250 data
= data
and data
[faction
]
251 data
= data
and data
[location
]
253 if not data
or data
~= npc
then
254 if verbose
then self
:TextOut(QuestHelper
:HighlightText(faction
).." flight master "..QuestHelper
:HighlightText(npc
).." was missing.") end
255 info
.new
["fp"] = (info
.new
["fp"] or 0)+1
262 for version
, data
in pairs(QuestHelper_FlightRoutes
) do
263 for faction
, start_list
in pairs(data
) do
264 if not local_only
or faction
== self
.faction
then
265 for start
, dest_list
in pairs(start_list
) do
266 for dest
, hash_list
in pairs(dest_list
) do
267 for hash
, data
in pairs(hash_list
) do
268 if hash
~= "no_interrupt_count" and hash
~= "interrupt_count" then
269 local static
= QuestHelper_StaticData
[self
.locale
]
270 static
= static
and static
.flight_routes
271 static
= static
and static
[faction
]
272 static
= static
and static
[start
]
273 static
= static
and static
[dest
]
274 static
= static
and static
[hash
]
276 if not static
or static
== true and type(data
) == "number" then
277 if verbose
then self
:TextOut("Flight time from "..QuestHelper
:HighlightText((select(3, string.find(start
, "^(.*),")) or start
)).." to "..QuestHelper
:HighlightText((select(3, string.find(dest
, "^(.*),")) or dest
)).." was missing.") end
278 info
.new
["route"] = (info
.new
["route"] or 0)+1
290 for what
, count
in pairs(info
.new
) do
291 local what1
= count
== 1 and QHText("NAG_SINGLE_"..string.upper(what
)) or
292 QHFormat("NAG_MULTIPLE_"..string.upper(what
), count
)
294 total
= total
+ count
295 local count2
= info
.update
[what
]
297 total
= total
+ count2
298 local what2
= count2
== 1 and QHText("NAG_SINGLE_"..string.upper(what
)) or
299 QHFormat("NAG_MULTIPLE_"..string.upper(what
), count2
)
300 self
:TextOut(QHFormat("NAG_MULTIPLE_NEW", what1
, what2
))
302 self
:TextOut(QHFormat("NAG_SINGLE_NEW", what1
))
306 for what
, count
in pairs(info
.update
) do
307 if not info
.new
[what
] then
308 local what
= count
== 1 and QHText("NAG_SINGLE_"..string.upper(what
)) or
309 QHFormat("NAG_MULTIPLE_"..string.upper(what
), count
)
310 total
= total
+ count
311 self
:TextOut(QHFormat("NAG_ADDITIONAL", what
))
316 self
:TextOut(QHText("NAG_NOT_NEW"))
318 self
:TextOut(QHText("NAG_NEW"))
319 self
:TextOut(QHText("NAG_INSTRUCTIONS"))
324 local day
= 24 * 60 * 60
327 if not QuestHelper_Pref
.nag_next_time
then
328 QuestHelper_Pref
.nag_next_time
= time() + 7 * day
+ 14 * day
* math
.random() -- at least a week, at most 3 weeks
329 QuestHelper_Pref
.nag_type
= "OFF"
332 if QuestHelper_Pref
.nag_next_time
< time() then
333 if QuestHelper_Pref
.nag_type
== "OFF" then
334 -- we now begin nagging for 48 hours
335 QuestHelper_Pref
.nag_next_time
= time() + 2 * day
336 QuestHelper_Pref
.nag_type
= "ON"
338 -- we now stop nagging for 2-3 weeks
339 QuestHelper_Pref
.nag_next_time
= time() + 14 * day
+ 7 * day
* math
.random()
340 QuestHelper_Pref
.nag_type
= "OFF"
344 return QuestHelper_Pref
.nag_type
== "ON"
348 local update_nag_yell_at
= nil
350 function QHUpdateNagInit()
351 if not QuestHelper_Pref
.update_nag_last_version
or QuestHelper_Pref
.update_nag_last_version
~= GetAddOnMetadata("QuestHelper", "Version") then
352 QuestHelper_Pref
.update_nag_last_version
= GetAddOnMetadata("QuestHelper", "Version")
353 QuestHelper_Pref
.update_nag_next_notify
= time() + 24 * day
356 if QuestHelper_Pref
.update_nag_next_notify
< time() then
357 update_nag_yell_at
= time() + 60 * 10 + 50 * 60 * math
.random() -- 10 to 60 minutes from now
361 function QHUpdateNagTick()
362 if update_nag_yell_at
and update_nag_yell_at
< time() then
363 --QuestHelper:TextOut(QHText("TIME_TO_UPDATE")) -- We're just disabling this, I think.
364 QuestHelper_Pref
.update_nag_next_notify
= time() + day
* 6 + day
* 2 * math
.random()
365 update_nag_yell_at
= nil