TourGuide - Starting GUI for guide selection
[WoW-TourGuide.git] / TourGuide.lua
blob8f830fe6e99050b81f5dccfd131647390bfc0a4e
2 local OptionHouse = DongleStub("OptionHouse-1.0")
5 TourGuide = DongleStub("Dongle-1.0"):New("TourGuide")
6 TourGuide.guides = {}
7 TourGuide.guidelist = {}
8 TourGuide.nextzones = {}
11 TourGuide.icons = setmetatable({
12 ACCEPT = "Interface\\GossipFrame\\AvailableQuestIcon",
13 COMPLETE = "Interface\\Icons\\Ability_DualWield",
14 TURNIN = "Interface\\GossipFrame\\ActiveQuestIcon",
15 RUN = "Interface\\Icons\\Ability_Tracking",
16 MAP = "Interface\\Icons\\Ability_Spy",
17 FLY = "Interface\\Icons\\Ability_Druid_FlightForm",
18 TRAIN = "Interface\\GossipFrame\\trainerGossipIcon",
19 SETHEARTH = "Interface\\Icons\\Spell_Holy_ElunesGrace",
20 HEARTH = "Interface\\Icons\\INV_Misc_Rune_01",
21 NOTE = "Interface\\Icons\\INV_Misc_Note_01",
22 GRIND = "Interface\\Icons\\INV_Stone_GrindingStone_05",
23 ITEM = "Interface\\Icons\\INV_Misc_Bag_08",
24 BUY = "Interface\\Icons\\INV_Misc_Coin_01",
25 }, {__index = function() return "Interface\\Icons\\INV_Misc_QuestionMark" end})
28 local actiontypes = {
29 A = "ACCEPT",
30 C = "COMPLETE",
31 T = "TURNIN",
32 R = "RUN",
33 t = "TRAIN",
34 H = "HEARTH",
35 h = "SETHEARTH",
36 G = "GRIND",
37 I = "ITEM",
38 F = "FLY",
39 N = "NOTE",
40 B = "BUY",
44 function TourGuide:Initialize()
45 self.db = self:InitializeDB("TourGuideAlphaDB", {
46 char = {
47 currentguide = self.guidelist[1],
48 turnedin = {},
49 cachedturnins = {},
52 self.turnedin = self.db.char.turnedin
53 self.cachedturnins = self.db.char.cachedturnins
55 self:LoadGuide(self.db.char.currentguide)
56 end
59 function TourGuide:Enable()
60 local _, title = GetAddOnInfo("TourGuide")
61 local author, version = GetAddOnMetadata("TourGuide", "Author"), GetAddOnMetadata("TourGuide", "Version")
62 local oh = OptionHouse:RegisterAddOn("Tour Guide", title, author, version)
63 oh:RegisterCategory("Guides", TourGuide, "CreateGuidesPanel")
64 oh:RegisterCategory("Objectives", TourGuide, "CreateObjectivePanel")
66 for _,event in pairs(self.TrackEvents) do self:RegisterEvent(event) end
67 self.TrackEvents = nil
68 self:UpdateStatusFrame()
69 end
72 function TourGuide:RegisterGuide(name, nextzone, sequencefunc)
73 self.guides[name] = sequencefunc
74 self.nextzones[name] = nextzone
75 table.insert(self.guidelist, name)
76 end
79 function TourGuide:LoadGuide(name)
80 name = name or self.nextzones[self.db.char.currentguide]
81 if not name then return end
83 -- Clean out old completed objectives, to avoid conflicts
84 if name ~= self.db.char.currentguide then
85 for i,quest in ipairs(self.quests) do self.turnedin[quest] = nil end
86 end
88 self.db.char.currentguide = name
89 self:ParseObjectives(self.guides[name](), showdebug)
90 end
93 function TourGuide:GetQuestLogIndexByName(name)
94 name = name or self.quests[self.current]
95 for i=1,GetNumQuestLogEntries() do
96 if GetQuestLogTitle(i) == name then return i end
97 end
98 end
100 function TourGuide:GetQuestDetails(name)
101 local i = self:GetQuestLogIndexByName(name)
102 local complete = i and select(7, GetQuestLogTitle(i)) == 1
103 return i, complete
107 local function FindBagSlot(itemid)
108 for bag=0,4 do
109 for slot=1,GetContainerNumSlots(bag) do
110 local item = GetContainerItemLink(bag, slot)
111 if item and string.find(item, "item:"..itemid) then return bag, slot end
117 function TourGuide:GetCurrentObjectiveInfo()
118 return self:GetObjectiveInfo(self.current)
122 function TourGuide:GetObjectiveInfo(i)
123 local action, quest, note = self.actions[i], self.quests[i], self.notes[i]
124 if not action then return end
126 local logi, complete = self:GetQuestDetails(quest)
127 local hasitem = action == "ITEM" and self.questitems[i] and FindBagSlot(self.questitems[i])
129 return action, quest:gsub("@.*@", ""), note, logi, complete, hasitem, self.turnedin[quest], quest
133 local isdebugging = false
134 local titlematches = {"For", "A", "The", "Or", "In", "Then", "From", "Our"}
135 local accepts, turnins, completes = {}, {}, {}
136 local function ParseQuests(...)
137 local uniqueid = 1
138 local actions, notes, quests, items = {}, {}, {}, {}
140 for i=1,select("#", ...) do
141 local text = select(i, ...)
142 if text ~= "" then
143 local _, _, action, quest = text:find("^(%a) ([^|]*)")
144 local _, _, detailtype, detail = string.find(text, "|(.)|([^|]+)|?")
145 quest = quest:trim()
146 if not (action == "I" or action == "A" or action =="C" or action =="T") then
147 quest = quest.."@"..uniqueid.."@"
148 uniqueid = uniqueid + 1
151 actions[i], quests[i] = actiontypes[action], quest
152 if detailtype == "N" then notes[i] = detail end
153 if action == "I" then items[i] = select(3, string.find(text, "|I|(%d+)|")) end
155 -- Debuggery
156 if isdebugging and action == "A" then accepts[quest] = true
157 elseif isdebugging and action == "T" then turnins[quest] = true
158 elseif isdebugging and action == "C" then completes[quest] = true end
160 if isdebugging and (action == "A" or action == "C" or action == "T") then
161 -- Catch bad Title Case
162 for _,word in pairs(titlematches) do
163 if quest:find("[^:]%s"..word.."%s") or quest:find("[^:]%s"..word.."$") or quest:find("[^:]%s"..word.."@") then
164 TourGuide:PrintF("%s %s -- Contains bad title case", action, quest)
171 -- More debug
172 if isdebugging then
173 for quest in pairs(accepts) do if not turnins[quest] then TourGuide:PrintF("Quest has no 'turnin' objective: %s", quest) end end
174 for quest in pairs(turnins) do if not accepts[quest] then TourGuide:PrintF("Quest has no 'accept' objective: %s", quest) end end
175 for quest in pairs(completes) do if not accepts[quest] and not turnins[quest] then TourGuide:PrintF("Quest has no 'accept' and 'turnin' objectives: %s", quest) end end
178 return actions, notes, quests, items
182 function TourGuide:ParseObjectives(text, showdebug)
183 isdebugging = showdebug
184 self.actions, self.notes, self.quests, self.questitems = ParseQuests(string.split("\n", text))
188 function TourGuide:SetTurnedIn(i, value)
189 if not i then
190 i = self.current
191 value = true
194 self.turnedin[self.quests[i]] = value
195 self:UpdateStatusFrame()