vanilla-wow-addons – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 --[[
2  
3 LootLink 3.5: An in-game item database
4 copyright 2004 by Telo
5  
6 - Watches all chat links you see to cache link color and link data
7 - Automatically extracts data from items already in or added to your inventory
8 - Automatically caches link data from items already in or added to your bank
9 - Automatically inspects your target and extracts data for each of their equipped items
10 - Automatically gets link data from your auction queries
11 - Can perform a fully automatic scan of the entire auction house inventory
12 - Stores sell prices for items that you've had in inventory when you've talked to a merchant
13 and displays them in the tooltips for stacks of items that you are looting, stacks of items
14 in your inventory and entries in the LootLink browse window
15 - Converts green loot messages into correctly colored item messages if the item is cached
16 - Provides a browsable, searchable window that allows you to find any item in the cache
17 - Allows you to shift-click items in the browse window to insert links in the chat edit box
18  
19 ]]
20  
21 --------------------------------------------------------------------------------------------------
22 -- Local LootLink variables
23 --------------------------------------------------------------------------------------------------
24  
25 -- Function hooks
26 local lOriginal_CanSendAuctionQuery;
27 local lOriginal_AuctionFrameBrowse_OnEvent;
28 local lOriginal_ContainerFrameItemButton_OnEnter;
29 local lOriginal_ContainerFrame_Update;
30 local lOriginal_GameTooltip_SetLootItem;
31 local lOriginal_GameTooltip_SetOwner;
32 local lOriginal_GameTooltip_OnHide;
33 local lOriginal_GameTooltip_ClearMoney;
34 local lOriginal_GameTooltip_ClearMoney_Temp;
35 local lOriginal_ShoppingTooltip1_SetMerchantCompareItem;
36 local lOriginal_ShoppingTooltip2_SetMerchantCompareItem;
37 local lOriginal_ShoppingTooltip1_SetAuctionCompareItem;
38 local lOriginal_ShoppingTooltip2_SetAuctionCompareItem;
39 local lOriginal_SetItemRef;
40 local lOriginal_OnTooltipAddMoney;
41  
42 --local ll = {};
43  
44 -- If non-nil, kick off a full auction scan next time auctioneer is used
45 local lScanAuction;
46  
47 -- Used for scanning inventory items for their sell prices at a merchant
48 local lBagID;
49 local lSlotID;
50  
51 -- If non-nil, don't add extra information to the tooltip on GameTooltip_ClearMoney
52 local lSuppressInfoAdd;
53  
54 -- If non-nil, check for appearance of GameTooltip for adding information
55 local lCheckTooltip;
56  
57 -- Timer for frequency of tooltip checks
58 local lCheckTimer = 0;
59  
60 -- The current owner of the GameTooltip
61 local lGameToolTipOwner;
62  
63 -- Cache of auction item information
64 local lAuctionItemInfo;
65  
66 -- Used to remember that confirmation is needed of irreversible commands
67 local lResetNeedsConfirm;
68 local lMakeHomeNeedsConfirm;
69 local lLightModeNeedsConfirm;
70  
71 -- If non-nil, the data version upgrade reminder is not displayed on every /lootlink or /ll command
72 local lDisableVersionReminder;
73  
74 -- The current server name and index
75 local lServer;
76 local lServerIndex;
77  
78 -- The number of items in the database, total and for this server
79 local lItemLinksSizeTotal;
80 local lItemLinksSizeServer;
81  
82 local STATE_NAME = 0;
83 local STATE_BOUND = 1;
84 local STATE_UNIQUE = 2;
85 local STATE_LOCATION = 3;
86 local STATE_TYPE = 4;
87 local STATE_DAMAGE = 5;
88 local STATE_DPS = 6;
89 local STATE_ARMOR = 7;
90 local STATE_BLOCK = 8;
91 local STATE_CONTAINER = 9;
92 local STATE_REQUIRES = 10;
93 local STATE_FINISH = 11;
94 local STATE_SPACE = 12
95 local STATE_SET = 13;
96  
97 local tooltipSpace = " "..string.char(10);
98  
99 local BINDS_DOES_NOT_BIND = 0;
100 local BINDS_EQUIP = 1;
101 local BINDS_PICKUP = 2;
102 local BINDS_USED = 3;
103  
104 local TYPE_ARMOR = 0;
105 local TYPE_WEAPON = 1;
106 local TYPE_SHIELD = 2;
107 local TYPE_RECIPE = 3;
108 local TYPE_CONTAINER = 4;
109 local TYPE_MISC = 5;
110  
111 local SUBTYPE_ARMOR_CLOTH = 0;
112 local SUBTYPE_ARMOR_LEATHER = 1;
113 local SUBTYPE_ARMOR_MAIL = 2;
114 local SUBTYPE_ARMOR_PLATE = 3;
115 local SUBTYPE_ARMOR_RELIC = 4;
116  
117 local lColorSortTable = { };
118 lColorSortTable["ffff8000"] = 1; -- legendary, orange
119 lColorSortTable["ffa335ee"] = 2; -- epic, purple
120 lColorSortTable["ff0070dd"] = 3; -- rare, blue
121 lColorSortTable["ff1eff00"] = 4; -- uncommon, green
122 lColorSortTable["ffffffff"] = 5; -- common, white
123 lColorSortTable["ff9d9d9d"] = 6; -- poor, gray
124 lColorSortTable["ff40ffc0"] = 100; -- unknown, teal
125  
126 local ArmorSubtypes = { };
127 ArmorSubtypes[CLOTH] = SUBTYPE_ARMOR_CLOTH;
128 ArmorSubtypes[LEATHER] = SUBTYPE_ARMOR_LEATHER;
129 ArmorSubtypes[MAIL] = SUBTYPE_ARMOR_MAIL;
130 ArmorSubtypes[PLATE] = SUBTYPE_ARMOR_PLATE;
131 ArmorSubtypes[INVTYPE_RELIC] = SUBTYPE_ARMOR_RELIC;
132  
133 local SUBTYPE_WEAPON_AXE = 0;
134 local SUBTYPE_WEAPON_BOW = 1;
135 local SUBTYPE_WEAPON_DAGGER = 2;
136 local SUBTYPE_WEAPON_MACE = 3;
137 local SUBTYPE_WEAPON_FISHING_POLE = 4;
138 local SUBTYPE_WEAPON_STAFF = 5;
139 local SUBTYPE_WEAPON_SWORD = 6;
140 local SUBTYPE_WEAPON_GUN = 7;
141 local SUBTYPE_WEAPON_WAND = 8;
142 local SUBTYPE_WEAPON_THROWN = 9;
143 local SUBTYPE_WEAPON_POLEARM = 10;
144 local SUBTYPE_WEAPON_FIST_WEAPON = 11;
145 local SUBTYPE_WEAPON_CROSSBOW = 12;
146  
147 local WeaponSubtypes = { };
148 WeaponSubtypes[AXE] = SUBTYPE_WEAPON_AXE;
149 WeaponSubtypes[BOW] = SUBTYPE_WEAPON_BOW;
150 WeaponSubtypes[DAGGER] = SUBTYPE_WEAPON_DAGGER;
151 WeaponSubtypes[MACE] = SUBTYPE_WEAPON_MACE;
152 WeaponSubtypes[FISHING_POLE] = SUBTYPE_WEAPON_FISHING_POLE;
153 WeaponSubtypes[STAFF] = SUBTYPE_WEAPON_STAFF;
154 WeaponSubtypes[SWORD] = SUBTYPE_WEAPON_SWORD;
155 WeaponSubtypes[GUN] = SUBTYPE_WEAPON_GUN;
156 WeaponSubtypes[WAND] = SUBTYPE_WEAPON_WAND;
157 WeaponSubtypes[THROWN] = SUBTYPE_WEAPON_THROWN;
158 WeaponSubtypes[POLEARM] = SUBTYPE_WEAPON_POLEARM;
159 WeaponSubtypes[FIST_WEAPON] = SUBTYPE_WEAPON_FIST_WEAPON;
160 WeaponSubtypes[CROSSBOW] = SUBTYPE_WEAPON_CROSSBOW;
161  
162 local SUBTYPE_SHIELD_BUCKLER = 0;
163 local SUBTYPE_SHIELD_SHIELD = 1;
164  
165 local ShieldSubtypes = { };
166 ShieldSubtypes["Buckler"] = SUBTYPE_SHIELD_BUCKLER;
167 ShieldSubtypes[SHIELD] = SUBTYPE_SHIELD_SHIELD;
168  
169 local SUBTYPE_RECIPE_ALCHEMY = 0;
170 local SUBTYPE_RECIPE_BLACKSMITHING = 1;
171 local SUBTYPE_RECIPE_COOKING = 2;
172 local SUBTYPE_RECIPE_ENCHANTING = 3;
173 local SUBTYPE_RECIPE_ENGINEERING = 4;
174 local SUBTYPE_RECIPE_LEATHERWORKING = 5;
175 local SUBTYPE_RECIPE_TAILORING = 6;
176 local SUBTYPE_RECIPE_FIRST_AID = 7;
177 local SUBTYPE_RECIPE_FISHING = 8;
178  
179 local RecipeSubtypes = { };
180 RecipeSubtypes[ALCHEMY] = SUBTYPE_RECIPE_ALCHEMY;
181 RecipeSubtypes[BLACKSMITHING] = SUBTYPE_RECIPE_BLACKSMITHING;
182 RecipeSubtypes[COOKING] = SUBTYPE_RECIPE_COOKING;
183 RecipeSubtypes[ENCHANTING] = SUBTYPE_RECIPE_ENCHANTING;
184 RecipeSubtypes[ENGINEERING] = SUBTYPE_RECIPE_ENGINEERING;
185 RecipeSubtypes[LEATHERWORKING] = SUBTYPE_RECIPE_LEATHERWORKING;
186 RecipeSubtypes[TAILORING] = SUBTYPE_RECIPE_TAILORING;
187 RecipeSubtypes[FIRST_AID] = SUBTYPE_RECIPE_FIRST_AID;
188 RecipeSubtypes[FISHING] = SUBTYPE_RECIPE_FISHING;
189  
190 local SUBTYPE_CONTAINER_BAG = 0;
191 local SUBTYPE_CONTAINER_AMMO_POUCH = 1;
192 local SUBTYPE_CONTAINER_QUIVER = 2;
193 local SUBTYPE_CONTAINER_SOUL_BAG = 3;
194 local SUBTYPE_CONTAINER_HERB_BAG = 4;
195 local SUBTYPE_CONTAINER_ENCHANTING_BAG = 5;
196 local SUBTYPE_CONTAINER_ENGINEERING_BAG = 6;
197  
198 local ContainerSubtypes = { };
199 ContainerSubtypes[BAG] = SUBTYPE_CONTAINER_BAG;
200 ContainerSubtypes[AMMO_POUCH] = SUBTYPE_CONTAINER_AMMO_POUCH;
201 ContainerSubtypes[QUIVER] = SUBTYPE_CONTAINER_QUIVER;
202 ContainerSubtypes[SOUL_BAG] = SUBTYPE_CONTAINER_SOUL_BAG;
203 ContainerSubtypes[HERB_BAG] = SUBTYPE_CONTAINER_HERB_BAG;
204 ContainerSubtypes[ENCHANTING_BAG] = SUBTYPE_CONTAINER_ENCHANTING_BAG;
205 ContainerSubtypes[ENGINEERING_BAG] = SUBTYPE_CONTAINER_ENGINEERING_BAG;
206  
207 local lTypeAndSubtypeToSkill = { };
208 lTypeAndSubtypeToSkill[TYPE_ARMOR] = { };
209 lTypeAndSubtypeToSkill[TYPE_ARMOR][SUBTYPE_ARMOR_CLOTH] = CLOTH;
210 lTypeAndSubtypeToSkill[TYPE_ARMOR][SUBTYPE_ARMOR_LEATHER] = LEATHER;
211 lTypeAndSubtypeToSkill[TYPE_ARMOR][SUBTYPE_ARMOR_MAIL] = MAIL;
212 lTypeAndSubtypeToSkill[TYPE_ARMOR][SUBTYPE_ARMOR_PLATE] = PLATE_MAIL;
213 lTypeAndSubtypeToSkill[TYPE_ARMOR][SUBTYPE_ARMOR_RELIC] = INVTYPE_RELIC;
214 lTypeAndSubtypeToSkill[TYPE_WEAPON] = { };
215 lTypeAndSubtypeToSkill[TYPE_WEAPON][SUBTYPE_WEAPON_AXE] = { }
216 lTypeAndSubtypeToSkill[TYPE_WEAPON][SUBTYPE_WEAPON_AXE][0] = AXES;
217 lTypeAndSubtypeToSkill[TYPE_WEAPON][SUBTYPE_WEAPON_AXE][1] = TWO_HANDED_AXES;
218 lTypeAndSubtypeToSkill[TYPE_WEAPON][SUBTYPE_WEAPON_BOW] = BOWS;
219 lTypeAndSubtypeToSkill[TYPE_WEAPON][SUBTYPE_WEAPON_DAGGER] = DAGGERS;
220 lTypeAndSubtypeToSkill[TYPE_WEAPON][SUBTYPE_WEAPON_MACE] = { }
221 lTypeAndSubtypeToSkill[TYPE_WEAPON][SUBTYPE_WEAPON_MACE][0] = MACES;
222 lTypeAndSubtypeToSkill[TYPE_WEAPON][SUBTYPE_WEAPON_MACE][1] = TWO_HANDED_MACES;
223 lTypeAndSubtypeToSkill[TYPE_WEAPON][SUBTYPE_WEAPON_FISHING_POLE] = FISHING_POLE;
224 lTypeAndSubtypeToSkill[TYPE_WEAPON][SUBTYPE_WEAPON_STAFF] = STAVES;
225 lTypeAndSubtypeToSkill[TYPE_WEAPON][SUBTYPE_WEAPON_SWORD] = { };
226 lTypeAndSubtypeToSkill[TYPE_WEAPON][SUBTYPE_WEAPON_SWORD][0] = SWORDS;
227 lTypeAndSubtypeToSkill[TYPE_WEAPON][SUBTYPE_WEAPON_SWORD][1] = TWO_HANDED_SWORDS;
228 lTypeAndSubtypeToSkill[TYPE_WEAPON][SUBTYPE_WEAPON_GUN] = GUNS;
229 lTypeAndSubtypeToSkill[TYPE_WEAPON][SUBTYPE_WEAPON_WAND] = WANDS;
230 lTypeAndSubtypeToSkill[TYPE_WEAPON][SUBTYPE_WEAPON_THROWN] = THROWN;
231 lTypeAndSubtypeToSkill[TYPE_WEAPON][SUBTYPE_WEAPON_POLEARM] = POLEARMS; --@todo Telo: unconfirmed
232 lTypeAndSubtypeToSkill[TYPE_WEAPON][SUBTYPE_WEAPON_FIST_WEAPON] = UNARMED;
233 lTypeAndSubtypeToSkill[TYPE_WEAPON][SUBTYPE_WEAPON_CROSSBOW] = CROSSBOWS;
234 lTypeAndSubtypeToSkill[TYPE_SHIELD] = { };
235 lTypeAndSubtypeToSkill[TYPE_SHIELD][SUBTYPE_SHIELD_BUCKLER] = SHIELD; --@todo Telo: deprecated subtype, should remove
236 lTypeAndSubtypeToSkill[TYPE_SHIELD][SUBTYPE_SHIELD_SHIELD] = SHIELD;
237 lTypeAndSubtypeToSkill[TYPE_RECIPE] = { };
238 lTypeAndSubtypeToSkill[TYPE_RECIPE][SUBTYPE_RECIPE_ALCHEMY] = ALCHEMY;
239 lTypeAndSubtypeToSkill[TYPE_RECIPE][SUBTYPE_RECIPE_BLACKSMITHING] = BLACKSMITHING;
240 lTypeAndSubtypeToSkill[TYPE_RECIPE][SUBTYPE_RECIPE_COOKING] = COOKING;
241 lTypeAndSubtypeToSkill[TYPE_RECIPE][SUBTYPE_RECIPE_ENCHANTING] = ENCHANTING;
242 lTypeAndSubtypeToSkill[TYPE_RECIPE][SUBTYPE_RECIPE_ENGINEERING] = ENGINEERING;
243 lTypeAndSubtypeToSkill[TYPE_RECIPE][SUBTYPE_RECIPE_LEATHERWORKING] = LEATHERWORKING;
244 lTypeAndSubtypeToSkill[TYPE_RECIPE][SUBTYPE_RECIPE_TAILORING] = TAILORING;
245 lTypeAndSubtypeToSkill[TYPE_RECIPE][SUBTYPE_RECIPE_FIRST_AID] = FIRST_AID;
246 lTypeAndSubtypeToSkill[TYPE_RECIPE][SUBTYPE_RECIPE_FISHING] = FISHING;
247 lTypeAndSubtypeToSkill[TYPE_CONTAINER] = { };
248 lTypeAndSubtypeToSkill[TYPE_CONTAINER][SUBTYPE_CONTAINER_BAG] = BAG;
249 lTypeAndSubtypeToSkill[TYPE_CONTAINER][SUBTYPE_CONTAINER_AMMO_POUCH] = AMMO_POUCH;
250 lTypeAndSubtypeToSkill[TYPE_CONTAINER][SUBTYPE_CONTAINER_QUIVER] = QUIVER;
251 lTypeAndSubtypeToSkill[TYPE_CONTAINER][SUBTYPE_CONTAINER_SOUL_BAG] = SOUL_BAG;
252 lTypeAndSubtypeToSkill[TYPE_CONTAINER][SUBTYPE_CONTAINER_ENCHANTING_BAG] = ENCHANTING_BAG;
253  
254 local LocationTypes = { };
255 LocationTypes[INVTYPE_HOLDABLE] = { i = 0, type = TYPE_MISC };
256 LocationTypes[INVTYPE_CLOAK] = { i = 1, type = TYPE_ARMOR, subtypes = ArmorSubtypes };
257 LocationTypes[INVTYPE_WEAPON] = { i = 2, type = TYPE_WEAPON, subtypes = WeaponSubtypes };
258 LocationTypes[INVTYPE_2HWEAPON] = { i = 3, type = TYPE_WEAPON, subtypes = WeaponSubtypes };
259 LocationTypes[INVTYPE_WEAPONOFFHAND] = { i = 4, type = TYPE_SHIELD, subtypes = ShieldSubtypes };
260 LocationTypes[INVTYPE_WRIST] = { i = 5, type = TYPE_ARMOR, subtypes = ArmorSubtypes };
261 LocationTypes[INVTYPE_CHEST] = { i = 6, type = TYPE_ARMOR, subtypes = ArmorSubtypes };
262 LocationTypes[INVTYPE_LEGS] = { i = 7, type = TYPE_ARMOR, subtypes = ArmorSubtypes };
263 LocationTypes[INVTYPE_FEET] = { i = 8, type = TYPE_ARMOR, subtypes = ArmorSubtypes };
264 LocationTypes[INVTYPE_BODY] = { i = 9, type = TYPE_MISC };
265 LocationTypes[INVTYPE_RANGED] = { i = 10, type = TYPE_WEAPON, subtypes = WeaponSubtypes };
266 LocationTypes[INVTYPE_WEAPONMAINHAND] = { i = 11, type = TYPE_WEAPON, subtypes = WeaponSubtypes };
267 LocationTypes[INVTYPE_WAIST] = { i = 12, type = TYPE_ARMOR, subtypes = ArmorSubtypes };
268 LocationTypes[INVTYPE_HEAD] = { i = 13, type = TYPE_ARMOR, subtypes = ArmorSubtypes };
269 LocationTypes[GUN] = { i = 14, type = TYPE_WEAPON, subtype = SUBTYPE_WEAPON_GUN };
270 LocationTypes[INVTYPE_FINGER] = { i = 15, type = TYPE_MISC };
271 LocationTypes[INVTYPE_HAND] = { i = 16, type = TYPE_ARMOR, subtypes = ArmorSubtypes };
272 LocationTypes[INVTYPE_SHOULDER] = { i = 17, type = TYPE_ARMOR, subtypes = ArmorSubtypes };
273 LocationTypes[WAND] = { i = 18, type = TYPE_WEAPON, subtype = SUBTYPE_WEAPON_WAND };
274 LocationTypes[INVTYPE_TRINKET] = { i = 19, type = TYPE_MISC };
275 LocationTypes[INVTYPE_TABARD] = { i = 20, type = TYPE_MISC };
276 LocationTypes[INVTYPE_NECK] = { i = 21, type = TYPE_MISC };
277 LocationTypes[THROWN] = { i = 22, type = TYPE_WEAPON, subtype = SUBTYPE_WEAPON_THROWN };
278 LocationTypes[CROSSBOW] = { i = 23, type = TYPE_WEAPON, subtype = SUBTYPE_WEAPON_CROSSBOW };
279 LocationTypes[INVTYPE_RELIC] = { i = 24, type = TYPE_ARMOR, subtype = SUBTYPE_ARMOR_RELIC };
280  
281 local INVENTORY_SLOT_LIST = {
282 { name = "HeadSlot" },
283 { name = "NeckSlot" },
284 { name = "ShoulderSlot" },
285 { name = "BackSlot" },
286 { name = "ChestSlot" },
287 { name = "ShirtSlot" },
288 { name = "TabardSlot" },
289 { name = "WristSlot" },
290 { name = "HandsSlot" },
291 { name = "WaistSlot" },
292 { name = "LegsSlot" },
293 { name = "FeetSlot" },
294 { name = "Finger0Slot" },
295 { name = "Finger1Slot" },
296 { name = "Trinket0Slot" },
297 { name = "Trinket1Slot" },
298 { name = "MainHandSlot" },
299 { name = "SecondaryHandSlot" },
300 { name = "RangedSlot" },
301 };
302  
303 local ChatMessageTypes = {
304 "CHAT_MSG_SYSTEM",
305 "CHAT_MSG_SAY",
306 "CHAT_MSG_TEXT_EMOTE",
307 "CHAT_MSG_YELL",
308 "CHAT_MSG_WHISPER",
309 "CHAT_MSG_PARTY",
310 "CHAT_MSG_GUILD",
311 "CHAT_MSG_OFFICER",
312 "CHAT_MSG_CHANNEL",
313 "CHAT_MSG_RAID",
314 "CHAT_MSG_LOOT",
315 };
316  
317 local LOOTLINK_DROPDOWN_LIST = {
318 { name = SORT_NAME, sortType = "name" },
319 { name = SORT_RARITY, sortType = "rarity" },
320 { name = SORT_LOCATION, sortType = "location" },
321 { name = SORT_TYPE, sortType = "type" },
322 { name = SORT_SUBTYPE, sortType = "subtype" },
323 { name = SORT_LEVEL, sortType = "level" },
324 { name = SORT_BINDS, sortType = "binds" },
325 { name = SORT_UNIQUE, sortType = "unique" },
326 { name = SORT_ARMOR, sortType = "armor" },
327 { name = SORT_BLOCK, sortType = "block" },
328 { name = SORT_MINDAMAGE, sortType = "minDamage" },
329 { name = SORT_MAXDAMAGE, sortType = "maxDamage" },
330 { name = SORT_DPS, sortType = "DPS" },
331 { name = SORT_SPEED, sortType = "speed" },
332 { name = SORT_SLOTS, sortType = "slots" },
333 { name = SORT_SKILL, sortType = "skill" },
334 { name = SORT_SET, sortType = "set" },
335 };
336  
337 local LLS_RARITY_LIST = {
338 { name = ANY, value = nil },
339 { name = UNKNOWN, value = "ff40ffc0", r = 64 / 255, g = 255 / 255, b = 192 / 255 },
340 { name = POOR, value = "ff9d9d9d", r = 157 / 255, g = 157 / 255, b = 157 / 255 },
341 { name = COMMON, value = "ffffffff", r = 1, g = 1, b = 1 },
342 { name = UNCOMMON, value = "ff1eff00", r = 30 / 255, g = 1, b = 0 },
343 { name = RARE, value = "ff0070dd", r = 0, g = 70 / 255, b = 221 / 255 },
344 { name = EPIC, value = "ffa335ee", r = 163 / 255, g = 53 / 255, b = 238 / 255 },
345 { name = LEGENDARY, value = "ffff8000", r = 1, g = 128 / 255, b = 0 },
346 };
347  
348 local LLS_BINDS_LIST = {
349 { name = ANY, value = nil },
350 { name = DOES_NOT, value = BINDS_DOES_NOT_BIND },
351 { name = ON_EQUIP, value = BINDS_EQUIP },
352 { name = ON_PICKUP, value = BINDS_PICKUP },
353 { name = ON_USE, value = BINDS_USE },
354 };
355  
356 local LLS_TYPE_LIST = {
357 { name = ANY, value = nil },
358 { name = ARMOR, value = TYPE_ARMOR },
359 { name = CONTAINER, value = TYPE_CONTAINER },
360 { name = OTHER, value = TYPE_MISC },
361 { name = RECIPE, value = TYPE_RECIPE },
362 { name = SHIELD, value = TYPE_SHIELD },
363 { name = WEAPON, value = TYPE_WEAPON },
364 };
365  
366 local LLS_SUBTYPE_ARMOR_LIST = {
367 { name = ANY, value = nil },
368 { name = CLOTH, value = SUBTYPE_ARMOR_CLOTH },
369 { name = LEATHER, value = SUBTYPE_ARMOR_LEATHER },
370 { name = MAIL, value = SUBTYPE_ARMOR_MAIL },
371 { name = PLATE, value = SUBTYPE_ARMOR_PLATE },
372 { name = INVTYPE_RELIC, value = SUBTYPE_ARMOR_RELIC },
373 };
374  
375 local LLS_SUBTYPE_WEAPON_LIST = {
376 { name = ANY, value = nil },
377 { name = AXE, value = SUBTYPE_WEAPON_AXE },
378 { name = BOW, value = SUBTYPE_WEAPON_BOW },
379 { name = CROSSBOW, value = SUBTYPE_WEAPON_CROSSBOW },
380 { name = DAGGER, value = SUBTYPE_WEAPON_DAGGER },
381 { name = FISHING_POLE, value = SUBTYPE_WEAPON_FISHING_POLE },
382 { name = FIST_WEAPON, value = SUBTYPE_WEAPON_FIST_WEAPON },
383 { name = GUN, value = SUBTYPE_WEAPON_GUN },
384 { name = MACE, value = SUBTYPE_WEAPON_MACE },
385 { name = POLEARM, value = SUBTYPE_WEAPON_POLEARM },
386 { name = STAFF, value = SUBTYPE_WEAPON_STAFF },
387 { name = SWORD, value = SUBTYPE_WEAPON_SWORD },
388 { name = THROWN, value = SUBTYPE_WEAPON_THROWN },
389 { name = WAND, value = SUBTYPE_WEAPON_WAND },
390 };
391  
392 local LLS_SUBTYPE_SHIELD_LIST = {
393 { name = ANY, value = nil },
394 { name = BUCKLER, value = SUBTYPE_SHIELD_BUCKLER },
395 { name = SHIELD, value = SUBTYPE_SHIELD_SHIELD },
396 };
397  
398 local LLS_SUBTYPE_RECIPE_LIST = {
399 { name = ANY, value = nil },
400 { name = ALCHEMY, value = SUBTYPE_RECIPE_ALCHEMY },
401 { name = BLACKSMITHING, value = SUBTYPE_RECIPE_BLACKSMITHING },
402 { name = COOKING, value = SUBTYPE_RECIPE_COOKING },
403 { name = ENCHANTING, value = SUBTYPE_RECIPE_ENCHANTING },
404 { name = ENGINEERING, value = SUBTYPE_RECIPE_ENGINEERING },
405 { name = LEATHERWORKING, value = SUBTYPE_RECIPE_LEATHERWORKING },
406 { name = TAILORING, value = SUBTYPE_RECIPE_TAILORING },
407 };
408  
409 local LLS_SUBTYPE_CONTAINER_LIST = {
410 { name = ANY, value = nil },
411 { name = BAG, value = SUBTYPE_CONTAINER_BAG },
412 { name = AMMO_POUCH, value = SUBTYPE_CONTAINER_AMMO_POUCH },
413 { name = QUIVER, value = SUBTYPE_CONTAINER_QUIVER },
414 { name = ENCHANTING_BAG, value = SUBTYPE_CONTAINER_ENCHANTING_BAG },
415 { name = ENGINEERING_BAG, value = SUBTYPE_CONTAINER_ENGINEERING_BAG },
416 { name = HERB_BAG, value = SUBTYPE_CONTAINER_HERB_BAG },
417 { name = SOUL_BAG, value = SUBTYPE_CONTAINER_SOUL_BAG },
418 };
419  
420 local LLS_LOCATION_LIST = {
421 { name = ANY, },
422 { name = NONE, },
423 { name = INVTYPE_CLOAK, },
424 { name = INVTYPE_CHEST, },
425 { name = CROSSBOW, },
426 { name = INVTYPE_FEET, },
427 { name = INVTYPE_FINGER, },
428 { name = INVTYPE_HAND, },
429 { name = INVTYPE_HEAD, },
430 { name = INVTYPE_HOLDABLE, },
431 { name = GUN, },
432 { name = INVTYPE_LEGS, },
433 { name = INVTYPE_WEAPONMAINHAND, },
434 { name = INVTYPE_NECK, },
435 { name = INVTYPE_WEAPONOFFHAND, },
436 { name = INVTYPE_WEAPON, },
437 { name = INVTYPE_RANGED, },
438 { name = INVTYPE_BODY, },
439 { name = INVTYPE_SHOULDER, },
440 { name = INVTYPE_TABARD, },
441 { name = THROWN, },
442 { name = INVTYPE_TRINKET, },
443 { name = INVTYPE_2HWEAPON, },
444 { name = INVTYPE_WAIST, },
445 { name = WAND, },
446 { name = INVTYPE_WRIST, },
447 };
448  
449 local LLS_EXTRA_LIST = {
450 { name = ALL, },
451 { name = ONLY, },
452 { name = NONE, },
453 };
454  
455 local LLO_RARITY_LIST = {
456 { name = NONE },
457 { name = "|cff9d9d9d"..POOR },
458 { name = "|cffffffff"..COMMON },
459 { name = "|cff1eff00"..UNCOMMON },
460 { name = "|cff0070dd"..RARE },
461 { name = "|cffa335ee"..EPIC },
462 { name = "|cffff8000"..LEGENDARY },
463 };
464  
465 local lMagicCharacters = { };
466 lMagicCharacters["^"] = 1;
467 lMagicCharacters["$"] = 1;
468 lMagicCharacters["("] = 1;
469 lMagicCharacters[")"] = 1;
470 lMagicCharacters["%"] = 1;
471 lMagicCharacters["."] = 1;
472 lMagicCharacters["["] = 1;
473 lMagicCharacters["]"] = 1;
474 lMagicCharacters["*"] = 1;
475 lMagicCharacters["+"] = 1;
476 lMagicCharacters["-"] = 1;
477 lMagicCharacters["?"] = 1;
478  
479 local lBankBagIDs = { BANK_CONTAINER, 5, 6, 7, 8, 9, 10, };
480  
481 -- Item types that can't have enchants or "of" stat bonuses
482 local lNoBonuses = {
483 [""] = 2,
484 ["INVTYPE_TRINKET"] = 2,
485 ["INVTYPE_AMMO"] = 2,
486 ["INVTYPE_THROWN"] = 2,
487 ["INVTYPE_BAG"] = 2,
488 ["INVTYPE_TABARD"] = 2,
489 ["INVTYPE_BODY"] = 2,
490 ["INVTYPE_HOLDABLE"] = 1,
491 ["INVTYPE_FINGER"] = 1,
492 ["INVTYPE_WAIST"] = 1,
493 }
494  
495 local lRarityFilter = {
496 ff40ffc0 = -1,
497 ff9d9d9d = 0,
498 ffffffff = 1,
499 ff1eff00 = 2,
500 ff0070dd = 3,
501 ffa335ee = 4,
502 ffff8000 = 5,
503 };
504  
505 --------------------------------------------------------------------------------------------------
506 -- Global LootLink variables
507 --------------------------------------------------------------------------------------------------
508  
509 LOOTLINK_VERSION = 350; -- version 3.50
510  
511 LOOTLINK_ITEM_HEIGHT = 16;
512 LOOTLINK_ITEMS_SHOWN = 22;
513  
514 UIPanelWindows["LootLinkFrame"] = { area = "left", pushable = 11, whileDead = 1 };
515 UIPanelWindows["LootLinkSearchFrame"] = { area = "center", pushable = 0, whileDead = 1 };
516 UIPanelWindows["LootLinkOptionsFrame"] = { area = "center", pushable = 0, whileDead = 1 };
517  
518 --------------------------------------------------------------------------------------------------
519 -- Internal functions
520 --------------------------------------------------------------------------------------------------
521  
522 --
523 -- Functions with no other functional dependencies
524 --
525  
526 local function LootLink_MakeIntFromHexString(str)
527 local remain = str;
528 local amount = 0;
529 while( remain ~= "" ) do
530 amount = amount * 16;
531 local byteVal = string.byte(strupper(strsub(remain, 1, 1)));
532 if( byteVal >= string.byte("0") and byteVal <= string.byte("9") ) then
533 amount = amount + (byteVal - string.byte("0"));
534 elseif( byteVal >= string.byte("A") and byteVal <= string.byte("F") ) then
535 amount = amount + 10 + (byteVal - string.byte("A"));
536 end
537 remain = strsub(remain, 2);
538 end
539 return amount;
540 end
541  
542 local function LootLink_GetRGBFromHexColor(hexColor)
543 local red = LootLink_MakeIntFromHexString(strsub(hexColor, 3, 4)) / 255;
544 local green = LootLink_MakeIntFromHexString(strsub(hexColor, 5, 6)) / 255;
545 local blue = LootLink_MakeIntFromHexString(strsub(hexColor, 7, 8)) / 255;
546 return red, green, blue;
547 end
548  
549 local function LootLink_MouseIsOver(frame)
550 local x, y = GetCursorPosition();
551  
552 if( not frame ) then
553 return nil;
554 end
555  
556 x = x / frame:GetEffectiveScale();
557 y = y / frame:GetEffectiveScale();
558  
559 local left = frame:GetLeft();
560 local right = frame:GetRight();
561 local top = frame:GetTop();
562 local bottom = frame:GetBottom();
563  
564 if( not left or not right or not top or not bottom ) then
565 return nil;
566 end
567  
568 if( (x > left and x < right) and (y > bottom and y < top) ) then
569 return 1;
570 else
571 return nil;
572 end
573 end
574  
575 local function LootLink_GetDataVersion()
576 if( not LootLinkState or not LootLinkState.DataVersion ) then
577 return 0;
578 end
579 return LootLinkState.DataVersion;
580 end
581  
582 local function LootLink_SetDataVersion(version)
583 if( not LootLinkState ) then
584 LootLinkState = { };
585 end
586 if( not LootLinkState.DataVersion or LootLinkState.DataVersion < version ) then
587 LootLinkState.DataVersion = version;
588 end
589 end
590  
591 local function LootLink_AddServer(name)
592 if( not LootLinkState ) then
593 LootLinkState = { };
594 end
595  
596 if( not LootLinkState.Servers ) then
597 LootLinkState.Servers = 0;
598 LootLinkState.ServerNamesToIndices = { };
599 end
600  
601 if( not LootLinkState.ServerNamesToIndices[name] ) then
602 LootLinkState.ServerNamesToIndices[name] = LootLinkState.Servers;
603 LootLinkState.Servers = LootLinkState.Servers + 1;
604 end
605  
606 return LootLinkState.ServerNamesToIndices[name];
607 end
608  
609 local function LootLink_ConvertServerFormat(item)
610 if( item.servers ) then
611 local i, v;
612 local list;
613 for i, v in item.servers do
614 if( not list ) then
615 list = TEXT(i);
616 else
617 list = list.." "..i;
618 end
619 end
620 item.s = list;
621 item.servers = nil;
622 end
623 end
624  
625 local function LootLink_CheckItemServerRaw(item, serverIndex)
626 if( not item.s ) then
627 return nil;
628 end
629  
630 local server;
631 for server in string.gfind(item.s, "(%d+)") do
632 if( tonumber(server) == serverIndex ) then
633 return 1;
634 end
635 end
636  
637 return nil;
638 end
639  
640 local function LootLink_AddItemServer(item, serverIndex)
641 if( not item.s ) then
642 item.s = TEXT(serverIndex);
643 elseif( not LootLink_CheckItemServerRaw(item, serverIndex) ) then
644 item.s = item.s.." "..serverIndex;
645 end
646 end
647  
648 local function LootLink_EscapeString(string)
649 return string.gsub(string, "\"", "\\\"");
650 end
651  
652 local function LootLink_UnescapeString(string)
653 return string.gsub(string, "\\\"", "\"");
654 end
655  
656 local function LootLink_EscapePattern(string)
657 local result = "";
658 local remain = string;
659 local char;
660  
661 while( remain ~= "" ) do
662 char = strsub(remain, 1, 1);
663 if( lMagicCharacters[char] ) then
664 result = result.."%"..char;
665 else
666 result = result..char;
667 end
668 remain = strsub(remain, 2);
669 end
670  
671 return result;
672 end
673  
674 local function LootLink_CheckNumeric(string)
675 local remain = string;
676 local hasNumber;
677 local hasPeriod;
678 local char;
679  
680 while( remain ~= "" ) do
681 char = strsub(remain, 1, 1);
682 if( char >= "0" and char <= "9" ) then
683 hasNumber = 1;
684 elseif( char == "." and not hasPeriod ) then
685 hasPeriod = 1;
686 else
687 return nil;
688 end
689 remain = strsub(remain, 2);
690 end
691  
692 return hasNumber;
693 end
694  
695 local function LootLink_NameFromLink(link)
696 local name;
697 if( not link ) then
698 return nil;
699 end
700 for name in string.gfind(link, "|c%x+|Hitem:%d+:%d+:%d+:%d+|h%[(.-)%]|h|r") do
701 return name;
702 end
703 return nil;
704 end
705  
706 function LootLink_MoneyToggle(force)
707 if( lOriginal_GameTooltip_ClearMoney_Temp ) then
708 GameTooltip_ClearMoney = lOriginal_GameTooltip_ClearMoney_Temp;
709 lOriginal_GameTooltip_ClearMoney_Temp = nil;
710 elseif ( not force ) then
711 lOriginal_GameTooltip_ClearMoney_Temp = GameTooltip_ClearMoney;
712 GameTooltip_ClearMoney = LootLink_GameTooltip_ClearMoney_Temp;
713 else
714 DEFAULT_CHAT_FRAME:AddMessage( "LootLink_MoneyToggle just tried to break?" );
715 end
716 end
717  
718 local function LootLink_MatchType(left, right)
719 local lt = LocationTypes[left];
720 local _type;
721 local subtype;
722  
723 if( lt ) then
724 local subtypes;
725  
726 -- Check for weapon override of base type
727 if( WeaponSubtypes[right] ) then
728 _type = TYPE_WEAPON;
729 subtypes = WeaponSubtypes;
730 else
731 _type = lt.type;
732 subtypes = lt.subtypes;
733 end
734  
735 if( subtypes ) then
736 subtype = subtypes[right];
737 else
738 subtype = lt.subtype;
739 end
740 return nil, lt.i, _type, subtype;
741 end
742  
743 return 1, nil, TYPE_MISC, nil;
744 end
745  
746 local function LootLink_HideTooltipMoney()
747 LootLinkTooltipMoneyFrame:SetPoint("LEFT", "LootLinkTooltipTextLeft1", "LEFT", 0, 0);
748 LootLinkTooltipMoneyFrame:Hide();
749 end
750  
751 local function LootLink_SetTooltipMoney(frame, count, money, stack)
752 if( count and count > 1 ) then
753 money = money * count;
754 frame:AddLine(format(LOOTLINK_SELL_PRICE_N, count), 1.0, 1.0, 1.0);
755 elseif( stack ) then
756 frame:AddLine(LOOTLINK_SELL_PRICE_EACH, 1.0, 1.0, 1.0);
757 else
758 frame:AddLine(LOOTLINK_SELL_PRICE, 1.0, 1.0, 1.0);
759 end
760  
761 local numLines = frame:NumLines();
762 local moneyFrame = getglobal(frame:GetName().."MoneyFrame");
763 local newLine = frame:GetName().."TextLeft"..numLines;
764  
765 moneyFrame:SetPoint("LEFT", newLine, "RIGHT", 4, 0);
766 moneyFrame:Show();
767 MoneyFrame_Update(moneyFrame:GetName(), money);
768 frame:SetMinimumWidth(moneyFrame:GetWidth() + getglobal(newLine):GetWidth() - 10);
769 end
770  
771 local function LL_SearchData(item, tag)
772 if( item.d ) then
773 local s, e;
774 local value;
775  
776 s, e, value = string.find(item.d, tag.."(.-)·")
777 if( value ) then
778 return tonumber(value);
779 end
780 end
781 return nil;
782 end
783  
784 --
785 -- Functions that are dependent on preceding local functions, ordered appropriately
786 --
787  
788 local function LootLink_GetName( elem )
789 if ( type(elem) == "table" ) then
790 return elem[1], elem[2];
791 else
792 return elem;
793 end
794 end
795  
796 local function LootLink_GetValue( elem, index, link )
797 local name;
798 if ( type(elem) == "table" ) then
799 index = elem[2];
800 elem = elem[1];
801 end
802 if ( link and ItemLinks[elem] and ItemLinks[elem].i ~= link ) then
803 if ( ItemLinks[elem].m ) then
804 for k, v in ItemLinks[elem].m do
805 if v.i == link then
806 index = k;
807 break;
808 end
809 end
810 if ( not index ) then
811 --DEFAULT_CHAT_FRAME:AddMessage( elem.." "..link.." doesn't appear to exist yet?" );
812 return nil;
813 end
814 end
815 end
816 if ( index and ItemLinks[elem] and ItemLinks[elem].m ) then
817 return ItemLinks[elem].m[index], index;
818 elseif ( ItemLinks[elem] ) then
819 return ItemLinks[elem];
820 else
821 return nil;
822 end
823 end
824  
825 local function LootLink_InitSizes(serverIndex)
826 local index;
827 local value;
828  
829 lItemLinksSizeTotal = 0;
830 lItemLinksSizeServer = 0;
831  
832 for index, value in ItemLinks do
833 lItemLinksSizeTotal = lItemLinksSizeTotal + 1;
834 if( LootLink_CheckItemServer(value, serverIndex) ) then
835 lItemLinksSizeServer = lItemLinksSizeServer + 1;
836 end
837 end
838 end
839  
840 local function LootLink_GetSize(serverIndex)
841 if( not serverIndex ) then
842 return lItemLinksSizeTotal;
843 end
844 return lItemLinksSizeServer;
845 end
846  
847 local function LootLink_Status()
848 DEFAULT_CHAT_FRAME:AddMessage(format(LOOTLINK_STATUS_HEADER, LOOTLINK_VERSION / 100));
849 if( LootLinkState ) then
850 DEFAULT_CHAT_FRAME:AddMessage(format(LOOTLINK_DATA_VERSION, LootLink_GetSize(), LootLink_GetSize(lServerIndex), lServer, LootLink_GetDataVersion() / 100));
851 if( LootLinkState.HideInfo ) then
852 DEFAULT_CHAT_FRAME:AddMessage(LOOTLINK_INFO_HIDDEN);
853 else
854 DEFAULT_CHAT_FRAME:AddMessage(LOOTLINK_INFO_SHOWN);
855 end
856 if( LootLinkState.LightMode ) then
857 DEFAULT_CHAT_FRAME:AddMessage(LOOTLINK_LIGHT_MODE);
858 else
859 DEFAULT_CHAT_FRAME:AddMessage(LOOTLINK_FULL_MODE);
860 end
861 else
862 DEFAULT_CHAT_FRAME:AddMessage(LOOTLINK_INFO_SHOWN);
863 end
864 if( lScanAuction ) then
865 DEFAULT_CHAT_FRAME:AddMessage(LOOTLINK_SCHEDULED_AUCTION_SCAN);
866 end
867 end
868  
869 local function LootLink_GetHyperlink(name, index)
870 local itemLink = LootLink_GetValue( name, index );
871 if( itemLink and itemLink.i --[[and LootLink_CheckItemServer(itemLink, lServerIndex)]] ) then
872 -- Remove instance-specific data that we captured from the link we return
873 local item = string.gsub(itemLink.i, "(%d+):(%d+):(%d+):(%d+)", "%1:%2:%3:0");
874 return "item:"..item;
875 end
876 return nil;
877 end
878  
879 local function LootLink_GetLink(name, index)
880 local itemLink = LootLink_GetValue(name, index);
881 if( itemLink and itemLink.c and itemLink.i --[[and (IsAltKeyDown() or LootLink_CheckItemServer(itemLink, lServerIndex))]] ) then
882 local link = "|c"..itemLink.c.."|H"..LootLink_GetHyperlink(name, index).."|h["..name.."]|h|r";
883 return link;
884 end
885 return nil;
886 end
887  
888 local function LootLink_GetSet(set)
889 if ( not LootLinkState.sets ) then
890 LootLinkState.sets = {}
891 end
892 local sets = LootLinkState.sets;
893 for k, v in sets do
894 if ( v == set ) then
895 return k;
896 end
897 end
898 tinsert(sets, set);
899 return getn(sets);
900 end
901  
902 function LootLink_BuildSearchData(name, value, alternate)
903 local state, itemLink, loop, index, field, left, right, iStart, iEnd, val1, val2, val3, foundRequires, _type, subtype = STATE_NAME, LootLink_GetHyperlink(name, alternate);
904  
905 if( not itemLink ) then
906 return nil;
907 end
908  
909 -- This is the only place the tooltip hyperlink is set directly, therefore
910 -- this should only be called when we know that the tooltip will be valid
911  
912 -- Protect money frame while we set hidden tooltip
913 LootLink_MoneyToggle();
914 LLHiddenTooltip:SetOwner(WorldFrame,"ANCHOR_NONE");
915 LLHiddenTooltip:SetHyperlink(itemLink);
916 LootLink_MoneyToggle(1);
917  
918 -- Double check that the data is good
919 local realname, link, quality, level, _, _, _, count = GetItemInfo(itemLink);
920 if ( not realname ) then
921 LootLink_ScheduleItem(name,LootLink_GetValue(name,alternate).i);
922 return nil;
923 else
924 local tooltipname = LLHiddenTooltipTextLeft1:GetText();
925 if ( realname ~= tooltipname ) then
926 -- if this returns, we're in trouble.
927 return nil;
928 end
929 end
930  
931 local savedD = value.d;
932 local savedT = value.t;
933  
934 value.d = "";
935 if( not LootLinkState.LightMode ) then
936 value.t = "";
937 end
938  
939 value.c = string.gsub( ITEM_QUALITY_COLORS[quality].hex, "|c(.+)", "%1" );
940  
941 for index = 1, 30, 1 do
942 field = getglobal("LLHiddenTooltipTextLeft"..index);
943 if( field and field:IsShown() ) then
944 left = field:GetText();
945 else
946 left = nil;
947 end
948  
949 field = getglobal("LLHiddenTooltipTextRight"..index);
950 if( field and field:IsShown() ) then
951 right = field:GetText();
952 else
953 right = nil;
954 end
955  
956 if( left ) then
957 if( not LootLinkState.LightMode ) then
958 -- cull set data to show 0/# and don't save durability
959 left = string.gsub( left, "(.+ %()%d+(%/%d%))", "%10%2" );
960 if ( string.sub( left, 1, 10 ) ~= "Durability" ) then
961 value.t = value.t..left.."·";
962 end
963 end
964 else
965 left = "";
966 end
967 if( right ) then
968 if( not LootLinkState.LightMode ) then
969 value.t = value.t..right.."·";
970 end
971 else
972 right = "";
973 end
974  
975 loop = 1;
976 while( loop ) do
977 if( state == STATE_NAME ) then
978 state = STATE_BOUND;
979 loop = nil;
980 elseif( state == STATE_BOUND ) then
981 iStart, iEnd, val1 = string.find(left, "Binds when (.+)");
982 if( val1 ) then
983 if( val1 == "equipped" ) then
984 value.d = value.d.."bi"..BINDS_EQUIP.."·";
985 elseif( val1 == "picked up" ) then
986 value.d = value.d.."bi"..BINDS_PICKUP.."·";
987 elseif( val1 == "used" ) then
988 value.d = value.d.."bi"..BINDS_USED.."·";
989 end
990 loop = nil;
991 else
992 value.d = value.d.."bi"..BINDS_DOES_NOT_BIND.."·";
993 end
994 state = STATE_UNIQUE;
995 elseif( state == STATE_UNIQUE ) then
996 if( string.find(left, "Unique") ) then
997 value.d = value.d.."un1·";
998 loop = nil;
999 end
1000 state = STATE_LOCATION;
1001 elseif( state == STATE_LOCATION ) then
1002 local location;
1003 loop, location, _type, subtype = LootLink_MatchType(left, right);
1004 if( location ) then
1005 value.d = value.d.."lo"..location.."·";
1006 end
1007 if( _type == TYPE_WEAPON ) then
1008 state = STATE_DAMAGE;
1009 elseif( _type == TYPE_ARMOR or _type == TYPE_SHIELD ) then
1010 state = STATE_ARMOR;
1011 else
1012 state = STATE_CONTAINER;
1013 end
1014 elseif( state == STATE_DAMAGE ) then
1015 iStart, iEnd, val1, val2 = string.find(left, "(%d+) %- (%d+) Damage");
1016 if( val1 and val2 ) then
1017 value.d = value.d.."mi"..val1.."·ma"..val2.."·";
1018 end
1019 iStart, iEnd, val1 = string.find(right, "Speed (.+)");
1020 if( val1 ) then
1021 value.d = value.d.."sp"..val1.."·";
1022 end
1023 state = STATE_DPS;
1024 loop = nil;
1025 elseif( state == STATE_DPS ) then
1026 iStart, iEnd, val1 = string.find(left, "%((.+) damage per second%)");
1027 if( val1 ) then
1028 value.d = value.d.."dp"..val1.."·";
1029 end
1030 state = STATE_REQUIRES;
1031 loop = nil;
1032 elseif( state == STATE_ARMOR ) then
1033 iStart, iEnd, val1 = string.find(left, "(%d+) Armor");
1034 if( val1 ) then
1035 value.d = value.d.."ar"..val1.."·";
1036 end
1037 if( _type == TYPE_SHIELD ) then
1038 state = STATE_BLOCK;
1039 else
1040 state = STATE_REQUIRES;
1041 end
1042 loop = nil;
1043 elseif( state == STATE_BLOCK ) then
1044 iStart, iEnd, val1 = string.find(left, "(%d+) Block");
1045 if( val1 ) then
1046 value.d = value.d.."bl"..val1.."·";
1047 end
1048 state = STATE_REQUIRES;
1049 loop = nil;
1050 elseif( state == STATE_CONTAINER ) then
1051 iStart, iEnd, val1, val2 = string.find(left, "(%d+) Slot (.+)");
1052 if( val1 ) then
1053 _type = TYPE_CONTAINER;
1054 subtype = ContainerSubtypes[val2];
1055 value.d = value.d.."sl"..val1.."·";
1056 loop = nil;
1057 end
1058 state = STATE_REQUIRES;
1059 elseif( state == STATE_REQUIRES ) then
1060 iStart, iEnd, val1 = string.find(left, "Requires (.+)");
1061 if( val1 ) then
1062 iStart, iEnd, val2 = string.find(val1, "Level (%d+)");
1063 if( val2 ) then
1064 value.d = value.d.."le"..val2.."·";
1065 else
1066 iStart, iEnd, val2, val3 = string.find(val1, "(.+) %((%d+)%)");
1067 if( val2 and val3 ) then
1068 val1 = RecipeSubtypes[val2];
1069 if( val1 and _type == TYPE_MISC ) then
1070 _type = TYPE_RECIPE;
1071 subtype = val1;
1072 value.d = value.d.."sk"..val3.."·";
1073 end
1074 end
1075 end
1076 else
1077 state = STATE_SPACE;
1078 end
1079 loop = nil;
1080 elseif( state == STATE_SPACE ) then
1081 if ( left == tooltipSpace ) then
1082 state = STATE_SET;
1083 end
1084 loop = nil;
1085 elseif( state == STATE_SET ) then
1086 if ( left ~= "" ) then
1087 iStart, iEnd, val1, val2 = string.find(left, "(.+) %(%d+%/(%d+)%)");
1088 if( val2 ) then
1089 local set = LootLink_GetSet(val1);
1090 value.d = value.d.."se"..set.."·";
1091 state = STATE_FINISH;
1092 end
1093 end
1094 loop = nil;
1095 elseif( state == STATE_FINISH ) then
1096 loop = nil;
1097 end
1098 end
1099 end
1100 if( _type ) then
1101 value.d = value.d.."ty".._type.."·";
1102 end
1103 if( subtype ) then
1104 value.d = value.d.."su"..subtype.."·";
1105 end
1106  
1107 if ( realname and name ~= realname ) then
1108 if ( not ItemLinks[realname] ) then
1109 ItemLinks[realname] = {};
1110 ItemLinks[realname] = value;
1111 else
1112 if ( ItemLinks[realname].i ~= value.i and ItemLinks[realname].m ) then
1113 local found;
1114 for k, v in ItemLinks[realname].m do
1115 if v.i == value.i then
1116 found = 1;
1117 break;
1118 end
1119 end
1120 if ( not found ) then
1121 tinsert( ItemLinks[realname].m, value );
1122 end
1123 end
1124 end
1125 end
1126  
1127 if ( savedD ~= value.d or savedT ~= value.t ) then
1128 return 2;
1129 end
1130 return 1;
1131 end
1132  
1133 local function BuildUsabilityData(data)
1134 local nSkills;
1135 local iSkill;
1136 local HeaderData = { };
1137 local name, header, isExpanded, rank;
1138 local Collapse = { };
1139 local nToCollapse = 0;
1140 local iCollapse;
1141  
1142 data.class = UnitClass("player");
1143 data.race = UnitRace("player");
1144 data.level = UnitLevel("player");
1145 data.skills = { };
1146  
1147 -- We need to expand all of the skills, but first want to save off their state
1148 nSkills = GetNumSkillLines();
1149 for iSkill = 1, nSkills do
1150 local name, header, isExpanded, rank = GetSkillLineInfo(iSkill);
1151 if( header and not isExpanded ) then
1152 -- Since we don't know the final index for this item yet, we'll store it by name
1153 HeaderData[name] = 0;
1154 end
1155 end
1156  
1157 -- Now expand everything and save off our known skills
1158 ExpandSkillHeader(0);
1159 nSkills = GetNumSkillLines()
1160 for iSkill = 1, nSkills do
1161 local name, header, isExpanded, rank = GetSkillLineInfo(iSkill);
1162 if( not header ) then
1163 data.skills[name] = rank;
1164 elseif( HeaderData[name] ) then
1165 -- We now know the final index for this header item
1166 HeaderData[name] = iSkill;
1167 end
1168 end
1169  
1170 -- Finally, return the skills page to its original state
1171 for name, iSkill in HeaderData do
1172 Collapse[nToCollapse + 1] = iSkill;
1173 nToCollapse = nToCollapse + 1;
1174 end
1175 if( nToCollapse > 0 ) then
1176 table.sort(Collapse);
1177 for iCollapse = nToCollapse, 1, -1 do
1178 CollapseSkillHeader(Collapse[iCollapse]);
1179 end
1180 end
1181 end
1182  
1183 local function LootLink_GetSkillRank(ud, _type, subtype, location)
1184 local entry = lTypeAndSubtypeToSkill[_type][subtype];
1185  
1186 if( type(entry) == "table" ) then
1187 -- Two-handed vs. One-handed weapon
1188 if( location ) then
1189 if( location == 3 ) then
1190 return ud.skills[entry[1]];
1191 else
1192 return ud.skills[entry[0]];
1193 end
1194 else
1195 return nil;
1196 end
1197 else
1198 -- Everything else
1199 return ud.skills[entry];
1200 end
1201 end
1202  
1203 local function LootLink_SetHyperlink(tooltip, name, link, index)
1204 -- If the link isn't in the local cache, it may not be valid
1205 if ( not link ) then
1206 return nil;
1207 end
1208 local value = ItemLinks[name];
1209 if ( index and value.m ) then
1210 value = value.m[index];
1211 end
1212 if( not GetItemInfo(link) ) then
1213 -- To avoid disconnects, we'll create our own lame tooltip for these
1214 if( value ) then
1215 local extraSkip = 0;
1216 local lines = 1;
1217 local usabilityData;
1218  
1219 -- Name, in rarity color
1220 tooltip:SetText("|c"..value.c..name.."|r");
1221  
1222 -- Binds on equip, binds on pickup
1223 local binds = LL_SearchData(value, "bi");
1224 if( binds == BINDS_EQUIP ) then
1225 tooltip:AddLine(ITEM_BIND_ON_EQUIP, 1, 1, 1);
1226 lines = lines + 1;
1227 elseif( binds == BINDS_PICKUP ) then
1228 tooltip:AddLine(ITEM_BIND_ON_PICKUP, 1, 1, 1);
1229 lines = lines + 1;
1230 elseif( binds == BINDS_USED ) then
1231 tooltip:AddLine(ITEM_BIND_ON_USE, 1, 1, 1);
1232 lines = lines + 1;
1233 end
1234  
1235 -- Unique?
1236 local unique = LL_SearchData(value, "un");
1237 if( unique ) then
1238 tooltip:AddLine("Unique", 1, 1, 1);
1239 lines = lines + 1;
1240 end
1241  
1242 local _type = LL_SearchData(value, "ty");
1243 local subtype = LL_SearchData(value, "su");
1244  
1245 -- Equip location and type/subtype
1246 local location = LL_SearchData(value, "lo");
1247 if( location ) then
1248 local subtypes;
1249 local name;
1250 for i, v in LocationTypes do
1251 if( v.i == location ) then
1252 name = i;
1253 subtypes = v.subtypes;
1254 break;
1255 end
1256 end
1257 if( name ) then
1258 tooltip:AddLine(name, 1, 1, 1);
1259 lines = lines + 1;
1260 if( subtype ) then
1261 if( _type == TYPE_WEAPON ) then
1262 subtypes = WeaponSubtypes;
1263 end
1264 if( subtypes ) then
1265 for i, v in subtypes do
1266 if( v == subtype ) then
1267 if( i == name ) then
1268 local line = getglobal(tooltip:GetName().."TextLeft"..lines);
1269  
1270 if( not usabilityData ) then
1271 usabilityData = { };
1272 BuildUsabilityData(usabilityData);
1273 end
1274 if( not LootLink_GetSkillRank(usabilityData, _type, subtype, location) ) then
1275 line:SetTextColor(1, 0, 0);
1276 end
1277 else
1278 local line = getglobal(tooltip:GetName().."TextRight"..lines);
1279 line:SetText(i);
1280  
1281 if( not usabilityData ) then
1282 usabilityData = { };
1283 BuildUsabilityData(usabilityData);
1284 end
1285 if( LootLink_GetSkillRank(usabilityData, _type, subtype, location) ) then
1286 line:SetTextColor(1, 1, 1);
1287 else
1288 line:SetTextColor(1, 0, 0);
1289 end
1290  
1291 line:Show();
1292 extraSkip = extraSkip + 1;
1293 break;
1294 end
1295 end
1296 end
1297 end
1298 end
1299 end
1300 end
1301  
1302 -- Now do type specific data
1303 if( _type == TYPE_ARMOR ) then
1304 local armor = LL_SearchData(value, "ar");
1305 if( armor ) then
1306 tooltip:AddLine(armor.." Armor", 1, 1, 1);
1307 lines = lines + 1;
1308 end
1309 elseif( _type == TYPE_WEAPON ) then
1310 local min = LL_SearchData(value, "mi");
1311 local max = LL_SearchData(value, "ma");
1312 local speed = LL_SearchData(value, "sp");
1313 local dps = LL_SearchData(value, "dp");
1314  
1315 if( min and max ) then
1316 tooltip:AddLine(min.." - "..max.." Damage", 1, 1, 1);
1317 lines = lines + 1;
1318 if( speed ) then
1319 local line = getglobal(tooltip:GetName().."TextRight"..lines);
1320 line:SetText(format("Speed %.2f", tonumber(speed)));
1321 line:SetTextColor(1, 1, 1);
1322 line:Show();
1323 extraSkip = extraSkip + 1;
1324 end
1325 end
1326 if( dps ) then
1327 tooltip:AddLine("("..dps.." damage per second)", 1, 1, 1);
1328 lines = lines + 1;
1329 end
1330 elseif( _type == TYPE_SHIELD ) then
1331 local armor = LL_SearchData(value, "ar");
1332 local block = LL_SearchData(value, "bl");
1333 if( armor ) then
1334 tooltip:AddLine(armor.." Armor", 1, 1, 1);
1335 lines = lines + 1;
1336 end
1337 if( block ) then
1338 tooltip:AddLine(block.." Block", 1, 1, 1);
1339 lines = lines + 1;
1340 end
1341 elseif( _type == TYPE_RECIPE ) then
1342 local skill = LL_SearchData(value, "sk");
1343 if( skill and subtype ) then
1344 for i, v in RecipeSubtypes do
1345 if( v == subtype ) then
1346 if( not usabilityData ) then
1347 usabilityData = { };
1348 BuildUsabilityData(usabilityData);
1349 end
1350 local rank = LootLink_GetSkillRank(usabilityData, _type, subtype, location);
1351 if( not rank or rank < skill ) then
1352 tooltip:AddLine("Requires "..i.." ("..skill..")", 1, 0, 0);
1353 else
1354 tooltip:AddLine("Requires "..i.." ("..skill..")", 1, 1, 1);
1355 end
1356 lines = lines + 1;
1357 break;
1358 end
1359 end
1360 end
1361 elseif( _type == TYPE_CONTAINER ) then
1362 local slots = LL_SearchData(value, "sl");
1363 if( slots ) then
1364 local subtype = LL_SearchData(value, "su") or 0;
1365 local bag = lTypeAndSubtypeToSkill[_type][subtype]; -- repurposed skill table, fix later?
1366 tooltip:AddLine(slots.." Slot "..bag, 1, 1, 1);
1367 lines = lines + 1;
1368 end
1369 end
1370  
1371 local level = LL_SearchData(value, "le");
1372  
1373 -- Now add any extra text data that we have
1374 if( value.t ) then
1375 local skip = lines + extraSkip;
1376 local piece;
1377 for piece in string.gfind(value.t, "(.-)·") do
1378 if( lines < 29 ) then
1379 if( skip == 0 ) then
1380 if( string.find(piece, "Requires Level .*") ) then
1381 if( level and tonumber(level) > UnitLevel("player") ) then
1382 tooltip:AddLine(piece, 1, 0, 0, 1, 1);
1383 else
1384 tooltip:AddLine(piece, 1, 1, 1, 1, 1);
1385 end
1386 elseif( string.find(piece, ":") ) then
1387 if( string.find(piece, "^Class") ) then
1388 if( string.find(piece, "^Class.*"..UnitClass("player")) ) then
1389 tooltip:AddLine(piece, 1, 1, 1, 1, 1);
1390 else
1391 tooltip:AddLine(piece, 1, 0, 0, 1, 1);
1392 end
1393 else
1394 tooltip:AddLine(piece, 0, 1, 0, 1, 1);
1395 end
1396 elseif( string.find(piece, "\"") or string.find(piece, "%(%d+/%d+%)") ) then
1397 tooltip:AddLine(piece, 1, 0.8235, 0, 1, 1);
1398 elseif( string.find(piece, "^ ") ) then
1399 tooltip:AddLine(piece, 0.5, 0.5, 0.5, 1, 1);
1400 else
1401 tooltip:AddLine(piece, 1, 1, 1, 1, 1);
1402 end
1403 lines = lines + 1;
1404 else
1405 skip = skip - 1;
1406 end
1407 end
1408 end
1409 end
1410  
1411 -- And, after all that, let the user know that we faked this tooltip
1412 if( lines < 30 ) then
1413 tooltip:AddLine("|cff40ffc0<"..LOOTLINK_TOOLTIP_GENERATED..">|r");
1414 lines = lines + 1;
1415 end
1416  
1417 if( lines < 30 and not LootLink_CheckItemServer(value, lServerIndex) ) then
1418 tooltip:AddLine("|cff40ffc0<"..LOOTLINK_TOOLTIP_SERVER..">|r");
1419 lines = lines + 1;
1420 end
1421  
1422 -- Finally, show the tooltip, which adjusts its size
1423 tooltip:Show();
1424 end
1425 else
1426 -- Get the actual tooltip from the cache
1427 tooltip:SetHyperlink(link);
1428  
1429 -- After setting the tooltip, parse its data
1430 LootLink_ScheduleItem(name, value.i);
1431 --LootLink_BuildSearchData(name, value, index);
1432  
1433 if( not LootLink_ValidateItem(name, link) ) then
1434 tooltip:AddLine("|cff40ffc0<"..LOOTLINK_TOOLTIP_BAD_ITEM..">|r");
1435 elseif( not LootLink_CheckItemServerRaw(value, lServerIndex) ) then
1436 tooltip:AddLine("|cff40ffc0<"..LOOTLINK_TOOLTIP_SERVER..">|r");
1437 --LootLink_AddItemServer(value, lServerIndex);
1438 --lItemLinksSizeServer = lItemLinksSizeServer + 1;
1439 --return 1;
1440 end
1441 end
1442 end
1443  
1444 local function LootLink_SetTitle()
1445 local lootLinkTitle = getglobal("LootLinkTitleText");
1446 local total = LootLink_GetSize(lServerIndex);
1447 local size;
1448  
1449 if( not DisplayIndices ) then
1450 size = total;
1451 else
1452 size = DisplayIndices.onePastEnd - 1;
1453 end
1454 if( size < total ) then
1455 if( size == 1 ) then
1456 lootLinkTitle:SetText(TEXT(LOOTLINK_TITLE_FORMAT_PARTIAL_SINGULAR));
1457 else
1458 lootLinkTitle:SetText(format(TEXT(LOOTLINK_TITLE_FORMAT_PARTIAL_PLURAL), size));
1459 end
1460 else
1461 if( size == 1 ) then
1462 lootLinkTitle:SetText(TEXT(LOOTLINK_TITLE_FORMAT_SINGULAR));
1463 else
1464 lootLinkTitle:SetText(format(TEXT(LOOTLINK_TITLE_FORMAT_PLURAL), size));
1465 end
1466 end
1467 end
1468  
1469 local function LootLink_MatchesSearch(name, value, ud)
1470 if( not value ) then
1471 return nil;
1472 end
1473 if( LootLinkState ) then
1474 if ( LootLinkState.spoof and name ) then
1475 if ( not LootLink_ValidateItem( name, value.i ) ) then
1476 return nil;
1477 end
1478 end
1479 if ( LootLinkState.server ) then
1480 if ( not LootLink_CheckItemServer(value, lServerIndex) ) then
1481 return nil;
1482 end
1483 end
1484 if ( LootLinkState.rarityfilter ) then
1485 if ( value.c and lRarityFilter[value.c] < LootLinkState.rarityfilter ) then
1486 return nil;
1487 end
1488 end
1489 if ( LootLinkState.noname ) then
1490 if ( ItemLinks[name] and ItemLinks[name].i and ItemLinks[name].i ~= value.i ) then
1491 return nil;
1492 end
1493 else
1494 if ( LootLinkState.novariants ) then
1495 if ( string.gsub(value.i, "%d+:%d+:(%d+):%d+", "%1") ~="0" and ItemLinks[name] and ItemLinks[name].i and ItemLinks[name].i ~= value.i ) then
1496 return nil;
1497 end
1498 end
1499 if ( LootLinkState.enchants ) then
1500 if ( string.gsub(value.i, "%d+:(%d+):%d+:%d+", "%1") ~= "0" ) then
1501 return nil;
1502 end
1503 end
1504 end
1505 end
1506 if( not LootLinkFrame.SearchParams or not name ) then
1507 return 1;
1508 end
1509  
1510 if( value.d ) then
1511 local sp = LootLinkFrame.SearchParams;
1512  
1513 if( sp.server ) then
1514 if ( not LootLink_CheckItemServer(value, lServerIndex) ) then
1515 return nil;
1516 end
1517 end
1518  
1519 if( sp.spoof ) then
1520 if ( LootLink_ValidateItem( name, value.i ) ) then
1521 return nil;
1522 end
1523 end
1524  
1525 if( sp.text ) then
1526 if( not value.t ) then
1527 return nil;
1528 end
1529 if( not string.find(string.lower(value.t), string.lower(sp.text), 1, sp.plain) ) then
1530 return nil;
1531 end
1532 end
1533  
1534 if( sp.name ) then
1535 if( not string.find(string.lower(name), string.lower(sp.name), 1, sp.plain) ) then
1536 return nil;
1537 end
1538 end
1539  
1540 if( sp.rarity ) then
1541 if( LLS_RARITY_LIST[sp.rarity].value ~= value.c ) then
1542 return nil;
1543 end
1544 end
1545  
1546 if( sp.binds ) then
1547 if( LLS_BINDS_LIST[sp.binds].value ~= LL_SearchData(value, "bi") ) then
1548 return nil;
1549 end
1550 end
1551  
1552 if( sp.unique ) then
1553 if( sp.unique ~= LL_SearchData(value, "un") ) then
1554 return nil;
1555 end
1556 end
1557  
1558 if( sp.usable ) then
1559 local _type = LL_SearchData(value, "ty");
1560 local subtype = LL_SearchData(value, "su");
1561 local level = LL_SearchData(value, "le");
1562 local skill = LL_SearchData(value, "sk");
1563  
1564 -- Check for the required skill
1565 if( _type ) then
1566 if( subtype ) then
1567 local rank = LootLink_GetSkillRank(ud, _type, subtype, LL_SearchData(value, "lo"));
1568 if( not rank or (skill and skill > rank) ) then
1569 return nil;
1570 end
1571 end
1572 end
1573  
1574 -- Check for the required class
1575 if( value.t and string.find(value.t, "·Class") and not string.find(value.t, "·Class.*"..UnitClass("player")) ) then
1576 return nil;
1577 end
1578  
1579 -- Check level requirement
1580 if( level and level > ud.level ) then
1581 return nil;
1582 end
1583 end
1584  
1585 if( sp.location ) then
1586 local location = LL_SearchData(value, "lo");
1587  
1588 if( sp.location == 2 ) then
1589 if( location ) then
1590 return nil;
1591 end
1592 elseif( sp.location ~= 1 ) then
1593 if( LocationTypes[LLS_LOCATION_LIST[sp.location].name].i ~= location ) then
1594 return nil;
1595 end
1596 end
1597 end
1598  
1599 if( sp.minLevel ) then
1600 local level = LL_SearchData(value, "le");
1601 if( not level or level < sp.minLevel ) then
1602 return nil;
1603 end
1604 end
1605  
1606 if( sp.maxLevel ) then
1607 local level = LL_SearchData(value, "le");
1608 if( level and level > sp.maxLevel ) then
1609 return nil;
1610 end
1611 end
1612  
1613 if( sp.set ) then
1614 local set = LL_SearchData(value, "se");
1615 if( not set ) then
1616 return nil;
1617 end
1618 end
1619  
1620 if( sp.type ) then
1621 local _type = LLS_TYPE_LIST[sp.type].value;
1622 if( _type ~= LL_SearchData(value, "ty") ) then
1623 return nil;
1624 end
1625 if( sp.subtype ) then
1626 local subtype;
1627 if( _type == TYPE_ARMOR ) then
1628 subtype = LLS_SUBTYPE_ARMOR_LIST[sp.subtype].value;
1629 elseif( _type == TYPE_SHIELD ) then
1630 subtype = LLS_SUBTYPE_SHIELD_LIST[sp.subtype].value;
1631 elseif( _type == TYPE_WEAPON ) then
1632 subtype = LLS_SUBTYPE_WEAPON_LIST[sp.subtype].value;
1633 elseif( _type == TYPE_RECIPE ) then
1634 subtype = LLS_SUBTYPE_RECIPE_LIST[sp.subtype].value;
1635 elseif( _type == TYPE_CONTAINER ) then
1636 subtype = LLS_SUBTYPE_CONTAINER_LIST[sp.subtype].value;
1637 end
1638 if( subtype and subtype ~= LL_SearchData(value, "su") ) then
1639 return nil;
1640 end
1641 end
1642  
1643 if( _type == TYPE_WEAPON ) then
1644 if( sp.minMinDamage ) then
1645 local damage = LL_SearchData(value, "mi");
1646 if( not damage or damage < sp.minMinDamage ) then
1647 return nil;
1648 end
1649 end
1650  
1651 if( sp.minMaxDamage ) then
1652 local damage = LL_SearchData(value, "ma");
1653 if( not damage or damage < sp.minMaxDamage ) then
1654 return nil;
1655 end
1656 end
1657  
1658 if( sp.maxSpeed ) then
1659 local speed = LL_SearchData(value, "sp");
1660 if( not speed or speed > sp.maxSpeed ) then
1661 return nil;
1662 end
1663 end
1664  
1665 if( sp.minDPS ) then
1666 local DPS = LL_SearchData(value, "dp");
1667 if( not DPS or DPS < sp.minDPS ) then
1668 return nil;
1669 end
1670 end
1671 elseif( _type == TYPE_ARMOR or _type == TYPE_SHIELD ) then
1672 if( sp.minArmor ) then
1673 local armor = LL_SearchData(value, "ar");
1674 if( not armor or armor < sp.minArmor ) then
1675 return nil;
1676 end
1677 end
1678  
1679 if( _type == TYPE_SHIELD ) then
1680 if( sp.minBlock ) then
1681 local block = LL_SearchData(value, "bl");
1682 if( not block or block < sp.minBlock ) then
1683 return nil;
1684 end
1685 end
1686 end
1687 elseif( _type == TYPE_CONTAINER ) then
1688 if( sp.minSlots ) then
1689 local slots = LL_SearchData(value, "sl");
1690 if( not slots or slots < sp.minSlots ) then
1691 return nil;
1692 end
1693 end
1694 elseif( _type == TYPE_RECIPE ) then
1695 if( sp.minSkill ) then
1696 local skill = LL_SearchData(value, "sk");
1697 if( not skill or skill < sp.minSkill ) then
1698 return nil;
1699 end
1700 end
1701  
1702 if( sp.maxSkill ) then
1703 local skill = LL_SearchData(value, "sk");
1704 if( not skill or skill > sp.maxSkill ) then
1705 return nil;
1706 end
1707 end
1708 end
1709 end
1710 else
1711 return nil;
1712 end
1713  
1714 return 1;
1715 end
1716  
1717 local function LootLink_NameComparison(elem1, elem2)
1718 local v1, i1 = elem1[1], elem1[3];
1719 local v2, i2 = elem2[1], elem2[3];
1720  
1721 if ( v1 == v2 ) then
1722 if ( i1 and i2 ) then
1723 return i1 < i2;
1724 elseif ( i1 ) then
1725 return false;
1726 elseif ( i2 ) then
1727 return true;
1728 end
1729 end
1730 return v1 < v2;
1731 end
1732  
1733 local function LootLink_ColorComparison(elem1, elem2)
1734 local color1;
1735 local color2;
1736 local v1 = elem1[2];
1737 local v2 = elem2[2];
1738  
1739 if( v1 and v1.c ) then
1740 color1 = v1.c;
1741 else
1742 color1 = "ffffffff";
1743 end
1744 if( v2 and v2.c ) then
1745 color2 = v2.c;
1746 else
1747 color2 = "ffffffff";
1748 end
1749  
1750 if( color1 == color2 ) then
1751 return LootLink_NameComparison( elem1, elem2 );
1752 end
1753  
1754 if( not lColorSortTable[color1] and not lColorSortTable[color2] ) then
1755 return color1 < color2;
1756 end
1757  
1758 if( lColorSortTable[color1] ) then
1759 if( lColorSortTable[color2] ) then
1760 return lColorSortTable[color1] < lColorSortTable[color2];
1761 end
1762 return nil;
1763 end
1764 return 1;
1765 end
1766  
1767 local function LootLink_GenericComparison(elem1, elem2, v1, v2)
1768 if( v1 == v2 ) then
1769 return LootLink_NameComparison( elem1, elem2 );
1770 end
1771 if( not v1 ) then
1772 return 1;
1773 end
1774 if( not v2 ) then
1775 return nil;
1776 end
1777 if( tonumber(v1) and tonumber(v2) ) then
1778 return tonumber(v1) < tonumber(v2);
1779 end
1780 return v1 < v2;
1781 end
1782  
1783 local function LootLink_BindsComparison(elem1, elem2)
1784 local v1, v2;
1785  
1786 local value1 = elem1[2];
1787 local value2 = elem2[2];
1788  
1789 if( value1 and value1.d ) then
1790 v1 = LL_SearchData(ItemLinks[elem1], "bi");
1791 end
1792 if( value2 and value2.d ) then
1793 v2 = LL_SearchData(ItemLinks[elem2], "bi");
1794 end
1795  
1796 return LootLink_GenericComparison(elem1, elem2, v1, v2);
1797 end
1798  
1799 local function LootLink_UniqueComparison(elem1, elem2)
1800 local v1, v2;
1801  
1802 local value1 = elem1[2];
1803 local value2 = elem2[2];
1804  
1805 if( value1 and value1.d ) then
1806 v1 = LL_SearchData(value1, "un");
1807 end
1808 if( value2 and value2.d ) then
1809 v2 = LL_SearchData(value2, "un");
1810 end
1811  
1812 return LootLink_GenericComparison(elem1, elem2, v1, v2);
1813 end
1814  
1815 local function LootLink_LocationComparison(elem1, elem2)
1816 local v1, v2;
1817  
1818 local value1 = elem1[2];
1819 local value2 = elem2[2];
1820  
1821 if( value1 and value1.d ) then
1822 v1 = LL_SearchData(value1, "lo");
1823 end
1824 if( value2 and value2.d ) then
1825 v2 = LL_SearchData(value2, "lo");
1826 end
1827  
1828 return LootLink_GenericComparison(elem1, elem2, v1, v2);
1829 end
1830  
1831 local function LootLink_TypeComparison(elem1, elem2)
1832 local v1, v2;
1833  
1834 local value1 = elem1[2];
1835 local value2 = elem2[2];
1836  
1837 if( value1 and value1.d ) then
1838 v1 = LL_SearchData(value1, "ty");
1839 end
1840 if( value2 and value2.d ) then
1841 v2 = LL_SearchData(value2, "ty");
1842 end
1843  
1844 return LootLink_GenericComparison(elem1, elem2, v1, v2);
1845 end
1846  
1847 local function LootLink_SubtypeComparison(elem1, elem2)
1848 local v1, v2;
1849  
1850 local value1 = elem1[2];
1851 local value2 = elem2[2];
1852  
1853 if( value1 and value1.d ) then
1854 v1 = LL_SearchData(value1, "su");
1855 end
1856 if( value2 and value2.d ) then
1857 v2 = LL_SearchData(value2, "su");
1858 end
1859  
1860 return LootLink_GenericComparison(elem1, elem2, v1, v2);
1861 end
1862  
1863 local function LootLink_MinDamageComparison(elem1, elem2)
1864 local v1, v2;
1865  
1866 local value1 = elem1[2];
1867 local value2 = elem2[2];
1868  
1869 if( value1 and value1.d ) then
1870 v1 = LL_SearchData(value1, "mi");
1871 end
1872 if( value2 and value2.d ) then
1873 v2 = LL_SearchData(value2, "mi");
1874 end
1875  
1876 return LootLink_GenericComparison(elem1, elem2, v1, v2);
1877 end
1878  
1879 local function LootLink_MaxDamageComparison(elem1, elem2)
1880 local v1, v2;
1881  
1882 local value1 = elem1[2];
1883 local value2 = elem2[2];
1884  
1885 if( value1 and value1.d ) then
1886 v1 = LL_SearchData(value1, "ma");
1887 end
1888 if( value2 and value2.d ) then
1889 v2 = LL_SearchData(value2, "ma");
1890 end
1891  
1892 return LootLink_GenericComparison(elem1, elem2, v1, v2);
1893 end
1894  
1895 local function LootLink_SpeedComparison(elem1, elem2)
1896 local v1, v2;
1897  
1898 local value1 = elem1[2];
1899 local value2 = elem2[2];
1900  
1901 if( value1 and value1.d ) then
1902 v1 = LL_SearchData(value1, "sp");
1903 end
1904 if( value2 and value2.d ) then
1905 v2 = LL_SearchData(value2, "sp");
1906 end
1907  
1908 return LootLink_GenericComparison(elem1, elem2, v1, v2);
1909 end
1910  
1911 local function LootLink_DPSComparison(elem1, elem2)
1912 local v1, v2;
1913  
1914 local value1 = elem1[2];
1915 local value2 = elem2[2];
1916  
1917 if( value1 and value1.d ) then
1918 v1 = LL_SearchData(value1, "dp");
1919 end
1920 if( value2 and value2.d ) then
1921 v2 = LL_SearchData(value2, "dp");
1922 end
1923  
1924 return LootLink_GenericComparison(elem1, elem2, v1, v2);
1925 end
1926  
1927 local function LootLink_ArmorComparison(elem1, elem2)
1928 local v1, v2;
1929  
1930 local value1 = elem1[2];
1931 local value2 = elem2[2];
1932  
1933 if( value1 and value1.d ) then
1934 v1 = LL_SearchData(value1, "ar");
1935 end
1936 if( value2 and value2.d ) then
1937 v2 = LL_SearchData(value2, "ar");
1938 end
1939  
1940 return LootLink_GenericComparison(elem1, elem2, v1, v2);
1941 end
1942  
1943 local function LootLink_BlockComparison(elem1, elem2)
1944 local v1, v2;
1945  
1946 local value1 = elem1[2];
1947 local value2 = elem2[2];
1948  
1949 if( value1 and value1.d ) then
1950 v1 = LL_SearchData(value1, "bl");
1951 end
1952 if( value2 and value2.d ) then
1953 v2 = LL_SearchData(value2, "bl");
1954 end
1955  
1956 return LootLink_GenericComparison(elem1, elem2, v1, v2);
1957 end
1958  
1959 local function LootLink_SlotsComparison(elem1, elem2)
1960 local v1, v2;
1961  
1962 local value1 = elem1[2];
1963 local value2 = elem2[2];
1964  
1965 if( value1 and value1.d ) then
1966 v1 = LL_SearchData(value1, "sl");
1967 end
1968 if( value2 and value2.d ) then
1969 v2 = LL_SearchData(value2, "sl");
1970 end
1971  
1972 return LootLink_GenericComparison(elem1, elem2, v1, v2);
1973 end
1974  
1975 local function LootLink_SkillComparison(elem1, elem2)
1976 local v1, v2;
1977  
1978 local value1 = elem1[2];
1979 local value2 = elem2[2];
1980  
1981 if( value1 and value1.d ) then
1982 v1 = LL_SearchData(value1, "sk");
1983 end
1984 if( value2 and value2.d ) then
1985 v2 = LL_SearchData(value2, "sk");
1986 end
1987  
1988 return LootLink_GenericComparison(elem1, elem2, v1, v2);
1989 end
1990  
1991 local function LootLink_LevelComparison(elem1, elem2)
1992 local v1, v2;
1993  
1994 local value1 = elem1[2];
1995 local value2 = elem2[2];
1996  
1997 if( value1 and value1.d ) then
1998 v1 = LL_SearchData(value1, "le");
1999 end
2000 if( value2 and value2.d ) then
2001 v2 = LL_SearchData(value2, "le");
2002 end
2003  
2004 return LootLink_GenericComparison(elem1, elem2, v1, v2);
2005 end
2006  
2007 -- Ugly, but functional
2008 local function LootLink_SetComparison(elem1, elem2)
2009 local v1, v2;
2010  
2011 local value1 = elem1[2];
2012 local value2 = elem2[2];
2013  
2014 local sets = LootLinkState.sets;
2015  
2016 if ( not sets ) then
2017 return LootLink_NameComparison(elem1, elem2);
2018 end
2019  
2020 if( value1 and value1.d ) then
2021 v1 = LL_SearchData(value1, "se");
2022 v1 = sets[v1];
2023 end
2024 if( value2 and value2.d ) then
2025 v2 = LL_SearchData(value2, "se");
2026 v2 = sets[v2];
2027 end
2028  
2029 if ( not v1 and not v2 ) then
2030 return LootLink_NameComparison(elem1, elem2);
2031 elseif ( not v1 ) then
2032 return nil;
2033 elseif ( not v2 ) then
2034 return 1;
2035 else
2036 if ( v1 == v2 ) then
2037 return LootLink_NameComparison(elem1, elem2);
2038 else
2039 return v1 < v2;
2040 end
2041 end
2042 end
2043  
2044 local function LootLink_Sort()
2045 if( LOOTLINK_DROPDOWN_LIST[UIDropDownMenu_GetSelectedID(LootLinkFrameDropDown)].sortType ) then
2046 local sortType = LOOTLINK_DROPDOWN_LIST[UIDropDownMenu_GetSelectedID(LootLinkFrameDropDown)].sortType;
2047 if( sortType == "name" ) then
2048 table.sort(DisplayIndices, LootLink_NameComparison);
2049 elseif( sortType == "rarity" ) then
2050 table.sort(DisplayIndices, LootLink_ColorComparison);
2051 elseif( sortType == "binds" ) then
2052 table.sort(DisplayIndices, LootLink_BindsComparison);
2053 elseif( sortType == "unique" ) then
2054 table.sort(DisplayIndices, LootLink_UniqueComparison);
2055 elseif( sortType == "location" ) then
2056 table.sort(DisplayIndices, LootLink_LocationComparison);
2057 elseif( sortType == "type" ) then
2058 table.sort(DisplayIndices, LootLink_TypeComparison);
2059 elseif( sortType == "subtype" ) then
2060 table.sort(DisplayIndices, LootLink_SubtypeComparison);
2061 elseif( sortType == "minDamage" ) then
2062 table.sort(DisplayIndices, LootLink_MinDamageComparison);
2063 elseif( sortType == "maxDamage" ) then
2064 table.sort(DisplayIndices, LootLink_MaxDamageComparison);
2065 elseif( sortType == "speed" ) then
2066 table.sort(DisplayIndices, LootLink_SpeedComparison);
2067 elseif( sortType == "DPS" ) then
2068 table.sort(DisplayIndices, LootLink_DPSComparison);
2069 elseif( sortType == "armor" ) then
2070 table.sort(DisplayIndices, LootLink_ArmorComparison);
2071 elseif( sortType == "block" ) then
2072 table.sort(DisplayIndices, LootLink_BlockComparison);
2073 elseif( sortType == "slots" ) then
2074 table.sort(DisplayIndices, LootLink_SlotsComparison);
2075 elseif( sortType == "skill" ) then
2076 table.sort(DisplayIndices, LootLink_SkillComparison);
2077 elseif( sortType == "level" ) then
2078 table.sort(DisplayIndices, LootLink_LevelComparison);
2079 elseif( sortType == "set" ) then
2080 table.sort(DisplayIndices, LootLink_SetComparison);
2081 end
2082 end
2083 end
2084  
2085 local function LootLink_BuildDisplayIndices()
2086 local iNew = 1;
2087 local index;
2088 local value;
2089 local UsabilityData;
2090  
2091 if( LootLinkFrame.SearchParams and LootLinkFrame.SearchParams.usable ) then
2092 UsabilityData = { };
2093 BuildUsabilityData(UsabilityData);
2094 end
2095  
2096 DisplayIndices = { };
2097 for index, value in ItemLinks do
2098 if( LootLink_MatchesSearch(index, value, UsabilityData) ) then
2099 DisplayIndices[iNew] = { index, value, nil };
2100 iNew = iNew + 1;
2101 end
2102 if( value.m ) then
2103 for i, altvalue in value.m do
2104 if( LootLink_MatchesSearch(index, altvalue, UsabilityData) ) then
2105 DisplayIndices[iNew] = { index, altvalue, i };
2106 iNew = iNew + 1;
2107 end
2108 end
2109 end
2110 end
2111 DisplayIndices.onePastEnd = iNew;
2112 LootLink_SetDataVersion(100); -- version 1.00
2113 LootLink_Sort();
2114 LootLink_SetTitle();
2115 LootLinkQuickSearch_Clear();
2116 end
2117  
2118 local function LootLink_Reset()
2119 ItemLinks = { };
2120  
2121 LootLink_SetDataVersion(110); -- version 1.10
2122  
2123 LootLink_InitSizes(lServerIndex);
2124  
2125 if( DisplayIndices ) then
2126 LootLink_BuildDisplayIndices();
2127 LootLink_Update();
2128 end
2129 end
2130  
2131 local function LootLink_MakeHome()
2132 local index;
2133 local value;
2134  
2135 LootLink_SetDataVersion(110); -- version 1.10
2136  
2137 for index, value in ItemLinks do
2138 if( not value._ ) then
2139 -- If this item predates multiple server support, mark is as seen on this server
2140 LootLink_AddItemServer(value, lServerIndex);
2141 else
2142 -- Otherwise just wipe the flag since it only applies to pre-1.10 data
2143 value._ = nil;
2144 end
2145 end
2146  
2147 LootLink_InitSizes(lServerIndex);
2148 end
2149  
2150 local function LootLink_LightMode()
2151 local index;
2152 local value;
2153  
2154 for index, value in ItemLinks do
2155 value.t = nil;
2156 end
2157 LootLinkState.LightMode = 1;
2158 end
2159  
2160 --
2161 -- Uncategorized functions; will sort later
2162 --
2163  
2164 local function LootLinkFrameDropDown_Initialize()
2165 local info;
2166 for i = 1, getn(LOOTLINK_DROPDOWN_LIST), 1 do
2167 info = { };
2168 info.text = LOOTLINK_DROPDOWN_LIST[i].name;
2169 info.func = LootLinkFrameDropDownButton_OnClick;
2170 UIDropDownMenu_AddButton(info);
2171 end
2172 end
2173  
2174 local function LLS_RarityDropDown_Initialize()
2175 local info;
2176 for i = 1, getn(LLS_RARITY_LIST), 1 do
2177 info = { };
2178 info.text = LLS_RARITY_LIST[i].name;
2179 info.func = LLS_RarityDropDown_OnClick;
2180 if( LLS_RARITY_LIST[i].value ) then
2181 info.textR = LLS_RARITY_LIST[i].r;
2182 info.textG = LLS_RARITY_LIST[i].g;
2183 info.textB = LLS_RARITY_LIST[i].b;
2184 end
2185 UIDropDownMenu_AddButton(info);
2186 end
2187 end
2188  
2189 local function LLO_RarityDropDown_Initialize()
2190 local info;
2191 for i = 1, getn(LLO_RARITY_LIST), 1 do
2192 info = { };
2193 info.text = LLO_RARITY_LIST[i].name;
2194 info.func = LLO_RarityDropDown_OnClick;
2195 UIDropDownMenu_AddButton(info);
2196 end
2197 end
2198  
2199 local function LLS_BindsDropDown_Initialize()
2200 local info;
2201 for i = 1, getn(LLS_BINDS_LIST), 1 do
2202 info = { };
2203 info.text = LLS_BINDS_LIST[i].name;
2204 info.func = LLS_BindsDropDown_OnClick;
2205 UIDropDownMenu_AddButton(info);
2206 end
2207 end
2208  
2209 local function LLS_LocationDropDown_Initialize()
2210 local info;
2211 for i = 1, getn(LLS_LOCATION_LIST), 1 do
2212 info = { };
2213 info.text = LLS_LOCATION_LIST[i].name;
2214 info.func = LLS_LocationDropDown_OnClick;
2215 UIDropDownMenu_AddButton(info);
2216 end
2217 end
2218  
2219 local function LLS_TypeDropDown_Initialize()
2220 local info;
2221 for i = 1, getn(LLS_TYPE_LIST), 1 do
2222 info = { };
2223 info.text = LLS_TYPE_LIST[i].name;
2224 info.func = LLS_TypeDropDown_OnClick;
2225 UIDropDownMenu_AddButton(info);
2226 end
2227 end
2228  
2229 local function LLS_SubtypeDropDownArmor_Initialize()
2230 local info;
2231 for i = 1, getn(LLS_SUBTYPE_ARMOR_LIST), 1 do
2232 info = { };
2233 info.text = LLS_SUBTYPE_ARMOR_LIST[i].name;
2234 info.func = LLS_SubtypeDropDown_OnClick;
2235 UIDropDownMenu_AddButton(info);
2236 end
2237 end
2238  
2239 local function LLS_SubtypeDropDownShield_Initialize()
2240 local info;
2241 for i = 1, getn(LLS_SUBTYPE_SHIELD_LIST), 1 do
2242 info = { };
2243 info.text = LLS_SUBTYPE_SHIELD_LIST[i].name;
2244 info.func = LLS_SubtypeDropDown_OnClick;
2245 UIDropDownMenu_AddButton(info);
2246 end
2247 end
2248  
2249 local function LLS_SubtypeDropDownWeapon_Initialize()
2250 local info;
2251 for i = 1, getn(LLS_SUBTYPE_WEAPON_LIST), 1 do
2252 info = { };
2253 info.text = LLS_SUBTYPE_WEAPON_LIST[i].name;
2254 info.func = LLS_SubtypeDropDown_OnClick;
2255 UIDropDownMenu_AddButton(info);
2256 end
2257 end
2258  
2259 local function LLS_SubtypeDropDownRecipe_Initialize()
2260 local info;
2261 for i = 1, getn(LLS_SUBTYPE_RECIPE_LIST), 1 do
2262 info = { };
2263 info.text = LLS_SUBTYPE_RECIPE_LIST[i].name;
2264 info.func = LLS_SubtypeDropDown_OnClick;
2265 UIDropDownMenu_AddButton(info);
2266 end
2267 end
2268  
2269 local function LLS_SubtypeDropDownContainer_Initialize()
2270 local info;
2271 for i = 1, getn(LLS_SUBTYPE_CONTAINER_LIST), 1 do
2272 info = { };
2273 info.text = LLS_SUBTYPE_CONTAINER_LIST[i].name;
2274 info.func = LLS_SubtypeDropDown_OnClick;
2275 UIDropDownMenu_AddButton(info);
2276 end
2277 end
2278  
2279 local function LootLink_UIDropDownMenu_SetSelectedID(frame, id, names)
2280 UIDropDownMenu_SetSelectedID(frame, id);
2281 if( not frame ) then
2282 frame = this;
2283 end
2284 UIDropDownMenu_SetText(names[id].name, frame);
2285 end
2286  
2287 local function LootLink_SetupTypeUI(iType, iSubtype)
2288 local _type = LLS_TYPE_LIST[iType].value;
2289  
2290 if( not iSubtype ) then
2291 iSubtype = 1;
2292 end
2293  
2294 -- Hide all of the variable labels and fields to start
2295 getglobal("LLS_SubtypeLabel"):Hide();
2296 getglobal("LLS_SubtypeDropDown"):Hide();
2297 getglobal("LLS_MinimumArmorLabel"):Hide();
2298 getglobal("LLS_MinimumBlockLabel"):Hide();
2299 getglobal("LLS_MinimumDamageLabel"):Hide();
2300 getglobal("LLS_MaximumDamageLabel"):Hide();
2301 getglobal("LLS_MaximumSpeedLabel"):Hide();
2302 getglobal("LLS_MinimumDPSLabel"):Hide();
2303 getglobal("LLS_MinimumSlotsLabel"):Hide();
2304 getglobal("LLS_MinimumSkillLabel"):Hide();
2305 getglobal("LLS_MaximumSkillLabel"):Hide();
2306 getglobal("LLS_MinimumArmorEditBox"):Hide();
2307 getglobal("LLS_MinimumBlockEditBox"):Hide();
2308 getglobal("LLS_MinimumDamageEditBox"):Hide();
2309 getglobal("LLS_MaximumDamageEditBox"):Hide();
2310 getglobal("LLS_MaximumSpeedEditBox"):Hide();
2311 getglobal("LLS_MinimumDPSEditBox"):Hide();
2312 getglobal("LLS_MinimumSlotsEditBox"):Hide();
2313 getglobal("LLS_MinimumSkillEditBox"):Hide();
2314 getglobal("LLS_MaximumSkillEditBox"):Hide();
2315  
2316 if( _type ~= TYPE_OTHER ) then
2317 local label = getglobal("LLS_SubtypeLabel");
2318 local dropdown = getglobal("LLS_SubtypeDropDown");
2319 local initfunc;
2320  
2321 -- Show the dropdown and its label
2322 label:Show();
2323 dropdown:Show();
2324  
2325 if( _type == TYPE_ARMOR ) then
2326 label:SetText(LLS_SUBTYPE_ARMOR);
2327 initfunc = LLS_SubtypeDropDownArmor_Initialize;
2328  
2329 getglobal("LLS_MinimumArmorLabel"):Show();
2330 getglobal("LLS_MinimumArmorEditBox"):Show();
2331 elseif( _type == TYPE_SHIELD ) then
2332 label:SetText(LLS_SUBTYPE_SHIELD);
2333 initfunc = LLS_SubtypeDropDownShield_Initialize;
2334  
2335 getglobal("LLS_MinimumArmorLabel"):Show();
2336 getglobal("LLS_MinimumBlockLabel"):Show();
2337 getglobal("LLS_MinimumArmorEditBox"):Show();
2338 getglobal("LLS_MinimumBlockEditBox"):Show();
2339 elseif( _type == TYPE_WEAPON ) then
2340 label:SetText(LLS_SUBTYPE_WEAPON);
2341 initfunc = LLS_SubtypeDropDownWeapon_Initialize;
2342  
2343 getglobal("LLS_MinimumDamageLabel"):Show();
2344 getglobal("LLS_MaximumDamageLabel"):Show();
2345 getglobal("LLS_MaximumSpeedLabel"):Show();
2346 getglobal("LLS_MinimumDPSLabel"):Show();
2347 getglobal("LLS_MinimumDamageEditBox"):Show();
2348 getglobal("LLS_MaximumDamageEditBox"):Show();
2349 getglobal("LLS_MaximumSpeedEditBox"):Show();
2350 getglobal("LLS_MinimumDPSEditBox"):Show();
2351 elseif( _type == TYPE_CONTAINER ) then
2352 label:SetText(LLS_SUBTYPE_CONTAINER);
2353 initfunc = LLS_SubtypeDropDownContainer_Initialize;
2354  
2355 getglobal("LLS_MinimumSlotsLabel"):Show();
2356 getglobal("LLS_MinimumSlotsEditBox"):Show();
2357 else
2358 label:SetText(LLS_SUBTYPE_RECIPE);
2359 initfunc = LLS_SubtypeDropDownRecipe_Initialize;
2360  
2361 getglobal("LLS_MinimumSkillLabel"):Show();
2362 getglobal("LLS_MaximumSkillLabel"):Show();
2363 getglobal("LLS_MinimumSkillEditBox"):Show();
2364 getglobal("LLS_MaximumSkillEditBox"):Show();
2365 end
2366  
2367 UIDropDownMenu_Initialize(dropdown, initfunc);
2368 UIDropDownMenu_SetSelectedID(LLS_SubtypeDropDown, iSubtype);
2369 end
2370  
2371 LLS_TextEditBox:SetFocus();
2372 end
2373  
2374 local function LootLink_InspectSlot(unit, id)
2375 local link = GetInventoryItemLink(unit, id);
2376 if( link ) then
2377 local name = LootLink_ProcessLinks(link, 1);
2378 if( name and ItemLinks[name] ) then
2379 local count = GetInventoryItemCount(unit, id);
2380 if( count > 1 ) then
2381 ItemLinks[name].x = 1;
2382 end
2383 LootLink_Event_InspectSlot(name, count, ItemLinks[name], unit, id);
2384 end
2385 end
2386 end
2387  
2388 function LootLink_Inspect(who)
2389 if ( not UnitIsPlayer(who) ) then return; end
2390 if ( who == "mouseover" ) then
2391 if ( not LLInspect_List ) then
2392 LLInspect_List = {};
2393 end
2394 local name = UnitName(who);
2395 local time = GetTime();
2396 local lasttime = LLInspect_List[name];
2397 if ( lasttime and time - lasttime < 120 ) then
2398 return nil;
2399 end
2400 if ( not lasttime ) then
2401 LLInspect_List.total = (LLInspect_List.total or 0) + 1;
2402 end
2403 if ( LLInspect_List.total and LLInspect_List.total > 250 ) then
2404 local list = 0;
2405 for k, v in LLInspect_List do
2406 list = list + 1;
2407 v = nil;
2408 if ( list == 100 ) then
2409 break;
2410 end
2411 end
2412 end
2413  
2414 LLInspect_List[name] = time;
2415 end
2416  
2417 local index;
2418  
2419 for index = 1, getn(INVENTORY_SLOT_LIST), 1 do
2420 LootLink_InspectSlot(who, INVENTORY_SLOT_LIST[index].id)
2421 end
2422 end
2423  
2424 local function LootLink_ScanInventory()
2425 local bagid;
2426 local size;
2427 local slotid;
2428 local link;
2429  
2430 for bagid = 0, 4, 1 do
2431 size = GetContainerNumSlots(bagid);
2432 if( size ) then
2433 for slotid = size, 1, -1 do
2434 link = GetContainerItemLink(bagid, slotid);
2435 if( link ) then
2436 local name = LootLink_ProcessLinks(link, 1);
2437 if( name and ItemLinks[name] ) then
2438 local texture, count, locked, quality, readable = GetContainerItemInfo(bagid, slotid);
2439 if( count > 1 ) then
2440 ItemLinks[name].x = 1;
2441 end
2442 LootLink_Event_ScanInventory(name, count, ItemLinks[name], bagid, slotid);
2443 end
2444 end
2445 end
2446 end
2447 end
2448 end
2449  
2450 local function LootLink_ScanSellPrices()
2451 local bagid;
2452 local size;
2453 local slotid;
2454 local link;
2455  
2456 LootLink_MoneyToggle();
2457 for bagid = 0, 4, 1 do
2458 lBagID = bagid;
2459 size = GetContainerNumSlots(bagid);
2460 if( size ) then
2461 for slotid = size, 1, -1 do
2462 lSlotID = slotid;
2463 LLHiddenTooltip:SetBagItem(bagid, slotid);
2464 end
2465 end
2466 end
2467  
2468 lBagID = nil;
2469 lSlotID = nil;
2470  
2471 LootLink_MoneyToggle(1);
2472 end
2473  
2474 local function LootLink_StartAuctionScan()
2475 -- Start with the first page
2476 lCurrentAuctionPage = nil;
2477  
2478 -- Hook the functions that we need for the scan
2479 if( not lOriginal_CanSendAuctionQuery ) then
2480 lOriginal_CanSendAuctionQuery = CanSendAuctionQuery;
2481 CanSendAuctionQuery = LootLink_CanSendAuctionQuery;
2482 end
2483 if( not lOriginal_AuctionFrameBrowse_OnEvent ) then
2484 lOriginal_AuctionFrameBrowse_OnEvent = AuctionFrameBrowse_OnEvent;
2485 AuctionFrameBrowse_OnEvent = LootLink_AuctionFrameBrowse_OnEvent;
2486 end
2487  
2488 LootLink_Event_StartAuctionScan();
2489 end
2490  
2491 local function LootLink_StopAuctionScan()
2492 LootLink_Event_StopAuctionScan();
2493  
2494 -- Unhook the scanning functions
2495 if( lOriginal_CanSendAuctionQuery ) then
2496 CanSendAuctionQuery = lOriginal_CanSendAuctionQuery;
2497 lOriginal_CanSendAuctionQuery = nil;
2498 end
2499 if( lOriginal_AuctionFrameBrowse_OnEvent ) then
2500 AuctionFrameBrowse_OnEvent = lOriginal_AuctionFrameBrowse_OnEvent;
2501 lOriginal_AuctionFrameBrowse_OnEvent = nil;
2502 end
2503 end
2504  
2505 local function LootLink_AuctionNextQuery()
2506 if( lCurrentAuctionPage ) then
2507 local numBatchAuctions, totalAuctions = GetNumAuctionItems("list");
2508 local maxPages = floor(totalAuctions / NUM_AUCTION_ITEMS_PER_PAGE);
2509  
2510 if( lCurrentAuctionPage < maxPages ) then
2511 lCurrentAuctionPage = lCurrentAuctionPage + 1;
2512 BrowseNoResultsText:SetText(format(LOOTLINK_AUCTION_PAGE_N, lCurrentAuctionPage + 1, maxPages + 1));
2513 else
2514 lScanAuction = nil;
2515 LootLink_StopAuctionScan();
2516 if( totalAuctions > 0 ) then
2517 BrowseNoResultsText:SetText(LOOTLINK_AUCTION_SCAN_DONE);
2518 LootLink_Event_FinishedAuctionScan();
2519 end
2520 return;
2521 end
2522 else
2523 lCurrentAuctionPage = 0;
2524 BrowseNoResultsText:SetText(LOOTLINK_AUCTION_SCAN_START);
2525 end
2526 QueryAuctionItems("", "", "", nil, nil, nil, lCurrentAuctionPage, nil, nil);
2527 LootLink_Event_AuctionQuery(lCurrentAuctionPage);
2528 end
2529  
2530 local function LootLink_ScanAuction()
2531 local numBatchAuctions, totalAuctions = GetNumAuctionItems("list");
2532 local auctionid;
2533 local link;
2534  
2535 if( numBatchAuctions > 0 ) then
2536 for auctionid = 1, numBatchAuctions do
2537 link = GetAuctionItemLink("list", auctionid);
2538 if( link ) then
2539 local name = LootLink_ProcessLinks(link, 1);
2540 if( name and ItemLinks[name] ) then
2541 local name_, texture, count, quality, canUse, level, minBid, minIncrement, buyoutPrice, bidAmount, highBidder, owner = GetAuctionItemInfo("list", auctionid);
2542 if( count > 1 ) then
2543 ItemLinks[name].x = 1;
2544 end
2545 LootLink_Event_ScanAuction(name, count, ItemLinks[name], lCurrentAuctionPage, auctionid);
2546 end
2547 end
2548 end
2549 end
2550 end
2551  
2552 local function LootLink_ScanBank()
2553 local index;
2554 local bagid;
2555 local size;
2556 local slotid;
2557 local link;
2558  
2559 for index, bagid in lBankBagIDs do
2560 size = GetContainerNumSlots(bagid);
2561 if( size ) then
2562 for slotid = size, 1, -1 do
2563 link = GetContainerItemLink(bagid, slotid);
2564 if( link ) then
2565 local name = LootLink_ProcessLinks(link, 1);
2566 if( name and ItemLinks[name] ) then
2567 local texture, count, locked, quality, readable = GetContainerItemInfo(bagid, slotid);
2568 if( count > 1 ) then
2569 ItemLinks[name].x = 1;
2570 end
2571 LootLink_Event_ScanBank(name, count, ItemLinks[name], bagid, slotid);
2572 end
2573 end
2574 end
2575 end
2576 end
2577 end
2578  
2579 local function LootLink_ScanSellPrice(price)
2580 local link = GetContainerItemLink(lBagID, lSlotID);
2581 local texture, itemCount, locked, quality, readable = GetContainerItemInfo(lBagID, lSlotID);
2582 local name;
2583  
2584 if( itemCount and itemCount > 1 ) then
2585 price = price / itemCount;
2586 end
2587  
2588 name = LootLink_NameFromLink(link);
2589 if( name and ItemLinks[name] ) then
2590 ItemLinks[name].p = price;
2591 if( itemCount and itemCount > 1 ) then
2592 ItemLinks[name].x = 1;
2593 end
2594 end
2595 end
2596  
2597 local function LootLink_CheckTooltipInfo()
2598 if( GameTooltip:IsVisible() ) then
2599 -- If we've already added our information or money is already showing, no need to do it again
2600 if( GameTooltip.llDone or GameTooltipMoneyFrame:IsVisible() ) then
2601 return nil;
2602 end
2603  
2604 -- Don't add information to tooltips generated while the mouse is over the minimap
2605 if( LootLink_MouseIsOver(MinimapCluster) ) then
2606 return nil;
2607 end
2608  
2609 local field = getglobal("GameTooltipTextLeft1");
2610 if( field and field:IsShown() ) then
2611 local name = field:GetText();
2612 if( name ) then
2613 if( ItemLinks[name] ) then
2614 LootLink_AddTooltipInfo(name, GameTooltip);
2615 end
2616 -- Whether or not we had information for this item, there's no need to check it again
2617 return nil;
2618 end
2619 end
2620 end
2621  
2622 return 1;
2623 end
2624  
2625 local function LootLink_CheckVersionReminder()
2626 local index;
2627 local value;
2628 local version;
2629  
2630 version = LootLink_GetDataVersion();
2631 for index, value in LOOTLINK_DATA_UPGRADE_HELP do
2632 if( version < value.version ) then
2633 DEFAULT_CHAT_FRAME:AddMessage(value.text);
2634 end
2635 end
2636 end
2637  
2638 local function LootLink_UpgradeData()
2639 local index;
2640 local item;
2641  
2642 for index, item in ItemLinks do
2643 LootLink_ConvertServerFormat(item);
2644 if( item.item ) then
2645 item.i = item.item;
2646 item.item = nil;
2647 end
2648 if( item.color ) then
2649 item.c = item.color;
2650 item.color = nil;
2651 end
2652 if( item.price ) then
2653 item.p = item.price;
2654 item.price = nil;
2655 end
2656 if( item.stack ) then
2657 item.x = item.stack;
2658 item.stack = nil;
2659 end
2660  
2661 if( item.SearchData ) then
2662 local data = "";
2663  
2664 if( item.SearchData.type ) then
2665 data = data.."ty"..item.SearchData.type.."·";
2666 end
2667 if( item.SearchData.location ) then
2668 data = data.."lo"..LocationTypes[item.SearchData.location].i.."·";
2669 end
2670 if( item.SearchData.subtype ) then
2671 data = data.."su"..item.SearchData.subtype.."·";
2672 end
2673 if( item.SearchData.binds ) then
2674 data = data.."bi"..item.SearchData.binds.."·";
2675 end
2676 if( item.SearchData.level ) then
2677 data = data.."le"..item.SearchData.level.."·";
2678 end
2679 if( item.SearchData.armor ) then
2680 data = data.."ar"..item.SearchData.armor.."·";
2681 end
2682 if( item.SearchData.minDamage ) then
2683 data = data.."mi"..item.SearchData.minDamage.."·";
2684 end
2685 if( item.SearchData.maxDamage ) then
2686 data = data.."ma"..item.SearchData.maxDamage.."·";
2687 end
2688 if( item.SearchData.speed ) then
2689 data = data.."sp"..item.SearchData.speed.."·";
2690 end
2691 if( item.SearchData.DPS ) then
2692 data = data.."dp"..item.SearchData.DPS.."·";
2693 end
2694 if( item.SearchData.unique ) then
2695 data = data.."un"..item.SearchData.unique.."·";
2696 end
2697 if( item.SearchData.block ) then
2698 data = data.."bl"..item.SearchData.block.."·";
2699 end
2700 if( item.SearchData.slots ) then
2701 data = data.."sl"..item.SearchData.slots.."·";
2702 end
2703 if( item.SearchData.skill ) then
2704 data = data.."sk"..item.SearchData.skill.."·";
2705 end
2706  
2707 if( item.SearchData.text ) then
2708 item.t = item.SearchData.text;
2709 end
2710  
2711 item.d = data;
2712 item.SearchData = nil;
2713 end
2714 end
2715 end
2716  
2717 local function LootLink_VariablesLoaded()
2718 local index;
2719 local value;
2720  
2721 if( not LootLinkState ) then
2722 LootLinkState = { };
2723 elseif ( LootLinkState.options ) then
2724 for k, v in LootLinkState.options do
2725 LootLinkState[k] = v;
2726 end
2727 LootLinkState.options = nil;
2728 end
2729  
2730 if( not ItemLinks ) then
2731 LootLink_Reset();
2732 end
2733  
2734 lServer = GetCVar("realmName");
2735 lServerIndex = LootLink_AddServer(lServer);
2736  
2737 LootLink_UpgradeData();
2738  
2739 LootLink_InitSizes(lServerIndex);
2740  
2741 -- Display and move minimap button --
2742 if ( not LootLinkState.hideminimap ) then
2743 LootLinkMinimapButton:Show();
2744 LootLink_Minimap_Position();
2745 end
2746  
2747 if ( LootLinkState.mouseover ) then
2748 this:RegisterEvent("UPDATE_MOUSEOVER_UNIT");
2749 end
2750 if ( LootLinkState.sortType ) then
2751 LootLink_UIDropDownMenu_SetSelectedID(LootLinkFrameDropDown, LootLinkState.sortType, LOOTLINK_DROPDOWN_LIST);
2752 end
2753 end
2754  
2755 --------------------------------------------------------------------------------------------------
2756 -- OnFoo functions
2757 --------------------------------------------------------------------------------------------------
2758 function LootLink_OnLoad()
2759 local index;
2760 local value;
2761  
2762 for index, value in ChatMessageTypes do
2763 this:RegisterEvent(value);
2764 end
2765  
2766 for index = 1, getn(INVENTORY_SLOT_LIST), 1 do
2767 INVENTORY_SLOT_LIST[index].id = GetInventorySlotInfo(INVENTORY_SLOT_LIST[index].name);
2768 end
2769  
2770 this:RegisterEvent("PLAYER_TARGET_CHANGED");
2771 this:RegisterEvent("PLAYER_ENTERING_WORLD");
2772 this:RegisterEvent("PLAYER_LEAVING_WORLD");
2773 this:RegisterEvent("BANKFRAME_OPENED");
2774 this:RegisterEvent("VARIABLES_LOADED");
2775 this:RegisterEvent("AUCTION_HOUSE_SHOW");
2776 this:RegisterEvent("AUCTION_HOUSE_CLOSE");
2777 this:RegisterEvent("AUCTION_ITEM_LIST_UPDATE");
2778 this:RegisterEvent("MERCHANT_SHOW");
2779 --this:RegisterEvent("PLAYER_LOGOUT");
2780 this:RegisterEvent("MEMORY_EXHAUSTED");
2781 this:RegisterEvent("MEMORY_RECOVERED");
2782  
2783 -- Register our slash command
2784 SLASH_LOOTLINK1 = "/lootlink";
2785 SLASH_LOOTLINK2 = "/ll";
2786 SlashCmdList["LOOTLINK"] = function(msg)
2787 LootLink_SlashCommandHandler(msg);
2788 end
2789  
2790 -- Hook the GameTooltip:SetOwner function
2791 lOriginal_GameTooltip_SetOwner = GameTooltip.SetOwner;
2792 GameTooltip.SetOwner = LootLink_GameTooltip_SetOwner;
2793  
2794 -- Hook the ContainerFrameItemButton_OnEnter, ContainerFrame_Update and GameTooltip:SetLootItem functions
2795 lOriginal_ContainerFrameItemButton_OnEnter = ContainerFrameItemButton_OnEnter;
2796 ContainerFrameItemButton_OnEnter = LootLink_ContainerFrameItemButton_OnEnter;
2797 lOriginal_ContainerFrame_Update = ContainerFrame_Update;
2798 ContainerFrame_Update = LootLink_ContainerFrame_Update;
2799 lOriginal_GameTooltip_SetLootItem = GameTooltip.SetLootItem;
2800 GameTooltip.SetLootItem = LootLink_GameTooltip_SetLootItem;
2801  
2802 -- Hook GameTooltip_OnHide and GameTooltip_ClearMoney
2803 lOriginal_GameTooltip_OnHide = GameTooltip_OnHide;
2804 GameTooltip_OnHide = LootLink_GameTooltip_OnHide;
2805 lOriginal_GameTooltip_ClearMoney = GameTooltip_ClearMoney;
2806 GameTooltip_ClearMoney = LootLink_GameTooltip_ClearMoney;
2807  
2808 -- Hook the shopping tooltip functions
2809 lOriginal_ShoppingTooltip1_SetMerchantCompareItem = ShoppingTooltip1.SetMerchantCompareItem;
2810 ShoppingTooltip1.SetMerchantCompareItem = LootLink_ShoppingTooltip1_SetMerchantCompareItem;
2811 lOriginal_ShoppingTooltip2_SetMerchantCompareItem = ShoppingTooltip2.SetMerchantCompareItem;
2812 ShoppingTooltip2.SetMerchantCompareItem = LootLink_ShoppingTooltip2_SetMerchantCompareItem;
2813  
2814 lOriginal_ShoppingTooltip1_SetAuctionCompareItem = ShoppingTooltip1.SetAuctionCompareItem;
2815 ShoppingTooltip1.SetAuctionCompareItem = LootLink_ShoppingTooltip1_SetAuctionCompareItem;
2816 lOriginal_ShoppingTooltip2_SetAuctionCompareItem = ShoppingTooltip2.SetAuctionCompareItem;
2817 ShoppingTooltip2.SetAuctionCompareItem = LootLink_ShoppingTooltip2_SetAuctionCompareItem;
2818  
2819 -- Hook SetItemRef
2820 lOriginal_SetItemRef = SetItemRef;
2821 SetItemRef = LootLink_SetItemRef;
2822  
2823 -- Hook our hidden tooltip's OnTooltipAddMoney
2824 lOriginal_OnTooltipAddMoney = LLHiddenTooltip:GetScript("OnTooltipAddMoney");
2825 LLHiddenTooltip:SetScript("OnTooltipAddMoney", LootLink_OnTooltipAddMoney);
2826  
2827 -- Hook chat edit box
2828 lOriginal_ChatEdit_OnTabPressed = ChatEdit_OnTabPressed;
2829 ChatEdit_OnTabPressed = LootLink_ChatEdit_OnTabPressed;
2830 lOriginal_ChatEdit_OnTextChanged = ChatEdit_OnTextChanged;
2831 ChatEdit_OnTextChanged = LootLink_ChatEdit_OnTextChanged;
2832  
2833 -- Hook CloseWindows
2834 lOriginal_CloseWindows = CloseWindows;
2835 CloseWindows = LootLink_CloseWindows;
2836  
2837 if( DEFAULT_CHAT_FRAME ) then
2838 DEFAULT_CHAT_FRAME:AddMessage(LOOTLINK_LOADED);
2839 end
2840 UIErrorsFrame:AddMessage(LOOTLINK_LOADED, 1.0, 1.0, 1.0, 1.0, UIERRORS_HOLD_TIME);
2841 end
2842  
2843 function LootLink_Minimap_OnEnter()
2844 GameTooltip:SetOwner(this, "ANCHOR_BOTTOMLEFT");
2845 GameTooltip:AddLine(LOOTLINK_TITLE);
2846 if ( not LootLinkState.lockminimap ) then
2847 GameTooltip:AddLine("|cffaaaaaa "..LOOTLINK_MINIMAP_DRAG);
2848 end
2849 if ( LootLinkFrame.process ) then
2850 GameTooltip:AddLine("|cffaaaaaa "..getglobal("LLP_"..LootLinkFrame.process.."_LABEL"));
2851 if ( LootLink_Process:IsVisible() ) then
2852 GameTooltip:AddLine("|cffaaaaaa "..LOOTLINK_MINIMAP_PROCESS_SHOW);
2853 else
2854 GameTooltip:AddLine("|cffaaaaaa "..LOOTLINK_MINIMAP_PROCESS_HIDE);
2855 end
2856 end
2857 GameTooltip:Show();
2858 end
2859  
2860 function LootLink_Minimap_Position(x,y)
2861 if ( x or y ) then
2862 if ( x ) then if ( x < 0 ) then x = x + 360; end LootLinkState.x = x; end
2863 if ( y ) then LootLinkState.y = y; end
2864 end
2865 x, y = LootLinkState.x, LootLinkState.y
2866  
2867 if ( LootLinkOptionsFrame:IsVisible() ) then
2868 LLO_MinimapPos:SetValue( x or LLO_MINIMAP_X );
2869 LLO_MinimapOffset:SetValue( y or LLO_MINIMAP_Y );
2870 end
2871 LootLinkMinimapButton:SetPoint("TOPLEFT","Minimap","TOPLEFT",53-((80+(y or LLO_MINIMAP_Y))*cos(x or LLO_MINIMAP_X)),((80+(y or LLO_MINIMAP_Y))*sin(x or LLO_MINIMAP_X))-55);
2872 end
2873  
2874 function LootLink_Minimap_DragStart()
2875 if ( LootLinkState.lockminimap ) then return; end
2876 this:SetScript("OnUpdate", LootLink_Minimap_DragUpdate);
2877 end
2878 function LootLink_Minimap_DragStop()
2879 LootLinkMinimapButton:UnlockHighlight()
2880 this:SetScript("OnUpdate", nil);
2881 end
2882 function LootLink_Minimap_DragUpdate()
2883 -- Thanks to Gello for making this a ton shorter
2884 LootLinkMinimapButton:LockHighlight();
2885 local curX, curY = GetCursorPosition();
2886 local mapX, mapY = Minimap:GetCenter();
2887 local x, y;
2888 if ( IsShiftKeyDown() ) then
2889 y = math.pow( math.pow(curY - mapY * Minimap:GetEffectiveScale(), 2) + math.pow(mapX * Minimap:GetEffectiveScale() - curX, 2), 0.5) - 70;
2890 y = min( max( y, -30 ), 30 );
2891 end
2892 x = math.deg(math.atan2( curY - mapY * Minimap:GetEffectiveScale(), mapX * Minimap:GetEffectiveScale() - curX ));
2893 LootLink_Minimap_Position(x,y);
2894 end
2895  
2896 function LootLink_CanSendAuctionQuery()
2897 local value = lOriginal_CanSendAuctionQuery();
2898 if( value ) then
2899 LootLink_AuctionNextQuery();
2900 return nil;
2901 end
2902 return value;
2903 end
2904  
2905 function LootLink_AuctionFrameBrowse_OnEvent()
2906 -- Intentionally empty; don't allow the auction UI to update while we're scanning
2907 end
2908  
2909 function LootLink_GameTooltip_SetOwner(this, owner, anchor)
2910 lOriginal_GameTooltip_SetOwner(this, owner, anchor);
2911 lGameToolTipOwner = owner;
2912 end
2913  
2914 function LootLink_GameTooltip_ClearMoney()
2915 lOriginal_GameTooltip_ClearMoney();
2916 if( not lSuppressInfoAdd ) then
2917 lCheckTooltip = LootLink_CheckTooltipInfo();
2918 end
2919 end
2920  
2921 function LootLink_GameTooltip_ClearMoney_Temp()
2922 -- Intentionally empty; don't clear money while we use our hidden tooltip
2923 end
2924  
2925 function LootLink_ContainerFrameItemButton_OnEnter()
2926 LootLink_AutoInfoOff();
2927 lOriginal_ContainerFrameItemButton_OnEnter();
2928 if( not InRepairMode() and not MerchantFrame:IsVisible() ) then
2929 local frameID = this:GetParent():GetID();
2930 local buttonID = this:GetID();
2931 local link = GetContainerItemLink(frameID, buttonID);
2932 local name = LootLink_NameFromLink(link);
2933  
2934 if( name and ItemLinks[name] ) then
2935 local texture, itemCount, locked, quality, readable = GetContainerItemInfo(frameID, buttonID);
2936 LootLink_AddTooltipInfo(name, GameTooltip, itemCount);
2937 GameTooltip:Show();
2938 end
2939 end
2940 LootLink_AutoInfoOn();
2941 end
2942  
2943 function LootLink_ContainerFrame_Update(frame)
2944 LootLink_AutoInfoOff();
2945 lOriginal_ContainerFrame_Update(frame);
2946 if( not InRepairMode() and not MerchantFrame:IsVisible() and GameTooltip:IsVisible() ) then
2947 local frameID = frame:GetID();
2948 local frameName = frame:GetName();
2949 local iButton;
2950 for iButton = 1, frame.size do
2951 local button = getglobal(frameName.."Item"..iButton);
2952 if( GameTooltip:IsOwned(button) ) then
2953 local buttonID = button:GetID();
2954 local link = GetContainerItemLink(frameID, buttonID);
2955 local name = LootLink_NameFromLink(link);
2956  
2957 if( name and ItemLinks[name] ) then
2958 local texture, itemCount, locked, quality, readable = GetContainerItemInfo(frameID, buttonID);
2959 LootLink_AddTooltipInfo(name, GameTooltip, itemCount);
2960 GameTooltip:Show();
2961 end
2962 end
2963 end
2964 end
2965 LootLink_AutoInfoOn();
2966 end
2967  
2968 function LootLink_GameTooltip_OnHide()
2969 lOriginal_GameTooltip_OnHide();
2970 GameTooltip.llDone = nil;
2971 lCheckTooltip = nil;
2972 end
2973  
2974 function LootLink_GameTooltip_SetLootItem(this, slot)
2975 LootLink_AutoInfoOff();
2976 lOriginal_GameTooltip_SetLootItem(this, slot);
2977  
2978 local link = GetLootSlotLink(slot);
2979 local name = LootLink_NameFromLink(link);
2980 if( name and ItemLinks[name] and ItemLinks[name].p ) then
2981 local texture, item, quantity, quality = GetLootSlotInfo(slot);
2982 LootLink_AddTooltipInfo(name, GameTooltip, quantity);
2983 end
2984 LootLink_AutoInfoOn();
2985 end
2986  
2987 function LootLink_ShoppingTooltip1_SetMerchantCompareItem(this, id, num)
2988 LootLink_MoneyToggle();
2989 local retval = lOriginal_ShoppingTooltip1_SetMerchantCompareItem(this, id, num);
2990 LootLink_MoneyToggle(1);
2991 return retval;
2992 end
2993  
2994 function LootLink_ShoppingTooltip2_SetMerchantCompareItem(this, id, num)
2995 LootLink_MoneyToggle();
2996 local retval = lOriginal_ShoppingTooltip2_SetMerchantCompareItem(this, id, num);
2997 LootLink_MoneyToggle(1);
2998 return retval;
2999 end
3000  
3001 function LootLink_ShoppingTooltip1_SetAuctionCompareItem(this, _type, index, num)
3002 LootLink_MoneyToggle();
3003 local retval = lOriginal_ShoppingTooltip1_SetAuctionCompareItem(this, _type, index, num);
3004 LootLink_MoneyToggle(1);
3005 return retval;
3006 end
3007  
3008 function LootLink_ShoppingTooltip2_SetAuctionCompareItem(this, _type, index, num)
3009 LootLink_MoneyToggle();
3010 local retval = lOriginal_ShoppingTooltip2_SetAuctionCompareItem(this, _type, index, num);
3011 LootLink_MoneyToggle(1);
3012 return retval;
3013 end
3014  
3015 function LootLink_SetItemRef(link, text, button)
3016 lOriginal_SetItemRef(link, text, button);
3017  
3018 -- If this is a tooltip-creating link, add our information to it
3019 if( strsub(link, 1, 6) ~= "Player" ) then
3020 ItemRefTooltipMoneyFrame:SetPoint("LEFT", "ItemRefTooltipTextLeft1", "LEFT", 0, 0);
3021 ItemRefTooltipMoneyFrame:Hide();
3022  
3023 if( ItemRefTooltip:IsVisible() ) then
3024 local field = getglobal("ItemRefTooltipTextLeft1");
3025 if( field and field:IsShown() ) then
3026 local name = field:GetText();
3027 if( name and ItemLinks[name] ) then
3028 LootLink_AddTooltipInfo(name, ItemRefTooltip);
3029 end
3030 end
3031 end
3032 end
3033 end
3034  
3035 function LootLink_OnTooltipAddMoney()
3036 lOriginal_OnTooltipAddMoney();
3037 if( lBagID and lSlotID ) then
3038 LootLink_ScanSellPrice(arg1);
3039 end
3040 end
3041  
3042 function LootLink_OnEvent()
3043 if( event == "PLAYER_TARGET_CHANGED" ) then
3044 if( UnitIsUnit("target", "player") ) then
3045 return;
3046 elseif( UnitIsPlayer("target") ) then
3047 LootLink_Inspect("target");
3048 end
3049 elseif( event == "UPDATE_MOUSEOVER_UNIT" ) then
3050 LootLink_Inspect("mouseover");
3051 elseif( event == "PLAYER_ENTERING_WORLD" ) then
3052 this:RegisterEvent("UNIT_INVENTORY_CHANGED");
3053 -- Now that we're in the world, we want to watch for inventory changes
3054 this:RegisterEvent("UNIT_INVENTORY_CHANGED");
3055  
3056 -- Check to see if the user needs to upgrade their database
3057 LootLink_CheckVersionReminder();
3058  
3059 -- Do initial scan of inventory and equipped items
3060 LootLink_ScanInventory();
3061 LootLink_Inspect("player");
3062 elseif( event == "PLAYER_LEAVING_WORLD" ) then
3063 -- When we leave the world, we don't need to watch for inventory changes,
3064 -- especially since zoning will cause one UNIT_INVENTORY_CHANGED event for
3065 -- each item in the player's inventory and that they have equipped
3066 this:UnregisterEvent("UNIT_INVENTORY_CHANGED");
3067 elseif( event == "UNIT_INVENTORY_CHANGED" ) then
3068 if( arg1 == "player" ) then
3069 LootLink_ScanInventory();
3070 LootLink_Inspect("player");
3071 end
3072 elseif( event == "BANKFRAME_OPENED" ) then
3073 LootLink_ScanBank();
3074 elseif( event == "VARIABLES_LOADED" ) then
3075 LootLink_VariablesLoaded();
3076 elseif( event == "AUCTION_HOUSE_SHOW" ) then
3077 if( lScanAuction ) then
3078 LootLink_StartAuctionScan();
3079 end
3080 elseif( event == "AUCTION_HOUSE_CLOSED" ) then
3081 LootLink_StopAuctionScan();
3082 elseif( event == "AUCTION_ITEM_LIST_UPDATE" ) then
3083 LootLink_ScanAuction();
3084 elseif( event == "MERCHANT_SHOW" ) then
3085 LootLink_ScanSellPrices();
3086 --elseif( event == "PLAYER_LOGOUT" ) then
3087 --LootLink_ClearDelayed();
3088 elseif( event == "MEMORY_EXHAUSTED" ) then
3089 LLP_OUTOFMEM = 1;
3090 elseif( event == "MEMORY_RECOVERED" ) then
3091 LLP_OUTOFMEM = nil;
3092 else
3093 local name = LootLink_ProcessLinks(arg1, event == "CHAT_MSG_LOOT");
3094 if( name and ItemLinks[name] ) then
3095 LootLink_Event_ScanChat(name, ItemLinks[name], arg1);
3096 end
3097 end
3098 end
3099  
3100 function LootLink_RemoveItem(name, link, displayindex, index)
3101 local value = ItemLinks[name];
3102 if ( not value ) then
3103 return;
3104 end
3105 local found;
3106 if ( link and string.sub(link, 1, 5) == "item:" ) then
3107 link = string.sub( link, 6 );
3108 end
3109 if ( displayindex and not link and not index ) then
3110 link = DisplayIndices[displayindex][2].i;
3111 end
3112 if ( not link and not index ) then
3113 index = 0;
3114 end
3115 if ( link or index ) then
3116 if ( (index and index == 0) or (value.i and value.i == link) ) then
3117 found = 1;
3118 if ( value.m and value.m[1] ) then
3119 for k, v in value.m[1] do
3120 value[k] = v;
3121 end
3122 tremove( value.m, 1 );
3123  
3124 if ( getn(value.m) == 0 ) then
3125 value.m = nil;
3126 end
3127 else
3128 ItemLinks[name] = nil;
3129 di = 0;
3130 end
3131 else
3132 if ( value.m ) then
3133 for i=1, getn(value.m) do
3134 if ( (index and index == i) or (value.m[i].i == link) ) then
3135 found = 1;
3136 tremove( value.m, i );
3137 break;
3138 end
3139 end
3140 end
3141 end
3142  
3143 if ( found ) then
3144 LootLink_SortAlternates( name );
3145  
3146 if ( DisplayIndices and LootLinkFrame:IsVisible() ) then
3147 local dName, start;
3148 local i = 1;
3149 if ( DisplayIndices[i] ) then
3150 dName = DisplayIndices[i][1];
3151 end
3152 while dName do
3153 if dName == name then
3154 if not start then
3155 start = i;
3156 end
3157 elseif start then
3158 break;
3159 end
3160 i = i+1;
3161 if ( DisplayIndices[i] ) then
3162 dName = DisplayIndices[i][1];
3163 else
3164 dName = nil;
3165 end
3166 end
3167 if ( start and i ) then
3168 tremove(DisplayIndices, i-1);
3169 DisplayIndices.onePastEnd = DisplayIndices.onePastEnd - 1;
3170 if ( displayindex ) then
3171 LootLink_Update();
3172 LootLink_SetTitle();
3173 end
3174 end
3175 else
3176 DisplayIndices = nil;
3177 end
3178 return 1;
3179 end
3180 end
3181 end
3182  
3183 function LootLinkItemButton_OnClick(button)
3184 local name = this:GetText();
3185 local index = this.i;
3186 if( button == "LeftButton" ) then
3187 local data = DisplayIndices[this:GetID()+FauxScrollFrame_GetOffset(LootLinkListScrollFrame)];
3188 if( IsShiftKeyDown() and ChatFrameEditBox:IsVisible() ) then
3189 if ( not LootLink_CheckItemServer(data[2], lServerIndex) ) then
3190 local dialog = StaticPopup_Show("LOOTLINK_LINK_CONFIRM", LOOTLINK_STATICPOPUP_SERVER, LOOTLINK_STATICPOPUP_LINKITEM);
3191 if ( dialog ) then
3192 dialog.data = data;
3193 end
3194 elseif ( not GetItemInfo("item:"..data[2].i) ) then
3195 local dialog = StaticPopup_Show("LOOTLINK_LINK_CONFIRM", LOOTLINK_STATICPOPUP_INVALID, LOOTLINK_STATICPOPUP_LINKITEM);
3196 if ( dialog ) then
3197 dialog.data = data;
3198 end
3199 else
3200 ChatFrameEditBox:Insert(LootLink_GetLink(name, data[3]));
3201 end
3202 end
3203 if( IsControlKeyDown() ) then
3204 if ( not LootLink_CheckItemServer(data[2], lServerIndex) ) then
3205 local dialog = StaticPopup_Show("LOOTLINK_DRESSUP_CONFIRM", LOOTLINK_STATICPOPUP_SERVER, LOOTLINK_STATICPOPUP_DRESSUP);
3206 if ( dialog ) then
3207 dialog.data = data;
3208 end
3209 elseif ( not GetItemInfo("item:"..data[2].i) ) then
3210 local dialog = StaticPopup_Show("LOOTLINK_DRESSUP_CONFIRM", LOOTLINK_STATICPOPUP_INVALID, LOOTLINK_STATICPOPUP_DRESSUP);
3211 if ( dialog ) then
3212 dialog.data = data;
3213 end
3214 else
3215 DressUpItemLink(LootLink_GetLink(name, data[3]));
3216 end
3217 end
3218 elseif( button == "RightButton" ) then
3219 if( IsShiftKeyDown() and IsControlKeyDown() ) then
3220 local data = DisplayIndices[this:GetID()+FauxScrollFrame_GetOffset(LootLinkListScrollFrame)];
3221 local dialog = StaticPopup_Show("LOOTLINK_DELETEITEM_CONFIRM", data[2].c, name);
3222 if ( dialog ) then
3223 dialog.data = data;
3224 end
3225 --if ( LootLink_RemoveItem(name, nil, this:GetID()+FauxScrollFrame_GetOffset(LootLinkListScrollFrame)) ) then
3226 -- LootLink_SortAlternates(name);
3227 --end
3228 end
3229 end
3230 --@todo Telo: add a method to correct the color of items
3231 end
3232  
3233 function LootLink_OnShow()
3234 PlaySound("igMainMenuOpen");
3235 LootLink_Update();
3236 end
3237  
3238 function LootLink_OnHide()
3239 PlaySound("igMainMenuClose");
3240 end
3241  
3242 function LootLink_ClearDelayed()
3243 if ( LootLinkFrame.schedule ) then
3244 for k, v in LootLinkFrame.schedule do
3245 local value, index = LootLink_GetValue( v[1], nil, v[2] );
3246 if ( v and not v.t ) then
3247 if ( LootLink_RemoveItem(v[1], v[2]) ) then
3248 LootLink_SortAlternates(v[1]);
3249 end
3250 end
3251 end
3252 end
3253 LootLinkFrame.schedule = nil;
3254 end
3255  
3256 function LootLink_ScheduleItem(name,link,time)
3257 if ( not LootLinkFrame.schedule ) then
3258 LootLinkFrame.schedule = {};
3259 end
3260 for k, v in LootLinkFrame.schedule do
3261 if ( v[1] == name and v[2] == link ) then
3262 return;
3263 end
3264 end
3265 LLHiddenTooltip:SetHyperlink("item:"..link);
3266 tinsert( LootLinkFrame.schedule, {name,link,(time or LOOTLINK_SCHEDULE_DELAY)} );
3267 end
3268  
3269 function LootLink_OnUpdate(elapsed)
3270 if( lCheckTooltip ) then
3271 lCheckTooltip = LootLink_CheckTooltipInfo();
3272 end
3273 if ( LootLinkFrame.process ) then
3274 LootLinkProcess_Run();
3275 end
3276 local list = LootLinkFrame.schedule;
3277 if ( list ) then
3278 for k, v in list do
3279 v[3] = v[3] - elapsed;
3280 if ( v[3] < 0 ) then
3281 local value, index = LootLink_GetValue( v[1], nil, v[2] );
3282 if ( not value ) then
3283 -- Item was remove from ItemLinks table, stop trying to check for it.
3284 tremove( list, k );
3285 return;
3286 elseif ( LootLink_BuildSearchData( v[1], value, index ) ) then
3287 tremove( list, k );
3288 return;
3289 else
3290 -- Still don't have information from server.
3291 if ( v[4] and v[4] == 60 ) then
3292 -- we've tried long enough, fail this item;
3293 if ( LootLink_RemoveItem(v[1], v[2]) ) then
3294 LootLink_SortAlternates(name);
3295 end
3296 tremove( list, k );
3297 return;
3298 end
3299 v[4] = (v[4] or 0) + 1;
3300 v[3] = LOOTLINK_SCHEDULE_DELAY;
3301 end
3302 end
3303 end
3304 if ( getn(list) == 0 ) then
3305 list = nil;
3306 end
3307 end
3308 end
3309  
3310 function LootLinkItemButton_OnEnter()
3311 local link = LootLink_GetHyperlink(this:GetText(), this.i);
3312 if( link ) then
3313 LootLinkFrame.TooltipButton = this:GetID();
3314 LootLinkTooltip:SetOwner(this, "ANCHOR_BOTTOMRIGHT");
3315 if ( LootLink_SetHyperlink(LootLinkTooltip, this:GetText(), link, this.i) ) then
3316 LootLink_Update();
3317 end
3318 LootLink_AddTooltipTexture(link);
3319 LootLink_AddTooltipInfo(this:GetText(), nil, nil, this.i);
3320 end
3321 end
3322  
3323 function LootLinkItemButton_OnLeave()
3324 if( LootLinkFrame.TooltipButton ) then
3325 LootLinkFrame.TooltipButton = nil;
3326 HideUIPanel(LootLinkTooltip);
3327 end
3328 LootLink_AddTooltipTexture();
3329 end
3330  
3331 function LootLinkFrameDropDown_OnLoad()
3332 UIDropDownMenu_Initialize(LootLinkFrameDropDown, LootLinkFrameDropDown_Initialize);
3333 LootLink_UIDropDownMenu_SetSelectedID(LootLinkFrameDropDown, 1, LOOTLINK_DROPDOWN_LIST);
3334 UIDropDownMenu_SetWidth(80);
3335 UIDropDownMenu_SetButtonWidth(24);
3336 UIDropDownMenu_JustifyText("LEFT", LootLinkFrameDropDown)
3337 end
3338  
3339 function LootLinkFrameDropDownButton_OnClick()
3340 local oldID = UIDropDownMenu_GetSelectedID(LootLinkFrameDropDown);
3341 UIDropDownMenu_SetSelectedID(LootLinkFrameDropDown, this:GetID());
3342 if( oldID ~= this:GetID() ) then
3343 LootLink_Refresh();
3344 end
3345 LootLinkState.sortType = this:GetID();
3346 end
3347  
3348 function LLS_RarityDropDown_OnLoad()
3349 UIDropDownMenu_SetWidth(90);
3350 UIDropDownMenu_SetButtonWidth(24);
3351 UIDropDownMenu_JustifyText("LEFT", LLS_RarityDropDown);
3352 end
3353  
3354 function LLS_RarityDropDown_OnClick()
3355 UIDropDownMenu_SetSelectedID(LLS_RarityDropDown, this:GetID());
3356 end
3357  
3358 function LLS_BindsDropDown_OnLoad()
3359 UIDropDownMenu_SetWidth(90);
3360 UIDropDownMenu_SetButtonWidth(24);
3361 UIDropDownMenu_JustifyText("LEFT", LLS_BindsDropDown);
3362 end
3363  
3364 function LLS_BindsDropDown_OnClick()
3365 UIDropDownMenu_SetSelectedID(LLS_BindsDropDown, this:GetID());
3366 end
3367  
3368 function LLS_LocationDropDown_OnLoad()
3369 UIDropDownMenu_SetWidth(90);
3370 UIDropDownMenu_SetButtonWidth(24);
3371 UIDropDownMenu_JustifyText("LEFT", LLS_LocationDropDown);
3372 end
3373  
3374 function LLS_LocationDropDown_OnClick()
3375 UIDropDownMenu_SetSelectedID(LLS_LocationDropDown, this:GetID());
3376 end
3377  
3378 function LLS_TypeDropDown_OnLoad()
3379 UIDropDownMenu_SetWidth(90);
3380 UIDropDownMenu_SetButtonWidth(24);
3381 UIDropDownMenu_JustifyText("LEFT", LLS_TypeDropDown);
3382 end
3383  
3384 function LLS_TypeDropDown_OnClick()
3385 local oldID = UIDropDownMenu_GetSelectedID(LLS_TypeDropDown);
3386 UIDropDownMenu_SetSelectedID(LLS_TypeDropDown, this:GetID());
3387 if( oldID ~= this:GetID() ) then
3388 LootLink_SetupTypeUI(this:GetID(), 1);
3389 end
3390 end
3391  
3392 function LLS_SubtypeDropDown_OnLoad()
3393 UIDropDownMenu_SetWidth(90);
3394 UIDropDownMenu_SetButtonWidth(24);
3395 UIDropDownMenu_JustifyText("LEFT", LLS_SubtypeDropDown);
3396 end
3397  
3398 function LLS_SubtypeDropDown_OnClick()
3399 UIDropDownMenu_SetSelectedID(LLS_SubtypeDropDown, this:GetID());
3400 end
3401  
3402 function LLO_RarityDropDown_OnLoad()
3403 UIDropDownMenu_SetWidth(90);
3404 UIDropDownMenu_SetButtonWidth(24);
3405 UIDropDownMenu_JustifyText("LEFT", LLO_RarityDropDown);
3406 end
3407  
3408 function LLO_RarityDropDown_OnClick()
3409 UIDropDownMenu_SetSelectedID(LLO_RarityDropDown, this:GetID());
3410 end
3411  
3412 --------------------------------------------------------------------------------------------------
3413 -- Callback functions
3414 --------------------------------------------------------------------------------------------------
3415 function ToggleLootLink()
3416 if( LootLinkFrame:IsVisible() ) then
3417 HideUIPanel(LootLinkFrame);
3418 else
3419 ShowUIPanel(LootLinkFrame);
3420 end
3421 end
3422  
3423 function LootLink_SlashCommandHandler(msg)
3424 local reset;
3425 local makehome;
3426 local light;
3427 local aborted;
3428  
3429 if( not lDisableVersionReminder ) then
3430 LootLink_CheckVersionReminder();
3431 end
3432 if( not msg or msg == "" ) then
3433 ToggleLootLink();
3434 else
3435 local command = string.lower(msg);
3436 if( command == LOOTLINK_HELP ) then
3437 local index = 0;
3438 local value = getglobal("LOOTLINK_HELP_TEXT"..index);
3439 while( value ) do
3440 DEFAULT_CHAT_FRAME:AddMessage(value);
3441 index = index + 1;
3442 value = getglobal("LOOTLINK_HELP_TEXT"..index);
3443 end
3444 elseif( command == LOOTLINK_STATUS ) then
3445 LootLink_Status();
3446 elseif( command == LOOTLINK_AUCTION or command == LOOTLINK_SCAN ) then
3447 if( AuctionFrame and AuctionFrame:IsVisible() ) then
3448 local iButton;
3449 local button;
3450  
3451 -- Hide the UI from any current results, show the no results text so we can use it
3452 BrowseNoResultsText:Show();
3453 for iButton = 1, NUM_BROWSE_TO_DISPLAY do
3454 button = getglobal("BrowseButton"..iButton);
3455 button:Hide();
3456 end
3457 BrowsePrevPageButton:Hide();
3458 BrowseNextPageButton:Hide();
3459 BrowseSearchCountText:Hide();
3460  
3461 LootLink_StartAuctionScan();
3462 else
3463 lScanAuction = 1;
3464 LootLink_Status();
3465 end
3466 elseif( command == LOOTLINK_SHOWINFO ) then
3467 LootLinkState.HideInfo = nil;
3468 LootLink_Status();
3469 elseif( command == LOOTLINK_HIDEINFO ) then
3470 LootLinkState.HideInfo = 1;
3471 LootLink_Status();
3472 elseif( command == LOOTLINK_FULLMODE ) then
3473 LootLinkState.LightMode = nil;
3474 LootLink_Status();
3475 else
3476 local iStart;
3477 local iEnd;
3478 local args;
3479  
3480 iStart, iEnd, command, args = string.find(command, "^(%w+)%s*(.*)$");
3481  
3482 if( command == LOOTLINK_RESET ) then
3483 if( lResetNeedsConfirm ) then
3484 if( args == LOOTLINK_CONFIRM ) then
3485 LootLink_Reset();
3486 lResetNeedsConfirm = nil;
3487 lDisableVersionReminder = nil
3488 DEFAULT_CHAT_FRAME:AddMessage(LOOTLINK_RESET_DONE);
3489 end
3490 else
3491 reset = 1;
3492 lResetNeedsConfirm = 1;
3493 lDisableVersionReminder = 1;
3494 end
3495 elseif( LootLink_GetDataVersion() < 110 and command == LOOTLINK_MAKEHOME ) then
3496 if( lMakeHomeNeedsConfirm ) then
3497 if( args == LOOTLINK_CONFIRM ) then
3498 LootLink_MakeHome();
3499 lMakeHomeNeedsConfirm = nil;
3500 lDisableVersionReminder = nil;
3501 DEFAULT_CHAT_FRAME:AddMessage(LOOTLINK_MAKEHOME_DONE);
3502 end
3503 else
3504 makehome = 1;
3505 lMakeHomeNeedsConfirm = 1;
3506 lDisableVersionReminder = 1;
3507 end
3508 elseif( command == LOOTLINK_LIGHTMODE ) then
3509 if( lLightModeNeedsConfirm ) then
3510 if( args == LOOTLINK_CONFIRM ) then
3511 LootLink_LightMode();
3512 lLightModeNeedsConfirm = nil;
3513 DEFAULT_CHAT_FRAME:AddMessage(LOOTLINK_LIGHTMODE_DONE);
3514 end
3515 else
3516 light = 1;
3517 lLightModeNeedsConfirm = 1;
3518 end
3519 end
3520 end
3521 end
3522  
3523 if( not reset ) then
3524 if( lResetNeedsConfirm ) then
3525 aborted = 1;
3526 lResetNeedsConfirm = nil;
3527 DEFAULT_CHAT_FRAME:AddMessage(LOOTLINK_RESET_ABORTED);
3528 end
3529 end
3530  
3531 if( not makehome ) then
3532 if( lMakeHomeNeedsConfirm ) then
3533 aborted = 1;
3534 lMakeHomeNeedsConfirm = nil;
3535 DEFAULT_CHAT_FRAME:AddMessage(LOOTLINK_MAKEHOME_ABORTED);
3536 end
3537 end
3538  
3539 if( not light ) then
3540 if( lLightModeNeedsConfirm ) then
3541 lLightModeNeedsConfirm = nil;
3542 DEFAULT_CHAT_FRAME:AddMessage(LOOTLINK_LIGHTMODE_ABORTED);
3543 end
3544 end
3545  
3546 if( reset ) then
3547 DEFAULT_CHAT_FRAME:AddMessage(LOOTLINK_RESET_NEEDS_CONFIRM);
3548 end
3549  
3550 if( makehome ) then
3551 DEFAULT_CHAT_FRAME:AddMessage(LOOTLINK_MAKEHOME_NEEDS_CONFIRM);
3552 end
3553  
3554 if( light ) then
3555 DEFAULT_CHAT_FRAME:AddMessage(LOOTLINK_LIGHTMODE_NEEDS_CONFIRM);
3556 end
3557  
3558 if( aborted and not reset and not makehome ) then
3559 lDisableVersionReminder = nil
3560 end
3561 end
3562  
3563 function LootLink_Update()
3564 local iItem;
3565  
3566 if( not DisplayIndices ) then
3567 LootLink_BuildDisplayIndices();
3568 end
3569 FauxScrollFrame_Update(LootLinkListScrollFrame, DisplayIndices.onePastEnd - 1, LOOTLINK_ITEMS_SHOWN, LOOTLINK_ITEM_HEIGHT, nil, nil, nil, LootLinkHighlightFrame, 293, 316);
3570 LootLinkHighlightFrame:Hide();
3571 for iItem = 1, LOOTLINK_ITEMS_SHOWN, 1 do
3572 local itemIndex = iItem + FauxScrollFrame_GetOffset(LootLinkListScrollFrame);
3573 local lootLinkItem = getglobal("LootLinkItem"..iItem);
3574  
3575 if( itemIndex < DisplayIndices.onePastEnd ) then
3576 local value = DisplayIndices[itemIndex][2]; --LootLink_GetValue(DisplayIndices[itemIndex]);
3577 if ( not value ) then
3578 LootLink_Refresh();
3579 return;
3580 end
3581 if ( value ) then
3582 local color = { };
3583 local name = DisplayIndices[itemIndex][1]; --LootLink_GetName(DisplayIndices[itemIndex]);
3584 local index = DisplayIndices[itemIndex][3];
3585 local extra = getglobal(lootLinkItem:GetName().."Type");
3586 lootLinkItem.i = nil;
3587 local text = getglobal(lootLinkItem:GetName().."Text");
3588 local indexed = getglobal(lootLinkItem:GetName().."Indexed");
3589 text:SetPoint( "LEFT", 20, 0 );
3590 text:SetWidth(275);
3591 getglobal(lootLinkItem:GetName().."Indexed"):Hide();
3592 if ( index and index > 0 ) then
3593 lootLinkItem.i = index;
3594 if ( DisplayIndices[itemIndex-1] and DisplayIndices[itemIndex-1][1] == name ) then
3595 local _,_, enchant, bonus = string.find(value.i, "%d+:(%d+):(%d+):%d+");
3596 bonus = tonumber(bonus);
3597 enchant = tonumber(enchant);
3598 if ( bonus > 0 or enchant > 0 ) then
3599 text:SetPoint( "LEFT", 30, 0 );
3600 text:SetWidth(245);
3601 indexed:Show();
3602 end
3603 if ( enchant > 0 ) then
3604 indexed:SetVertexColor(0,1,0);
3605 else
3606 indexed:SetVertexColor(1,1,1);
3607 end
3608 end
3609 end
3610 local link = "item:"..value.i;
3611 local realname
3612 if ( link ) then
3613 realname = GetItemInfo( link );
3614 end
3615 local onserver = LootLink_CheckItemServer(value, lServerIndex);
3616 extra:SetVertexColor(1.0,1.0,1.0)
3617 SetDesaturation(extra,0);
3618 extra:SetAlpha(1.0);
3619 if ( not onserver ) then
3620 extra:SetTexture("Interface\\GossipFrame\\TaxiGossipIcon");
3621 extra:Show();
3622 elseif ( not realname ) then
3623 extra:SetTexture("Interface\\GossipFrame\\ActiveQuestIcon");
3624 extra:SetAlpha(0.5);
3625 SetDesaturation(extra,1);
3626 extra:Show();
3627 elseif ( not LootLink_ValidateItem(name, link) ) then
3628 extra:SetTexture("Interface\\GossipFrame\\AvailableQuestIcon");
3629 extra:SetVertexColor(1.0,0,0)
3630 extra:Show();
3631 else
3632 extra:Hide();
3633 end
3634  
3635 lootLinkItem:SetText(name);
3636 if( value.c ) then
3637 color.r, color.g, color.b = LootLink_GetRGBFromHexColor(value.c);
3638 lootLinkItem:SetTextColor(color.r, color.g, color.b);
3639 lootLinkItem.r = color.r;
3640 lootLinkItem.g = color.g;
3641 lootLinkItem.b = color.b;
3642 else
3643 lootLinkItem.r = 0;
3644 lootLinkItem.g = 0;
3645 lootLinkItem.b = 0;
3646 end
3647 if ( LootLinkFrame.qs and LootLinkFrame.qs == itemIndex ) then
3648 if ( color ) then
3649 LootLinkHighlight:SetVertexColor(color.r, color.g, color.b);
3650 else
3651 LootLinkHighlight:SetVertexColor(0.5, 0.5, 0.5);
3652 end
3653 lootLinkItem:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
3654 LootLinkHighlightFrame:SetPoint("TOPLEFT", "LootLinkItem"..iItem, "TOPLEFT", 0, 0);
3655 LootLinkHighlightFrame:Show();
3656 end
3657 lootLinkItem:Show();
3658  
3659 if( LootLinkFrame.TooltipButton and LootLinkFrame.TooltipButton == iItem ) then
3660 if( value.i ) then
3661 local link = LootLink_GetHyperlink(name, index);
3662 LootLinkTooltip:SetOwner(lootLinkItem, "ANCHOR_BOTTOMRIGHT");
3663 LootLink_SetHyperlink(LootLinkTooltip, name, link, index);
3664 LootLink_AddTooltipInfo(name);
3665 LootLink_AddTooltipTexture(link);
3666 LootLinkTooltip:Show();
3667 else
3668 LootLinkItemButton_OnLeave();
3669 end
3670 end
3671 end
3672 else
3673 lootLinkItem:Hide();
3674 end
3675 end
3676 end
3677  
3678 function LootLink_Search()
3679 LootLinkSearchFrame:Show();
3680 end
3681  
3682 function LootLink_Refresh()
3683 FauxScrollFrame_SetOffset(LootLinkListScrollFrame, 0);
3684 getglobal("LootLinkListScrollFrameScrollBar"):SetValue(0);
3685 LootLink_BuildDisplayIndices();
3686 LootLink_Update();
3687 end
3688  
3689 function LootLink_DoSearch()
3690 LootLink_Refresh();
3691 end
3692  
3693 function LootLinkSearch_LoadValues()
3694 local sp = LootLinkFrame.SearchParams;
3695 local field;
3696  
3697 if( LootLinkState.LightMode ) then
3698 getglobal("LLS_TextDisabled"):Show();
3699 getglobal("LLS_TextEditBox"):Hide();
3700 getglobal("LLS_NameEditBox"):SetFocus();
3701 else
3702 getglobal("LLS_TextDisabled"):Hide();
3703 field = getglobal("LLS_TextEditBox");
3704 field:Show();
3705 field:SetFocus();
3706 if( sp and sp.text ) then
3707 field:SetText(sp.text);
3708 else
3709 field:SetText("");
3710 end
3711 end
3712  
3713 field = getglobal("LLS_NameEditBox");
3714 if( sp and sp.name ) then
3715 field:SetText(sp.name);
3716 else
3717 field:SetText("");
3718 end
3719  
3720 UIDropDownMenu_Initialize(LLS_RarityDropDown, LLS_RarityDropDown_Initialize);
3721 if( sp and sp.rarity ) then
3722 LootLink_UIDropDownMenu_SetSelectedID(LLS_RarityDropDown, sp.rarity, LLS_RARITY_LIST);
3723 else
3724 LootLink_UIDropDownMenu_SetSelectedID(LLS_RarityDropDown, 1, LLS_RARITY_LIST);
3725 end
3726  
3727 if( sp and sp.server ) then
3728 getglobal("LLS_ServerCheckButton"):SetChecked(1);
3729 else
3730 getglobal("LLS_ServerCheckButton"):SetChecked(0);
3731 end
3732  
3733 UIDropDownMenu_Initialize(LLS_BindsDropDown, LLS_BindsDropDown_Initialize);
3734 if( sp and sp.binds ) then
3735 LootLink_UIDropDownMenu_SetSelectedID(LLS_BindsDropDown, sp.binds, LLS_BINDS_LIST);
3736 else
3737 LootLink_UIDropDownMenu_SetSelectedID(LLS_BindsDropDown, 1, LLS_BINDS_LIST);
3738 end
3739  
3740 if( sp and sp.unique ) then
3741 getglobal("LLS_UniqueCheckButton"):SetChecked(1);
3742 else
3743 getglobal("LLS_UniqueCheckButton"):SetChecked(0);
3744 end
3745  
3746 UIDropDownMenu_Initialize(LLS_LocationDropDown, LLS_LocationDropDown_Initialize);
3747 if( sp and sp.location ) then
3748 LootLink_UIDropDownMenu_SetSelectedID(LLS_LocationDropDown, sp.location, LLS_LOCATION_LIST);
3749 else
3750 LootLink_UIDropDownMenu_SetSelectedID(LLS_LocationDropDown, 1, LLS_LOCATION_LIST);
3751 end
3752  
3753 if( LootLinkState and LootLinkState.spoof ) then
3754 LLS_SpoofCheckButton:Hide();
3755 else
3756 LLS_SpoofCheckButton:Show();
3757 if( sp and sp.spoof ) then
3758 getglobal("LLS_SpoofCheckButton"):SetChecked(1);
3759 else
3760 getglobal("LLS_SpoofCheckButton"):SetChecked(0);
3761 end
3762 end
3763  
3764 if( sp and sp.usable ) then
3765 getglobal("LLS_UsableCheckButton"):SetChecked(1);
3766 else
3767 getglobal("LLS_UsableCheckButton"):SetChecked(0);
3768 end
3769  
3770 field = getglobal("LLS_MinimumLevelEditBox");
3771 if( sp and sp.minLevel ) then
3772 field:SetText(sp.minLevel);
3773 else
3774 field:SetText("");
3775 end
3776  
3777 field = getglobal("LLS_MaximumLevelEditBox");
3778 if( sp and sp.maxLevel ) then
3779 field:SetText(sp.maxLevel);
3780 else
3781 field:SetText("");
3782 end
3783  
3784 UIDropDownMenu_Initialize(LLS_TypeDropDown, LLS_TypeDropDown_Initialize);
3785 if( sp and sp.type ) then
3786 LootLink_UIDropDownMenu_SetSelectedID(LLS_TypeDropDown, sp.type, LLS_TYPE_LIST);
3787 else
3788 LootLink_UIDropDownMenu_SetSelectedID(LLS_TypeDropDown, 1, LLS_TYPE_LIST);
3789 end
3790  
3791 if( sp and sp.type ) then
3792 LootLink_SetupTypeUI(sp.type, sp.subtype);
3793 else
3794 LootLink_SetupTypeUI(1, 1);
3795 end
3796  
3797 field = getglobal("LLS_MinimumDamageEditBox");
3798 if( sp and sp.minMinDamage ) then
3799 field:SetText(sp.minMinDamage);
3800 else
3801 field:SetText("");
3802 end
3803  
3804 field = getglobal("LLS_MaximumDamageEditBox");
3805 if( sp and sp.minMaxDamage ) then
3806 field:SetText(sp.minMaxDamage);
3807 else
3808 field:SetText("");
3809 end
3810  
3811 field = getglobal("LLS_MaximumSpeedEditBox");
3812 if( sp and sp.maxSpeed ) then
3813 field:SetText(sp.maxSpeed);
3814 else
3815 field:SetText("");
3816 end
3817  
3818 field = getglobal("LLS_MinimumDPSEditBox");
3819 if( sp and sp.minDPS ) then
3820 field:SetText(sp.minDPS);
3821 else
3822 field:SetText("");
3823 end
3824  
3825 field = getglobal("LLS_MinimumArmorEditBox");
3826 if( sp and sp.minArmor ) then
3827 field:SetText(sp.minArmor);
3828 else
3829 field:SetText("");
3830 end
3831  
3832 field = getglobal("LLS_MinimumBlockEditBox");
3833 if( sp and sp.minBlock ) then
3834 field:SetText(sp.minBlock);
3835 else
3836 field:SetText("");
3837 end
3838  
3839 field = getglobal("LLS_MinimumSlotsEditBox");
3840 if( sp and sp.minSlots ) then
3841 field:SetText(sp.minSlots);
3842 else
3843 field:SetText("");
3844 end
3845  
3846 field = getglobal("LLS_MinimumSkillEditBox");
3847 if( sp and sp.minSkill ) then
3848 field:SetText(sp.minSkill);
3849 else
3850 field:SetText("");
3851 end
3852  
3853 field = getglobal("LLS_MaximumSkillEditBox");
3854 if( sp and sp.maxSkill ) then
3855 field:SetText(sp.maxSkill);
3856 else
3857 field:SetText("");
3858 end
3859  
3860 --[[if( sp and sp.set ) then
3861 getglobal("LLS_SetCheckButton"):SetChecked(1);
3862 else
3863 getglobal("LLS_SetCheckButton"):SetChecked(0);
3864 end]]
3865 end
3866  
3867 function LootLinkSearch_SaveValues()
3868 local sp;
3869 local interesting;
3870 local field;
3871 local value;
3872  
3873 LootLinkFrame.SearchParams = { };
3874 sp = LootLinkFrame.SearchParams;
3875  
3876 field = getglobal("LLS_TextEditBox");
3877 value = field:GetText();
3878 if( value and value ~= "" ) then
3879 sp.text = value;
3880 interesting = 1;
3881 end
3882  
3883 field = getglobal("LLS_NameEditBox");
3884 value = field:GetText();
3885 if( value and value ~= "" ) then
3886 sp.name = value;
3887 interesting = 1;
3888 end
3889  
3890 value = UIDropDownMenu_GetSelectedID(LLS_RarityDropDown);
3891 if( value and value ~= 1 ) then
3892 sp.rarity = value;
3893 interesting = 1;
3894 end
3895  
3896 field = getglobal("LLS_ServerCheckButton");
3897 value = field:GetChecked();
3898 if( value ) then
3899 sp.server = value;
3900 interesting = 1;
3901 end
3902  
3903 value = UIDropDownMenu_GetSelectedID(LLS_BindsDropDown);
3904 if( value and value ~= 1 ) then
3905 sp.binds = value;
3906 interesting = 1;
3907 end
3908  
3909 field = getglobal("LLS_UniqueCheckButton");
3910 value = field:GetChecked();
3911 if( value ) then
3912 sp.unique = value;
3913 interesting = 1;
3914 end
3915  
3916 value = UIDropDownMenu_GetSelectedID(LLS_LocationDropDown);
3917 if( value and value ~= 1 ) then
3918 sp.location = value;
3919 interesting = 1;
3920 end
3921  
3922 field = getglobal("LLS_UsableCheckButton");
3923 value = field:GetChecked();
3924 if( value ) then
3925 sp.usable = value;
3926 interesting = 1;
3927 end
3928  
3929 field = getglobal("LLS_MinimumLevelEditBox");
3930 value = field:GetText();
3931 if( value and LootLink_CheckNumeric(value) ) then
3932 sp.minLevel = tonumber(value);
3933 interesting = 1;
3934 end
3935  
3936 field = getglobal("LLS_MaximumLevelEditBox");
3937 value = field:GetText();
3938 if( value and LootLink_CheckNumeric(value) ) then
3939 sp.maxLevel = tonumber(value);
3940 interesting = 1;
3941 end
3942  
3943 value = UIDropDownMenu_GetSelectedID(LLS_TypeDropDown);
3944 if( value and value ~= 1 ) then
3945 sp.type = value;
3946 interesting = 1;
3947 end
3948  
3949 field = getglobal("LLS_SpoofCheckButton");
3950 value = field:GetChecked();
3951 if( value ) then
3952 sp.spoof = value;
3953 interesting = 1;
3954 end
3955  
3956 value = UIDropDownMenu_GetSelectedID(LLS_SubtypeDropDown);
3957 if( value and value ~= 1 ) then
3958 sp.subtype = value;
3959 if( sp.type and sp.type ~= 1 ) then
3960 interesting = 1;
3961 end
3962 end
3963  
3964 field = getglobal("LLS_MinimumDamageEditBox");
3965 value = field:GetText();
3966 if( value and LootLink_CheckNumeric(value) ) then
3967 sp.minMinDamage = tonumber(value);
3968 interesting = 1;
3969 end
3970  
3971 field = getglobal("LLS_MaximumDamageEditBox");
3972 value = field:GetText();
3973 if( value and LootLink_CheckNumeric(value) ) then
3974 sp.minMaxDamage = tonumber(value);
3975 interesting = 1;
3976 end
3977  
3978 field = getglobal("LLS_MaximumSpeedEditBox");
3979 value = field:GetText();
3980 if( value and LootLink_CheckNumeric(value) ) then
3981 sp.maxSpeed = tonumber(value);
3982 interesting = 1;
3983 end
3984  
3985 field = getglobal("LLS_MinimumDPSEditBox");
3986 value = field:GetText();
3987 if( value and LootLink_CheckNumeric(value) ) then
3988 sp.minDPS = tonumber(value);
3989 interesting = 1;
3990 end
3991  
3992 field = getglobal("LLS_MinimumArmorEditBox");
3993 value = field:GetText();
3994 if( value and LootLink_CheckNumeric(value) ) then
3995 sp.minArmor = tonumber(value);
3996 interesting = 1;
3997 end
3998  
3999 field = getglobal("LLS_MinimumBlockEditBox");
4000 value = field:GetText();
4001 if( value and LootLink_CheckNumeric(value) ) then
4002 sp.minBlock = tonumber(value);
4003 interesting = 1;
4004 end
4005  
4006 field = getglobal("LLS_MinimumSlotsEditBox");
4007 value = field:GetText();
4008 if( value and LootLink_CheckNumeric(value) ) then
4009 sp.minSlots = tonumber(value);
4010 interesting = 1;
4011 end
4012  
4013 field = getglobal("LLS_MinimumSkillEditBox");
4014 value = field:GetText();
4015 if( value and LootLink_CheckNumeric(value) ) then
4016 sp.minSkill = tonumber(value);
4017 interesting = 1;
4018 end
4019  
4020 field = getglobal("LLS_MaximumSkillEditBox");
4021 value = field:GetText();
4022 if( value and LootLink_CheckNumeric(value) ) then
4023 sp.maxSkill = tonumber(value);
4024 interesting = 1;
4025 end
4026  
4027 --[[value = getglobal("LLS_SetCheckButton"):GetChecked();
4028 if ( value ) then
4029 sp.set = value;
4030 interesting = 1;
4031 end]]
4032  
4033 -- Only save search params if we had interesting data on the page
4034 if( not interesting ) then
4035 LootLinkFrame.SearchParams = nil;
4036 else
4037 if( IsControlKeyDown() ) then
4038 sp.plain = nil;
4039 else
4040 sp.plain = 1;
4041 end
4042 end
4043 end
4044  
4045 function LootLinkSearchFrame_SaveSearchParams()
4046 LootLinkSearchFrame.OldSearchParams = LootLinkFrame.SearchParams;
4047 end
4048  
4049 function LootLinkSearchFrame_RestoreSearchParams()
4050 LootLinkFrame.SearchParams = LootLinkSearchFrame.OldSearchParams;
4051 end
4052  
4053 function LootLinkSearchFrame_ChangeFocus()
4054 local frames = {"LLS_TextEditBox",
4055 "LLS_NameEditBox",
4056 "LLS_MinimumLevelEditBox",
4057 "LLS_MaximumLevelEditBox",
4058 "LLS_MinimumSlotsEditBox",
4059 "LLS_MinimumDamageEditBox",
4060 "LLS_MaximumDamageEditBox",
4061 "LLS_MaximumSpeedEditBox",
4062 "LLS_MinimumDPSEditBox",
4063 "LLS_MinimumArmorEditBox",
4064 "LLS_MinimumBlockEditBox",
4065 "LLS_MinimumSkillEditBox",
4066 "LLS_MaximumSkillEditBox",
4067 }
4068  
4069 local name = this:GetName();
4070 for i=1, 13 do
4071 if ( frames[i] == name ) then
4072 if ( IsShiftKeyDown() ) then
4073 i = i-1;
4074 else
4075 i = i+1;
4076 end
4077 while frames[i] do
4078 local nextframe = getglobal(frames[i]);
4079 if ( nextframe:IsVisible() ) then
4080 nextframe:SetFocus();
4081 return;
4082 end
4083 if ( IsShiftKeyDown() ) then
4084 i = i-1;
4085 else
4086 i = i+1;
4087 end
4088 end
4089 return;
4090 end
4091 end
4092 end
4093  
4094 function LootLinkSearchFrame_Cancel()
4095 PlaySound("gsTitleOptionExit");
4096 LootLinkSearchFrame:Hide();
4097 LootLinkSearchFrame_RestoreSearchParams();
4098 end
4099  
4100 function LootLinkSearchFrame_Okay()
4101 PlaySound("gsTitleOptionOK");
4102 LootLinkSearchFrame:Hide();
4103 LootLinkSearch_SaveValues();
4104 LootLink_DoSearch();
4105 end
4106  
4107 function LootLinkQuickSearch_Search(Next)
4108 if ( not Next ) then
4109 Next = 0;
4110 end
4111 local text = LootLinkFrameQuickSearch:GetText();
4112 local length = string.len( text );
4113 local last = LootLinkFrameQuickSearch.last;
4114 local function DoScroll(i)
4115 local offset = FauxScrollFrame_GetOffset(LootLinkListScrollFrame);
4116 if ( i < offset or i > offset + LOOTLINK_ITEMS_SHOWN ) then
4117 if ( i > DisplayIndices.onePastEnd - LOOTLINK_ITEMS_SHOWN ) then
4118 i = DisplayIndices.onePastEnd - LOOTLINK_ITEMS_SHOWN;
4119 end
4120 i = i-1;
4121 local val = (i * 16) - 0.5
4122 LootLinkListScrollFrameScrollBar:SetValue(val);
4123 LootLinkListScrollFrame.offset = i;
4124 end
4125 end
4126 local function DoSearch(index, offset)
4127 if ( not offset ) then
4128 offset = getn(DisplayIndices);
4129 end
4130 for i=index+Next, offset do
4131 local name = LootLink_GetName(DisplayIndices[i]);
4132 if ( name and string.find( string.lower(name), string.lower(text), 1, 1 ) ) then
4133 LootLinkFrame.qs = i;
4134 DoScroll(i);
4135 return 1;
4136 end
4137 end
4138 end
4139 if ( text and text ~= "" ) then
4140 if ( not last or length < last ) then
4141 if ( not DoSearch(LootLinkFrame.qs) and not DoSearch(1, LootLinkFrame.qs+1) ) then
4142 LootLinkFrameQuickSearch.last = length;
4143 LootLinkFrameQuickSearch:SetTextColor(1,0,0);
4144 LootLinkFrame.qs = 0;
4145 else
4146 LootLinkFrameQuickSearch:SetTextColor(1,1,1);
4147 LootLinkFrameQuickSearch.last = nil;
4148 end
4149 end
4150 else
4151 LootLinkFrame.qs = 0;
4152 LootLinkFrameQuickSearch:SetTextColor(1,1,1);
4153 end
4154 LootLink_Update();
4155 end
4156  
4157 function LootLinkQuickSearch_FullSearch()
4158 local name = this:GetText();
4159 if ( name ) then
4160 if ( name == "" ) then
4161 name = nil;
4162 end
4163 if ( name and not LootLinkFrame.SearchParams ) then
4164 LootLinkFrame.SearchParams = { };
4165 end
4166 if ( LootLinkFrame.SearchParams ) then
4167 LootLinkFrame.SearchParams.name = name;
4168 end
4169 end
4170 LootLink_DoSearch();
4171 LootLinkFrameQuickSearch:SetText(name or "");
4172 end
4173  
4174 function LootLinkQuickSearch_Clear()
4175 LootLinkFrameQuickSearch:SetText("");
4176 LootLinkFrameQuickSearch.last = nil;
4177 end
4178  
4179 LootLinkOptionsList = {
4180 hideminimap = { frame = "LLO_HideMinimap", flip = 1 },
4181 lockminimap = { frame = "LLO_LockMinimap" },
4182 hideicon = { frame = "LLO_IconCheckButton", flip = 1 },
4183 HideInfo = { frame = "LLO_ExtraInfoCheckButton", flip = 1 },
4184 mouseover = { frame = "LLO_MouseoverCheckButton" },
4185 typelinks = { frame = "LLO_TypeLinksCheckButton" },
4186 autotypelinks = { frame = "LLO_AutoTypeLinksCheckButton", dependancy = "typelinks" },
4187  
4188 server = { frame = "LLO_ServerCheckButton", refresh = 1 },
4189 spoof = { frame = "LLO_SpoofCheckButton", refresh = 1 },
4190 nosame = { frame = "LLO_SameNameCheckButton", flip = 1, refresh = 1 },
4191 novariants = { frame = "LLO_VariantCheckButton", flip = 1, dependancy = "nosame", refresh = 1 },
4192 enchants = { frame = "LLO_EnchantsCheckButton", flip = 1, dependancy = "nosame", refresh = 1 },
4193  
4194 x = { frame = "LLO_MinimapPos", slider = LLO_MINIMAP_X},
4195 y = { frame = "LLO_MinimapOffset", slider = LLO_MINIMAP_Y },
4196  
4197 rarityfilter = { frame = "LLO_RarityDropDown", dropdown = {LLO_RarityDropDown_Initialize, 2, LLO_RARITY_LIST}, refresh = 1 },
4198 };
4199  
4200 function LootLinkOptions_LoadValues()
4201 local op = LootLinkState;
4202  
4203 for k, v in LootLinkOptionsList do
4204 local frame = getglobal( v.frame );
4205 if ( frame ) then
4206 if ( v.dropdown ) then
4207 UIDropDownMenu_Initialize(frame, v.dropdown[1]);
4208 LootLink_UIDropDownMenu_SetSelectedID(frame, 1, v.dropdown[3]);
4209 end
4210 local value = op[k];
4211 if value then
4212 if ( v.slider ) then
4213 frame:SetValue( value );
4214 LootLinkOptionsFrame[k] = value;
4215 elseif ( v.dropdown ) then
4216 LootLink_UIDropDownMenu_SetSelectedID(frame, value+v.dropdown[2], v.dropdown[3]);
4217 end
4218 elseif ( v.slider ) then
4219 frame:SetValue( v.slider );
4220 LootLinkOptionsFrame[k] = nil;
4221 end
4222 if ( not v.slider and not v.dropdown ) then
4223 if ( v.flip ) then
4224 frame:SetChecked(1-(value or 0))
4225 else
4226 frame:SetChecked(value)
4227 end
4228 end
4229 if ( v.dependancy ) then
4230 if ( getglobal(LootLinkOptionsList[v.dependancy].frame):GetChecked() ) then
4231 frame:Enable();
4232 getglobal(frame:GetName().."Text"):SetTextColor(1, 0.82, 0);
4233 else
4234 frame:Disable();
4235 getglobal(frame:GetName().."Text"):SetTextColor(0.3, 0.3, 0.3);
4236 end
4237 end
4238 else
4239 ChatFrame1:AddMessage(k.." no frame?");
4240 end
4241 end
4242  
4243 LootLinkOptionsFrame.needsave = 1;
4244 end
4245  
4246 function LootLinkOptions_SaveValues()
4247 local op = LootLinkState;
4248 local refresh;
4249  
4250 for k, v in LootLinkOptionsList do
4251 local frame = getglobal( v.frame );
4252 if ( frame ) then
4253 local value = op[k];
4254 if ( v.dropdown ) then
4255 value = UIDropDownMenu_GetSelectedID(frame);
4256 if ( value == 1 ) then
4257 value = nil;
4258 else
4259 value = value - (v.dropdown[2] or 0);
4260 end
4261 elseif ( not v.slider ) then
4262 local checked = frame:GetChecked();
4263 if ( v.flip ) then
4264 if ( checked ) then
4265 checked = nil
4266 else
4267 checked = 1;
4268 end
4269 end
4270 value = checked;
4271 end
4272 if ( v.refresh and op[k] ~= value ) then
4273 refresh = 1;
4274 end
4275 op[k] = value;
4276 else
4277 ChatFrame1:AddMessage(k.." no frame?");
4278 end
4279 end
4280  
4281 if ( refresh ) then
4282 LootLink_Refresh();
4283 end
4284 LootLinkOptionsFrame.needsave = nil;
4285 end
4286  
4287 function LootLinkOptionsFrame_Defaults()
4288 local op = LootLinkState;
4289 for k, v in LootLinkOptionsList do
4290 op[k] = nil;
4291 end
4292 LootLinkOptions_LoadValues();
4293 end
4294  
4295 function LootLinkOptionsFrame_Cancel()
4296 if ( LootLinkOptionsFrame.needsave ) then
4297 LootLinkOptionsFrame.needsave = nil;
4298 if ( LootLinkOptionsFrame.x or LootLinkOptionsFrame.y ) then
4299 LootLink_Minimap_Position( LootLinkOptionsFrame.x, LootLinkOptionsFrame.y );
4300 end
4301 end
4302 PlaySound("gsTitleOptionExit");
4303 LootLinkOptionsFrame:Hide();
4304 end
4305  
4306 function LootLinkOptionsFrame_Okay()
4307 PlaySound("gsTitleOptionOK");
4308 LootLinkOptions_SaveValues();
4309 LootLinkOptionsFrame:Hide();
4310 end
4311  
4312 function LootLink_CloseWindows(ignoreCenter)
4313 if ( LootLinkOptionsFrame:IsVisible() ) then
4314 LootLinkOptionsFrame_Cancel();
4315 return 1;
4316 end
4317 if ( LootLinkSearchFrame:IsVisible() ) then
4318 LootLinkSearchFrame_Cancel();
4319 return 1;
4320 end
4321 return lOriginal_CloseWindows(ignoreCenter);
4322 end
4323  
4324 function LootLink_ValidateItem(name, link, fixlink)
4325 -- Basic validation of enchants and stat bonuses
4326 -- todo : more complex evaluation of the stat bonuses taking in to account item level and base stats
4327 if ( not link ) then return nil;
4328 elseif ( string.sub(link, 1, 5) ~= "item:" ) then
4329 link = "item:"..link;
4330 end
4331 local realname, ilink, quality, level, sType, sSubType, count, equip = GetItemInfo(link);
4332 if ( realname ) then
4333 if ( realname ~= name ) then
4334 -- quickly kill anything that's really wrong.
4335 if ( not fixlink ) then return nil; end
4336 name = realname;
4337 end
4338  
4339 local _,_, itemid, enchant, stat = string.find( link, "(%d+):(%d+):(%d+):%d+" );
4340  
4341 if ( tonumber(stat) > 0 ) then
4342 if ( quality ~= 2 and quality ~= 3 and itemid ~= "20039" ) then -- special case for Dark Iron Boots, grr.
4343 -- Nothing but Uncommon and Rare items have stat bonuses
4344 if ( not fixlink ) then return nil; end
4345 stat = 0;
4346 elseif( lNoBonuses[equip] == 2 ) then
4347 -- Nothing that can't be equiped can't have stat bonuses
4348 if ( not fixlink ) then return nil; end
4349 stat = 0;
4350 end
4351 end
4352 if ( tonumber(enchant) > 0 ) then
4353 if ( lNoBonuses[equip] ) then
4354 -- Nothing that isn't armor or weapons can have enchants
4355 if ( not fixlink ) then return nil; end
4356 enchant = 0;
4357 end
4358 end
4359  
4360 return name, itemid..":"..enchant..":"..stat..":0";
4361 else
4362 if ( not fixlink ) then return 1; end
4363 return name, string.sub(link,6);
4364 end
4365 end
4366  
4367  
4368 --------------------------------------------------------------------------------------------------
4369 -- Clean and Purge functions
4370 --------------------------------------------------------------------------------------------------
4371  
4372 local LLPtodo;
4373 local LLPvars;
4374  
4375 function LootLink_CheckDuplicate(name)
4376 local links = {};
4377 local value = ItemLinks[name];
4378 local dups = 0;
4379 if ( value and value.m ) then
4380 links[value.i] = 1;
4381 local i = 1;
4382 --while value and value.m and value.m[i] do
4383 for i=getn(value.m), 1, -1 do
4384 if ( links[value.m[i].i] ) then
4385 dups = dups + 1;
4386 LootLink_RemoveItem(name, nil, nil, i);
4387 else
4388 links[value.m[i].i] = 1;
4389 end
4390 end
4391 end
4392 return dups;
4393 end
4394  
4395 function LootLink_Process_Cancel()
4396 LootLink_Process:Hide();
4397 LootLink_Process:SetScript("OnUpdate", nil);
4398 LootLink_Process.fade = nil;
4399 LootLinkFrame.process = nil;
4400 LootLink_Process_ToggleButtons(1);
4401  
4402 if ( LLPtodo ) then
4403 local text = getglobal("LLP_"..LLPvars.functype.."_CANCEL");
4404 text = string.gsub( text, "%%r", LLPvars.total-LLPvars.done );
4405 text = string.gsub( text, "%%u", LLPvars.updated );
4406 text = string.gsub( text, "%%t", LLPvars.total );
4407 text = string.gsub( text, "%%f", LLPvars.failed );
4408 DEFAULT_CHAT_FRAME:AddMessage(text);
4409  
4410 LootLink_Process_Time:SetText("");
4411  
4412 LLPvars = nil;
4413 LLPtodo = nil;
4414 end
4415 end
4416  
4417 function LootLink_Process_Memory()
4418 LootLink_Process_Cancel();
4419 DEFAULT_CHAT_FRAME:AddMessage(LLP_ABORT1);
4420 DEFAULT_CHAT_FRAME:AddMessage(LLP_ABORT2);
4421 end
4422  
4423 function LootLink_Process_ToggleButtons(on)
4424 if ( on ) then
4425 LLO_Purge:Enable();
4426 LLO_Fix:Enable();
4427 else
4428 LLO_Purge:Disable();
4429 LLO_Fix:Disable();
4430 end
4431 end
4432  
4433 function LootLinkProcess_PURGE()
4434 local todo = LLPtodo[LLPvars.done+1];
4435  
4436 local name, link = todo[1], todo[2];
4437 local _,_,itemid,enchantid,suffixid=string.find(link, "(%d+):(%d+):(%d+):%d+");
4438  
4439 LootLink_SortAlternates(name);
4440 local op = LootLinkState;
4441 local value = ItemLinks[name];
4442  
4443 if ( value and value.m ) then
4444 if ( op.nosame or (op.novariants and tonumber(suffixid) > 0) ) then
4445 LLPvars.updated = LLPvars.updated + getn(value.m);
4446 value.m = nil;
4447 end
4448 if ( op.enchants ) then
4449 if ( tonumber(enchantid) > 0 ) then
4450 if ( LootLink_RemoveItem(name, link) ) then
4451 return 1;
4452 end
4453 end
4454 end
4455 end
4456 value = LootLink_GetValue(name, link);
4457 if ( not value ) then
4458 return 2;
4459 end
4460 if ( value.c and op.rarityfilter ) then
4461 local rarity = lRarityFilter[value.c];
4462 if ( rarity and rarity < op.rarityfilter ) then
4463 if ( LootLink_RemoveItem(name, link) ) then
4464 return 1;
4465 end
4466 end
4467 end
4468 if ( LootLinkState.spoof ) then
4469 local valid = LootLink_ValidateItem(name, link)
4470 if ( not valid ) then
4471 if ( LootLink_RemoveItem(name, link) ) then
4472 return 1;
4473 end
4474 elseif ( valid == 1 ) then
4475 return 2;
4476 end
4477 end
4478 end
4479  
4480 function LootLinkProcess_FIXCACHE()
4481 local todo = LLPtodo[LLPvars.done+1];
4482 local name, link, index = todo[1], todo[2], todo[3];
4483 local realname = GetItemInfo("item:"..link);
4484 local value = LootLink_GetValue( name, nil, link );
4485 if ( not value ) then return; end
4486 value.i = string.gsub(link,"(%d+:%d+:%d+:)%d+","%10");
4487 if ( realname ) then
4488 if ( LootLink_BuildSearchData( name, value, index ) == 2 ) then
4489 return 1;
4490 end
4491 elseif ( not value.t or value.t == "" ) then
4492 value.t = name.."·Bad Search Data·";
4493 return 1;
4494 else
4495 local changes;
4496 if ( value.t ) then
4497 local t = value.t;
4498 local d = value.d;
4499 local s, e, val = string.find(t, "^(.-)·");
4500 if ( not val or not string.find(name, val) ) then
4501 return 2;
4502 end
4503 if ( string.find(t, "%/") ) then
4504 -- cull out durability data.
4505 t = string.gsub(t, "Durability %d+ %/ %d+·", "");
4506 -- check set data.
4507 s,e,val = string.find(t, ".+·(.-) %(%d%/%d+%)·.+");
4508 if ( val ) then
4509 t = string.gsub(t, "(.+ %()%d+(%/%d+%)·.+)", "%10%2");
4510 local newset = LootLink_GetSet(val);
4511 local setnum = LL_SearchData(value, "se");
4512 if ( d ) then
4513 if ( not setnum ) then
4514 d = d.."se"..newset.."·";
4515 changes = 1;
4516 elseif( newset ~= setnum ) then
4517 d = string.gsub(d, "(.+·se)%d+(·.+)", "%1"..newset.."%2");
4518 changes = 1;
4519 end
4520 end
4521 end
4522 end
4523  
4524 if ( value.t ~= t ) then
4525 changes = 1;
4526 end
4527 value.t = t;
4528 value.d = d;
4529 end
4530 if ( changes ) then
4531 return 1;
4532 end
4533 return 2;
4534 end
4535 end
4536  
4537 function LootLinkProcess_Process(func)
4538 if ( not LLPvars ) then
4539 LootLink_Process_ToggleButtons();
4540  
4541 LLPvars = {};
4542  
4543 LLPvars.func = getglobal( "LootLinkProcess_"..func );
4544  
4545 if ( not LLPvars.func ) then
4546 LootLink_Process_ToggleButtons(1);
4547 preprocess = nil;
4548 return;
4549 end
4550  
4551 HideUIPanel(LootLinkFrame);
4552  
4553 LootLink_Process_Header:SetText(getglobal("LLP_"..func.."_LABEL") );
4554 LootLink_Process_Num:SetText("Preprocessing");
4555 LootLink_Process_Bar:SetMinMaxValues(0,1);
4556 LootLink_Process_Bar:SetValue(0);
4557  
4558 LLPvars.functype = func;
4559 LLPvars.elapsed = 0;
4560 LLPvars.done = 0;
4561 LLPvars.updated = 0;
4562 LLPvars.failed = 0;
4563 LLPvars.wait = 0;
4564 LLPvars.total = 0;
4565  
4566 LootLink_Process:SetAlpha( 1 );
4567 LootLink_Process:Show();
4568  
4569 LootLinkFrame.process = func;
4570 end
4571 end
4572  
4573 function LootLinkProcess_Run()
4574 local thisprocess = 0;
4575 local func = LLPvars.func;
4576  
4577 if ( LLP_OUTOFMEM ) then
4578 LootLink_Process_Memory();
4579 end
4580  
4581 if ( LLPvars.wait ) then
4582 LLPvars.wait = LLPvars.wait - arg1;
4583 if ( LLPvars.wait <= 0 ) then
4584 LLPvars.wait = nil;
4585 end
4586 return;
4587 end
4588  
4589 if ( not LLPtodo ) then
4590 local normal, mult = 0,0;
4591 LLPtodo = {};
4592 for k, v in ItemLinks do
4593 if ( strlen(k) == 0 ) then
4594 ItemLinks[k] = nil;
4595 LLPvars.updated = LLPvars.updated + 1;
4596 elseif ( v.i ) then
4597 normal = normal + 1;
4598 tinsert( LLPtodo, {k, v.i} );
4599 if ( GetItemInfo("item:"..v.i) ) then
4600 LLHiddenTooltip:SetHyperlink("item:"..v.i);
4601 end
4602 if ( v.m ) then
4603 for i=1, getn(v.m) do
4604 if v.m[i].i then
4605 mult = mult + 1;
4606 tinsert( LLPtodo, {k, v.m[i].i, i} );
4607 if ( GetItemInfo("item:"..v.m[i].i) ) then
4608 LLHiddenTooltip:SetHyperlink("item:"..v.m[i].i);
4609 end
4610 else
4611 LootLink_RemoveItem(k, i);
4612 LLPvars.updated = LLPvars.updated + 1;
4613 end
4614 end
4615 end
4616 else
4617 LootLink_RemoveItem(k);
4618 LLPvars.updated = LLPvars.updated + 1;
4619 end
4620 end
4621 LLPvars.total = normal + mult;
4622 LootLink_Process_Bar:SetValue(0)
4623 LootLink_Process_Bar:SetMinMaxValues(0, LLPvars.total)
4624 LLPvars.wait = 2;
4625 return;
4626 end
4627  
4628 local todo = LLPtodo;
4629  
4630 LLPvars.elapsed = LLPvars.elapsed + arg1;
4631  
4632 while todo and todo[LLPvars.done+1] do
4633 local ret = func();
4634 if ( ret ) then
4635 if ( ret == 1 ) then
4636 LLPvars.updated = LLPvars.updated + 1;
4637 else
4638 LLPvars.failed = LLPvars.failed + 1;
4639 end
4640 end
4641  
4642 LLPvars.updated = LLPvars.updated + LootLink_CheckDuplicate(todo[LLPvars.done+1][1]);
4643 LootLink_SortAlternates(todo[LLPvars.done+1][1]);
4644  
4645 thisprocess = thisprocess + 1;
4646 LLPvars.done = LLPvars.done + 1;
4647  
4648 if ( thisprocess == 50 ) then
4649 thisprocess = 0;
4650 LootLink_Process_Bar:SetValue( LLPvars.done );
4651 LootLink_Process_Num:SetText( LLPvars.done .. "/".. LLPvars.total );
4652 local time = (LLPvars.elapsed / LLPvars.done ) * (LLPvars.total - LLPvars.done);
4653 local s = mod( time, 60 );
4654 local m = (time-s) / 60;
4655 s = floor(s)
4656 if ( strlen(s) == 1 ) then
4657 s = "0"..s;
4658 end
4659 LootLink_Process_Time:SetText( "Estimated "..m..":"..s.." remaining" );
4660  
4661 if ( DisplayIndices and LootLinkFrame:IsVisible() ) then
4662 LootLink_Update();
4663 LootLink_SetTitle();
4664 end
4665  
4666 return;
4667 end
4668 end
4669  
4670 if ( todo and not todo[LLPvars.done+1] ) then
4671 local text = getglobal("LLP_"..LLPvars.functype.."_END");
4672 text = string.gsub( text, "%%u", LLPvars.updated );
4673 text = string.gsub( text, "%%t", LLPvars.total );
4674 text = string.gsub( text, "%%f", LLPvars.failed );
4675 DEFAULT_CHAT_FRAME:AddMessage(text);
4676 LootLink_Process_Time:SetText("");
4677 LootLink_Process_Num:SetText("Finished");
4678 LootLink_Process_Bar:SetValue(LLPvars.total);
4679  
4680 LootLink_Process_ToggleButtons(1);
4681  
4682 LLPvars = nil;
4683 LLPtodo = nil;
4684 LootLinkFrame.process = nil;
4685  
4686 LootLink_Process.fade = 2;
4687 LootLink_Process:SetScript("OnUpdate", LootLink_Process_Fade);
4688 end
4689 end
4690  
4691 function LootLink_Process_Fade()
4692 if ( LootLink_Process.fade ) then
4693 LootLink_Process.fade = LootLink_Process.fade - (arg1 / 2);
4694 if ( LootLink_Process.fade < 1 ) then
4695 this:SetAlpha( LootLink_Process.fade );
4696 if ( LootLink_Process.fade <= 0 ) then
4697 this:Hide();
4698 LootLink_Process.fade = nil;
4699 LootLink_Process:SetScript("OnUpdate", nil);
4700 end
4701 end
4702 end
4703 end
4704  
4705 --------------------------------------------------------------------------------------------------
4706 -- External functions
4707 --------------------------------------------------------------------------------------------------
4708  
4709 -- Looks for and deconstructs links contained in a text string; if trusted, existing information will be verified
4710 -- Trusted sources are everything except chat links; since these can be spoofed, we want to allow them to be replaced
4711 function LootLink_ProcessLinks(text, trusted)
4712 local enchants, spoof, nosame, rarityfilter, lastName = LootLinkState.enchants, LootLinkState.spoof, LootLinkState.nosame, LootLinkState.rarityfilter;
4713 if( text ) then
4714 for color, item, name in string.gfind(text, "|c(%x+)|Hitem:(%d+:%d+:%d+:%d+)|h%[(.-)%]|h|r") do
4715 if ( item ~= "0:0:0:0" and ( not rarityfilter or lRarityFilter[color] > rarityfilter ) and LootLink_CheckSame(name, item) ) then
4716 local fixedname, fixeditem;
4717 if ( not trusted ) then
4718 if ( spoof ) then
4719 name, item = LootLink_ValidateItem(name, item, 1);
4720 else
4721 fixedname, fixeditem = LootLink_ValidateItem(name, item, 1);
4722 if ( fixedname and fixedname ~= name ) then
4723 LootLink_AddItem(fixedname, fixeditem, color, trusted);
4724 end
4725 end
4726 end
4727 local enchant;
4728 if ( not enchants and not nosame ) then
4729 enchant = string.gsub(item, "^(%d+):(%d+):(%d+):%d+$", "%1:%2:%3:0");
4730 end
4731 item = string.gsub(item, "^(%d+):%d+:(%d+):%d+$", "%1:0:%2:0");
4732 LootLink_AddItem(name, item, color, trusted);
4733 if ( enchant and enchant ~= item ) then
4734 LootLink_AddItem(name, enchant, color, trusted);
4735 end
4736 LootLink_SortAlternates(name);
4737 lastName = name;
4738 end
4739 end
4740 end
4741 return lastName;
4742 end
4743  
4744 function LootLink_CheckSame(name, item)
4745 local _,_,itemid,suffixid=string.find(item, "(%d+):%d+:(%d+):%d+");
4746 local value = ItemLinks[name];
4747 if ( value and (LootLinkState.nosame or LootLinkState.novariants) ) then
4748 -- Assumes no same name items are both different itemid and have suffixids
4749 if ( value.i and value.i ~= item ) then
4750 for id, suf in string.gfind( value.i, "(%d+):%d+:(%d+):") do
4751 if ( nosame and tonumber(id) > tonumber(itemid) ) then
4752 return;
4753 elseif ( tonumber(suf) > tonumber(suffixid) ) then
4754 return;
4755 end
4756 end
4757 end
4758 end
4759 return 1;
4760 end
4761  
4762 -- old filter function, keeping for posterity
4763 --[[function LootLink_FilterCheck(name, item, color)
4764 if ( item == "0:0:0:0" ) then
4765 return;
4766 end
4767 local op = LootLinkState;
4768 if ( op.rarityfilter ) then
4769 local rarity = lRarityFilter[color];
4770 if ( rarity and rarity < op.rarityfilter ) then
4771 return;
4772 end
4773 end
4774 local _,_,itemid,enchantid,suffixid=string.find(item, "(%d+):(%d+):(%d+):%d+");
4775 if ( not tonumber(enchantid) ) then
4776 --ChatFrame1:AddMessage((name or "??").." no enchant id "..(item or "???"));
4777 return;
4778 end
4779 local value = ItemLinks[name];
4780 if ( value and (op.nosame or op.novariants) ) then
4781 -- Assumes no same name items are both different itemid and have suffixids
4782 if ( value.i and value.i ~= item ) then
4783 for id, suf in string.gfind( value.i, "(%d+):%d+:(%d+):") do
4784 if ( op.nosame and tonumber(id) > tonumber(itemid) ) then
4785 return;
4786 elseif ( tonumber(suf) > tonumber(suffixid) ) then
4787 return;
4788 end
4789 end
4790 end
4791 end
4792 return 1;
4793 end]]
4794  
4795 -- Add items to the database
4796 function LootLink_AddItem(name, link, color, trusted)
4797 local nosame, value, index = LootLinkState.nosame;
4798 if ( name and link ) then
4799 if ( not ItemLinks[name] ) then
4800 ItemLinks[name] = { };
4801 lItemLinksSizeTotal = lItemLinksSizeTotal + 1;
4802 if( LootLink_GetDataVersion() < 110 ) then
4803 -- Set a flag to indicate that this item is new and should be skipped on a makehome
4804 ItemLinks[name]._ = 1;
4805 end
4806 end
4807 value = ItemLinks[name];
4808 if ( not nosame and LootLinkState.novariants ) then
4809 for suffixid in string.gfind(link, "%d+:%d+:(%d+):%d+") do
4810 if ( tonumber(suffixid) > 0 ) then
4811 nosame = 1;
4812 end
4813 end
4814 end
4815 if ( not nosame and value.i and value.i ~= link ) then
4816 if ( value.m and getn(value.m) > 0 ) then
4817 for k, v in value.m do
4818 if ( v.i == link ) then
4819 if ( not trusted ) then
4820 return nil;
4821 end
4822 index = k;
4823 break;
4824 end
4825 end
4826 end
4827 if ( index ) then
4828 value = value.m[index];
4829 else
4830 if ( not value.m ) then
4831 value.m = {};
4832 end
4833 tinsert( value.m, {} );
4834 index = getn(value.m);
4835 value = value.m[index];
4836 lItemLinksSizeTotal = lItemLinksSizeTotal + 1;
4837 end
4838 end
4839  
4840 value.i = link;
4841 value.c = color;
4842  
4843 LootLink_BuildSearchData(name, value, index);
4844 if( not LootLink_CheckItemServerRaw(value, lServerIndex) ) then
4845 LootLink_AddItemServer(value, lServerIndex);
4846 end
4847 return value;
4848 end
4849 end
4850  
4851 -- Sort same name items by ids
4852 function LootLink_SortAlternates(name)
4853 if ( not name ) then return; end
4854 local value = ItemLinks[name];
4855 local newval;
4856 local values = {};
4857 local itemval = {};
4858  
4859 -- cleaned up by Adrine
4860 function sortByLink(e1, e2)
4861 if ( not e1 ) then return true; elseif ( not e2 ) then return false; end
4862 local _,_,a,b,c = string.find(e1.i, "(%d+):(%d+):(%d+)");
4863 local _,_,d,e,f = string.find(e2.i, "(%d+):(%d+):(%d+)");
4864  
4865 if a ~= d then return tonumber(a) > tonumber(d); end
4866 if c ~= f then return tonumber(c) > tonumber(f); end
4867 if b ~= e then return tonumber(b) < tonumber(e); end
4868 return false;
4869 end
4870  
4871 if value and value.m then
4872 if ( getn(value.m) == 0 ) then
4873 value.m = nil;
4874 return nil;
4875 end
4876 for k, v in value do
4877 if ( k ~= "m" ) then
4878 itemval[k] = v;
4879 end
4880 end
4881 tinsert( values, itemval );
4882 for k, v in value.m do
4883 tinsert( values, v );
4884 end
4885  
4886 table.sort(values, sortByLink);
4887  
4888 newval = values[1];
4889 newval.m = {};
4890 for i=2, getn(values) do
4891 tinsert( newval.m, values[i] );
4892 end
4893 else
4894 return nil;
4895 end
4896 ItemLinks[name] = {};
4897 ItemLinks[name] = newval;
4898 end
4899  
4900 -- Adds icon of the item if it's valid
4901 function LootLink_AddTooltipTexture(link)
4902 if ( link and not LootLinkState.hideicon) then
4903 local _, _, _, _, _, _, _, _, itemTexture = GetItemInfo(link);
4904 if ( itemTexture ) then
4905 local iItem = LootLinkFrame.TooltipButton or 0;
4906 LootLinkTooltipIconTexture:SetTexture( itemTexture );
4907 LootLinkTooltipIcon:ClearAllPoints();
4908 LootLinkTooltipIcon:SetPoint("BOTTOMLEFT", getglobal("LootLinkItem"..iItem), "BOTTOMRIGHT");
4909 LootLinkTooltipIcon:Show();
4910 return;
4911 end
4912 end
4913 LootLinkTooltipIcon:Hide();
4914 end
4915  
4916 -- Adds extra tooltip information for the item with the given name
4917 function LootLink_AddTooltipInfo(name, tooltip, quantity, index)
4918 if( not tooltip ) then
4919 tooltip = LootLinkTooltip;
4920 end
4921 if( not quantity ) then
4922 quantity = 1;
4923 end
4924 if( tooltip == LootLinkTooltip ) then
4925 LootLink_HideTooltipMoney();
4926 end
4927 if( not LootLinkState.HideInfo and ItemLinks[name] ) then
4928 if( tooltip == GameTooltip ) then
4929 GameTooltip.llDone = 1;
4930 end
4931 if( ItemLinks[name].p ) then
4932 LootLink_SetTooltipMoney(tooltip, quantity, ItemLinks[name].p, ItemLinks[name].x);
4933 end
4934 LootLink_AddExtraTooltipInfo(tooltip, name, quantity, ItemLinks[name]);
4935 tooltip:Show();
4936 end
4937 end
4938  
4939 -- This will set up a tooltip with item information for the given name if it's known
4940 function LootLink_SetTooltip(tooltip, name, quantity)
4941 local link;
4942  
4943 if( tooltip and name ) then
4944 link = LootLink_GetHyperlink(name);
4945 if( link ) then
4946 LootLink_SetHyperlink(tooltip, name, link);
4947 if( quantity ) then
4948 quantity = tonumber(quantity);
4949 else
4950 quantity = 1;
4951 end
4952 if( quantity > 0 ) then
4953 LootLink_AddTooltipInfo(name, tooltip, quantity);
4954 end
4955 end
4956 end
4957 end
4958  
4959 --
4960 function LootLink_ChatEdit_OnTabPressed()
4961  
4962 lOriginal_ChatEdit_OnTabPressed();
4963 end
4964  
4965 function LootLink_ChatEdit_OnTextChanged()
4966 local text = this:GetText();
4967 if (string.sub(text, 1, 7) ~= "/script" or string.sub(text, 1, 5) ~= "/dump") then
4968 --text = string.gsub(text, "([|]?[h]?)%[(.-)%]([|]?[h]?)", FLT_LinkifyName);
4969 --end
4970 end
4971 lOriginal_ChatEdit_OnTextChanged();
4972 end
4973  
4974 -- Calling this will allow LootLink to automatically add information to tooltips when needed
4975 function LootLink_AutoInfoOn()
4976 lSuppressInfoAdd = nil;
4977 end
4978  
4979 -- Calling this will prevent LootLink from automatically adding information to tooltips
4980 function LootLink_AutoInfoOff()
4981 lSuppressInfoAdd = 1;
4982 end
4983  
4984 -- Use this function to get the current server name from LootLink's perspective
4985 function LootLink_GetCurrentServerName()
4986 return lServer;
4987 end
4988  
4989 -- Use this function to get the current server index
4990 function LootLink_GetCurrentServerIndex()
4991 return lServerIndex;
4992 end
4993  
4994 -- Use this function to map a server name to the server index for the ItemLinks[name].servers array
4995 function LootLink_GetServerIndex(name)
4996 if( not LootLinkState or not LootLinkState.ServerNamesToIndices ) then
4997 return nil;
4998 end
4999 return LootLinkState.ServerNamesToIndices[name];
5000 end
5001  
5002 -- Use this function to check whether an ItemLinks[name] entry is valid for a given server index
5003 function LootLink_CheckItemServer(item, serverIndex)
5004 -- If we haven't converted and this item predates multiple server support, count it as valid
5005 if( LootLink_GetDataVersion() < 110 and not item._ ) then
5006 return 1;
5007 end
5008 return LootLink_CheckItemServerRaw(item, serverIndex);
5009 end
5010  
5011 -- Used for debugging changes in item data and tooltip format
5012 function LootLink_Validate()
5013 for index, value in ItemLinks do
5014 if( not value.d ) then
5015 DEFAULT_CHAT_FRAME:AddMessage(index.." has no search data");
5016 -- else
5017 -- if( not LL_SearchData(value, "su") ) then
5018 -- DEFAULT_CHAT_FRAME:AddMessage(index.." has no subtype");
5019 -- end
5020 end
5021 end
5022 end
5023  
5024 --------------------------------------------------------------------------------------------------
5025 -- Hookable callback functions
5026 --------------------------------------------------------------------------------------------------
5027  
5028 -- Hook this function to add any extra information you like to the tooltip
5029 function LootLink_AddExtraTooltipInfo(tooltip, name, quantity, item)
5030 -- tooltip: the current tooltip frame
5031 -- name: the name of the item
5032 -- quantity: the number of items, if known, else 1
5033 -- item: ItemLinks[name]; LootLink's data for this item
5034 end
5035  
5036 -- Hook this function to be called whenever an equipment slot is successfully inspected
5037 function LootLink_Event_InspectSlot(name, count, item, unit, slotid)
5038 -- name: the name of the item
5039 -- count: the number of items, if known, else 1
5040 -- item: ItemLinks[name]; LootLink's data for this item
5041 -- unit: "target", "player", etc.
5042 -- slotid: the id of the slot inspected
5043 end
5044  
5045 -- Hook this function to be called whenever an inventory slot is successfully inspected
5046 function LootLink_Event_ScanInventory(name, count, item, bagid, slotid)
5047 -- name: the name of the item
5048 -- count: the number of items, if known, else 1
5049 -- item: ItemLinks[name]; LootLink's data for this item
5050 -- bagid: the id of the bag containing the item
5051 -- slotid: the id of the slot inspected
5052 end
5053  
5054 -- Hook this function to be called whenever a bank slot is successfully inspected
5055 function LootLink_Event_ScanBank(name, count, item, bagid, slotid)
5056 -- name: the name of the item
5057 -- count: the number of items, if known, else 1
5058 -- item: ItemLinks[name]; LootLink's data for this item
5059 -- bagid: the id of the bag containing the item
5060 -- slotid: the id of the slot inspected
5061 end
5062  
5063 -- Hook this function to be called whenever an auction entry is successfully inspected
5064 function LootLink_Event_ScanAuction(name, count, item, auctionpage, auctionid)
5065 -- name: the name of the item
5066 -- count: the number of items, if known, else 1
5067 -- item: ItemLinks[name]; LootLink's data for this item
5068 -- auctionpage: the page number this item was found on
5069 -- auctionid: the id of the inspected item
5070 end
5071  
5072 -- Hook this function to be called whenever a chat message is successfully inspected
5073 function LootLink_Event_ScanChat(name, item, text)
5074 -- name: the name of the last item in the chat message
5075 -- item: ItemLinks[name]; LootLink's data for this item
5076 -- text: the inspected chat message
5077 end
5078  
5079 -- Hook this function to be called whenever LootLink starts an auction scan
5080 function LootLink_Event_StartAuctionScan()
5081 end
5082  
5083 -- Hook this function to be called whenever LootLink stops an auction scan
5084 function LootLink_Event_StopAuctionScan()
5085 end
5086  
5087 -- Hook this function to be called whenever LootLink completes a full auction scan
5088 function LootLink_Event_FinishedAuctionScan()
5089 end
5090  
5091 -- Hook this function to be called whenever LootLink sends a new auction query
5092 function LootLink_Event_AuctionQuery(auctionpage)
5093 -- auctionpage: the page number for the query that was just sent
5094 end
5095  
5096  
5097 --------------------------------------------------------------------------------------------------
5098 -- Static Popup Dialogs
5099 --------------------------------------------------------------------------------------------------
5100  
5101 StaticPopupDialogs["LOOTLINK_DELETEITEM_CONFIRM"] = {
5102 text = TEXT(LOOTLINK_STATICPOPUP_DELETE_ITEM_CONFIRM),
5103 button1 = TEXT(YES),
5104 button2 = TEXT(NO),
5105 OnAccept = function(data)
5106 if ( not data ) then return; end
5107 if ( LootLink_RemoveItem(data[1], data[2].i, data[3] ) ) then
5108 LootLink_Update();
5109 LootLink_SetTitle();
5110 end
5111 end,
5112 showAlert = 1,
5113 timeout = 0,
5114 exclusive = 1,
5115 whileDead = 1,
5116 hideOnEscape = 1,
5117 };
5118  
5119 StaticPopupDialogs["LOOTLINK_LITEMODE_CONFIRM"] = {
5120 text = TEXT(LOOTLINK_STATICPOPUP_LITE_MODE_CONFIRM),
5121 button1 = TEXT(OKAY),
5122 button2 = TEXT(CANCEL),
5123 OnCancel = function()
5124 LLO_LiteModeCheckButton:SetChecked();
5125 end,
5126 showAlert = 1,
5127 timeout = 0,
5128 exclusive = 1,
5129 whileDead = 1,
5130 hideOnEscape = 1,
5131 };
5132  
5133 StaticPopupDialogs["LOOTLINK_LINK_CONFIRM"] = {
5134 text = TEXT(LOOTLINK_STATICPOPUP_ITEM_CONFIRM),
5135 button1 = TEXT(OKAY),
5136 button2 = TEXT(CANCEL),
5137 OnAccept = function(data)
5138 ChatFrameEditBox:Insert(LootLink_GetLink(data[1], data[3]));
5139 end,
5140 showAlert = 1,
5141 timeout = 0,
5142 exclusive = 1,
5143 whileDead = 1,
5144 hideOnEscape = 1,
5145 };
5146  
5147 StaticPopupDialogs["LOOTLINK_DRESSUP_CONFIRM"] = {
5148 text = TEXT(LOOTLINK_STATICPOPUP_ITEM_CONFIRM),
5149 button1 = TEXT(OKAY),
5150 button2 = TEXT(CANCEL),
5151 OnAccept = function(data)
5152 DressUpItemLink(LootLink_GetLink(data[1], data[3]));
5153 end,
5154 showAlert = 1,
5155 timeout = 0,
5156 exclusive = 1,
5157 whileDead = 1,
5158 hideOnEscape = 1,
5159 };
5160  
5161  
5162 --------------------------------------------------------------------------------------------------
5163 -- Type links - borrowed from Gazmik Fizzwidget's Linkerator
5164 --------------------------------------------------------------------------------------------------
5165  
5166 function LootLink_TypeLinks_LinkifyName(head, text, tail)
5167 if (head ~= "|h" and tail ~= "|h") then -- only linkify things text that isn't linked already
5168 local link = LootLink_GetLink(text);
5169 if (link) then return link; end
5170 end
5171 return head.."["..text.."]"..tail;
5172 end
5173  
5174 function LootLink_TypeLinks_ParseChatMessage(text)
5175 return string.gsub(text, "([|]?[h]?)%[(.-)%]([|]?[h]?)", LootLink_TypeLinks_LinkifyName);
5176 end
5177  
5178 -- thank you ckknight
5179 function LootLink_TypeLinks_AutoComplete(text)
5180 local _,_,body,name = string.find( text, "(.*%[)(%S[^%[^%]]+)$" );
5181 if ( name ) then
5182 local textlen, namelen, found = strlen(text), strlen(name);
5183 if ( this.lastLength and this.lastItem and textlen > this.lastLength ) then
5184 if string.find(strlower(this.lastItem), strlower(name)) then
5185 this.lastLength = textlen;
5186 this:SetText(body..this.lastItem);
5187 this:HighlightText(textlen);
5188 return 1;
5189 end
5190 end
5191 this.lastLength = textlen;
5192 for k, v in ItemLinks do
5193 if ( strlen(k) >= namelen and strlower(strsub(k,1,namelen)) == strlower(name) ) then
5194 found = 1;
5195 if ( (not this.itemComplete or not this.itemComplete[k]) ) then
5196 if ( not this.itemComplete ) then
5197 this.itemComplete = {};
5198 end
5199 this.ignoreTextChange = 1;
5200 this:SetText(body..k);
5201 this:HighlightText(textlen);
5202 this.lastItem = k;
5203 this.itemComplete[k] = 1;
5204 return 1;
5205 end
5206 end
5207 end
5208 if ( found ) then
5209 this.lastLength = nil;
5210 this.lastItem = nil;
5211 this.itemComplete = nil;
5212 return LootLink_TypeLinks_AutoComplete(text);
5213 end
5214 end
5215 this.lastItem = nil;
5216 this.itemComplete = nil;
5217 end
5218  
5219 -- Hooks
5220  
5221 lOrig_ChatEdit_OnTextChanged = ChatEdit_OnTextChanged;
5222 function ChatEdit_OnTextChanged()
5223 if ( LootLinkState.typelinks ) then
5224 local text = this:GetText();
5225 if (string.find(text, "^/script") or string.find(text, "^/dump")) then
5226 -- don't parse
5227 else
5228 local newtext = LootLink_TypeLinks_ParseChatMessage(text);
5229 if ( text ~= newtext ) then
5230 this:SetText(newtext);
5231 return;
5232 end
5233 end
5234 end
5235 lOrig_ChatEdit_OnTextChanged(this);
5236 end
5237  
5238 lOrig_ChatEdit_OnChar = ChatFrameEditBox:GetScript("OnChar");
5239 function ChatEdit_OnChar()
5240 if ( LootLinkState.typelinks and LootLinkState.autotypelinks ) then
5241 local text = this:GetText();
5242 if ( string.find(text, "^/script") or string.find(text, "^/dump")) then
5243 else
5244 LootLink_TypeLinks_AutoComplete(text);
5245 end
5246 elseif ( lOrig_ChatEdit_OnChar ) then
5247 lOrig_ChatEdit_OnChar(this);
5248 end
5249 end
5250 ChatFrameEditBox:SetScript("OnChar", ChatEdit_OnChar);
5251  
5252 lOrig_ChatEdit_OnTabPressed = ChatEdit_OnTabPressed;
5253 function ChatEdit_OnTabPressed()
5254 this.lastLength = nil;
5255 if ( LootLinkState.typelinks and LootLinkState.autotypelinks and this.lastItem ) then
5256 this:Insert("");
5257 else
5258 lOrig_ChatEdit_OnTabPressed();
5259 end
5260 end
5261  
5262 lOrig_ChatEdit_OnEnterPressed = ChatEdit_OnEnterPressed;
5263 function ChatEdit_OnEnterPressed()
5264 if ( LootLinkState.typelinks and LootLinkState.autotypelinks and this.itemComplete ) then
5265 this:SetText(this:GetText().."]");
5266 else
5267 lOrig_ChatEdit_OnEnterPressed();
5268 end
5269 this.itemComplete = nil;
5270 end