vanilla-wow-addons – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 -- Gatherer
2 -- Written by Chandora
3  
4 GATHERER_VERSION="1.0.0";
5  
6 --
7 -- Look, seriously a full half of this code is from MapNotes.
8 -- The only reason I pinched it and put it in here is I couldn't
9 -- work out how to extend MapNotes to do what I wanted it to do
10 -- without actually editing the MapNotes files.
11 --
12 -- Full credit to the MapNotes guys
13 --
14  
15 -- Global variables
16 GATHERNOTE_UPDATE_INTERVAL = 0.25;
17 GATHERNOTE_CHECK_INTERVAL = 5.0;
18 GATHERER_MAXNUMNOTES = 25;
19 GATHERER_LOADED = false;
20 GATHERER_CLOSESTCHECK=0.4;
21 Gatherer_RecordFlag=0;
22 Gatherer_currentNode="";
23 Gatherer_currentAction="";
24  
25 GatherMap_InCity = false;
26 Gatherer_LoadCount = 0;
27 Gatherer_MapOpen = false;
28 Gatherer_UpdateWorldMap = -1;
29  
30 Gatherer_InWorld = false;
31 GatherItems = { };
32 GatherSkills = { };
33 GatherZoneData = { }; -- Dict[ZoneName, Tuple[Continent, Zone]]
34 GatherMainMapItem = { };
35 -- UI variables
36 Gatherer_WorldMapDetailFrameWidth = 0;
37 Gatherer_WorldMapDetailFrameHeight = 0;
38 Gatherer_WorldMapPlayerFrameLevel = 0;
39  
40 Gather_Player = UnitName("player");
41  
42 StaticPopupDialogs["GATHERER_VERSION_DIALOG"] = {
43 text = TEXT(GATHERER_VERSION_WARNING),
44 button1 = TEXT(OKAY),
45 showAlert = 1,
46 timeout = 0,
47 };
48  
49 --- ************************************************************************
50 -- Utilities
51  
52 function Gatherer_Round(x)
53 if( x - math.floor(x) > 0.5) then
54 x = x + 0.5;
55 end
56 return math.floor(x);
57 end
58  
59 function Gatherer_GetMenuName(inputName)
60 local name, info;
61 if (inputName) then
62 local firstLetter = string.sub(inputName, 1, 2);
63 local carReplace = {["\195\160"] = "a", ["\195\161"] = "a", ["\195\162"] = "a", ["\195\163"] = "a", ["\195\164"] = "a",
64 ["\195\168"] = "e", ["\195\169"] = "e", ["\195\170"] = "e", ["\195\171"] = "e",
65 ["\195\180"] = "i", ["\195\173"] = "i", ["\195\174"] = "i", ["\195\175"] = "i",
66 ["\195\179"] = "o", ["\195\180"] = "o", ["\195\181"] = "o", ["\195\182"] = "o",
67 ["\195\185"] = "u", ["\195\186"] = "u", ["\195\187"] = "u", ["\195\188"] = "u"}
68 local found;
69 for code, repl in carReplace do
70 firstLetter, found = string.gsub(firstLetter, code, repl);
71 if (found > 0) then
72 break;
73 end
74 end
75 if (found > 0) then
76 name = string.upper(firstLetter)..(string.sub(inputName, 3) or "");
77 else
78 if (GetLocale()=="ruRU") then
79 name = inputName;
80 else
81 name = string.upper(string.sub(inputName, 1, 1))..(string.sub(inputName, 2) or "");
82 end
83 end
84  
85 local iconName, _ = Gatherer_GetDB_IconByGatherName(inputName);
86 iconName = iconName or inputName;
87 for _, rareMatch in Gather_RareMatch do
88 if (iconName == rareMatch) then
89 name = name.." ["..TYPE_RARE.."]";
90 break;
91 end
92 end
93 if (Gather_SkillLevel[iconName]) then
94 name = name.." ["..Gather_SkillLevel[iconName].."]";
95 end
96 end
97 return name, info;
98 end
99  
100 -- *************************************************************************
101 -- Init and command line handler
102  
103 function Gatherer_OnLoad()
104 this:RegisterEvent("WORLD_MAP_UPDATE");
105 this:RegisterEvent("CLOSE_WORLD_MAP"); -- never triggered apparently
106 this:RegisterEvent("LEARNED_SPELL_IN_TAB"); -- follow current skills
107 this:RegisterEvent("SPELLS_CHANGED"); -- follow current skills
108 this:RegisterEvent("SKILL_LINES_CHANGED"); -- follow current skills
109 this:RegisterEvent("SPELLCAST_START");
110 this:RegisterEvent("SPELLCAST_STOP");
111 this:RegisterEvent("SPELLCAST_FAILED");
112 this:RegisterEvent("CHAT_MSG_ADDON");
113  
114 -- Events for off world non processing
115 this:RegisterEvent("PLAYER_ENTERING_WORLD");
116 this:RegisterEvent("PLAYER_LEAVING_WORLD");
117  
118 -- Addon Loaded and player login/logout events
119 this:RegisterEvent("ADDON_LOADED");
120 this:RegisterEvent("PLAYER_LOGIN");
121 this:RegisterEvent("PLAYER_LOGOUT");
122  
123 Gatherer_LoadZoneData();
124  
125 SLASH_GATHER1 = "/gather";
126 SLASH_GATHER2 = "/gatherer";
127 SlashCmdList["GATHER"] = function(msg)
128 Gatherer_Command(msg);
129 end
130 end
131  
132 function Gatherer_Command(command)
133 local SETTINGS = Gatherer_Settings;
134 local i,j, cmd, param = string.find(command, "^([^ ]+) (.+)$");
135 if (not cmd) then cmd = command; end
136 if (not cmd) then cmd = ""; end
137 if (not param) then param = ""; end
138  
139 if ((cmd == "") or (cmd == "help")) then
140 local useMinimap = "Off";
141 if (SETTINGS.useMinimap) then useMinimap = "On"; end
142 local useMainmap = "Off";
143 if (SETTINGS.useMainmap) then useMainmap = "On"; end
144 local mapMinder = "Off";
145 if (SETTINGS.mapMinder) then mapMinder = "On"; end
146 local minderTime = "5s";
147 if (SETTINGS.minderTime) then minderTime = SETTINGS.minderTime.."s"; end
148  
149 Gatherer_ChatPrint("Usage:");
150 Gatherer_ChatPrint(" |cffffffff/gather (on|off|toggle)|r |cff2040ff["..useMinimap.."]|r - turns the gather minimap display on and off");
151 Gatherer_ChatPrint(" |cffffffff/gather mainmap (on|off|toggle)|r |cff2040ff["..useMainmap.."]|r - turns the gather mainmap display on and off");
152 Gatherer_ChatPrint(" |cffffffff/gather minder (on|off|toggle|<n>)|r |cff2040ff["..mapMinder.."]|r - turns the gather map minder on and off (remembers and reopens your last open main map; within "..minderTime..")");
153 Gatherer_ChatPrint(" |cffffffff/gather dist <n>|r |cff2040ff["..SETTINGS.maxDist.."]|r - sets the maximum search distance for display (0=infinite(default), typical=10)");
154 Gatherer_ChatPrint(" |cffffffff/gather num <n>|r |cff2040ff["..SETTINGS.number.."]|r - sets the maximum number of items to display (default=10, up to 25)");
155 Gatherer_ChatPrint(" |cffffffff/gather fdist <n>|r |cff2040ff["..SETTINGS.fadeDist.."]|r - sets a fade distance (in units) for the icons to fade out by (default = 20)");
156 Gatherer_ChatPrint(" |cffffffff/gather fperc <n>|r |cff2040ff["..SETTINGS.fadePerc.."]|r - sets the percentage for fade at max fade distance (default = 80 [=80% faded])");
157 Gatherer_ChatPrint(" |cffffffff/gather theme <name>|r |cff2040ff["..SETTINGS.iconSet.."]|r - sets the icon theme: original, shaded (default), iconic or iconshade");
158 Gatherer_ChatPrint(" |cffffffff/gather idist <n>|r |cff2040ff["..SETTINGS.miniIconDist.."]|r - sets the minimap distance at which the gather icon will become iconic (0 = off, 1-60 = pixel radius on minimap, default = 40)");
159 Gatherer_ChatPrint(" |cffffffff/gather herbs (on|off|toggle|auto)|r |cff2040ff["..Gatherer_GetFilterVal("herbs").."]|r - select whether to show herb data on the minimap");
160 Gatherer_ChatPrint(" |cffffffff/gather mining (on|off|toggle|auto)|r |cff2040ff["..Gatherer_GetFilterVal("mining").."]|r - select whether to show mining data on the minimap");
161 Gatherer_ChatPrint(" |cffffffff/gather treasure (on|off|toggle|auto)|r |cff2040ff["..Gatherer_GetFilterVal("treasure").."]|r - select whether to show treasure data on the minimap");
162 Gatherer_ChatPrint(" |cffffffff/gather options|r - show/hide UI Options dialog.");
163 Gatherer_ChatPrint(" |cffffffff/gather report|r - show/hide report dialog.");
164 Gatherer_ChatPrint(" |cffffffff/gather search|r - show/hide search dialog.");
165 Gatherer_ChatPrint(" |cffffffff/gather loginfo (on|off)|r - show/hide logon information.");
166 Gatherer_ChatPrint(" |cffffffff/gather filterrec (herbs|mining|treasure)|r - link display filter to recording for selected gathering type");
167 Gatherer_ChatPrint(" |cffffffff/gather debug ([on]|off)|r |cff2040ff["..Gatherer_EBoolean[SETTINGS.debug].."]|r - show/hide debug messages");
168 Gatherer_ChatPrint(" |cffffffff/gather p2p ([on]|off)|r |cff2040ff["..Gatherer_EBoolean[SETTINGS.p2p].."]|r - enable/disable peer-to-peer functions");
169 elseif (cmd == "options" ) then
170 if ( GathererUI_DialogFrame:IsVisible() ) then
171 GathererUI_HideOptions();
172 else
173 GathererUI_ShowOptions();
174 end
175 elseif (cmd == "debug") then
176 if (not param or param == "" or param == "on") then
177 SETTINGS.debug = true;
178 Gatherer_ChatPrint("Debug messages enabled");
179 elseif (param == "off") then
180 SETTINGS.debug = false;
181 Gatherer_ChatPrint("Debug messages disabled");
182 end
183 elseif (cmd == "p2p") then
184 if (not param or param == "" or param == "on") then
185 SETTINGS.p2p = true;
186 Gatherer_ChatPrint("Peer-to-peer functions enabled");
187 elseif (param == "off") then
188 SETTINGS.p2p = false;
189 Gatherer_ChatPrint("Peer-to-peer functions disabled");
190 end
191 elseif (cmd == "report" ) then
192 showGathererInfo(1);
193 elseif (cmd == "search" ) then
194 showGathererInfo(2);
195 elseif (cmd == "loginfo" ) then
196 local value;
197 if (not param or param == "") then value = "on"; else value = param; end
198 Gatherer_ChatPrint("Setting log information display to "..value);
199 SETTINGS.logInfo = value;
200 elseif ( cmd == "filterrec" ) then
201 local value=-1;
202 if (not param) then
203 return;
204 end;
205 if ( param == "treasure" ) then
206 value = 0;
207 elseif ( param == "herbs" ) then
208 value = 1;
209 elseif ( param == "mining" ) then
210 value = 2;
211 end
212  
213 if ( value > -1 ) then
214 if ( SETTINGS.filterRecording[value] ) then
215 SETTINGS.filterRecording[value] = nil;
216 Gatherer_ChatPrint("Turned filter/recording link for "..param.." off.");
217 else
218 SETTINGS.filterRecording[value] = 1;
219 Gatherer_ChatPrint("Turned filter/recording link for "..param.." on.");
220 end
221 end
222 elseif (cmd == "on") then
223 SETTINGS.useMinimap = true;
224 Gatherer_OnUpdate(0, true);
225 SETTINGS.useMinimapText = "on";
226 Gatherer_ChatPrint("Turned gather minimap display on");
227 elseif (cmd == "off") then
228 SETTINGS.useMinimap = false;
229 SETTINGS.useMinimapText = "off";
230 Gatherer_OnUpdate(0, true);
231 Gatherer_ChatPrint("Turned gather minimap display off (still collecting)");
232 elseif (cmd == "toggle") then
233 SETTINGS.useMinimap = not SETTINGS.useMinimap;
234 Gatherer_OnUpdate(0, true);
235 if (SETTINGS.useMinimap) then
236 Gatherer_ChatPrint("Turned gather minimap display on");
237 SETTINGS.useMinimapText = "on";
238 else
239 Gatherer_ChatPrint("Turned gather minimap display off (still collecting)");
240 SETTINGS.useMinimapText = "off";
241 end
242 elseif (cmd == "dist") then
243 local i,j, value = string.find(param, "(%d+)");
244 if (not value) then value = 0; else value = value + 0.0; end
245 if (value <= 0) then
246 SETTINGS.maxDist = 0;
247 else
248 SETTINGS.maxDist = value + 0.0;
249 end
250 Gatherer_ChatPrint("Setting maximum note distance to "..SETTINGS.maxDist);
251 Gatherer_OnUpdate(0, true);
252 elseif (cmd == "fdist") then
253 local i,j, value = string.find(param, "(%d+)");
254 if (not value) then value = 0; else value = value + 0.0; end
255 if (value <= 0) then
256 SETTINGS.fadeDist = 0;
257 else
258 SETTINGS.fadeDist = value + 0.0;
259 end
260 Gatherer_ChatPrint("Setting fade distance to "..SETTINGS.fadeDist);
261 Gatherer_OnUpdate(0, true);
262 elseif (cmd == "fperc") then
263 local i,j, value = string.find(param, "(%d+)");
264 if (not value) then value = 0; else value = value + 0.0; end
265 if (value <= 0) then
266 SETTINGS.fadePerc = 0;
267 else
268 SETTINGS.fadePerc = value + 0.0;
269 end
270 Gatherer_ChatPrint("Setting fade percent at fade distance to "..SETTINGS.fadePerc);
271 Gatherer_OnUpdate(0, true);
272 elseif ((cmd == "idist") or (cmd == "icondist")) then
273 local i,j, value = string.find(param, "(%d+)");
274 if (not value) then value = 0; else value = value + 0; end
275 if (value <= 0) then
276 SETTINGS.miniIconDist = 0;
277 else
278 SETTINGS.miniIconDist = value + 0;
279 end
280 Gatherer_ChatPrint("Setting iconic distance to "..SETTINGS.miniIconDist);
281 Gatherer_OnUpdate(0, true);
282 elseif (cmd == "theme") then
283 if (Gather_IconSet[param]) then
284 SETTINGS.iconSet = param;
285 Gatherer_ChatPrint("Gatherer theme set to "..SETTINGS.iconSet);
286 else
287 Gatherer_ChatPrint("Unknown theme: "..param);
288 end
289 Gatherer_OnUpdate(0, true);
290 elseif ((cmd == "num") or (cmd == "number")) then
291 local i,j, value = string.find(param, "(%d+)");
292 if (not value) then value = 0; else value = value + 0; end
293 if (value < 0) then
294 SETTINGS.number = 10;
295 elseif (value <= GATHERER_MAXNUMNOTES) then
296 SETTINGS.number = math.floor(value + 0);
297 else
298 SETTINGS.number = GATHERER_MAXNUMNOTES;
299 end
300 if (SETTINGS.number == 0) then
301 SETTINGS.useMinimap = false;
302 SETTINGS.useMinimapText = "off";
303 Gatherer_OnUpdate(0, true);
304 Gatherer_ChatPrint("Turned gather minimap display off (still collecting)");
305 else
306 if ((SETTINGS.number > 0) and (SETTINGS.useMinimap == false)) then
307 SETTINGS.useMinimap = true;
308 SETTINGS.useMinimapText = "on";
309 Gatherer_ChatPrint("Turned gather minimap display on");
310 end
311 Gatherer_ChatPrint("Displaying "..SETTINGS.number.." notes at once");
312 Gatherer_OnUpdate(0, true);
313 end
314 elseif (cmd == "mainmap") then
315 if ((param == "false") or (param == "off") or (param == "no") or (param == "0")) then
316 SETTINGS.useMainmap = false;
317 elseif (param == "toggle") then
318 SETTINGS.useMainmap = not SETTINGS.useMainmap;
319 else
320 SETTINGS.useMainmap = true;
321 end
322 if (SETTINGS.useMainmap) then
323 Gatherer_ChatPrint("Displaying notes in main map");
324 Gatherer_WorldMapDisplay:SetText("Hide Items");
325 else
326 Gatherer_ChatPrint("Not displaying notes in main map");
327 Gatherer_WorldMapDisplay:SetText("Show Items");
328 end
329  
330 if (SETTINGS.useMainmap and SETTINGS.showWorldMapFilters and SETTINGS.showWorldMapFilters == 1) then
331 GathererWD_DropDownFilters:Show();
332 end
333  
334 elseif (cmd == "minder") then
335 if ((param == "false") or (param == "off") or (param == "no") or (param == "0")) then
336 SETTINGS.mapMinder = false;
337 elseif (param == "toggle") then
338 SETTINGS.mapMinder = not SETTINGS.mapMinder;
339 elseif (param == "on") then
340 SETTINGS.mapMinder = true;
341 else
342 local i,j, value = string.find(param, "(%d+)");
343 if (not value) then value = 0; else value = value + 0; end
344 if (value <= 0) then
345 SETTINGS.mapMinder = false;
346 SETTINGS.minderTime = 0;
347 else
348 SETTINGS.mapMinder = true;
349 SETTINGS.minderTime = value + 0;
350 end
351 Gatherer_ChatPrint("Setting map minder timeout to "..SETTINGS.minderTime);
352 end
353 if (SETTINGS.mapMinder) then
354 Gatherer_ChatPrint("Map minder activated at "..SETTINGS.minderTime);
355 else
356 Gatherer_ChatPrint("Not minding your map");
357 end
358 elseif ((cmd == "herbs") or (cmd == "mining") or (cmd == "treasure")) then
359 if ((param == "false") or (param == "off") or (param == "no") or (param == "0")) then
360 Gatherer_SetFilter(cmd, "off");
361 Gatherer_ChatPrint("Not displaying "..cmd.." notes in minimap");
362 elseif (param == "on" or param == "On" ) then
363 Gatherer_SetFilter(cmd, "on");
364 Gatherer_ChatPrint("Displaying "..cmd.." notes in minimap");
365 elseif (param == "toggle" or param == "") then
366 local cur = Gatherer_GetFilterVal(cmd);
367 if ((cur == "on") or (cur == "auto")) then
368 cur = "off";
369 Gatherer_SetFilter(cmd, "off");
370 Gatherer_ChatPrint("Not displaying "..cmd.." notes in minimap");
371 else
372 cur = "on";
373 Gatherer_SetFilter(cmd, "on");
374 Gatherer_ChatPrint("Displaying "..cmd.." notes in minimap");
375 end
376 else
377 Gatherer_SetFilter(cmd, "auto");
378 Gatherer_ChatPrint("Displaying "..cmd.." notes in minimap based on ability");
379 end
380 Gatherer_OnUpdate(0, true);
381 GatherMain_Draw();
382 end
383 end
384  
385 -- *************************************************************************
386 -- Events Handler
387  
388 function Gatherer_OnEvent(event)
389 if (not event) then return; end;
390  
391 -- Enable/Disable event processing for zoning
392 if (event == "PLAYER_ENTERING_WORLD" ) then
393 this:RegisterEvent("CHAT_MSG_SPELL_SELF_BUFF"); -- standard gathering event
394 this:RegisterEvent("UI_ERROR_MESSAGE"); -- event added for impossible to gather item
395 this:RegisterEvent("CHAT_MSG_LOOT"); -- event added for fishing node
396 Gatherer_InWorld = true;
397  
398 elseif (event == "PLAYER_LEAVING_WORLD" ) then
399 this:UnregisterEvent("CHAT_MSG_SPELL_SELF_BUFF"); -- standard gathering event
400 this:UnregisterEvent("UI_ERROR_MESSAGE"); -- event added for impossible to gather item
401 this:UnregisterEvent("CHAT_MSG_LOOT"); -- event added for fishing node
402 Gatherer_InWorld = false;
403  
404 -- process loot received message for fishing node trigger
405 elseif ( event == "CHAT_MSG_LOOT" ) then
406 local _, _, fishItem = string.find(arg1, GATHERER_ReceivesLoot );
407 local gfishTooltip = Gatherer_ExtractItemFromTooltip()
408  
409 if ( fishItem and not UnitExists("mouseover") ) then
410 Gatherer_ReadBuff(event, fishItem, gfishTooltip);
411 end
412 -- process event to record, normally not possible gather (low/inexistant skill)
413 elseif ( event == "UI_ERROR_MESSAGE" ) then
414 -- process gather error message
415 -- need to be in standard gather range to get the correct message to process.
416 if (arg1 and
417 (strfind(arg1, GATHERER_REQUIRE.." "..OLD_TRADE_HERBALISM) or strfind(arg1, GATHERER_NOSKILL.." "..OLD_TRADE_HERBALISM) or
418 strfind(arg1, OLD_TRADE_HERBALISM.." "..GATHERER_NOSKILL) or strfind(arg1, GATHERER_REQUIRE.." "..TRADE_MINING) or
419 strfind(arg1, GATHERER_NOSKILL.." "..TRADE_MINING) or strfind(arg1, TRADE_MINING.." "..GATHERER_NOSKILL))) then
420 Gatherer_ReadBuff(event);
421 end
422 -- process chatmessages
423 elseif ( event == "CHAT_MSG_SPELL_SELF_BUFF" ) then
424 Gatherer_ReadBuff(event);
425  
426 -- process AddOn communication
427 elseif strfind(event, "CHAT_MSG_ADDON") then
428 Gatherer_AddonMessageEvent(arg1, arg2, arg3);
429  
430 -- process tooltips text for 1.12
431 elseif ( event == "SPELLCAST_START" ) then
432 if ( arg1 and (arg1 == GATHER_HERBALISM or arg1 == TRADE_MINING or arg1 == TRADE_OPENING or arg1 =="") ) then
433 Gatherer_Debug("|cffffffffEvent :|r "..event.." => "..arg1);
434 Gatherer_currentNode = GameTooltipTextLeft1:GetText();
435 Gatherer_currentAction = arg1;
436  
437 Gatherer_Debug("Current node: "..(Gatherer_currentNode or "nil"));
438 Gatherer_RecordFlag=1;
439 end
440 elseif ( event == "SPELLCAST_STOP" and Gatherer_RecordFlag == 1 ) then
441 Gatherer_ReadBuff(event);
442 Gatherer_currentNode=nil;
443 elseif ( event == "SPELLCAST_STOP" and Gatherer_RecordFlag == 0 ) then
444 Gatherer_currentNode=nil;
445 Gatherer_RecordFlag = 0;
446  
447 elseif ( event == "SPELLCAST_FAILED" ) then
448 Gatherer_RecordFlag = 0;
449  
450 elseif (event == "WORLD_MAP_UPDATE") then
451 if (WorldMapFrame:IsVisible()) then
452 local serverTime = GetTime();
453 if (Gatherer_Settings.mapMinder == true and Gatherer_MapOpen == false) then
454 -- Enhancement to open to last opened map if we were there less than a minute ago
455 -- Otherwise, go to the player's current position
456 local startContinent, startZone;
457 if (Gatherer_CloseMap and (serverTime - Gatherer_CloseMap.time < Gatherer_Settings.minderTime)) then
458 startContinent = Gatherer_CloseMap.continent;
459 startZone = Gatherer_CloseMap.zone;
460 else
461 startContinent, startZone = Gatherer_GetCurrentZone();
462 end
463  
464 Gatherer_MapOpen = true;
465 if ( GetCurrentMapContinent()>0 and startZone and startZone > 0 ) then
466 SetMapZoom(startContinent, startZone);
467 end
468 end
469 Gatherer_MapOpen = true;
470 local mapContinent = GetCurrentMapContinent();
471 local mapZone = GetCurrentMapZone();
472 Gatherer_CloseMap = { continent = mapContinent, zone = mapZone, time = GetTime() };
473 GatherMain_Draw();
474 elseif (Gatherer_MapOpen) then
475 Gatherer_MapOpen = false;
476 Gatherer_ChangeMap();
477 GatherMain_Draw();
478 end
479 elseif ( event == "CLOSE_WORLD_MAP") then
480 -- never called apparently
481 Gatherer_MapOpen = false;
482  
483 Gatherer_ChangeMap()
484 GatherMain_Draw();
485 elseif( event == "ADDON_LOADED") then
486 if ( myAddOnsFrame_Register ) then
487 -- myAddons Support
488 GathererDetails["name"] = "Gatherer";
489 GathererDetails["version"] = GATHERER_VERSION;
490 GathererDetails["author"] = "Norganna";
491 GathererDetails["website"] = "http://gathereraddon.com";
492 GathererDetails["category"] = MYADDONS_CATEGORY_PROFESSIONS;
493 GathererDetails["frame"] = "Gatherer";
494 GathererDetails["optionsframe"] = "GathererUI_DialogFrame";
495  
496 -- Register the addon in myAddOns
497 if(myAddOnsFrame_Register) then
498 myAddOnsFrame_Register(GathererDetails, GathererHelp);
499 end
500 end
501  
502 if (arg1 and string.lower(arg1) == "gatherer") then
503 Gatherer_Configuration.Load();
504 GATHERER_LOADED = true;
505 Gatherer_sanitizeDatabase(GatherItems)
506 Gatherer_OnUpdate(0, true);
507  
508 Gatherer_Print("Gatherer p2p v"..GATHERER_VERSION.." -- Loaded!");
509  
510 if (Gatherer_Settings.useMainmap == true) then
511 Gatherer_WorldMapDisplay:SetText("Hide Items");
512 else
513 Gatherer_WorldMapDisplay:SetText("Show Items");
514 end
515  
516 -- Warning at logon on Gatherer Version number change to check for localization zone change (commented, not needed in 1.12)
517 --if ( GetLocale() == "deDE" and (not Gatherer_Settings.Version or (Gatherer_Settings.Version and Gatherer_Settings.Version ~= GATHERER_VERSION ))) then
518 -- StaticPopup_Show("GATHERER_VERSION_DIALOG");
519 --end
520  
521 -- record current version number in order to identify the data for backup utilities
522 Gatherer_Settings.Version = GATHERER_VERSION;
523  
524 -- Get values for World Map once for all
525 Gatherer_WorldMapDetailFrameWidth = WorldMapDetailFrame:GetWidth();
526 Gatherer_WorldMapDetailFrameHeight = WorldMapDetailFrame:GetHeight();
527 Gatherer_WorldMapPlayerFrameLevel = WorldMapPlayer:GetFrameLevel();
528  
529 -- New backup format allows the user to permenantly save their data
530 -- in an automatically restoring file "GatherBase.lua"
531 -- All data in this file will be loaded "under" the saved data every
532 -- time the addon loads so that in the event of a savedVariables wipe
533 -- the next time they run WoW, their data will be back to the last
534 -- backed up point. (This utility will appear in a later version of
535 -- Gatherer as a Java applet)
536 if (GatherItemBase ~= nil) then
537 for c, cd in GatherItems do
538 for z, zd in cd do
539 for n,nd in zd do
540 for i,id in nd do
541 local matched = 0;
542 local max = 0;
543 for j,jd in GatherItemBase[c][z][n] do
544 if (math.abs(id.x- jd.y) < 0.05) then
545 matched = j;
546 end
547 max = j;
548 end
549 if (matched > 0) then
550 GatherItemBase[c][z][n][matched] = id;
551 else
552 GatherItemBase[c][z][n][max+1] = id;
553 end
554 end
555 end
556 end
557 end
558 GatherItems = GatherItemBase;
559 end
560 end
561 elseif ( event == "PLAYER_LOGIN" ) then
562 local SETTINGS = Gatherer_Settings;
563 local useMinimap = (SETTINGS.useMinimap) and "On" or "Off";
564 local useMainmap = (SETTINGS.useMainmap) and "On" or "Off";
565 local mapMinder = (SETTINGS.mapMinder) and "On" or "Off";
566 local minderTime = SETTINGS.minderTime.."s";
567  
568 if ( SETTINGS.logInfo and SETTINGS.logInfo == "on" ) then
569 Gatherer_Print("[Player: "..Gather_Player..", Theme: "..SETTINGS.iconSet..", Mainmap: "..useMainmap..", Minimap: "..useMinimap..", MaxDist: "..SETTINGS.maxDist.." units, NoteCount: "..SETTINGS.number..", Fade: "..SETTINGS.fadePerc.."% at "..SETTINGS.fadeDist.." units, IconDist: "..SETTINGS.miniIconDist.."px on minimap, MapMinder: "..mapMinder.." ("..minderTime.."), Filters: herbs="..Gatherer_GetFilterVal("herbs")..", mining="..Gatherer_GetFilterVal("mining")..", treasure="..Gatherer_GetFilterVal("treasure").."]");
570 end
571  
572 elseif ( event == "PLAYER_LOGOUT" ) then
573 Gatherer_Configuration.Save();
574  
575 elseif ( event == "LEARNED_SPELL_IN_TAB" or event == "SPELLS_CHANGED" ) then
576 local numSkills = tonumber(GetNumSkillLines());
577 if ( GetNumSkillLines() > 0 ) then
578 Gatherer_GetSkills();
579 end
580 elseif ( event == "SKILL_LINES_CHANGED" ) then
581 local numSkills = tonumber(GetNumSkillLines());
582 if ( GetNumSkillLines() > 0 ) then
583 Gatherer_GetSkills();
584 end
585 else
586 Gatherer_ChatPrint("Gatherer Unknown event: "..event);
587 end
588 end
589  
590 -- *************************************************************************
591 -- Filter related functions
592  
593 local filterConversion = {
594 ["herbs"] = 1,
595 ["mining"] = 2,
596 ["treasure"] = 0,
597 [0] = 0,
598 [1] = 1,
599 [2] = 2,
600 }
601  
602 function Gatherer_SetFilter(type, value)
603 local type = filterConversion[type];
604 if ( type ) then
605 Gatherer_Settings.filters[type] = value;
606 end
607 end
608  
609 function Gatherer_GetFilterVal(type)
610 local type = filterConversion[type];
611 value = Gatherer_Settings.filters[type];
612 if (not value) then return "auto"; end
613 return value;
614 end
615  
616 function Gatherer_GetFilter(filter)
617 local value = Gatherer_GetFilterVal(filter);
618 local filterVal = false;
619  
620 if (value == "on") then
621 filterVal = true;
622 elseif (value == "off") then
623 filterVal = false;
624 elseif (value == "auto") then
625 if (filter == "treasure") then
626 filterVal = true;
627 end
628 if (not GatherSkills) then
629 filterVal = true;
630 end
631 if ((GatherSkills[filter]) and (GatherSkills[filter] > 0)) then
632 filterVal = true;
633 end
634 end
635  
636 return filterVal;
637 end
638  
639 function Gatherer_GetSkills()
640 local GatherExpandedHeaders = {};
641 local i, j;
642  
643 if ( not GatherSkills ) then GatherSkills = {}; end;
644 Gatherer:UnregisterEvent("SKILL_LINES_CHANGED");
645  
646 -- search the skill tree for gathering skills
647 for i=0, GetNumSkillLines(), 1 do
648 local skillName, header, isExpanded, skillRank, _, _, _, _, _, _, _, _ = GetSkillLineInfo(i);
649  
650 -- expand the header if necessary
651 if ( header and not isExpanded ) then
652 GatherExpandedHeaders[i] = skillName;
653 end
654 end
655  
656 ExpandSkillHeader(0);
657 for i=1, GetNumSkillLines(), 1 do
658 local skillName, header, _, skillRank, _, _, _, _, _, _, _, _ = GetSkillLineInfo(i);
659 -- check for the skill name
660 if (skillName and not header) then
661 if (skillName == TRADE_HERBALISM) then
662 GatherSkills.herbs = skillRank;
663 elseif (skillName == TRADE_MINING) then
664 GatherSkills.mining = skillRank;
665 end
666 end
667  
668 -- once we got both, no need to look the rest
669 if ( GatherSkills.herbs and GatherSkills.mining ) then
670 break;
671 end
672 end
673  
674 -- close headers expanded during search process
675 for i=0, GetNumSkillLines() do
676 local skillName, header, isExpanded, _, _, _, _, _, _, _, _, _ = GetSkillLineInfo(i);
677 for j in GatherExpandedHeaders do
678 if ( header and skillName == GatherExpandedHeaders[j] ) then
679 CollapseSkillHeader(i);
680 GatherExpandedHeaders[j] = nil;
681 end
682 end
683 end
684 end
685  
686  
687 local function random_choice(t)
688 if not t then return end
689 local choiceI = nil;
690 local choiceO = nil;
691 local n = 0;
692 for i, o in pairs(t) do
693 n = n + 1
694 if math.random() < (1/n) then
695 choiceI, choiceO = i, o
696 end
697 end
698 return choiceI, choiceO
699 end
700  
701  
702 local function selectRandomGather()
703 -- type: () -> Tuple[GatherName, Gatherer_EGatherType, Continent, Zone, float, float, IconName, EGatherEventType]
704 -- returns the arguments set for the Gatherer_BroadcastGather function
705 local randomContinent, continentData = random_choice(GatherItems);
706 local randomZone, zoneData = random_choice(continentData);
707 local randomGather, gatherNodes = random_choice(zoneData);
708 local nodeIndex, randomNode = random_choice(gatherNodes);
709 Gatherer_ChatNotify('randomly selected: '..table.concat(
710 {randomContinent, randomZone, randomGather, nodeIndex}, ', '
711 ), Gatherer_ENotificationType.debug);
712 if not nodeIndex then
713 return nil
714 end
715  
716 local eventType = 1; -- EGatherEventType.no_skill
717 -- values don't matter, I just hate lua
718 local FISHING_GATHERS = {['floating wreckage']=0, ['school']=''};
719 if FISHING_GATHERS[randomGather] then
720 eventType = 2; -- EGatherEventType.fishing
721 end
722  
723 return
724 randomGather, randomNode.gtype, randomContinent, randomZone, randomNode.x, randomNode.y,
725 randomNode.icon, eventType
726 end
727  
728  
729 -- *************************************************************************
730 -- Update related functions
731  
732 local Gatherer_UpdateTicker = 0.0;
733 local Gatherer_AnnouncePeriod = 10;
734 local Gatherer_CycleCount = 0;
735 local Gatherer_SecondsToAnnounce = Gatherer_AnnouncePeriod;
736 function Gatherer_TimeCheck(timeDelta)
737 if (not GatherNotes) then
738 GatherNotes = { timeDiff=0, checkDiff=0 };
739 else
740 GatherNotes.checkDiff = GatherNotes.checkDiff + timeDelta;
741 if (GatherNotes.checkDiff > GATHERNOTE_CHECK_INTERVAL) then
742 GatherNotes.checkDiff = 0;
743 Gatherer_OnUpdate(0,true);
744 end
745 end
746 Gatherer_UpdateTicker = Gatherer_UpdateTicker + arg1;
747 if( Gatherer_UpdateTicker < 1 ) then
748 return
749 end
750 -- reset seconds counter
751 Gatherer_UpdateTicker = 0.0;
752 -- the code below will run not more frequently
753 -- than once a second
754 Gatherer_SecondsToAnnounce = Gatherer_SecondsToAnnounce - 1
755 -- Gatherer_Print('Every second '..Gatherer_SecondsToAnnounce..' seconds.')
756 if Gatherer_SecondsToAnnounce > 0 then
757 return
758 end
759 -- the code below will run not more frequently
760 -- than once Gatherer_AnnouncePeriod seconds
761 if Gatherer_Settings.p2p then
762 local args = {selectRandomGather()};
763 -- if failed to get a random node skip cycle
764 if not args[1] then
765 return
766 end
767 Gatherer_CycleCount = Gatherer_CycleCount + 1
768 if Gatherer_Settings.debug then
769 Gatherer_ChatPrint('Gatherer: Cycle #'..Gatherer_CycleCount);
770 Gatherer_ChatNotify(
771 'Sending random node once in '..Gatherer_AnnouncePeriod..' seconds.',
772 Gatherer_ENotificationType.sending
773 );
774 Gatherer_ChatNotify(
775 'args to send: '..table.concat(args, ', '), Gatherer_ENotificationType.sending
776 );
777 end
778 Gatherer_BroadcastGather(unpack(args))
779 end
780 Gatherer_SecondsToAnnounce = Gatherer_AnnouncePeriod
781 end
782  
783 function Gatherer_OnUpdate(timeDelta, force)
784 if (not GATHERER_LOADED) then
785 Gatherer_Print("Gatherer not loaded");
786 return;
787 end
788  
789 local SETTINGS = Gatherer_Settings;
790  
791 if (Gatherer_InWorld == false ) then
792 return;
793 end
794  
795 if (not SETTINGS.useMinimap) then
796 Gatherer_HideAll();
797 return;
798 end
799  
800 local recalculate = false;
801 local needsUpdate = false;
802 if (not GatherNotes) then
803 GatherNotes = { timeDiff=0, checkDiff=0 };
804 needsUpdate = true;
805 else
806 GatherNotes.timeDiff = GatherNotes.timeDiff + timeDelta;
807 if (GatherNotes.timeDiff > GATHERNOTE_UPDATE_INTERVAL) then
808 needsUpdate = true;
809 end
810 end
811 if (force) then
812 needsUpdate = true;
813 recalculate = true;
814 end
815  
816 if (needsUpdate) then
817 GatherNotes.timeDiff = 0;
818 -- Find the closest gathers
819 local continent, zone = Gatherer_GetCurrentZone();
820 if ((continent == 0) or (zone == 0)) then
821 Gatherer_HideAll();
822 return;
823 end
824  
825 local inCity = GatherMap_InCity;
826 local zoomLevel = Minimap:GetZoom();
827 local px, py = Gatherer_PlayerPos();
828 if ((px == 0) and (py == 0)) then
829 return;
830 end
831 local xMovement = 0; if (ClosestGathers and ClosestGathers.px) then xMovement = math.abs(ClosestGathers.px - px); end
832 local yMovement = 0; if (ClosestGathers and ClosestGathers.py) then yMovement = math.abs(ClosestGathers.py - py); end
833 if (not ClosestGathers
834 or ClosestGathers.playerC ~= continent
835 or ClosestGathers.playerZ ~= zone
836 or xMovement + yMovement > 0.01) then
837 recalculate = true;
838 end
839  
840 local displayNumber = 10;
841 if (SETTINGS.number and SETTINGS.number > 0) then
842 displayNumber = SETTINGS.number;
843 end
844  
845 local playerDeltaX = 0;
846 local playerDeltaY = 0;
847 if (recalculate == true) then
848 ClosestGathers = {};
849 ClosestGathers = Gatherer_FindClosest(displayNumber);
850 if (ClosestGathers.count > 0) then
851 ClosestGathers.inCity = inCity;
852 ClosestGathers.zoomLevel = zoomLevel;
853 ClosestGathers.scaleX, ClosestGathers.scaleY = Gatherer_GetMapScale(continent, zone, inCity, zoomLevel);
854 end
855 else
856 if ((inCity ~= ClosestGathers.inCity) or (zoomLevel ~= ClosestGathers.zoomLevel)) then
857 ClosestGathers.inCity = inCity;
858 ClosestGathers.zoomLevel = zoomLevel;
859 ClosestGathers.scaleX, ClosestGathers.scaleY = Gatherer_GetMapScale(continent, zone, inCity, zoomLevel);
860 end
861 local absX, absY = Gatherer_AbsCoord(continent, zone, px, py);
862 playerDeltaX = ClosestGathers.playerX - absX;
863 playerDeltaY = ClosestGathers.playerY - absY;
864 end
865  
866 local maxPos = 0;
867 if (ClosestGathers and ClosestGathers.count > 0) then
868 local closestPos, closestGather, closestID;
869 local currentPos = 1;
870 for closestPos, closestGather in ClosestGathers.items do
871 local skip_node = 0;
872  
873 if ( currentPos > SETTINGS.number ) then skip_node =1; end
874  
875 if ( skip_node == 0 ) then
876 -- need to position and label the corresponding button
877 local gatherNote = getglobal("GatherNote"..currentPos);
878 local gatherNoteTexture = getglobal("GatherNote"..currentPos.."Texture");
879  
880 local itemDeltaX = closestGather.deltax+playerDeltaX;
881 local itemDeltaY = closestGather.deltay+playerDeltaY;
882 local offsX, offsY, gDist = Gatherer_MiniMapPos(itemDeltaX, itemDeltaY, ClosestGathers.scaleX, ClosestGathers.scaleY);
883 gatherNote:SetPoint("CENTER", Minimap, "CENTER", offsX, -offsY);
884  
885 local iconSet = SETTINGS.iconSet;
886 local iDist = SETTINGS.miniIconDist;
887 if (not iconSet) then iconSet = "shaded"; end
888 if (not iDist) then iDist = 38; end
889  
890 local _, _, sDist = Gatherer_MiniMapPos(iDist/10000, 0, ClosestGathers.scaleX, ClosestGathers.scaleY);
891  
892 if ((iDist > 0) and (gDist > (math.floor(sDist)-1))) then
893 iconSet = "iconic";
894 end
895  
896 local fadeDist = SETTINGS.fadeDist / 1000;
897 local fadePerc = SETTINGS.fadePerc / 100;
898 local alpha = 1.0;
899 local objDist = Gatherer_Pythag(itemDeltaX, itemDeltaY);
900 if ((fadeDist > 0) and (fadePerc > 0)) then
901 local distRatio = objDist / fadeDist ;
902 alpha = 1.0 - (math.min(1.0, math.max(0.0, distRatio)) * fadePerc);
903 end
904  
905 local textureType = closestGather.item.gtype;
906 local textureIcon = closestGather.item.icon;
907  
908 if ( type(textureType) == "number" ) then
909 textureType = Gatherer_EGatherType[textureType];
910 end
911  
912 if ( type(textureIcon) == "number" ) then
913 textureIcon = Gatherer_GetDB_IconIndex(textureIcon, textureType);
914 end
915  
916 if (not textureIcon) then textureIcon = "default"; end;
917 if (SETTINGS.iconSet == "iconshade" )
918 then
919 iconSet="iconic";
920 if ( gDist < (math.floor(sDist)-1) )
921 then
922 alpha=0.4;
923 end
924 end
925 if (not Gather_IconSet[iconSet]) then iconSet = "shaded"; end
926 if (not Gather_IconSet[iconSet][textureType]) then textureType = "Default"; end
927 local selectedTexture = Gather_IconSet[iconSet][textureType][textureIcon];
928 if (not selectedTexture) then
929 selectedTexture = Gather_IconSet[iconSet][textureType]["default"];
930 end
931  
932 gatherNoteTexture:SetTexture(selectedTexture);
933 gatherNote:SetFrameLevel(MiniMapTrackingFrame:GetFrameLevel());
934 gatherNote:SetAlpha(alpha);
935  
936 -- Added to allow hiding if under min distance
937 if ( SETTINGS.NoIconOnMinDist ~= nil and SETTINGS.NoIconOnMinDist == 1 ) then
938 if ( gDist < (math.floor(sDist)-1) ) then
939 gatherNote:Hide();
940 else
941 gatherNote:Show();
942 end
943 elseif ( (not SETTINGS.NoIconOnMinDist or SETTINGS.NoIconOnMinDist == 0) and SETTINGS.alphaUnderMinIcon and gDist < (math.floor(sDist)-1) ) then
944 if ( SETTINGS.iconSet and SETTINGS.iconSet ~= "iconshade" ) then
945 gatherNote:SetAlpha(SETTINGS.alphaUnderMinIcon / 100);
946 end
947 gatherNote:Show();
948 else
949 gatherNote:Show();
950 end
951  
952 if (currentPos > maxPos) then maxPos = currentPos; end
953  
954 currentPos = currentPos + 1;
955 end
956 skip_node = 0;
957 end
958 end
959  
960 while (maxPos < GATHERER_MAXNUMNOTES) do
961 maxPos = maxPos+1;
962 local gatherNote = getglobal("GatherNote"..maxPos);
963 if ( gatherNote:IsShown() ) then
964 gatherNote:Hide();
965 end
966 end
967 end
968 end
969  
970 -- *************************************************************************
971 -- UI related functions
972  
973 function Gatherer_OnClick() -- function changed to be able to ping through the MiniNote (mostly direct copy) (only change: this -> Minimap)
974 local x, y = GetCursorPosition();
975 if ( Minimap.GetEffectiveScale ~= nil ) then
976 x = x / Minimap:GetEffectiveScale();
977 y = y / Minimap:GetEffectiveScale();
978 else
979 x = x / Minimap:GetScale();
980 y = y / Minimap:GetScale();
981 end
982  
983 local cx, cy = Minimap:GetCenter();
984 x = x + CURSOR_OFFSET_X - cx;
985 y = y + CURSOR_OFFSET_Y - cy;
986 if ( sqrt(x * x + y * y) < (Minimap:GetWidth() / 2) ) then
987 Minimap:PingLocation(x, y);
988 end
989 end
990  
991 -- *************************************************************************
992 -- Display functions
993  
994 function Gatherer_HideAll()
995 local mmPos = 0;
996 while (mmPos < GATHERER_MAXNUMNOTES) do
997 mmPos = mmPos+1;
998 local gatherNote = getglobal("GatherNote"..mmPos);
999 gatherNote:Hide();
1000 end
1001 end
1002  
1003 function Gatherer_CreateNoteObject(noteNumber)
1004 local button;
1005 local overlayFrameNumber = math.floor((noteNumber - 1000) / 100 + 1);
1006 if(getglobal("GatherMain"..noteNumber)) then
1007 button = getglobal("GatherMain"..noteNumber);
1008 else
1009 Gatherer_Debug("create id "..noteNumber.." frame ".. overlayFrameNumber);
1010 button = CreateFrame("Button" ,"GatherMain"..noteNumber, getglobal("GathererMapOverlayFrame"..overlayFrameNumber), "GatherMainTemplate");
1011 button:SetID(noteNumber);
1012 end
1013  
1014 return button;
1015 end
1016  
1017 function GatherMain_Draw()
1018 local lastUnused = 1000;
1019 local maxNotes = 1600;
1020 local gatherName, gatherData;
1021 local SETTINGS = Gatherer_Settings;
1022  
1023 -- prevent the function from running twice at the same time.
1024 if (Gatherer_UpdateWorldMap == 0 ) then return; end;
1025 Gatherer_UpdateWorldMap = 0;
1026  
1027 if ((Gatherer_MapOpen) and (SETTINGS.useMainmap)) then
1028 local mapContinent = GetCurrentMapContinent();
1029 local mapZone = GetCurrentMapZone();
1030 if ((mapContinent > 0) and (mapZone > 0) and (GatherItems[mapContinent]) and (GatherItems[mapContinent][mapZone])) then
1031 for gatherName, gatherData in GatherItems[mapContinent][mapZone] do
1032 local gatherType = "Default";
1033 local specificType = "";
1034 local allowed = true;
1035 local minSetSkillLevel = 0;
1036 local idx_count=0;
1037  
1038 specificType = Gatherer_FindOreType(gatherName);
1039 if (specificType) then -- Ore
1040 gatherType = 2;
1041 allowed = Gatherer_GetFilter("mining");
1042 else
1043 specificType = Gatherer_FindTreasureType(gatherName);
1044 if (specificType ) then -- Treasure
1045 gatherType = 0;
1046 allowed = Gatherer_GetFilter("treasure");
1047 else
1048 specificType = Gatherer_FindFishType(gatherName);
1049 if ( specificType ) then -- Treasure Fish
1050 gatherType = 0;
1051 allowed = Gatherer_GetFilter("treasure");
1052 else
1053 -- Herb
1054 specificType = gatherName;
1055 gatherType = 1;
1056 allowed = Gatherer_GetFilter("herbs");
1057 end
1058 end
1059 end
1060 if (not specificType) then
1061 specificType = "default";
1062 end
1063  
1064 -- extra filtering options
1065 if (SETTINGS) then
1066 if ( SETTINGS.interested and SETTINGS.interested[gatherType] ) then
1067 for interest_index in SETTINGS.interested[gatherType] do
1068 idx_count= idx_count +1;
1069 end
1070 end
1071  
1072 if( gatherType == 2 ) then -- Ore
1073 minSetSkillLevel = SETTINGS.minSetOreSkill;
1074 if ( not minSetSkillLevel ) then minSetSkillLevel = -1; end
1075 elseif ( gatherType == 1 ) then -- Herb
1076 minSetSkillLevel = SETTINGS.minSetHerbSkill;
1077 if ( not minSetSkillLevel ) then minSetSkillLevel = -1; end
1078 end
1079  
1080 if ( allowed == true and Gather_SkillLevel[specificType] and
1081 minSetSkillLevel > 0 and
1082 (minSetSkillLevel > Gather_SkillLevel[specificType] or
1083 (SETTINGS.rareOre == 1 and Gather_SkillLevel[Gather_RareMatch[specificType]] and
1084 Gather_SkillLevel[specificType] < Gather_SkillLevel[Gather_RareMatch[specificType]] and
1085 minSetSkillLevel > Gather_SkillLevel[Gather_RareMatch[specificType]] ))
1086 ) then
1087 allowed = false;
1088 end
1089 end
1090  
1091 if ((allowed == true) and
1092 ((SETTINGS == nil) or
1093 (SETTINGS.interested == nil) or (idx_count == 0) or SETTINGS.interested[gatherType] == nil or
1094 (SETTINGS.interested[gatherType][specificType] == true or
1095 (SETTINGS.rareOre == 1 and SETTINGS.interested[gatherType][Gather_RareMatch[specificType]])
1096 )
1097 )
1098 ) then
1099 for hPos, gatherInfo in gatherData do
1100 local convertedGatherType="";
1101 local numGatherType, numGatherIcon;
1102  
1103 if ( lastUnused > 1000 and lastUnused < maxNotes and mod(lastUnused, 100) == 0 ) then
1104 local overlayFrameNumber = math.floor((lastUnused - 1000 )/100 + 1);
1105  
1106 getglobal("GathererMapOverlayFrame"..overlayFrameNumber):Show();
1107 elseif (lastUnused < 1100 and not GathererMapOverlayFrame1:IsShown() ) then
1108 GathererMapOverlayFrame1:Show();
1109 end
1110  
1111 if ((gatherInfo.x) and (gatherInfo.y) and (gatherInfo.x>0) and (gatherInfo.y>0) and (lastUnused <= maxNotes)) then
1112 local mainNote = Gatherer_CreateNoteObject(lastUnused);
1113  
1114 local mnX,mnY;
1115 mnX = gatherInfo.x / 100 * Gatherer_WorldMapDetailFrameWidth;
1116 mnY = -gatherInfo.y / 100 * Gatherer_WorldMapDetailFrameHeight;
1117  
1118 if ( SETTINGS and SETTINGS.IconAlpha ~= nil ) then
1119 mainNote:SetAlpha(SETTINGS.IconAlpha / 100);
1120 else
1121 mainNote:SetAlpha(0.8);
1122 end
1123  
1124 mainNote:SetPoint("CENTER", "GathererMapOverlayFrame", "TOPLEFT", mnX, mnY);
1125  
1126 if ( SETTINGS and SETTINGS.ToggleWorldNotes and SETTINGS.ToggleWorldNotes == 1)
1127 then
1128 mainNote.toolTip = Gatherer_GetMenuName(gatherName);
1129 else
1130 mainNote.toolTip = Gatherer_GetMenuName(specificType);
1131 end
1132  
1133 if ( type(gatherType) == "number" ) then
1134 convertedGatherType = Gatherer_EGatherType[gatherType];
1135 numGatherType = gatherType
1136 else
1137 convertedGatherType = gatherType;
1138 numGatherType = Gatherer_EGatherType[gatherType];
1139 end
1140  
1141 if (not Gather_IconSet["iconic"][convertedGatherType]) then
1142 gatherType = "Default";
1143 else
1144 gatherType = convertedGatherType;
1145 end
1146 if ( type(specificType) == "number" ) then
1147 specificType = Gatherer_GetDB_IconIndex(specificType, convertedGatherType);
1148 end
1149 local texture = Gather_IconSet["iconic"][convertedGatherType][specificType];
1150 if (not texture) then
1151 texture = Gather_IconSet["iconic"][gatherType]["default"];
1152 end
1153  
1154 if ( gatherInfo.gtype == "Default" or gatherInfo.gtype == 3 ) then
1155 texture = Gather_IconSet["iconic"]["Default"]["default"];
1156 end
1157  
1158 local mainNoteTexture = getglobal("GatherMain"..lastUnused.."Texture");
1159 mainNoteTexture:SetTexture(texture);
1160 if ( SETTINGS and SETTINGS.IconSize ~= nil ) then
1161 mainNote:SetWidth(SETTINGS.IconSize);
1162 mainNote:SetHeight(SETTINGS.IconSize);
1163 end
1164  
1165 -- setting value for editing
1166 if (type(gatherInfo.icon) == "string" ) then
1167 numGatherIcon = Gather_DB_IconIndex[numGatherType];
1168 else
1169 numGatherIcon = gatherInfo.icon;
1170 end
1171  
1172 mainNote.continent = mapContinent;
1173 mainNote.zoneIndex = mapZone;
1174 mainNote.gatherName = gatherName;
1175 mainNote.localIndex = hPos;
1176 mainNote.gatherType = numGatherType;
1177 mainNote.gatherIcon = numGatherIcon;
1178  
1179 if ( not mainNote:IsShown() ) then
1180 mainNote:Show();
1181 end
1182 lastUnused = lastUnused + 1;
1183 end
1184 end
1185 end
1186 end
1187 end
1188 end
1189  
1190 local i=1000;
1191 for i=lastUnused, maxNotes, 1 do
1192 -- Delay code to try to work around the delay display problem, pause for 50 ms each 100 items
1193 local overlayFrameNumber = math.floor((i - 1000) / 100 +1);
1194  
1195 if ( i < maxNotes and mod(i, 100) == 0 )
1196 then
1197 getglobal("GathererMapOverlayFrame"..overlayFrameNumber):Hide();
1198 end
1199  
1200 local mainNote = getglobal("GatherMain"..i);
1201 if ( mainNote and mainNote:IsShown() ) then
1202 mainNote:SetPoint("CENTER", "GathererMapOverlayFrame", "TOPLEFT", Gatherer_WorldMapDetailFrameWidth+16, Gatherer_WorldMapDetailFrameHeight+16);
1203 end
1204 end
1205  
1206 Gatherer_UpdateWorldMap = -1;
1207 end
1208  
1209 function Gatherer_FindClosest(num, interested)
1210 local SETTINGS = Gatherer_Settings;
1211 local gatherLocal = {playerC=0,playerZ=0,playerX=0,playerY=0,px=0,py=0,items={},count=0};
1212  
1213 if (not GATHERER_LOADED) then return gatherLocal; end
1214 if (Gatherer_InWorld == false ) then return gatherLocal; end
1215  
1216  
1217 local continent, zone = Gatherer_GetCurrentZone();
1218  
1219 if ((continent == 0) or (zone == 0)) then return gatherLocal; end
1220  
1221 local px,py = Gatherer_PlayerPos();
1222 if ((px == 0) and (py == 0)) then return gatherLocal; end
1223  
1224 local absPx, absPy = Gatherer_AbsCoord(continent, zone, px, py);
1225 gatherLocal = { playerC=continent, playerZ=zone, playerX=absPx, playerY=absPy, px=px, py=py, items={}, count=0 };
1226  
1227 local gatherCount = 0;
1228 local maxAllowable = 0;
1229 if ((SETTINGS.maxDist) and (SETTINGS.maxDist > 0)) then
1230 maxAllowable = SETTINGS.maxDist / 1000;
1231 end
1232  
1233 if (not GatherItems[continent] or (GatherItems[continent] and not GatherItems[continent][zone])) then return gatherLocal; end
1234  
1235 -- local gatherZone, gathersInZone;
1236 -- for gatherZone, gathersInZone in GatherItems[continent] do
1237 local gatherName, gatherData;
1238 for gatherName, gatherData in GatherItems[continent][zone] do
1239 -- for gatherName, gatherData in gathersInZone do
1240 local gatherType = "Default";
1241 local specificType = "";
1242 local allowed = true;
1243  
1244 specificType = Gatherer_FindOreType(gatherName);
1245 if (specificType) then -- Ore
1246 gatherType = 2;
1247 allowed = Gatherer_GetFilter("mining");
1248 else
1249 specificType = Gatherer_FindTreasureType(gatherName);
1250 if (specificType) then -- Treasure
1251 gatherType = 0;
1252 allowed = Gatherer_GetFilter("treasure");
1253 else -- Herb
1254 specificType = gatherName;
1255 gatherType = 1;
1256 allowed = Gatherer_GetFilter("herbs");
1257 end
1258 end
1259  
1260 if (not specificType) then
1261 specificType = "default";
1262 end
1263  
1264 local idx_count=0;
1265  
1266 if (SETTINGS) then
1267 if ( SETTINGS.interested and SETTINGS.interested[gatherType] ) then
1268 for interest_index in SETTINGS.interested[gatherType] do
1269 idx_count= idx_count +1;
1270 end
1271 end
1272  
1273 if( gatherType == 2 ) then -- Ore
1274 minSetSkillLevel = SETTINGS.minSetOreSkill;
1275 if ( not minSetSkillLevel ) then minSetSkillLevel = -1; end
1276 elseif ( gatherType == 1 ) then -- Herb
1277 minSetSkillLevel = SETTINGS.minSetHerbSkill;
1278 if ( not minSetSkillLevel ) then minSetSkillLevel = -1; end
1279 end
1280  
1281 if ( allowed == true and Gather_SkillLevel[specificType] and
1282 minSetSkillLevel > 0 and
1283 (minSetSkillLevel > Gather_SkillLevel[specificType] or
1284 (SETTINGS.rareOre == 1 and Gather_SkillLevel[Gather_RareMatch[specificType]] and
1285 minSetSkillLevel > Gather_SkillLevel[Gather_RareMatch[specificType]] ))
1286 ) then
1287 allowed = false;
1288 end
1289 end
1290  
1291 if ((allowed == true) and
1292 ((SETTINGS == nil) or
1293 (SETTINGS.interested == nil) or (idx_count == 0) or SETTINGS.interested[gatherType] == nil or
1294 (SETTINGS.interested[gatherType][specificType] == true or
1295 (SETTINGS.rareOre == 1 and SETTINGS.interested[gatherType][Gather_RareMatch[specificType]])
1296 )
1297 )
1298 ) then
1299 local maxNum=100;
1300 local gatherInfo;
1301  
1302 for _, gatherInfo in gatherData do
1303 local absHx;
1304 local absHy;
1305  
1306 if ((not gatherInfo.gtype) or (gatherInfo.gtype == "")) then
1307 gatherInfo.gtype = gatherType;
1308 end
1309  
1310 if ((not gatherInfo.icon) or (gatherInfo.icon == "")) then
1311 gatherInfo.icon = Gatherer_GetDB_IconIndex(specificType, gatherType);
1312 end
1313  
1314 absHx, absHy = Gatherer_AbsCoord(continent, zone, gatherInfo.x/100, gatherInfo.y/100);
1315 -- absHx, absHy = Gatherer_AbsCoord(continent, gatherZone, gatherInfo.x/100, gatherInfo.y/100); absHx = math.floor(absHx * 100000)/100000;
1316 absHy = math.floor(absHy * 100000)/100000;
1317  
1318 if ((absHx ~= 0) and (absHy ~= 0)) then
1319 local maxLocalPos = 0;
1320 local replCandidate = 0;
1321 local dist, deltaX, deltaY = Gatherer_Distance(absPx, absPy, absHx, absHy);
1322  
1323 if ((maxAllowable == 0) or (dist < maxAllowable)) then
1324 local localPos, localInfo;
1325  
1326 for localPos, localInfo in gatherLocal.items do
1327  
1328 if ( localPos <= num ) then
1329 if (localPos > maxLocalPos) then maxLocalPos = localPos; end
1330  
1331 -- take node at the same approximate spot into consideration
1332 if ( (abs(gatherInfo.x - localInfo.item.x) <= GATHERER_CLOSESTCHECK or
1333 Gatherer_Round(gatherInfo.x * 10) == Gatherer_Round(localInfo.item.x * 10)) and
1334 (abs(gatherInfo.y - localInfo.item.y) <= GATHERER_CLOSESTCHECK or
1335 Gatherer_Round(gatherInfo.y * 10) == Gatherer_Round(localInfo.item.y * 10)) )
1336 then
1337 replCandidate = maxNum;
1338 maxNum = maxNum + 1;
1339 -- shorter distance
1340 elseif (localInfo.dist > dist) then
1341 if ((replCandidate == 0) or (gatherLocal.items[replCandidate] and (localInfo.dist > gatherLocal.items[replCandidate].dist)))
1342 then
1343 replCandidate = localPos;
1344 end
1345 end
1346 end
1347 end
1348  
1349 -- select candidate
1350 if ( maxLocalPos < num ) then
1351 replCandidate = maxLocalPos+1;
1352 elseif ( maxLocalPos == num and gatherLocal.items[replCandidate] and dist > gatherLocal.items[replCandidate].dist ) then
1353 replCandidate = 0;
1354 end
1355  
1356 if (replCandidate > 0) then
1357 local setItem = {};
1358 setItem.name = gatherName;
1359 setItem.item = gatherInfo;
1360 setItem.dist = dist;
1361 setItem.deltax = deltaX;
1362 setItem.deltay = deltaY;
1363  
1364 gatherLocal["items"][replCandidate] = setItem;
1365 gatherCount = gatherCount+1;
1366 end
1367 end
1368 end
1369 end
1370 end
1371 -- end
1372 end
1373  
1374 gatherLocal.count = gatherCount;
1375 return gatherLocal;
1376 end
1377  
1378 -- *************************************************************************
1379 -- Coordinates computing related functions
1380  
1381 function isMinimapInCity()
1382 local tempzoom = 0;
1383 local inCity = false;
1384 if (GetCVar("minimapZoom") == GetCVar("minimapInsideZoom")) then
1385 if (GetCVar("minimapInsideZoom")+0 >= 3) then
1386 Minimap:SetZoom(Minimap:GetZoom() - 1);
1387 tempzoom = 1;
1388 else
1389 Minimap:SetZoom(Minimap:GetZoom() + 1);
1390 tempzoom = -1;
1391 end
1392 end
1393 if (GetCVar("minimapInsideZoom")+0 == Minimap:GetZoom()) then inCity = true; end
1394 Minimap:SetZoom(Minimap:GetZoom() + tempzoom);
1395 return inCity;
1396 end
1397  
1398 function Gatherer_AbsCoord(continent, zone, x, y)
1399 if ((continent == 0) or (zone == 0)) then return x, y; end
1400 local r = GatherRegionData[continent][zone];
1401 local absX = x * r.scale + r.xoffset;
1402 local absY = y * r.scale + r.yoffset;
1403 return absX, absY;
1404 end
1405  
1406 function Gatherer_Distance(originX, originY, targetX, targetY)
1407 local dx = (targetX - originX);
1408 local dy = (targetY - originY);
1409 local d = Gatherer_Pythag(dx, dy);
1410 return d, dx, dy;
1411 end
1412  
1413 function Gatherer_Pythag(dx, dy)
1414 local d = math.sqrt(dx*dx + dy*dy); -- (a*a) is usually computationally faster than math.pow(a,2)
1415 if (d == 0) then d = 0.0000000001; end -- to avoid divide by zero errors.
1416 return d;
1417 end
1418  
1419 function Gatherer_GetMapScale(continent, zone, inCity, zoomLevel)
1420 if ((continent == nil) or (zoomLevel == nil)) then return 0,0; end
1421 if ((not GatherRegionData) or
1422 (not GatherRegionData[continent]) or
1423 (not GatherRegionData[continent].scales) or
1424 (not GatherRegionData[continent].scales[zoomLevel]) or
1425 (not GatherRegionData[continent].scales[zoomLevel].xscale) or
1426 (not GatherRegionData[continent].scales[zoomLevel].yscale)) then
1427 return 0,0;
1428 end
1429  
1430 local scaleX = GatherRegionData[continent].scales[zoomLevel].xscale;
1431 local scaleY = GatherRegionData[continent].scales[zoomLevel].yscale;
1432 if (inCity == true) then
1433 local cityScale = GatherRegionData.cityZoom[zoomLevel];
1434 scaleX = scaleX * cityScale;
1435 scaleY = scaleY * cityScale;
1436 end
1437  
1438 return scaleX, scaleY;
1439 end
1440  
1441 function Gatherer_MiniMapPos(deltaX, deltaY, scaleX, scaleY) -- works out the distance on the minimap
1442 local mapX = deltaX * scaleX;
1443 local mapY = deltaY * scaleY;
1444 local mapDist = 0;
1445  
1446 mapDist = Gatherer_Pythag(mapX, mapY);
1447 local mapWidth = Minimap:GetWidth()/2;
1448 local mapHeight = Minimap:GetHeight()/2;
1449 if (Squeenix or (pfUI and pfUI_config["disabled"]["minimap"] ~= "1") or
1450 (simpleMinimap_Skins and simpleMinimap_Skins:GetShape() == "square")) then
1451 if (math.abs(mapX) > mapWidth) then
1452 mapX = (mapWidth)*((mapX<0 and -1) or 1);
1453 end
1454 if (math.abs(mapY) > mapHeight) then
1455 mapY = (mapHeight)*((mapY<0 and -1) or 1);
1456 end
1457 elseif (mapDist >= mapWidth) then
1458 -- Remap it to just inside the minimap, by:converting dx,dy to angle,distance
1459 -- then truncate distance to 58 and convert angle,58 to dx,dy
1460 local flipAxis = 1;
1461 if (mapX == 0) then mapX = 0.0000000001;
1462 elseif (mapX < 0) then flipAxis = -1;
1463 end
1464 local angle = math.atan(mapY / mapX);
1465 mapX = math.cos(angle) * mapWidth * flipAxis;
1466 mapY = math.sin(angle) * mapHeight * flipAxis;
1467 end
1468 return mapX, mapY, mapDist;
1469 end
1470  
1471 -- *************************************************************************
1472 -- Recording related functions
1473  
1474 -- Test: /script arg1="You perform Herb Gathering on Mageroyal."; Gatherer_ReadBuff("event");
1475 function Gatherer_ReadBuff(event, fishItem, fishTooltip)
1476 local record = false;
1477 local gather, chatline;
1478 local gatherType, gatherIcon, gatherCanonicalName;
1479 local gatherEventType = 0;
1480 if (not arg1 and not event == "SPELLCAST_STOP") then
1481 Gatherer_Print("Gatherer: error, no arg recording aborted.");
1482 Gatherer_RecordFlag = 0;
1483 return;
1484 elseif (arg1) then
1485 chatline = string.gsub(arg1, GATHERER_NOTEXT, "");
1486 end
1487  
1488 if ( strfind(event, "CHAT_MSG_LOOT") ) then
1489 -- process loot received message for fishing node recording
1490 gather = Gatherer_FindFishType(fishItem, fishTooltip);
1491 if ( gather ) then
1492 gatherIcon = gather;
1493 gatherType = 0; -- considered as treasure
1494 gatherEventType = 2;
1495 record = true;
1496 end
1497 elseif( strfind(event, "CHAT_MSG") or strfind(event, "CHAT_MSG_SPELL_SELF_BUFF")) then
1498 if (string.find(chatline, HERB_GATHER_STRING)) then
1499 record = true;
1500 gather = string.lower(strsub(chatline, HERB_GATHER_LENGTH, HERB_GATHER_END))
1501 gatherType = 1;
1502 gatherIcon = gather;
1503 elseif (string.find(chatline, ORE_GATHER_STRING)) then
1504 record = true;
1505 gather = string.lower(strsub(chatline, ORE_GATHER_LENGTH, ORE_GATHER_END))
1506 gatherType = 2;
1507 gatherIcon = Gatherer_FindOreType(gather);
1508 if (not gatherIcon) then return; end;
1509 elseif (string.find(chatline, TREASURE_GATHER_STRING)) then
1510 record = true;
1511 gather = string.lower(strsub(chatline, TREASURE_GATHER_LENGTH, TREASURE_GATHER_END));
1512  
1513 gatherType = 0;
1514 gatherIcon, gatherCanonicalName = Gatherer_FindTreasureType(gather);
1515 if (not gatherIcon) then return; end;
1516 if ( gatherCanonicalName ) then gather = gatherCanonicalName; end;
1517 end
1518  
1519 elseif (strfind(event, "UI_ERROR_MESSAGE") or (strfind(event, "SPELLCAST_STOP") and Gatherer_RecordFlag == 1)) then
1520 -- process event to record, normally not possible gather (low/inexistant skill)
1521 gather = string.lower(Gatherer_ExtractItemFromTooltip());
1522 if ( Gatherer_currentNode and Gatherer_currentNode ~= gather and event == "SPELLCAST_STOP" and Gatherer_RecordFlag == 1) then
1523 gather = string.lower(Gatherer_currentNode);
1524 end;
1525 if (not arg1 and Gatherer_currentAction==nil and event == "SPELLCAST_STOP" and Gatherer_RecordFlag == 1) then
1526 chatline="";
1527 elseif (event ~= "UI_ERROR_MESSAGE" ) then
1528 chatline = Gatherer_currentAction;
1529 end
1530 -- process non gatherable item because of low/lack of skill
1531 if( gather and not gather ~= "" and (strfind(chatline, TRADE_HERBALISM) or strfind(chatline, OLD_TRADE_HERBALISM) or strfind(chatline, GATHER_HERBALISM)) ) then -- Herb
1532 Gatherer_Debug("record Herb");
1533 record = true;
1534 gatherType = 1;
1535 gatherIcon = Gatherer_FindHerbType(gather);
1536 gatherEventType = 1;
1537 elseif (gather and not gather ~= "" and strfind(chatline, TRADE_MINING)) then -- Ore
1538 Gatherer_Debug("record Ore");
1539 record = true;
1540 gatherType = 2;
1541 gatherIcon = Gatherer_FindOreType(gather);
1542 gatherEventType = 1;
1543 elseif(gather and not gather ~= "" and (strfind(chatline, TRADE_OPENING) or chatline=="")) then -- Treasure
1544 Gatherer_Debug("record Treasure");
1545 record = true
1546 gatherType = 0;
1547 gatherIcon, gatherCanonicalName = Gatherer_FindTreasureType(gather);
1548 if ( gatherCanonicalName ) then gather = gatherCanonicalName; end;
1549 gatherEventType = 1;
1550 end
1551 if (not gatherIcon) then
1552 Gatherer_Print("Gatherer: no icon identified, aborting record.");
1553 Gatherer_RecordFlag = 0;
1554 return;
1555 end
1556 if (event == "SPELLCAST_STOP" and Gatherer_RecordFlag == 1) then
1557 gatherEventType = 0;
1558 end
1559 Gatherer_RecordFlag = 0;
1560 else
1561 Gatherer_RecordFlag = 0;
1562 return;
1563 end
1564  
1565 if (record == true) then
1566 Gatherer_Debug("record type: "..gatherEventType);
1567 Gatherer_AddGatherHere(gather, gatherType, gatherIcon, gatherEventType);
1568 end
1569 end
1570  
1571  
1572 local function insertionGatherIndex(gatherList, maxCheckDist, gatherX, gatherY)
1573 -- type: (GatherList, float, float, float) -> Tuple(int, bool, float, float)
1574 -- gatherList - list of the same gather
1575 -- maxCheckDist - two nodes closer than this distance are considered the same node
1576 -- returns: index to insert new gather, whether new node was found, corrected gathering coordinates
1577 local resultIndex = 0;
1578 local lastGather = 0;
1579 local firstNumerationGap = 0;
1580 local count = 0;
1581 local closest = 0;
1582 local newNodeFound = true;
1583  
1584 for gatherIndex, gatherData in gatherList do
1585 count = count + 1;
1586 if ( firstNumerationGap == 0 and gatherIndex ~= count ) then
1587 firstNumerationGap = count;
1588 end
1589 local dist, deltaX, deltaY = Gatherer_Distance(gatherX,gatherY, gatherData.x,gatherData.y);
1590 if ((dist < maxCheckDist) and ((closest == 0) or (closest > dist))) then -- same gather
1591 gatherX = (gatherX + gatherData.x) / 2;
1592 gatherY = (gatherY + gatherData.y) / 2;
1593 closest = dist;
1594 resultIndex = gatherIndex;
1595 newNodeFound = false;
1596 end
1597 if (gatherIndex > lastGather) then
1598 lastGather = gatherIndex;
1599 end
1600 end
1601  
1602 local thereIsNumerationGap = firstNumerationGap ~= 0;
1603 if (newNodeFound) then
1604 -- need to create a new one (at gatherIndex+1)
1605 resultIndex = lastGather+1;
1606 -- no duplicate but there's a hole, let's fill it
1607 if thereIsNumerationGap then
1608 resultIndex = firstNumerationGap;
1609 end
1610 end
1611 return resultIndex, newNodeFound, gatherX, gatherY
1612 end
1613  
1614  
1615 function Gatherer_AddGatherToBase(gather, gatherType, gatherC, gatherZ, gatherX, gatherY, iconIndex, gatherEventType, updateCount)
1616 -- type: (GatherName, Gatherer_EGatherType, Continent, Zone, float, float, IconIndex, EGatherEventType, bool) -> bool
1617 -- comparing to the latest official version (2.99.0.0284)
1618 -- this function was brought out into the global space and extended with the updateCount argument.
1619 -- The latter denotes whether the gather count should be incremented.
1620 -- Also it has started to return whether new node was found.
1621 if (not GatherItems[gatherC]) then GatherItems[gatherC] = { }; end
1622 if (not GatherItems[gatherC][gatherZ]) then GatherItems[gatherC][gatherZ] = { }; end
1623 if (not GatherItems[gatherC][gatherZ][gather]) then GatherItems[gatherC][gatherZ][gather] = { }; end
1624  
1625 local maxCheckDist = 0.5;
1626 if ( gatherEventType and gatherEventType == 2 ) then maxCheckDist = 1; end
1627  
1628 local insertionIndex, newNodeFound;
1629 insertionIndex, newNodeFound, gatherX, gatherY = insertionGatherIndex(
1630 GatherItems[gatherC][gatherZ][gather], maxCheckDist, gatherX, gatherY
1631 );
1632  
1633 local countIncrement = 1;
1634 -- when gathered without required skill or received via broacast
1635 if (not updateCount) or (gatherEventType and gatherEventType == 1) then
1636 countIncrement = 0
1637 end
1638  
1639 local newCount;
1640 if (GatherItems[gatherC][gatherZ][gather][insertionIndex] == nil) then
1641 GatherItems[gatherC][gatherZ][gather][insertionIndex] = { };
1642 newCount = countIncrement;
1643 else
1644 newCount = GatherItems[gatherC][gatherZ][gather][insertionIndex].count + countIncrement;
1645 end
1646  
1647 -- Round off those coordinates
1648 gatherX = math.floor(gatherX * 100)/100;
1649 gatherY = math.floor(gatherY * 100)/100;
1650  
1651 assert(type(iconIndex) == 'number')
1652 GatherItems[gatherC][gatherZ][gather][insertionIndex].x = gatherX;
1653 GatherItems[gatherC][gatherZ][gather][insertionIndex].y = gatherY;
1654 GatherItems[gatherC][gatherZ][gather][insertionIndex].gtype = gatherType;
1655 GatherItems[gatherC][gatherZ][gather][insertionIndex].count = newCount;
1656 GatherItems[gatherC][gatherZ][gather][insertionIndex].icon = iconIndex
1657  
1658 return newNodeFound;
1659 end
1660  
1661 -- this function can be used as an interface by other addons to record things
1662 -- in Gatherer's database, though display is still based only on what is defined
1663 -- in Gatherer items and icons tables.
1664 -- Parameters:
1665 -- gather (string): gather name (string printed in chat)
1666 -- gatherType (number): gather type (0 treasure, 1 herbs, 2 ore)
1667 -- gatherIcon (string): matching icon from Gatherer icon table (match gather name)
1668 -- gatherEventType (number): 0 normal gather, 1 gather without required skill, 2 fishing node
1669 function Gatherer_AddGatherHere(gather, gatherType, gatherIcon, gatherEventType)
1670 -- type: (GatherName, EGatherType, IconName, EGatherEventType) -> nil
1671 assert(type(gatherIcon) == 'string')
1672 if ( Gatherer_Settings.filterRecording[gatherType] and not Gatherer_Settings.interested[gatherType][gatherIcon] ) then
1673 return;
1674 end
1675 local px, py = Gatherer_PlayerPos(1);
1676 if (px == 0 and py == 0) then
1677 --Gatherer_Print("Gatherer: Cannot record item position as client is reporting position 0,0");
1678 return;
1679 end
1680 local gatherContinent, gatherZone = Gatherer_GetCurrentZone();
1681 if (gatherContinent == 0 or gatherZone == 0) then
1682 --Gatherer_Print("Gatherer: Cannot record item, invalid continent/zone.");
1683 return;
1684 end
1685 local gatherX = px * 100;
1686 local gatherY = py * 100;
1687  
1688 if (not GatherItems) then
1689 Gatherer_Print("Initializing empty gatherable database");
1690 GatherItems = { };
1691 end
1692  
1693 local iconIndex = Gatherer_GetDB_IconIndex(gatherIcon, gatherType);
1694 if Gatherer_Settings.p2p then
1695 -- Broadcast to guild
1696 Gatherer_BroadcastGather(gather, gatherType, gatherContinent, gatherZone, gatherX, gatherY, iconIndex, gatherEventType)
1697 end
1698  
1699 Gatherer_AddGatherToBase(gather, gatherType, gatherContinent, gatherZone, gatherX, gatherY, iconIndex, gatherEventType, true);
1700 Gatherer_OnUpdate(0,true);
1701 GatherMain_Draw();
1702 end
1703  
1704  
1705 -- *************************************************************************
1706 -- Miscellaneous functions (clearing DB, dumping DB content)
1707 function Gatherer_Clear()
1708 Gatherer_Print("Clearing your gather data");
1709 GatherItems = { };
1710 ClosestList = { };
1711 ClosestSearchGather = "";
1712 Gatherer_OnUpdate(0,true);
1713 GatherMain_Draw();
1714 end
1715  
1716 function Gatherer_Show()
1717 local gatherCont, gatherZone, gatherName, contData, zoneData, nameData, gatherPos, gatherItem;
1718  
1719 for gatherCont, contData in GatherItems do
1720 for gatherZone, zoneData in contData do
1721 for gatherName, nameData in zoneData do
1722 for gatherPos, gatherItem in nameData do
1723 Gatherer_Print(Gatherer_EGatherType[gatherItem.gtype].." "..gatherName.." was found in zone "..gatherCont..":"..gatherZone.." at "..gatherItem.x..","..gatherItem.y.." ("..gatherItem.count.." times)");
1724 end
1725 end
1726 end
1727 end
1728 end
1729  
1730 -- *************************************************************************
1731 -- String display related functions
1732  
1733 function Gatherer_ChatPrint(str)
1734 -- usually DEFAULT_CHAT_FRAME is the default "General" chat window
1735 if ( DEFAULT_CHAT_FRAME ) then
1736 DEFAULT_CHAT_FRAME:AddMessage(str, 1.0, 0.5, 0.25);
1737 end
1738 end
1739  
1740 function Gatherer_Print(str, add)
1741 if ((Gather_LastPrinted) and (str == Gather_LastPrinted)) then
1742 return;
1743 end
1744 Gather_LastPrinted = str;
1745 if (add) then
1746 str = str..": "..add;
1747 end
1748 -- adds a message into the combat log
1749 if(ChatFrame2) then
1750 ChatFrame2:AddMessage(str, 1.0, 1.0, 0.0);
1751 end
1752 end
1753  
1754 function Gatherer_Debug(str, add)
1755 if not ( type(Gatherer_DebugFrame) == "table" and Gatherer_DebugFrame.AddMessage ) then
1756 return;
1757 end
1758 if (add) then
1759 str = str..": "..add;
1760 end
1761 Gatherer_DebugFrame:AddMessage("DEBUG: "..str, 1.0, 1.0, 0.0);
1762 end
1763  
1764 function Gatherer_TitleCase(str)
1765 if (GetLocale() == "frFR") then return str; end
1766 local function ucaseWord(first, rest)
1767 return string.upper(first)..string.lower(rest)
1768 end
1769 return string.gsub(str, "([a-zA-Z])([a-zA-Z']*)", ucaseWord);
1770 end
1771  
1772 function Gatherer_MakeName(frameID)
1773 local tmpClosest = ClosestGathers;
1774 local tmpItemIDtable = { }
1775 local tmpCount = 1;
1776 if ( GATHERER_LOADED ) then
1777 local gatherInfo = tmpClosest.items[frameID];
1778  
1779 tmpItemIDtable[tmpCount] = {};
1780 tmpItemIDtable[tmpCount].name = Gatherer_GetMenuName(gatherInfo.name);
1781 tmpItemIDtable[tmpCount].count = gatherInfo.item.count;
1782 tmpItemIDtable[tmpCount].dist = math.floor(gatherInfo.dist*10000)/10;
1783  
1784 tmpCount = tmpCount + 1;
1785  
1786 for id in tmpClosest.items do
1787 if (id ~= frameID and
1788 (abs(gatherInfo.item.x - tmpClosest.items[id].item.x) <= GATHERER_CLOSESTCHECK or
1789 Gatherer_Round(gatherInfo.item.x * 10) == Gatherer_Round(tmpClosest.items[id].item.x * 10)) and
1790 (abs(gatherInfo.item.y - tmpClosest.items[id].item.y) <= GATHERER_CLOSESTCHECK or
1791 Gatherer_Round(gatherInfo.item.y * 10) == Gatherer_Round(tmpClosest.items[id].item.y * 10))) then
1792 tmpItemIDtable[tmpCount] = {};
1793 tmpItemIDtable[tmpCount].name = Gatherer_GetMenuName(tmpClosest.items[id].name);
1794 tmpItemIDtable[tmpCount].count = tmpClosest.items[id].item.count;
1795 tmpItemIDtable[tmpCount].dist = math.floor(tmpClosest.items[id].dist*10000)/10;
1796  
1797 tmpCount = tmpCount + 1;
1798 end
1799 end
1800 else
1801 tmpItemIDtable[1].name = "Unknown";
1802 tmpItemIDtable[1].count = 0;
1803 tmpItemIDtable[1].dist = 0;
1804 end
1805  
1806 return tmpItemIDtable;
1807 end
1808  
1809 -- *************************************************************************
1810 -- Position/Map related functions
1811  
1812 function Gatherer_LoadZoneData()
1813 local continentData = {GetMapContinents()};
1814 for continentIndex, _ in continentData do
1815 local zoneData = {GetMapZones(continentIndex)};
1816 for zoneIndex, zoneName in zoneData do
1817 GatherZoneData[zoneName] = { [1] = continentIndex, [2] = zoneIndex };
1818 end
1819 end
1820 end
1821  
1822 function Gatherer_GetCurrentZone()
1823 -- type: () -> Tuple[Continent, Zone]
1824 local zoneData = GatherZoneData[GetRealZoneText()];
1825 if ( zoneData ) then
1826 return zoneData[1], zoneData[2];
1827 else
1828 return 0,0;
1829 end
1830 end
1831  
1832 Gatherer_LastZone = {};
1833 function Gatherer_ChangeMap()
1834 local mapContinent = GetCurrentMapContinent();
1835 local mapZone = GetCurrentMapZone();
1836 local minderCurZone = false;
1837  
1838 if ((Gatherer_CloseMap ~= nil) and (Gatherer_CloseMap.continent == Gatherer_LastZone.continent) and (Gatherer_CloseMap.zone == Gatherer_LastZone.zone)) then
1839 minderCurZone = true;
1840 end
1841  
1842 local playerContinent, playerZone = Gatherer_GetCurrentZone();
1843 Gatherer_LastZone = { continent = playerContinent, zone = playerZone };
1844 if ((playerContinent == 0) or (playerZone == 0)) then return false; end
1845 if ((playerContinent == mapContinent) and (playerZone == mapZone)) then return true; end
1846  
1847 if ( GetCurrentMapContinent()>0 and playerZone and playerZone > 0 ) then
1848 if (not WorldMapFrame:IsVisible()) then
1849 SetMapZoom(playerContinent, playerZone);
1850 end
1851 end
1852 local lastTime = 0;
1853 if ((Gatherer_CloseMap ~= nil) and (Gatherer_CloseMap.time ~= nil)) then
1854 lastTime = Gatherer_CloseMap.time;
1855 end
1856  
1857 if (minderCurZone) then
1858 Gatherer_MapOpen = false;
1859 Gatherer_CloseMap = { continent = playerContinent, zone = playerZone, time = lastTime };
1860 end
1861  
1862 return true;
1863 end
1864  
1865 function Gatherer_PlayerPos(forced)
1866 local currentZoneName = GetRealZoneText();
1867 if (currentZoneName ~= Gather_LastZone) then
1868 forced = true;
1869 end
1870 Gather_LastZone = currentZoneName;
1871 if (forced) then Gatherer_ChangeMap(); end
1872  
1873 local px, py = GetPlayerMapPosition("player");
1874 if ((px == 0) and (py == 0)) then
1875 if (not forced) then
1876 if (Gatherer_ChangeMap()) then
1877 px, py = GetPlayerMapPosition("player");
1878 else
1879 return 0,0;
1880 end
1881 end
1882 end
1883 return px, py;
1884 end
1885  
1886 -- *************************************************************************
1887 -- Special Item handling functions: Database manipulation from world map.
1888 -- following 2 functions have to take scope into account.
1889 function Gatherer_DeleteItem()
1890 local gathIdx = 0;
1891 local zoneIdx = 0;
1892 local cntIdx = 0;
1893  
1894 if ( GatherMainMapItem.scope == "Node" ) then
1895 GatherItems[GatherMainMapItem.continent][GatherMainMapItem.zoneIndex][GatherMainMapItem.gatherName][GatherMainMapItem.localIndex] = nil;
1896 elseif ( GatherMainMapItem.scope == "Zone" ) then
1897 GatherItems[GatherMainMapItem.continent][GatherMainMapItem.zoneIndex][GatherMainMapItem.gatherName] = nil;
1898 elseif ( GatherMainMapItem.scope == "Continent" ) then
1899 local search_index;
1900 for search_index in GatherItems[GatherMainMapItem.continent] do
1901 if ( GatherItems[GatherMainMapItem.continent][search_index][GatherMainMapItem.gatherName] ) then
1902 GatherItems[GatherMainMapItem.continent][search_index][GatherMainMapItem.gatherName] = nil;
1903 end
1904 end
1905 elseif ( GatherMainMapItem.scope == "World" ) then
1906 local search_index;
1907 -- continent 1
1908 if ( GatherItems[1] ) then
1909 for search_index in GatherItems[1] do
1910 if ( GatherItems[1][search_index][GatherMainMapItem.gatherName] ) then
1911 GatherItems[1][search_index][GatherMainMapItem.gatherName] = nil;
1912 end
1913 end
1914 end
1915 -- continent 2
1916 if ( GatherItems[2] ) then
1917 for search_index in GatherItems[2] do
1918 if ( GatherItems[2][search_index][GatherMainMapItem.gatherName] ) then
1919 GatherItems[2][search_index][GatherMainMapItem.gatherName] = nil;
1920 end
1921 end
1922 end
1923 end
1924 GatherMain_Draw();
1925  
1926 -- clean up for empty zones/continent
1927 for locIdx in GatherItems[GatherMainMapItem.continent][GatherMainMapItem.zoneIndex][GatherMainMapItem.gatherName] do
1928 gathIdx = gathIdx + 1;
1929 end
1930  
1931 if ( gathIdx == 0 ) then
1932 GatherItems[GatherMainMapItem.continent][GatherMainMapItem.zoneIndex][GatherMainMapItem.gatherName] = nil;
1933 for locIdx in GatherItems[GatherMainMapItem.continent][GatherMainMapItem.zoneIndex] do
1934 zoneIdx = zoneIdx + 1;
1935 end
1936  
1937 if ( zoneIdx == 0 ) then
1938 GatherItems[GatherMainMapItem.continent][GatherMainMapItem.zoneIndex] = nil;
1939  
1940 --DEFAULT_CHAT_FRAME:AddMessage("Removed zone no data left")
1941 for locIdx in GatherItems[GatherMainMapItem.continent] do
1942 cntIdx = cntIdx + 1;
1943 end
1944  
1945 if ( cntIdx == 0 ) then
1946 --DEFAULT_CHAT_FRAME:AddMessage("Removed continents no data left")
1947 GatherItems[GatherMainMapItem.continent] = nil;
1948 end
1949 end
1950 end
1951 GatherMain_Draw();
1952 end
1953  
1954 -- Modify Gather Name and/or icon
1955 function Gatherer_ModifyItem()
1956 local newIcon, newGatherName, newType;
1957 local mod_continent = GatherMainMapItem.continent;
1958 local mod_zone = GatherMainMapItem.zoneIndex;
1959 local mod_name = GatherMainMapItem.gatherName;
1960  
1961 -- setting new names (NB: icons on world map are deduced from gather name)
1962 if ( GatherMainMapItem.newIcon and GatherMainMapItem.newIcon ~= GatherMainMapItem.gatherIcon ) then
1963 newIcon = GatherMainMapItem.newIcon;
1964 else
1965 newIcon = GatherMainMapItem.gatherIcon;
1966 end
1967  
1968 if ( GatherMainMapItem.newType and GatherMainMapItem.newType ~= GatherMainMapItem.gatherType ) then
1969 newType = GatherMainMapItem.newType;
1970 else
1971 newType = GatherMainMapItem.gatherType;
1972 end
1973  
1974 if ( GatherMainMapItem.newGatherName ) then
1975 newGatherName = GatherMainMapItem.newGatherName;
1976 else
1977 newGatherName = mod_name;
1978 end
1979 if ( GatherMainMapItem.scope == "Node" ) then
1980 -- remove old entries if gather name different
1981 if ( GatherMainMapItem.newGatherName and mod_name ~= GatherMainMapItem.newGatherName ) then
1982 if ( not GatherItems[mod_continent][mod_zone][newGatherName] ) then
1983 GatherItems[mod_continent][mod_zone][newGatherName] = {};
1984 GatherItems[mod_continent][mod_zone][newGatherName][GatherMainMapItem.localIndex] = GatherItems[mod_continent][mod_zone][mod_name][GatherMainMapItem.localIndex];
1985 GatherItems[mod_continent][mod_zone][mod_name][GatherMainMapItem.localIndex] = nil;
1986 end
1987 end
1988  
1989 -- replace icons if different
1990 GatherItems[mod_continent][mod_zone][newGatherName][GatherMainMapItem.localIndex].icon = newIcon;
1991 GatherItems[mod_continent][mod_zone][newGatherName][GatherMainMapItem.localIndex].gtype = newType;
1992  
1993 elseif ( GatherMainMapItem.scope == "Zone" ) then
1994 -- remove old entries if gather name different
1995 if ( GatherMainMapItem.newGatherName and mod_name ~= GatherMainMapItem.newGatherName ) then
1996 GatherItems[mod_continent][mod_zone][newGatherName] = {};
1997 GatherItems[mod_continent][mod_zone][newGatherName] = GatherItems[mod_continent][mod_zone][mod_name];
1998 GatherItems[mod_continent][mod_zone][mod_name] = nil;
1999 end
2000  
2001 -- replace icons if different
2002 if ( newIcon ~= GatherMainMapItem.gatherIcon ) then
2003 local index;
2004 for index in GatherItems[mod_continent][mod_zone][newGatherName] do
2005 GatherItems[mod_continent][mod_zone][newGatherName][index].icon = newIcon;
2006 end
2007 end
2008  
2009 -- replace type if different
2010 if ( newType ~= GatherMainMapItem.gatherType ) then
2011 local index;
2012 for index in GatherItems[mod_continent][mod_zone][newGatherName] do
2013 GatherItems[mod_continent][mod_zone][newGatherName][index].gtype = newType;
2014 end
2015 end
2016  
2017 elseif ( GatherMainMapItem.scope == "Continent" ) then
2018 local search_index;
2019 for search_index in GatherItems[mod_continent] do
2020 if ( GatherItems[mod_continent][search_index][mod_name] ) then
2021 -- remove old entries if gather name different
2022 if ( GatherMainMapItem.newGatherName and mod_name ~= GatherMainMapItem.newGatherName ) then
2023 GatherItems[mod_continent][search_index][newGatherName] = {};
2024 GatherItems[mod_continent][search_index][newGatherName] = GatherItems[mod_continent][search_index][mod_name];
2025 GatherItems[mod_continent][search_index][mod_name] = nil;
2026 end
2027  
2028 -- replace icons if different
2029 if ( newIcon ~= GatherMainMapItem.gatherIcon ) then
2030 local index;
2031 for index in GatherItems[mod_continent][search_index][newGatherName] do
2032 GatherItems[mod_continent][search_index][newGatherName][index].icon = newIcon;
2033 end
2034 end
2035  
2036 -- replace type if different
2037 if ( newType ~= GatherMainMapItem.gatherType ) then
2038 local index;
2039 for index in GatherItems[mod_continent][search_index][newGatherName] do
2040 GatherItems[mod_continent][search_index][newGatherName][index].gtype = newType;
2041 end
2042 end
2043 end
2044 end
2045  
2046 elseif ( GatherMainMapItem.scope == "World" ) then
2047 local search_index;
2048 -- continent 1
2049 if ( GatherItems[1] ) then
2050 for search_index in GatherItems[1] do
2051 if ( GatherItems[1][search_index][mod_name] ) then
2052 -- remove old entries if gather name different
2053 if ( GatherMainMapItem.newGatherName and mod_name ~= GatherMainMapItem.newGatherName ) then
2054 GatherItems[1][search_index][newGatherName] = {};
2055 GatherItems[1][search_index][newGatherName] = GatherItems[1][search_index][mod_name];
2056 GatherItems[1][search_index][mod_name] = nil;
2057 end
2058  
2059 -- replace icons if different
2060 if ( newIcon ~= GatherMainMapItem.gatherIcon ) then
2061 local index;
2062 for index in GatherItems[1][search_index][newGatherName] do
2063 GatherItems[1][search_index][newGatherName][index].icon = newIcon;
2064 end
2065 end
2066  
2067 -- replace type if different
2068 if ( newType ~= GatherMainMapItem.gatherType ) then
2069 local index;
2070 for index in GatherItems[1][search_index][newGatherName] do
2071 GatherItems[1][search_index][newGatherName][index].gtype = newType;
2072 end
2073 end
2074 end
2075 end
2076 end
2077 -- continent 2
2078 if ( GatherItems[2] ) then
2079 for search_index in GatherItems[2] do
2080 if ( GatherItems[2][search_index][mod_name] ) then
2081 -- remove old entries if gather name different
2082 if ( GatherMainMapItem.newGatherName and mod_name ~= GatherMainMapItem.newGatherName ) then
2083 GatherItems[2][search_index][newGatherName] = {};
2084 GatherItems[2][search_index][newGatherName] = GatherItems[2][search_index][mod_name];
2085 GatherItems[2][search_index][mod_name] = nil;
2086 end
2087  
2088 -- replace icons if different
2089 if ( newIcon ~= GatherMainMapItem.gatherIcon ) then
2090 local index;
2091 for index in GatherItems[2][search_index][newGatherName] do
2092 GatherItems[2][search_index][newGatherName][index].icon = newIcon;
2093 end
2094 end
2095  
2096 -- replace type if different
2097 if ( newType ~= GatherMainMapItem.gatherType ) then
2098 local index;
2099 for index in GatherItems[2][search_index][newGatherName] do
2100 GatherItems[2][search_index][newGatherName][index].gtype = newType;
2101 end
2102 end
2103 end
2104 end
2105 end
2106 end
2107  
2108 GatherMain_Draw();
2109 GatherMainMapItem.newIcon = nil;
2110 GatherMainMapItem.newGatherName = nil;
2111 end
2112  
2113 -- dropdown menus
2114 function Gatherer_WMDropDownGType_Initialize()
2115 local index;
2116 local info = {};
2117 local iconGtype = GatherMainMapItem.gatherType;
2118  
2119 if ( GatherMainMapItem.newType ) then
2120 iconGtype = GatherMainMapItem.newType;
2121 end
2122  
2123 for index, value in Gatherer_EGatherType do
2124 if ( type(value) == "number" and value ~= 3 )
2125 then
2126 info.text = index;
2127 info.value = value;
2128 if ( value == iconGtype ) then
2129 info.checked = 1;
2130 else
2131 info.checked = nil;
2132 end
2133 info.func = Gatherer_WMDropDownGType_OnClick;
2134 UIDropDownMenu_AddButton(info);
2135 end
2136 end
2137  
2138 if ( type(GatherMainMapItem.gatherType) == "number" )
2139 then
2140 UIDropDownMenu_SetText(Gatherer_EGatherType[GatherMainMapItem.gatherType], Gatherer_WMDropDownGType);
2141 else
2142 UIDropDownMenu_SetText(GatherMainMapItem.gatherType, Gatherer_WMDropDownGType);
2143 end
2144 end
2145  
2146 function Gatherer_WMDropDownGType_OnClick()
2147 UIDropDownMenu_SetSelectedID(Gatherer_WMDropDownGType, this:GetID());
2148 GatherMainMapItem.newType = Gatherer_EGatherType[UIDropDownMenu_GetText(Gatherer_WMDropDownGType)];
2149  
2150 UIDropDownMenu_ClearAll(Gatherer_WMDropDownIcons);
2151 UIDropDownMenu_Initialize(Gatherer_WMDropDownIcons, Gatherer_WMDropDownIcons_Initialize);
2152 end
2153  
2154 function Gatherer_WMDropDownIcons_Initialize()
2155 local index;
2156 local info = {};
2157 local iconGtype = "Default";
2158  
2159 if ( GatherMainMapItem.newType ) then
2160 iconGtype = GatherMainMapItem.newType;
2161 else
2162 iconGtype = GatherMainMapItem.gatherType;
2163 end
2164  
2165 for index, value in Gather_DB_IconIndex[iconGtype] do
2166 info.text = index;
2167 info.value = value;
2168 if ( value == GatherMainMapItem.gatherIcon and not GatherMainMapItem.newType) then
2169 info.checked = 1;
2170 else
2171 info.checked = nil;
2172 end
2173 info.func = Gatherer_WMDropDownIcons_OnClick;
2174 UIDropDownMenu_AddButton(info);
2175 end
2176  
2177 UIDropDownMenu_SetText(Gatherer_GetDB_IconIndex(GatherMainMapItem.gatherIcon, iconGtype), Gatherer_WMDropDownIcons);
2178 end
2179  
2180 function Gatherer_WMDropDownIcons_OnClick()
2181 UIDropDownMenu_SetSelectedID(Gatherer_WMDropDownIcons, this:GetID());
2182 GatherMainMapItem.newIcon = Gatherer_GetDB_IconIndex(UIDropDownMenu_GetText(Gatherer_WMDropDownIcons), GatherMainMapItem.gatherType);
2183 end
2184  
2185 function Gatherer_WMDropDownScope_Initialize()
2186 local index;
2187 local scope_list = { "Node", "Zone", "Continent", "World" };
2188 local info = {};
2189  
2190 GatherMainMapItem.scope = "Node";
2191 for index in scope_list do
2192 info.text = scope_list[index];
2193 info.value = index;
2194 if ( scope_list[index] == "Node" ) then
2195 info.checked = 1;
2196 else
2197 info.checked = nil;
2198 end
2199 info.func = Gatherer_WMDropDownScope_OnClick;
2200 UIDropDownMenu_AddButton(info);
2201 end
2202 UIDropDownMenu_SetSelectedID(Gatherer_WMDropDownScope, 1);
2203 end
2204  
2205 function Gatherer_WMDropDownScope_OnClick()
2206 UIDropDownMenu_SetSelectedID(Gatherer_WMDropDownScope, this:GetID());
2207 GatherMainMapItem.scope = UIDropDownMenu_GetText(Gatherer_WMDropDownScope);
2208 end
2209  
2210 -- Toggle item to bugged state
2211 -- this one always ignore scope, only done on origin item.
2212 function Gatherer_ToggleBuggedItem()
2213 Gatherer_ChatPrint("Toggling node to bugged state");
2214 local gtype = GatherItems[GatherMainMapItem.continent][GatherMainMapItem.zoneIndex][GatherMainMapItem.gatherName][GatherMainMapItem.localIndex].gtype;
2215 local icon = GatherItems[GatherMainMapItem.continent][GatherMainMapItem.zoneIndex][GatherMainMapItem.gatherName][GatherMainMapItem.localIndex].icon;
2216  
2217 if ( GatherItems[GatherMainMapItem.continent][GatherMainMapItem.zoneIndex][GatherMainMapItem.gatherName][GatherMainMapItem.localIndex].icon ~= "default" ) then
2218 GatherItems[GatherMainMapItem.continent][GatherMainMapItem.zoneIndex][GatherMainMapItem.gatherName][GatherMainMapItem.localIndex].oldicon = icon;
2219 GatherItems[GatherMainMapItem.continent][GatherMainMapItem.zoneIndex][GatherMainMapItem.gatherName][GatherMainMapItem.localIndex].oldgtype = gtype;
2220  
2221 GatherItems[GatherMainMapItem.continent][GatherMainMapItem.zoneIndex][GatherMainMapItem.gatherName][GatherMainMapItem.localIndex].icon = "default";
2222 GatherItems[GatherMainMapItem.continent][GatherMainMapItem.zoneIndex][GatherMainMapItem.gatherName][GatherMainMapItem.localIndex].gtype = "Default";
2223 else
2224 GatherItems[GatherMainMapItem.continent][GatherMainMapItem.zoneIndex][GatherMainMapItem.gatherName][GatherMainMapItem.localIndex].icon = GatherItems[GatherMainMapItem.continent][GatherMainMapItem.zoneIndex][GatherMainMapItem.gatherName][GatherMainMapItem.localIndex].oldicon;
2225 GatherItems[GatherMainMapItem.continent][GatherMainMapItem.zoneIndex][GatherMainMapItem.gatherName][GatherMainMapItem.localIndex].gtype = GatherItems[GatherMainMapItem.continent][GatherMainMapItem.zoneIndex][GatherMainMapItem.gatherName][GatherMainMapItem.localIndex].oldgtype;
2226  
2227 GatherItems[GatherMainMapItem.continent][GatherMainMapItem.zoneIndex][GatherMainMapItem.gatherName][GatherMainMapItem.localIndex].oldicon = nil;
2228 GatherItems[GatherMainMapItem.continent][GatherMainMapItem.zoneIndex][GatherMainMapItem.gatherName][GatherMainMapItem.localIndex].oldgtype = nil;
2229 end
2230  
2231 GatherMain_Draw();
2232 end
2233