1 WoWData
= {item
={},quest
={},npc
={}} -- The build script will replace this with actual data if it can.
5 function CreateAverage()
9 function AppendToAverage(average
, value
)
10 table.insert(average
, value
)
13 function CollapseAverage(average
)
15 local to_remove
= math
.floor(#average
*0.2)
16 for i
= 1,to_remove
do
17 table.remove(average
, 1)
24 for _
, v
in pairs(average
) do
30 function GetQuest(locale
, faction
, level
, name
, hash
)
31 local l
= StaticData
[locale
]
36 StaticData
[locale
] = l
38 local a
= l
.quest
[faction
]
56 if hash
and hash
~= q
.hash
then
62 if hash
and not q
.hash
then
63 -- If the old quest didn't have a hash, we'll assume this is it. If we're wrong, we'll
64 -- hopefully overwrite it with the correct data.
66 elseif not hash
and q
.hash
then
67 -- If the old quest had a hash, but this one doesn't, we'll return a dummy object
68 -- so that we don't overwrite it with the wrong quest data.
70 elseif hash
~= q
.hash
then
80 function GetObjective(locale
, category
, name
)
81 local l
= StaticData
[locale
]
86 StaticData
[locale
] = l
88 local list
= l
.objective
[category
]
91 l
.objective
[category
] = list
93 local obj
= list
[name
]
101 local function Distance(a
, b
)
102 -- Doing this, because the distances are going to be rounded later, and I don't want it to create
103 -- a situation where if you ran TidyPositionList twice, it would have a different result.
105 local x
, y
= math
.floor(a
[2]*10000+0.5)/10000-math
.floor(b
[2]*10000+0.5)/10000,
106 math
.floor(a
[3]*10000+0.5)/10000-math
.floor(b
[3]*10000+0.5)/10000
108 return math
.sqrt(x
*x
+y
*y
)
111 local function TidyDropList(locale
, list
)
114 for monster
, count
in pairs(list
) do
115 local monster_obj
= GetObjective(locale
, "monster", monster
)
116 if monster_obj
.looted
and monster_obj
.looted
> 0 then
117 high
= math
.max(high
, math
.max(1, math
.floor(count
))/math
.ceil(monster_obj
.looted
))
121 for monster
, count
in pairs(list
) do
122 local monster_obj
= GetObjective(locale
, "monster", monster
)
123 count
= math
.max(1, math
.floor(count
))
125 if monster_obj
.looted
and monster_obj
.looted
> 0 and count
/math
.ceil(monster_obj
.looted
) > high
*0.2 then
126 list
[monster
] = count
134 local function TidyContainedList(locale
, list
)
137 for item
, count
in pairs(list
) do
138 local item_obj
= GetObjective(locale
, "item", item
)
139 if item_obj
.opened
and item_obj
.opened
> 0 then
140 high
= math
.max(high
, math
.max(1, math
.floor(count
))/math
.ceil(item_obj
.opened
))
144 for item
, count
in pairs(list
) do
145 local item_obj
= GetObjective(locale
, "item", item
)
146 count
= math
.max(1, math
.floor(count
))
148 if item_obj
.opened
and item_obj
.opened
> 0 and count
/math
.ceil(item_obj
.opened
) > high
*0.2 then
156 local function TidyPositionList(list
, min_distance
)
157 min_distance
= min_distance
or 0.03
159 if #list
== 0 then return end
160 local changed
= false
163 local nearest
, distance
= nil, 0
164 for j
= i
+1, #list
do
165 local d
= Distance(list
[i
], list
[j
])
166 if not nearest
or d
< distance
then
167 nearest
, distance
= j
, d
170 if nearest
and distance
< min_distance
then
171 local a
, b
= list
[i
], list
[nearest
]
172 a
[2] = (a
[2]*a
[4]+b
[2]*b
[4])/(a
[4]+b
[4])
173 a
[3] = (a
[3]*a
[4]+b
[3]*b
[4])/(a
[4]+b
[4])
175 table.remove(list
, nearest
)
182 -- Because we moved nodes around, we'll check again to make sure we didn't move too close together
189 for i
, data
in ipairs(list
) do
190 data
[4] = math
.pow(data
[4], 0.73575888234288) -- Raising it to this number to make huge numbers seem closer together, the positions are probably correct and not some mistake.
191 highest
= math
.max(highest
, data
[4])
194 local i
= 1 -- Remove anything that doesn't seem very likely.
196 if list
[i
][4] < highest
*0.2 then
197 table.remove(list
, i
)
199 list
[i
][4] = math
.max(1, math
.floor(list
[i
][4]*100/highest
+0.5))
204 for i
, j
in ipairs(list
) do
205 j
[2] = math
.floor(j
[2]*10000+0.5)/10000
206 j
[3] = math
.floor(j
[3]*10000+0.5)/10000
209 table.sort(list
, function(a
, b
)
210 if a
[4] > b
[4] then return true end
211 if a
[4] < b
[4] then return false end
212 if a
[1] < b
[1] then return true end
213 if a
[1] > b
[1] then return false end
214 if a
[2] < b
[2] then return true end
215 if a
[2] > b
[2] then return false end
220 local function DropListMass(list
)
222 for item
, count
in pairs(list
) do
228 local function PositionListMass(list
)
230 for _
, pos
in ipairs(list
) do
236 local function CollapseDropList(list
)
237 local result
, c
= nil, 0
238 for item
, count
in pairs(list
) do
239 if not result
or count
> c
then
240 result
, c
= item
, count
246 local function MergeDropLists(list
, add
)
247 for item
, count
in pairs(add
) do
248 list
[item
] = (list
[item
] or 0) + count
252 local function MergePositionLists(list
, add
)
253 for _
, pos
in ipairs(add
) do
254 local index
, x
, y
, w
= pos
[1], pos
[2], pos
[3], pos
[4]
255 if type(index
) == "number" and QuestHelper_NameLookup
[index
] and
256 type(w
) == "number" and w
> 0 then
257 local bp
, distance
= nil, 0
258 for i
, pos2
in ipairs(list
) do
259 if index
== pos2
[1] then
260 local d
= math
.sqrt((x
-pos2
[2])*(x
-pos2
[2])+(y
-pos2
[3])*(y
-pos2
[3]))
261 if not nearest
or d
< distance
then
262 bp
, distance
= pos2
, d
266 if bp
and distance
< 0.03 then
267 bp
[2] = (bp
[2]*bp
[4]+x
*w
)/(bp
[4]+w
)
268 bp
[3] = (bp
[3]*bp
[4]+y
*w
)/(bp
[4]+w
)
271 table.insert(list
, {index
,x
,y
,w
})
277 local function AddQuestEnd(quest
, npc
)
278 if not quest
.finish
then quest
.finish
= {} end
279 quest
.finish
[npc
] = (quest
.finish
[npc
] or 0) + 1
282 local function AddQuestPos(quest
, pos
)
283 if not quest
.pos
then quest
.pos
= {} end
284 MergePositionLists(quest
.pos
, pos
)
287 local function AddQuestItems(quest
, list
)
288 for item
, data
in pairs(list
) do
289 if type(data
.drop
) == "table" then
290 if not quest
.item
then quest
.item
= {} end
291 if not quest
.item
[item
] then quest
.item
[item
] = {} end
292 if not quest
.item
[item
].drop
then quest
.item
[item
].drop
= {} end
293 MergeDropLists(quest
.item
[item
].drop
, data
.drop
)
294 elseif type(data
.pos
) == "table" then
295 if not quest
.item
then quest
.item
= {} end
296 if not quest
.item
[item
] then quest
.item
[item
] = {} end
297 if not quest
.item
[item
].pos
then quest
.item
[item
].pos
= {} end
298 MergePositionLists(quest
.item
[item
].pos
, data
.pos
)
303 local function ValidFaction(faction
)
304 return faction
== 1 or faction
== 2
307 local function AddQuest(locale
, faction
, level
, name
, data
)
308 if ValidFaction(faction
)
309 and type(level
) == "number" and level
>= 1 and level
<= 100
310 and type(name
) == "string" and type(data
) == "table" then
312 local _
, _
, real_name
= string.find(name
, "^%["..level
.."[^%s]-%]%s?(.+)$")
315 -- The Quest Level AddOn mangles level names.
319 local q
= GetQuest(locale
, faction
, level
, name
, type(data
.hash
) == "number" and data
.hash
or nil)
321 if type(data
.id
) == "number" then
322 local wdq
= WoWData
.quest
[data
.id
]
324 wdq
= {name
={},hash
={},faction
={}}
325 WoWData
.quest
[data
.id
] = wdq
327 wdq
.name
[locale
] = name
328 wdq
.hash
[locale
] = data
.hash
or wdq
.hash
[locale
]
332 if type(data
.finish
) == "string" then
333 AddQuestEnd(q
, data
.finish
)
334 elseif type(data
.pos
) == "table" then
335 AddQuestPos(q
, data
.pos
)
338 if type(data
.item
) == "table" then
339 AddQuestItems(q
, data
.item
)
342 if type(data
.hash
) == "number" and type(data
.alt
) == "table" then
343 for hash
, quest
in pairs(data
.alt
) do
345 AddQuest(locale
, faction
, level
, name
, quest
)
351 local function AddFlightInstructor(locale
, faction
, location
, npc
)
352 if ValidFaction(faction
) and type(location
) == "string" and type(npc
) == "string" then
353 local l
= StaticData
[locale
]
356 StaticData
[locale
] = l
358 local faction_list
= l
.flight_instructors
359 if not faction_list
then
361 l
.flight_instructors
= faction_list
364 local location_list
= faction_list
[faction
]
365 if not location_list
then
367 faction_list
[faction
] = location_list
369 location_list
[location
] = npc
373 local function AddFlightRoute(locale
, faction
, start
, destination
, hash
, value
)
374 if ValidFaction(faction
) and
375 type(start
) == "string" and
376 type(destination
) == "string" and
377 type(hash
) == "number" and
378 ((value
== true and hash
== 0) or (type(value
) == "number" and value
> 0)) then
379 local l
= StaticData
[locale
]
382 StaticData
[locale
] = l
384 local faction_list
= l
.flight_routes
385 if not faction_list
then
387 l
.flight_routes
= faction_list
389 local start_list
= faction_list
[faction
]
390 if not start_list
then
392 faction_list
[faction
] = start_list
394 local end_list
= start_list
[start
]
397 start_list
[start
] = end_list
399 local hash_list
= end_list
[destination
]
400 if not hash_list
then
402 end_list
[destination
] = hash_list
404 if value
== true then
405 hash_list
[hash
] = hash_list
[hash
] or true
407 local average
= hash_list
[hash
]
408 if type(average
) ~= "table" then
409 average
= CreateAverage()
410 hash_list
[hash
] = average
412 AppendToAverage(average
, value
)
417 local function addVendor(list
, npc
)
418 for _
, existing
in ipairs(list
) do
419 if existing
== npc
then
424 table.insert(list
, npc
)
427 local function addVendors(list
, to_add
)
428 if not list
then list
= {} end
430 for _
, npc
in ipairs(to_add
) do
438 local function AddObjective(locale
, category
, name
, objective
)
439 if type(category
) == "string"
440 and type(name
) == "string"
441 and type(objective
) == "table" then
442 local o
= GetObjective(locale
, category
, name
)
444 if objective
.quest
== true then o
.quest
= true end
446 if type(objective
.pos
) == "table" then
447 if not o
.pos
then o
.pos
= {} end
448 MergePositionLists(o
.pos
, objective
.pos
)
451 if category
== "monster" then
452 if type(objective
.id
) == "number" then
453 local wdm
= WoWData
.npc
[objective
.id
]
456 WoWData
.npc
[objective
.id
] = wdm
458 wdm
.name
[locale
] = name
461 if type(objective
.looted
) == "number" and objective
.looted
>= 1 then
462 o
.looted
= (o
.looted
or 0) + objective
.looted
464 if ValidFaction(objective
.faction
) then
465 o
.faction
= objective
.faction
467 elseif category
== "item" then
468 if type(objective
.id
) == "number" then
469 local wdi
= WoWData
.item
[objective
.id
]
472 WoWData
.item
[objective
.id
] = wdi
474 wdi
.name
[locale
] = name
477 if type(objective
.opened
) == "number" and objective
.opened
>= 1 then
478 o
.opened
= (o
.opened
or 0) + objective
.opened
480 if type(objective
.vendor
) == "table" then
481 o
.vendor
= addVendors(o
.vendor
, objective
.vendor
)
483 if type(objective
.drop
) == "table" then
484 if not o
.drop
then o
.drop
= {} end
485 for monster
, count
in pairs(objective
.drop
) do
486 if type(monster
) == "string" and type(count
) == "number" then
487 o
.drop
[monster
] = (o
.drop
[monster
] or 0) + count
491 if type(objective
.contained
) == "table" then
492 if not o
.contained
then o
.contained
= {} end
493 for item
, count
in pairs(objective
.contained
) do
494 if type(item
) == "string" and type(count
) == "number" then
495 o
.contained
[item
] = (o
.contained
[item
] or 0) + count
503 local function CollapseQuest(locale
, quest
)
504 local name_score
= quest
.finish
and DropListMass(quest
.finish
) or 0
505 local pos_score
= quest
.pos
and PositionListMass(quest
.pos
)*0.25 or 0
507 if name_score
> pos_score
then
508 quest
.finish
= CollapseDropList(quest
.finish
)
513 TidyPositionList(quest
.pos
)
517 if quest
.item
and not next(quest
.item
) then
522 -- This NPC is for a quest. Need to know them.
523 GetObjective(locale
, "monster", quest
.finish
).quest
= true
526 return quest
.pos
== nil and quest
.finish
== nil and quest
.item
== nil
529 local function CollapseObjective(locale
, objective
)
530 if not objective
.quest
then return true end
531 objective
.quest
= nil
533 if objective
.vendor
and not next(objective
.vendor
, nil) then objective
.vendor
= nil end
535 if objective
.pos
and (PositionListMass(objective
.pos
) >
536 ((objective
.drop
and DropListMass(objective
.drop
) or 0) +
537 (objective
.contained
and DropListMass(objective
.contained
) or 0))) then
539 objective
.contained
= nil
541 TidyPositionList(objective
.pos
)
543 if not next(objective
.pos
, nil) then
549 if objective
.drop
and not next(objective
.drop
) then objective
.drop
= nil end
550 if objective
.contained
and not next(objective
.contained
) then objective
.contained
= nil end
553 if objective
.looted
then
554 objective
.looted
= math
.max(1, math
.ceil(objective
.looted
))
557 if objective
.opened
then
558 objective
.opened
= math
.max(1, math
.ceil(objective
.opened
))
561 if objective
.vendor
and next(objective
.vendor
) then
562 table.sort(objective
.vendor
)
564 objective
.vendor
= nil
567 return objective
.drop
== nil and objective
.contained
== nil and objective
.pos
== nil and objective
.vendor
== nil
570 local function AddInputData(data
)
571 if data
.QuestHelper_StaticData
then
572 -- Importing a static data file.
573 local static
= data
.QuestHelper_StaticData
574 data
.QuestHelper_StaticData
= nil
576 for locale
, info
in pairs(static
) do
577 data
.QuestHelper_Locale
= locale
578 data
.QuestHelper_Quests
= info
.quest
579 data
.QuestHelper_Objectives
= info
.objective
580 data
.QuestHelper_FlightRoutes
= info
.flight_routes
581 data
.QuestHelper_FlightInstructors
= info
.flight_instructors
583 for cat
, list
in pairs(data
.QuestHelper_Objectives
) do
584 for name
, info
in pairs(list
) do
595 QuestHelper_UpgradeDatabase(data
)
597 if type(data
.QuestHelper_Locale
) == "string" then
598 local locale
= data
.QuestHelper_Locale
600 if type(data
.QuestHelper_Quests
) == "table" then for faction
, levels
in pairs(data
.QuestHelper_Quests
) do
601 if type(levels
) == "table" then for level
, quest_list
in pairs(levels
) do
602 if type(quest_list
) == "table" then for quest_name
, quest_data
in pairs(quest_list
) do
603 AddQuest(locale
, faction
, level
, quest_name
, quest_data
)
608 if type(data
.QuestHelper_Objectives
) == "table" then for category
, objectives
in pairs(data
.QuestHelper_Objectives
) do
609 if type(objectives
) == "table" then for name
, objective
in pairs(objectives
) do
610 AddObjective(locale
, category
, name
, objective
)
614 if type(data
.QuestHelper_FlightInstructors
) == "table" then for faction
, list
in pairs(data
.QuestHelper_FlightInstructors
) do
615 if type(list
) == "table" then for location
, npc
in pairs(list
) do
616 AddFlightInstructor(locale
, faction
, location
, npc
)
620 if type(data
.QuestHelper_FlightRoutes
) == "table" then for faction
, start_list
in pairs(data
.QuestHelper_FlightRoutes
) do
621 if type(start_list
) == "table" then for start
, destination_list
in pairs(start_list
) do
622 if type(destination_list
) == "table" then for destination
, hash_list
in pairs(destination_list
) do
623 if type(hash_list
) == "table" then for hash
, value
in pairs(hash_list
) do
624 AddFlightRoute(locale
, faction
, start
, destination
, hash
, value
)
632 local function QuestItemsAreSimilar(item
, quest_list
)
633 -- TODO: Write this function. Should make sure all the quests get item from the same place.
634 return #quest_list
<= 1
637 local function RemoveQuestByData(data
)
638 for locale
, l
in pairs(StaticData
) do
639 for faction
, levels
in pairs(l
.quest
) do
640 for level
, quest_list
in pairs(levels
) do
641 for quest
, quest_data
in pairs(quest_list
) do
642 if data
== quest_data
then
643 if quest_data
.alt
then
644 local alt
= quest_data
.alt
645 local hash
= next(alt
, nil)
646 local quest_data2
= alt
[hash
]
648 quest_list
[quest
] = quest_data2
649 if next(alt
, nil) then
650 quest_data2
.alt
= alt
651 quest_data2
.hash
= hash
654 quest_list
[quest
] = nil
656 elseif quest_data
.alt
then
657 for hash
, quest_data2
in pairs(quest_data
.alt
) do
658 if data
== quest_data2
then
659 quest_data
.alt
[hash
] = nil
663 if not next(quest_data
.alt
) then
665 quest_data
.hash
= nil
669 if not next(levels
[level
], nil) then levels
[level
] = nil end
671 if not next(l
.quest
[faction
], nil) then l
.quest
[faction
] = nil end
676 function CompileInputFile(filename
)
677 local data_loader
= loadfile(filename
)
680 setfenv(data_loader
, data
)
684 print("'"..filename
.."' couldn't be loaded!")
688 function handleTranslations()
689 for locale
, l
in pairs(StaticData
) do
692 local monster_map
= {}
695 for id
, data
in pairs(WoWData
.item
) do
696 if data
.name
[locale
] then
697 item_map
[data
.name
[locale]]
= id
701 for id
, data
in pairs(WoWData
.npc
) do
702 if data
.name
[locale
] then
703 monster_map
[data
.name
[locale]]
= id
707 for id
, data
in pairs(WoWData
.quest
) do
708 if data
.name
[locale
] then
709 quest_map
[data
.level
.."/"..data
.hash
[locale
].."/"..data
.name
[locale]]
= id
713 local function item2dat(data
, item
)
714 if not item
then item
= {} end
716 item
.quest
= item
.quest
or data
.quest
719 item
.opened
= (item
.opened
or 0) + data
.opened
727 MergePositionLists(item
.pos
, data
.pos
)
734 if not item
.vendor
then
738 for i
, npc
in ipairs(data
.vendor
) do
739 local id
= monster_map
[npc
]
741 addVendor(item
.vendor
, id
)
747 if not item
.drop
then
751 for name
, count
in pairs(data
.drop
) do
752 local id
= monster_map
[name
]
754 item
.drop
[id
] = (item
.drop
[id
] or 0) + count
755 data
.drop
[name
] = nil
760 if data
.contained
then
761 if not item
.contained
then
765 for name
, count
in pairs(data
.contained
) do
766 local id
= item_map
[name
]
768 item
.contained
[id
] = (item
.contained
[id
] or 0) + count
769 data
.contained
[name
] = nil
777 if l
.objective
.item
then for name
, data
in pairs(l
.objective
.item
) do
778 local id
= item_map
[name
]
780 item2dat(data
, WoWData
.item
[id
])
781 local item
= WoWData
.item
[id
]
785 if l
.objective
.monster
then for name
, data
in pairs(l
.objective
.monster
) do
786 local id
= monster_map
[name
]
788 local npc
= WoWData
.npc
[id
]
790 npc
.quest
= npc
.quest
or data
.quest
791 npc
.faction
= npc
.faction
or data
.faction
794 npc
.looted
= (npc
.looted
or 0) + data
.looted
802 MergePositionLists(npc
.pos
, data
.pos
)
810 local function q2static(faction
, name
, data
)
811 local id
= quest_map
[name
]
813 local quest
= WoWData
.quest
[id
]
814 quest
.faction
[faction
] = true
816 print("Copying Quest", faction
, name
)
818 if data
.finish
and next(data
.finish
) then
819 quest
.finish
= monster_map
[CollapseDropList(data
.finish
)] or quest
.finish
823 quest
.item
= quest
.item
or {}
825 for name
, idata
in pairs(data
.item
) do
826 local id
= item_map
[name
]
828 quest
.item
[id
] = item2dat(idata
, quest
.item
[id
])
835 if l
.quest
then for faction
, fqlist
in pairs(l
.quest
) do
836 for level
, qlist
in pairs(fqlist
) do
837 for name
, qdata
in pairs(qlist
) do
839 q2static(faction
, level
.."/"..qdata
.hash
.."/"..name
, qdata
)
842 if qdata
.alt
then for hash
, qdata2
in pairs(qdata
.alt
) do
843 q2static(faction
, level
.."/"..hash
.."/"..name
, qdata2
)
851 for id
, item
in pairs(WoWData
.item
) do
852 for locale
, name
in pairs(item
.name
) do
853 print("Adding item ", locale
, name
)
854 local data
= GetObjective(locale
, "item", name
)
856 data
.quest
= data
.quest
or item
.quest
859 data
.opened
= item
.opened
863 data
.pos
= data
.pos
or {}
864 MergePositionLists(data
.pos
, item
.pos
)
868 data
.vendor
= data
.vendor
or {}
870 for i
, id
in ipairs(item
.vendor
) do
871 local name
= WoWData
.npc
[id
] and WoWData
.npc
[id
].name
[locale
]
873 addVendor(data
.vendor
, name
)
879 data
.drop
= data
.drop
or {}
880 for id
, count
in pairs(item
.drop
) do
881 local name
= WoWData
.npc
[id
] and WoWData
.npc
[id
].name
[locale
]
883 data
.drop
[name
] = (data
.drop
[name
] or 0) + count
888 if item
.contained
then
889 data
.contained
= data
.contained
or {}
890 for id
, count
in pairs(item
.contained
) do
891 local name
= WoWData
.item
[id
] and WoWData
.item
[id
].name
[locale
]
893 data
.contained
[name
] = (data
.contained
[name
] or 0) + count
900 for id
, npc
in pairs(WoWData
.npc
) do
901 for locale
, name
in pairs(npc
.name
) do
902 print("Adding NPC ", locale
, name
)
903 local data
= GetObjective(locale
, "monster", name
)
905 data
.quest
= data
.quest
or npc
.quest
906 data
.faction
= data
.faction
or npc
.faction
909 data
.looted
= npc
.looted
913 data
.pos
= data
.pos
or {}
914 MergePositionLists(data
.pos
, npc
.pos
)
919 for id
, quest
in pairs(WoWData
.quest
) do
920 for faction
in pairs(quest
.faction
) do
921 for locale
, name
in pairs(quest
.name
) do
922 print("Adding Quest ", locale
, faction
, quest
.level
, quest
.hash
[locale
], name
)
923 local data
= GetQuest(locale
, faction
, quest
.level
, name
, quest
.hash
[locale
])
926 local fname
= WoWData
.npc
[quest
.finish
] and WoWData
.npc
[quest
.finish
].name
[locale
]
928 data
.finish
= {[fname
] = 1}
933 for id
, item
in pairs(quest
.item
) do
934 local iname
= WoWData
.item
[id
] and WoWData
.item
[id
].name
[locale
]
938 if not qdata
.item
then qdata
.item
= {} end
939 local data
= qdata
.item
[iname
] or {}
940 qdata
.item
[iname
] = data
943 data
.pos
= data
.pos
or {}
944 MergePositionLists(data
.pos
, item
.pos
)
948 data
.drop
= data
.drop
or {}
949 for id
, count
in pairs(item
.drop
) do
950 local name
= WoWData
.npc
[id
] and WoWData
.npc
[id
].name
[locale
]
952 data
.drop
[name
] = (data
.drop
[name
] or 0) + count
957 if item
.contained
then
958 data
.contained
= data
.contained
or {}
959 for id
, count
in pairs(item
.contained
) do
960 local name
= WoWData
.item
[id
] and WoWData
.item
[id
].name
[locale
]
962 data
.contained
[name
] = (data
.contained
[name
] or 0) + count
976 function CompileFinish()
979 for locale
, l
in pairs(StaticData
) do
980 local quest_item_mass
= {}
981 local quest_item_quests
= {}
983 local function WatchQuestItems(quest
)
984 if quest
.finish
then GetObjective(locale
, "monster", quest
.finish
).quest
= true end
987 for item
, data
in pairs(quest
.item
) do
988 quest_item_mass
[item
] = (quest_item_mass
[item
] or 0)+
989 (data
.drop
and DropListMass(data
.drop
) or 0)+
990 (data
.contained
and DropListMass(data
.contained
) or 0)+
991 (data
.pos
and PositionListMass(data
.pos
) or 0)
993 quest_item_quests
[item
] = quest_item_quests
[item
] or {}
994 table.insert(quest_item_quests
[item
], quest
)
999 print("Processing quests ", locale
)
1001 for faction
, levels
in pairs(l
.quest
) do
1002 local delete_faction
= true
1003 for level
, quest_list
in pairs(levels
) do
1004 local delete_level
= true
1005 for quest
, quest_data
in pairs(quest_list
) do
1006 if quest_data
.alt
then
1007 for hash
, quest_data2
in pairs(quest_data
.alt
) do
1008 if CollapseQuest(locale
, quest_data2
) then
1009 quest_data
.alt
[hash
] = nil
1011 quest_data2
.hash
= nil
1012 WatchQuestItems(quest_data2
)
1016 if not next(quest_data
.alt
, nil) then
1017 quest_data
.alt
= nil
1018 quest_data
.hash
= nil
1022 if CollapseQuest(locale
, quest_data
) then
1023 if quest_data
.alt
then
1024 local alt
= quest_data
.alt
1025 local hash
= next(alt
, nil)
1026 local quest_data2
= alt
[hash
]
1028 quest_list
[quest
] = quest_data2
1029 if next(alt
, nil) then
1030 quest_data2
.alt
= alt
1031 quest_data2
.hash
= hash
1034 delete_level
= false
1036 quest_list
[quest
] = nil
1039 WatchQuestItems(quest_data
)
1040 delete_level
= false
1044 if delete_level
then levels
[level
] = nil else delete_faction
= false end
1046 if delete_faction
then l
.quest
[faction
] = nil end
1049 if l
.flight_instructors
then for faction
, list
in pairs(l
.flight_instructors
) do
1050 for area
, npc
in pairs(list
) do
1051 -- Need to remember the flight instructors, for use in routing.
1052 GetObjective(locale
, "monster", npc
).quest
= true
1056 for item
, quest_list
in pairs(quest_item_quests
) do
1057 -- If all the items are similar, then we don't want quest item entries for them,
1058 -- we want to use the gobal item objective instead.
1059 if QuestItemsAreSimilar(item
, quest_list
) then
1060 quest_item_mass
[item
] = 0
1064 print("Processing quest items ", locale
)
1065 -- Will go through the items and either delete them, or merge the quest items into them, and then
1066 -- mark the relevent monsters as being quest objectives.
1067 if l
.objective
["item"] then
1068 for name
, objective
in pairs(l
.objective
["item"]) do
1069 -- If this is a quest item, mark anything that drops it as being a quest monster.
1070 local quest_mass
= quest_item_mass
[name
] or 0
1072 if objective
.vendor
and next(objective
.vendor
, nil) then
1073 quest_mass
= 0 -- If the item can be bought, then it shouldn't be quest specific.
1076 local item_mass
= (objective
.pos
and PositionListMass(objective
.pos
) or 0)+
1077 (objective
.drop
and DropListMass(objective
.drop
) or 0)+
1078 (objective
.contained
and DropListMass(objective
.contained
) or 0)
1080 if quest_mass
> item_mass
then
1081 -- Delete this item, we'll deal with the the quests using the items after.
1082 l
.objective
["item"][name
] = nil
1084 if quest_item_quests
[name
] then
1085 for i
, quest_data
in pairs(quest_item_quests
[name
]) do
1086 local quest_item
= quest_data
.item
and quest_data
.item
[name
]
1088 if quest_item
.drop
then
1089 if not objective
.drop
then objective
.drop
= {} end
1090 MergeDropLists(objective
.drop
, quest_item
.drop
)
1093 if quest_item
.contained
then
1094 if not objective
.contained
then objective
.contained
= {} end
1095 MergeDropLists(objective
.contained
, quest_item
.contained
)
1098 if quest_item
.pos
then
1099 if not objective
.pos
then objective
.pos
= {} end
1100 MergePositionLists(objective
.pos
, quest_item
.pos
)
1103 quest_data
.item
[name
] = nil
1104 if not next(quest_data
.item
, nil) then
1105 quest_data
.item
= nil
1107 if not quest_data
.finish
and not quest_data
.pos
then
1108 RemoveQuestByData(quest_data
)
1114 quest_item_quests
[name
] = nil
1115 objective
.quest
= true
1118 if objective
.quest
then
1119 if objective
.drop
then
1120 TidyDropList(locale
, objective
.drop
)
1121 for monster
, count
in pairs(objective
.drop
) do
1122 GetObjective(locale
, "monster", monster
).quest
= true
1126 if objective
.contained
then
1127 TidyContainedList(locale
, objective
.contained
)
1128 for item
, count
in pairs(objective
.contained
) do
1129 GetObjective(locale
, "item", item
).quest
= true
1133 if objective
.vendor
then
1134 for i
, npc
in ipairs(objective
.vendor
) do
1135 GetObjective(locale
, "monster", npc
).quest
= true
1143 -- For any quest items that didn't get handled above, we'll clean them up and leave them be.
1144 for item
, quest_list
in pairs(quest_item_quests
) do
1145 for _
, quest_data
in ipairs(quest_list
) do
1146 -- Item should already exist in quest, not going to check.
1147 local item_data
= quest_data
.item
[item
]
1150 if item_data
.pos
then
1151 pos_mass
= PositionListMass(item_data
.pos
)
1152 TidyPositionList(item_data
.pos
)
1156 if item_data
.drop
then
1157 drop_mass
= DropListMass(item_data
.drop
)
1158 TidyDropList(locale
, item_data
.drop
)
1161 local contained_mass
= 0
1162 if item_data
.contained
then
1163 contained_mass
= DropListMass(item_data
.contained
)
1164 TidyContainedList(locale
, item_data
.contained
)
1167 if drop_mass
+contained_mass
> pos_mass
then
1169 if item_data
.drop
then
1170 for monster
, count
in pairs(item_data
.drop
) do
1171 GetObjective(locale
, "monster", monster
).quest
= true
1175 if item_data
.contained
then
1176 for item
, count
in pairs(item_data
.contained
) do
1177 GetObjective(locale
, "item", item
).quest
= true
1181 item_data
.drop
= nil
1182 item_data
.contained
= nil
1185 if not item_data
.pos
and not item_data
.drop
then
1186 quest_data
.item
[item
] = nil
1187 if not next(quest_data
.item
, nil) then
1188 quest_data
.item
= nil
1190 if not quest_data
.finish
and not quest_data
.pos
then
1191 RemoveQuestByData(quest_data
)
1198 print("Processing objectives ", locale
)
1200 for category
, objectives
in pairs(l
.objective
) do
1201 local delete_category
= true
1202 for name
, objective
in pairs(objectives
) do
1203 if CollapseObjective(locale
, objective
) then
1204 objectives
[name
] = nil
1206 delete_category
= false
1209 if delete_category
then l
.objective
[category
] = nil end
1212 if l
.flight_routes
then
1213 for faction
, start_list
in pairs(l
.flight_routes
) do
1214 local delete_faction
= true
1215 for start
, dest_list
in pairs(start_list
) do
1216 local delete_start
= true
1217 for dest
, hash_list
in pairs(dest_list
) do
1218 local delete_dest
= true
1219 for hash
, value
in pairs(hash_list
) do
1220 if type(value
) == "table" then
1221 hash_list
[hash
] = CollapseAverage(value
)
1223 elseif value
== true and hash
== 0 then
1228 dest_list
[dest
] = nil
1230 delete_start
= false
1233 if delete_start
then
1234 start_list
[start
] = nil
1236 delete_faction
= false
1239 if delete_faction
then
1240 l
.flight_routes
[faction
] = nil
1246 local old_data
= StaticData