Repository navigation
Expand file tree
/
Copy pathRewards.lua
More file actions
278 lines (261 loc) · 12.6 KB
/
Copy pathRewards.lua
File metadata and controls
278 lines (261 loc) · 12.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
-- Quest rewards with a choice, picked and turned in without stopping.
--
-- 1. A quest you chose a reward for yourself before: the same reward again (it learns from you).
-- 2. Otherwise the first kind of reward in your priority list that is on offer, e.g. two-handed
-- weapon, then mail, then water. Of two of the same kind, the one that sells for more.
-- 3. Nothing in the list on offer: the most valuable reward, or leave it to you (a setting).
-- Only up to the level limit, and never while Shift is held - that is how you choose yourself, and
-- a choice made by hand is remembered for that quest. A choice with a green (or better) among it is
-- yours too (greenStop, per class, on by default), unless you chose for that quest by hand before.
-- Holding Shift also stops RestedXP's own quest automation (accept, hand in, its built-in reward
-- picks) for the window you open, and a green stops RestedXP's built-in reward picks.
-- YippRouteDB.rewardClasses[CLASS] = { on, maxLevel, order = { kind, ... }, off = { [kind] = true },
-- remember, fallback = "value" | "ask", chosen = { [questID] = { item, name, title } } }
local _, YR = ...
local WEAPON, ARMOR, CONSUMABLE, CONTAINER = 2, 4, 0, 1
-- Every kind the picker knows, in the order the settings list them.
YR.REWARD_KINDS = {
{ key = "twohand", label = "Two-handed weapon" },
{ key = "onehand", label = "One-handed weapon" },
{ key = "ranged", label = "Ranged weapon" },
{ key = "shield", label = "Shield" },
{ key = "plate", label = "Plate armour" },
{ key = "mail", label = "Mail armour" },
{ key = "leather", label = "Leather armour" },
{ key = "cloth", label = "Cloth armour" },
{ key = "cloak", label = "Cloak" },
{ key = "jewelry", label = "Ring, neck or trinket" },
{ key = "water", label = "Water" },
{ key = "food", label = "Food" },
{ key = "potion", label = "Potion" },
{ key = "bag", label = "Bag" },
}
-- A sensible start per class; everyone can reorder it in the settings.
local DEFAULT_ORDER = {
PALADIN = { "twohand", "mail", "shield", "water", "food" },
WARRIOR = { "twohand", "mail", "onehand", "shield", "food" },
HUNTER = { "ranged", "twohand", "leather", "mail", "food" },
ROGUE = { "onehand", "leather", "food" },
DRUID = { "leather", "twohand", "water", "food" },
SHAMAN = { "twohand", "leather", "mail", "shield", "water" },
PRIEST = { "cloth", "water", "food" },
MAGE = { "cloth", "water", "food" },
WARLOCK = { "cloth", "water", "food" },
}
local function Copy(t)
local c = {}
for k, v in pairs(t or {}) do c[k] = type(v) == "table" and Copy(v) or v end
return c
end
-- Per class: YippRouteDB.rewardClasses[CLASS] (plus .on: pick at all). From before that, one set for
-- all in YippRouteDB.rewards: left as it is, and copied into the first class that asks (the player's
-- own, at the first quest or on opening the settings), which is the class it was made on. Other
-- classes start from their own priority list and the same limits, and take over the choices you
-- made that weren't gear (a profession book is the same pick for everyone).
function YR:RewardSettings(class)
if not class then
local _, mine = UnitClass("player")
class = mine or "WARRIOR"
end
YippRouteDB.rewardClasses = YippRouteDB.rewardClasses or {}
local db = YippRouteDB.rewardClasses[class]
if not db then
local old = YippRouteDB.rewards
if old and not YippRouteDB.rewardsTakenBy then
db = Copy(old)
YippRouteDB.rewardsTakenBy = class
else
local order = {}
for _, k in ipairs(DEFAULT_ORDER[class] or DEFAULT_ORDER.WARRIOR) do order[#order + 1] = k end
db = { maxLevel = old and old.maxLevel or 10, order = order, off = {},
remember = not old or old.remember ~= false, fallback = old and old.fallback or "value", chosen = {},
greenStop = true }
for quest, pick in pairs(old and old.chosen or {}) do
if pick.item and YR.RewardKind(pick.item) == nil then db.chosen[quest] = Copy(pick) end
end
end
db.on = YippRouteDB.pickRewards == true
YippRouteDB.rewardClasses[class] = db
end
-- (picking is something you turn on: pickRewards is true on an account that had Headstart while
-- it was on from the start - Core's Latch - and after you turn it on in the welcome window)
if db.on == nil then db.on = YippRouteDB.pickRewards == true end
if db.greenStop == nil then db.greenStop = true end
-- every kind is in the list once, so the settings can switch any of them on
local seen = {}
for _, k in ipairs(db.order) do seen[k] = true end
for _, kind in ipairs(YR.REWARD_KINDS) do
if not seen[kind.key] then
db.order[#db.order + 1] = kind.key
db.off[kind.key] = true
end
end
return db
end
local SLOT = { INVTYPE_2HWEAPON = "twohand", INVTYPE_WEAPON = "onehand", INVTYPE_WEAPONMAINHAND = "onehand",
INVTYPE_WEAPONOFFHAND = "onehand", INVTYPE_RANGED = "ranged", INVTYPE_RANGEDRIGHT = "ranged",
INVTYPE_THROWN = "ranged", INVTYPE_CLOAK = "cloak", INVTYPE_FINGER = "jewelry", INVTYPE_NECK = "jewelry",
INVTYPE_TRINKET = "jewelry", INVTYPE_SHIELD = "shield" }
local ARMOR_KIND = { [1] = "cloth", [2] = "leather", [3] = "mail", [4] = "plate", [6] = "shield" }
-- The kind of reward an item is; false while its spell isn't loaded yet (ask again shortly).
function YR.RewardKind(itemID)
local _, _, _, equipLoc, _, classID, subclassID = C_Item.GetItemInfoInstant(itemID)
if SLOT[equipLoc] then return SLOT[equipLoc] end
if classID == ARMOR then return ARMOR_KIND[subclassID] end
-- a plain bag only: a mining pack or herb bag is a profession choice, not an upgrade
if classID == CONTAINER then return subclassID == 0 and "bag" or nil end
if classID == CONSUMABLE then
if subclassID == 1 then return "potion" end
if subclassID == 5 then
local spell = C_Item.GetItemSpell(itemID)
if spell == nil then return false end
return spell == "Drink" and "water" or "food"
end
end
return nil
end
local picking = false -- our own GetQuestReward call, so it isn't remembered as the player's choice
local function Take(index)
-- (the game says what you received: "reward: ..." in chat said it twice - 2026-10-21)
picking = true
GetQuestReward(index)
picking = false
end
-- Whether a choice of rewards has a green or better among it.
local function HasGreen()
local n = GetNumQuestChoices()
if n < 2 then return false end
for i = 1, n do
local _, _, _, quality = GetQuestItemInfo("choice", i)
if quality and quality >= 2 then return true end
end
return false
end
local function Choose(tries)
local n = GetNumQuestChoices()
if n < 2 or IsShiftKeyDown() then return end -- no choice to make (most quests), or yours
local db = YR:RewardSettings()
if UnitLevel("player") > db.maxLevel or not db.on then return end
local items, values, kinds = {}, {}, {}
for i = 1, n do
local _, _, _, _, isUsable, itemID = GetQuestItemInfo("choice", i)
local kind = itemID and YR.RewardKind(itemID)
if not itemID or kind == false then
return tries > 0 and C_Timer.After(0.2, function() Choose(tries - 1) end)
end
items[i], kinds[i] = isUsable and itemID, kind
values[i] = select(11, C_Item.GetItemInfo(itemID)) or 0
end
-- 1. the reward you chose for this quest before
local mine = db.remember and db.chosen[GetQuestID()]
if mine then
for i = 1, n do if items[i] == mine.item then return Take(i) end end
end
-- a green among the choices: yours
if db.greenStop and HasGreen() then return end -- (the quest window stays for you: no line needed)
-- a choice that isn't gear or food (a profession to learn, a profession bag, a pet): yours, unless you chose
-- it by hand on this quest before (above)
for i = 1, n do
if not kinds[i] then return end
end
-- 2. your priority list; the more valuable of two of the same kind
for _, kind in ipairs(db.order) do
if not db.off[kind] then
local best
for i = 1, n do
if items[i] and kinds[i] == kind and (not best or values[i] > values[best]) then best = i end
end
if best then return Take(best) end
end
end
-- 3. nothing from the list on offer
if db.fallback == "value" then
local best
for i = 1, n do if items[i] and (not best or values[i] > values[best]) then best = i end end
if best then return Take(best) end
end
end
-- Your class's settings as YR:RewardSettings would give them, without making them: whether rewards
-- are picked at all, and up to which level. (Asked at the login and when a setting changes.) This is
-- quality of life: with that main switch off nothing is picked.
local function Set()
if not YR.QoLOn() then return false end
local _, class = UnitClass("player")
local all = YippRouteDB.rewardClasses
local db = all and all[class or "WARRIOR"]
if db then return db.on == true, db.maxLevel end
local old = YippRouteDB.rewards
return YippRouteDB.pickRewards == true, old and old.maxLevel or 10
end
local function Picking() return (Set()) end
-- (a character past the level limit has nothing picked for it: it doesn't listen for quests either)
local function PickingNow()
local on, maxLevel = Set()
return on and (UnitLevel("player") or 1) <= (tonumber(maxLevel) or 10)
end
-- A reward you picked by hand is remembered for that quest. The hook is put on the first time picking
-- is on (it can't be taken off again), and comes straight back out while picking is off.
local learning = false
local function Learn(index)
if not learning or picking or not index or GetNumQuestChoices() < 2 then return end
local name, _, _, _, _, itemID = GetQuestItemInfo("choice", index)
local db = YR:RewardSettings()
if itemID and db.remember then
db.chosen[GetQuestID()] = { item = itemID, name = name, title = GetTitleText() }
end
end
local learnHooked
YR.Part(Picking, nil, nil, {
start = function()
learning = true
if not learnHooked then
learnHooked = true
hooksecurefunc("GetQuestReward", Learn)
end
end,
stop = function() learning = false end,
})
YR.Part(PickingNow, { "QUEST_COMPLETE" }, function() Choose(10) end)
-- The quest windows are hooked for RestedXP's sake alone (see below): once, with RestedXP loaded and
-- quality of life on.
local windowsHooked
YR.Part(function()
-- (only where one of the two things it is for is on: the routes, or reward picking. With neither,
-- RestedXP's windows are not hooked and its settings are never touched.)
return type(_G.RXP) == "table" and YR.QoLOn() and (YR.RoutesOn() or YR:RewardSettings().on == true)
end, nil, nil, { start = function()
if windowsHooked then return end
windowsHooked = true
YR:HookQuestWindows()
end })
-- RestedXP acts on the same events as these windows, after them (Blizzard's frames were there first):
-- switching one of its settings off when a window opens, back on the next frame, keeps it out of that
-- one window. Only for that moment, and RestedXP's setting is put back exactly as it was: a setting
-- nobody ever chose (not in its saved table at all) is taken out again, not written down as "on" -
-- that turned RestedXP's own reward picking on for good for anyone who had never set it.
local function Pause(key)
local p = type(RXP) == "table" and type(RXP.settings) == "table" and RXP.settings.profile
if type(p) ~= "table" or p[key] == false then return end
local was = p[key]
p[key] = false
C_Timer.After(0, function() if p[key] == false then p[key] = was end end)
end
function YR:HookQuestWindows()
for _, name in ipairs({ "GossipFrame", "QuestFrameGreetingPanel", "QuestFrameDetailPanel",
"QuestFrameProgressPanel", "QuestFrameRewardPanel" }) do
local frame = _G[name]
if frame and frame.HookScript then
frame:HookScript("OnShow", function()
if IsShiftKeyDown() and YR.QoLOn() and YR.RoutesOn() then Pause("enableQuestAutomation") end
end)
end
end
local reward = _G.QuestFrameRewardPanel
if reward and reward.HookScript then
reward:HookScript("OnShow", function()
if not YR.QoLOn() then return end
local db = YR:RewardSettings()
if db.on and db.greenStop and HasGreen() then Pause("enableQuestRewardAutomation") end
end)
end
end