vanilla-wow-addons – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 --[[
2 DamageMeters.lua
3 See the Readme for author and permissions.
4  
5  
6 TODO:
7 FEATURES
8 - Change commands to /dm command args
9 - Help tooltips.
10 - Test matrix cases (falling in party).
11 - Per-character settings.
12 - Individual reports.
13 - Accumulate self data only option?
14 - time monitoring, DPS over total combat time.
15 - How are sessions cleared?
16 - Sort-by-class or class filter or something.
17 - Store min/max.
18  
19 - Sync'ing of events for plugin dmi's.
20 - Make a second plug-in for testing?
21 - Document plug-in system somewhat.
22  
23 - Some way of seeing overheal percentage.
24 - Better tracking of unit health. Maybe actually query target for health? This seems
25 like it would either be a net hit or no more accurate than the messages.
26  
27 - Automatically use CTRA channel if available.
28  
29  
30 KNOWN BUGS
31 - Sometime tooltip doesn't show for the first bar. Making window big and small seems to fix it.
32 ]]--
33  
34 -------------------------------------------------------------------------------
35  
36 -- Plugin stuff --
37 DamageMeters_PLUGINS = {};
38  
39 -- CONSTANTS ---
40 DamageMeters_BARCOUNT_MAX = 40; -- Note this is also the table max size atm.
41 DamageMeters_DEFAULTBARWIDTH = 119;
42 DamageMeters_BARHEIGHT = 12;
43 DamageMeters_PULSE_TIME = 1.00;
44 -- This number represents the version number where the saved data format
45 -- was last changed. Every time the data stored in the tables are changed
46 -- this number needs to be changed so the mod knows not to load in obsolete
47 -- data.
48 DamageMeters_VERSION = 5110;
49 DamageMeters_VERSIONSTRING = "5.1.1";
50 DamageMeters_SYNCMSGCOLOR = { r = 0.35, g = 1.00, b = 0.75 };
51 DamageMeters_RPSCOLOR = { r = 0.00, g = 1.00, b = 1.00 };
52 DamageMeters_SYNCEMOTECOLOR = { r = 1.00, g = 0.60, b = 0.00 };
53 DM_COMBAT_TIMEOUT_SECONDS = 5.0;
54  
55 DamageMeters_Sort_DECREASING = 1;
56 DamageMeters_Sort_INCREASING = 2;
57 DamageMeters_Sort_ALPHABETICAL = 3;
58 DamageMeters_Sort_MAX = 3;
59  
60 DamageMeters_Text_RANK = 1;
61 DamageMeters_Text_NAME = 2;
62 DamageMeters_Text_TOTALPERCENTAGE = 3;
63 DamageMeters_Text_LEADERPERCENTAGE = 4;
64 DamageMeters_Text_VALUE = 5;
65 DamageMeters_Text_DELTA = 6;
66 DamageMeters_Text_MAX = 6;
67  
68 DamageMeters_EventData_NONE = 1;
69 DamageMeters_EventData_SELF = 2;
70 DamageMeters_EventData_ALL = 3;
71  
72 DamageMeters_colorScheme_RELATIONSHIP = 1;
73 DamageMeters_colorScheme_CLASS = 2;
74 DamageMeters_colorScheme_MAX = 2;
75  
76 DM_Pause_Not = 0;
77 DM_Pause_Paused = 1;
78 DM_Pause_Ready = 2;
79  
80 DMSYNC_PREFIX = "SYNC_12_";
81 DMSYNC_EVENT_PREFIX = "SYNCE_12_";
82 DamageMeters_SYNCREQUEST = "REQ_SYNC_12_";
83 DamageMeters_SYNCSTART = "SYNC_START_12_";
84 DamageMeters_SYNCCLEARREQUEST = "REQ_CLEAR_12_";
85 DamageMeters_SYNCCLEARACK = "REQ_CLEARACK_12_";
86 DamageMeters_SYNCPAUSEREQ = "SYNC_PAUSE_12_";
87 DamageMeters_SYNCUNPAUSEREQ = "SYNC_UNPAUSE_12_";
88 DamageMeters_SYNCREADYREQ = "SYNC_READY_12_";
89 DamageMeters_SYNCEND = "SYNC_END_12_";
90 --DamageMeters_SYNCBOSSSTART = "SYNC_BOSS_12_"
91 --DamageMeters_SYNCBOSSEND = "SYNC_BOSSEND_12_"
92  
93 DamageMeters_SYNC_ID = "DamageMeters";
94  
95 -- These are maintenance or informational functions, can be on a different version safely with
96 -- the real sync functions.
97 DamageMeters_SYNCMSG = "SYNC_MSG_6_";
98 DamageMeters_SYNCPING = "SYNC_PING_6_"
99 DamageMeters_SYNCPINGREQ = "SYNC_PINGREQ_6_";
100 DamageMeters_SYNCEMOTE = "SYNC_EMOTE_6_";
101 --DamageMeters_SYNCKICK = "SYNC_KICK_6_";
102 DamageMeters_SYNCJOINED = "SYNC_JOINED_7_";
103 DamageMeters_SYNCSESSIONMISMATCH = "SYNC_SESSIONMISMATCH_6_";
104 DamageMeters_SYNCHALT = "SYNC_HALT_6_";
105 DamageMeters_SYNCRPS = "SYNC_RPS_1_";
106 DamageMeters_SYNCRPSRESPONSE = "SYNC_RPSR_1_";
107 DamageMeters_SYNCRPSCOUNTERRESPONSE = "SYNC_RPSCR_1_";
108  
109 DamageMeters_MINSYNCCOOLDOWN = 1.0;
110 DamageMeters_SYNCMSGSENDDELAY = 0.25; -- seconds. increased from 0.05. again from 0.1 (dc'ed a few people).
111 DamageMeters_SYNCMSGPROCESSDELAY = 0.010; -- seconds. increased from 0.005 (slower processing should cause less fps lag)
112 -- 1 / (frame/sec * sec/msg) = msg /frame
113 -- 1 / (5 * 0.15) = 1.333, approx = 1;
114 DamageMeters_MAXSYNCMSGPERFRAME = 1;
115  
116 -- Default quantity color text codes (ex. "cFF..."). Construct at runtime.
117 DamageMeters_quantityColorCodeDefault = {};
118  
119 DamageMeters_TEXTSTATEDURATION = 6.0;
120 DamageMeters_BARFADEINMINTIME = 0.5;
121 DamageMeters_BARFADEINTIME = 0.01;
122 DamageMeters_BARCHARTIME = 0.02;
123 DamageMeters_QUANTITYSHOWDURATION = 6.0;
124  
125 DMVIEW_NORMAL = 1;
126 DMVIEW_MAX = 2;
127 DMVIEW_MIN = 3;
128  
129 DMPROF_PARSEMESSAGE = 1;
130 DMPROF_ADDVALUE = 2;
131 DMPROF_UPDATE = 3;
132 DMPROF_BARS = 4;
133 DMPROF_SORT = 5;
134 DMPROF_COUNT = 5;
135  
136 DMPROF_NAMES = {
137 "Parse",
138 "AddValue",
139 "Update",
140 "Bars",
141 "Sort",
142 };
143  
144 DamageMeters_watchedEventsTable = {
145 "PARTY_MEMBERS_CHANGED",
146 "PLAYER_REGEN_ENABLED",
147 "PLAYER_REGEN_DISABLED",
148 --"CHAT_MSG_CHANNEL_NOTICE",
149  
150 -- Messages to measure how much damage is dealt.
151 "CHAT_MSG_COMBAT_SELF_HITS", -- Melee you do on things.
152 "CHAT_MSG_COMBAT_PET_HITS", -- Melee your pets do.
153 "CHAT_MSG_COMBAT_PARTY_HITS", -- Melee done by part.
154 "CHAT_MSG_COMBAT_FRIENDLYPLAYER_HITS", -- Melee done by friendlies.
155 "CHAT_MSG_SPELL_SELF_DAMAGE", -- Your spells that damage other things.
156 "CHAT_MSG_SPELL_PET_DAMAGE",
157 "CHAT_MSG_SPELL_PARTY_DAMAGE", -- Party member's spell hits.
158 "CHAT_MSG_SPELL_FRIENDLYPLAYER_DAMAGE", -- Spells other people cast on things.
159 "CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE", -- Blah suffers # Arcane damage from #'s/your Spell. Works on self, party, friendly.
160 "CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE",
161 "CHAT_MSG_SPELL_DAMAGESHIELDS_ON_SELF", -- Thorns on self.
162 "CHAT_MSG_SPELL_DAMAGESHIELDS_ON_OTHERS", -- Thorns on others.
163  
164 -- Messages to measure healing done and received.
165 "CHAT_MSG_SPELL_SELF_BUFF",
166 "CHAT_MSG_SPELL_PARTY_BUFF",
167 "CHAT_MSG_SPELL_FRIENDLYPLAYER_BUFF",
168 "CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS",
169 "CHAT_MSG_SPELL_PERIODIC_PARTY_BUFFS",
170 "CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_BUFFS",
171 "CHAT_MSG_SPELL_HOSTILEPLAYER_BUFF",
172 "CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_BUFFS",
173  
174 -- Messages to measure damage taken.
175 "CHAT_MSG_COMBAT_CREATURE_VS_SELF_HITS",
176 --"CHAT_MSG_COMBAT_CREATURE_VS_SELF_MISSES",
177 "CHAT_MSG_COMBAT_CREATURE_VS_PARTY_HITS",
178 --"CHAT_MSG_COMBAT_CREATURE_VS_PARTY_MISSES",
179 "CHAT_MSG_COMBAT_CREATURE_VS_CREATURE_HITS",
180 --"CHAT_MSG_COMBAT_CREATURE_VS_CREATURE_MISSES",
181 "CHAT_MSG_SPELL_CREATURE_VS_SELF_DAMAGE",
182 "CHAT_MSG_SPELL_CREATURE_VS_PARTY_DAMAGE",
183 "CHAT_MSG_SPELL_CREATURE_VS_CREATURE_DAMAGE",
184 "CHAT_MSG_SPELL_PERIODIC_SELF_DAMAGE",
185 "CHAT_MSG_SPELL_PERIODIC_PARTY_DAMAGE",
186 "CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_DAMAGE",
187 -- The HOSTILEPLAYER ones are for dueling and pvp.
188 "CHAT_MSG_COMBAT_HOSTILEPLAYER_HITS",
189 "CHAT_MSG_SPELL_HOSTILEPLAYER_DAMAGE",
190 "CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE",
191  
192 -- For sync stuff.
193 --"CHAT_MSG_CHANNEL",
194 --"CHAT_MSG_RAID",
195 --"CHAT_MSG_PARTY",
196 "CHAT_MSG_ADDON",
197  
198 -- For overhealing.
199 "UNIT_HEALTH",
200 "UNIT_MAXHEALTH",
201 };
202  
203 -- GLOBALS ---
204 DamageMeters_bars = {};
205 DamageMeters_text = {};
206 --DamageMeters_table = {}; -- player, hitCount, critCount, lastTime, relationship, class, damageThisCombat, firstMsg
207 DamageMeters_tables = {};
208 DamageMeters_tableInfo = {}; -- sessionLabel, sessionIndex
209 DamageMeters_tableSortHash = {}; -- DamageMeters_tableSortHash[quantity][rank] = index in DamageMeters_tables[DMT_VISIBLE]
210 DMT_ACTIVE = DM_TABLE_A;
211 DMT_SAVED = DM_TABLE_B;
212 DMT_VISIBLE = DM_TABLE_A;
213 DamageMeters_bannedTable = {};
214 DamageMeters_tooltipBarIndex = nil;
215 DamageMeters_frameNeedsToBeGenerated = true;
216 DamageMeters_clickedBarIndex = nil;
217 DamageMeters_lastSyncTime = 0;
218 DamageMeters_listLocked = false;
219 DamageMeters_startCombatOnNextValue = true;
220 DamageMeters_inCombat = false; -- This doesn't mean the player is in combat, but rather that someone we're monitoring appears to be.
221 DamageMeters_playerInCombat = false; -- This means we are in combat or not.
222 DamageMeters_combatStartTime = 0;
223 DamageMeters_combatEndTime = 0;
224 DamageMeters_reportBuffer = "";
225 DamageMeters_textStateStartTime = 0;
226 DamageMeters_currentQuantStartTime = -1;
227 DamageMeters_firstGeneration = true;
228 DamageMeters_lastEvent = {};
229 DamageMeters_missedMessages = {};
230 --DamageMeters_requestSyncWhenReportDone = false;
231 DamageMeters_lastUpdateTime = -1;
232 DamageMeters_lastSyncMsgTime = 0;
233 DamageMeters_lastSyncIncMsgTime = 0;
234 DamageMeters_syncMsgQueue = {};
235 DamageMeters_syncIncMsgQueue = {};
236 DamageMeters_syncIncMsgSourceQueue = {};
237 DamageMeters_debug_syncTestFactor = 1;
238 DamageMeters_syncStartTime = -1;
239 DamageMeters_sendMsgQueueBar = nil
240 DamageMeters_sendMsgQueueBarText = nil;
241 DamageMeters_processMsgQueueBar = nil;
242 DamageMeters_processMsgQueueBarText = nil;
243 DamageMeters_totals = {0,0,0,0,0,0};
244 DamageMeters_lastProcessQueueTime = -1;
245 DamageMeters_syncEvents = false;
246 DamageMeters_waitingForChainHeal = false;
247 DamageMeters_queuedChainHealCount = 0;
248 DamageMeters_queuedChainHealValue = {};
249 DamageMeters_queuedChainHealCrit = {};
250 DamageMeters_lastEventTime = nil;
251 DamageMeters_lastPlayerPosition = -1;
252 DamageMeters_barStartIndex = -1;
253 DamageMeters_debugTimers = {};
254 DamageMeters_lastDebugTime = -1;
255 DamageMeters_tablesDirty = true;
256 DamageMeters_lastBarUpdateTime = 0;
257 DamageMeters_activeDebugTimer = 0;
258 DamageMeters_currentlyInParty = false;
259 DamageMeters_pluginDMITable = {};
260  
261 -- SETTINGS ---
262 DamageMeters_barCount = 10;
263 DamageMeters_quantity = DamageMeters_Quantity_DAMAGE;
264 DamageMeters_sort = DamageMeters_Sort_DECREASING;
265 DamageMeters_textOptions = {false, true, false, false};
266 DamageMeters_colorScheme = DamageMeters_colorScheme_CLASS;
267 DamageMeters_autoCountLimit = 0;
268 --DamageMeters_syncChannel = "";
269 DamageMeters_loadedDataVersion = 0;
270 DamageMeters_pauseState = DM_Pause_Not;
271 DamageMeters_quantityColor = {};
272 DamageMeters_contributorList = {};
273 DamageMeters_eventDataLevel = DamageMeters_EventData_SELF;
274 DamageMeters_textState = 0;
275 DamageMeters_savedBarCount = 1;
276 DamageMeters_syncEventDataLevel = DamageMeters_EventData_ALL;
277 DamageMeters_quantitiesFilter = {};
278 DamageMeters_viewMode = DMVIEW_NORMAL;
279 DMTIMERMODE = 0;
280 DamageMeters_debugEnabled = false; -- Debug: Enables display of various debug messages.
281 DamageMeters_BARWIDTH = DamageMeters_DEFAULTBARWIDTH;
282  
283 -- Flags. These are stored in a table to reduce the overall number of variables saved.
284 -- The .toc reader seems to only be able to handle lines that are under 1024 characters.
285 -- (Rather, it ignores text after that cutoff.)
286 DamageMeters_flags = {};
287 DMFLAG_showFightAsPS = 1;
288 DMFLAG_justifyTextLeft = 2;
289 DMFLAG_applyFilterToAutoCycle = 3;
290 DMFLAG_applyFilterToManualCycle = 4;
291 DMFLAG_playerAlwaysVisible = 5;
292 DMFLAG_groupDPSMode = 6;
293 DMFLAG_showEventTooltipsFirst = 7;
294 --DMFLAG_onlySyncWithGroup = 8;
295 --DMFLAG_permitAutoSyncChanJoin = 9;
296 DMFLAG_enableDMM = 10;
297 DMFLAG_visibleOnlyInParty = 11;
298 --DMFLAG_autoClearOnChannelJoin = 12;
299 DMFLAG_positionLocked = 13;
300 DMFLAG_isVisible = 14;
301 DMFLAG_groupMembersOnly = 15;
302 DMFLAG_addPetToPlayer = 16;
303 DMFLAG_showTotal = 17;
304 DMFLAG_resizeLeft = 18;
305 DMFLAG_resizeUp = 19;
306 DMFLAG_haveContributors = 20; -- For some reason this list can be non-empty but getn returns zero: thus this variable was added.
307 DMFLAG_cycleVisibleQuantity = 21;
308 DMFLAG_accumulateToMemory = 22;
309 DMFLAG_constantVisualUpdate = 23;
310 DMFLAG_resetWhenCombatStarts = 24;
311 DMFLAG_clearWhenJoinParty = 25;
312 DMFLAG_autoSync = 26;
313  
314 function DamageMeters_SetDefaultOptions()
315 DamageMeters_barCount = 10;
316 DamageMeters_quantity = DamageMeters_Quantity_DAMAGE;
317 DamageMeters_sort = DamageMeters_Sort_DECREASING;
318 DamageMeters_textOptions = {false, true, false, false};
319 DamageMeters_colorScheme = DamageMeters_colorScheme_CLASS;
320 DamageMeters_autoCountLimit = 0;
321 --DamageMeters_syncChannel = "";
322 DamageMeters_debugEnabled = false; -- Debug: Enables display of various debug messages.
323 DamageMeters_loadedDataVersion = 0;
324 DamageMeters_pauseState = DM_Pause_Not;
325 DamageMeters_quantityColor = {};
326 DamageMeters_contributorList = {};
327 DamageMeters_eventDataLevel = DamageMeters_EventData_SELF;
328 DamageMeters_textState = 0;
329 DamageMeters_savedBarCount = 1;
330 DamageMeters_syncEventDataLevel = DamageMeters_EventData_ALL;
331 DamageMeters_quantitiesFilter = {};
332 DamageMeters_viewMode = DMVIEW_NORMAL;
333 DMTIMERMODE = 0;
334 DamageMeters_BARWIDTH = DamageMeters_DEFAULTBARWIDTH;
335  
336 -- Flags
337 DamageMeters_flags = {};
338 DamageMeters_flags[DMFLAG_showFightAsPS] = true;
339 DamageMeters_flags[DMFLAG_justifyTextLeft] = false;
340 DamageMeters_flags[DMFLAG_applyFilterToAutoCycle] = true;
341 DamageMeters_flags[DMFLAG_applyFilterToManualCycle] = false;
342 DamageMeters_flags[DMFLAG_playerAlwaysVisible] = false;
343 DamageMeters_flags[DMFLAG_groupDPSMode] = true;
344 DamageMeters_flags[DMFLAG_showEventTooltipsFirst] = false;
345 --DamageMeters_flags[DMFLAG_onlySyncWithGroup] = true;
346 --DamageMeters_flags[DMFLAG_permitAutoSyncChanJoin] = true;
347 DamageMeters_flags[DMFLAG_enableDMM] = true;
348 DamageMeters_flags[DMFLAG_visibleOnlyInParty] = false;
349 --DamageMeters_flags[DMFLAG_autoClearOnChannelJoin] = true;
350 DamageMeters_flags[DMFLAG_positionLocked] = false;
351 DamageMeters_flags[DMFLAG_isVisible] = true;
352 DamageMeters_flags[DMFLAG_groupMembersOnly] = true;
353 DamageMeters_flags[DMFLAG_addPetToPlayer] = false;
354 DamageMeters_flags[DMFLAG_showTotal] = false;
355 DamageMeters_flags[DMFLAG_resizeLeft] = true;
356 DamageMeters_flags[DMFLAG_resizeUp] = true;
357 DamageMeters_flags[DMFLAG_haveContributors] = false;
358 DamageMeters_flags[DMFLAG_cycleVisibleQuantity] = false;
359 DamageMeters_flags[DMFLAG_accumulateToMemory] = false;
360 DamageMeters_flags[DMFLAG_constantVisualUpdate] = false;
361 DamageMeters_flags[DMFLAG_resetWhenCombatStarts] = false;
362 DamageMeters_flags[DMFLAG_clearWhenJoinParty] = true;
363 DamageMeters_flags[DMFLAG_autoSync] = false;
364  
365 -- Init cyclable quantities.
366 DamageMeters_quantitiesFilter = {};
367 DamageMeters_quantitiesFilter[DamageMeters_Quantity_DAMAGE] = true;
368 DamageMeters_quantitiesFilter[DamageMeters_Quantity_HEALING] = true;
369 DamageMeters_quantitiesFilter[DamageMeters_Quantity_DAMAGED] = true;
370 DamageMeters_quantitiesFilter[DamageMeters_Quantity_HEALINGRECEIVED] = true;
371 DamageMeters_quantitiesFilter[DamageMeters_Quantity_DPS] = true;
372 DamageMeters_quantitiesFilter[DamageMeters_Quantity_HPS] = false;
373 DamageMeters_quantitiesFilter[DamageMeters_Quantity_DTPS] = false;
374 DamageMeters_quantitiesFilter[DamageMeters_Quantity_HTPS] = false;
375 DamageMeters_quantitiesFilter[DamageMeters_Quantity_TIME] = true;
376  
377 --Debug
378 DamageMeters_ResetDebug();
379  
380 -- Initialize color table.
381 DamageMeters_SetDefaultColors();
382  
383 DamageMeters_InitTables();
384 end
385  
386 function DamageMeters_InitTables()
387 -- Init the tables.
388 local tableIndex;
389 for tableIndex = 1, DMT_MAX do
390 DamageMeters_tables[tableIndex] = {};
391 DamageMeters_tableInfo[tableIndex] = {};
392 DamageMeters_tableInfo[tableIndex].sessionLabel = "Default";
393 DamageMeters_tableInfo[tableIndex].sessionIndex = 1;
394 end
395 end
396  
397 -- DEBUG --
398 DamageMeters_msgCounts = {};
399  
400 -- NOTE: Whenever you add/remove a new variable, increase the number in this
401 -- tables name so that it gets reset.
402 DamageMeters_debug4 = {};
403 function DamageMeters_ResetDebug()
404 DamageMeters_debug4 = {};
405 -- Shows all messages.
406 DamageMeters_debug4.showAll = false;
407 DamageMeters_debug4.showParse = false;
408 -- When true, allows you to parse your own sync messages.
409 DamageMeters_debug4.syncSelf = false;
410 DamageMeters_debug4.syncSelfTestMode = false; -- Adds "x" to the end of player names for self-sync testing.
411 DamageMeters_debug4.showValueChanges = false;
412 -- When true, each incoming message becomes instead a 1 point of damage message
413 -- caused by a player by the name of the message.
414 DamageMeters_debug4.msgWatchMode = false;
415 DamageMeters_debug4.showSyncChanges = false;
416 DamageMeters_debug4.showSyncQueueInfo = false;
417 DamageMeters_debug4.showHealthChanges = false;
418 DamageMeters_debug4.showGCInfo = false;
419 end
420  
421  
422 -------------------------------------------------------------------------------
423  
424 function DMPrint(msg, color, bSecondChatWindow)
425 local r = 0.50;
426 local g = 0.50;
427 local b = 1.00;
428  
429 if (color) then
430 r = color.r;
431 g = color.g;
432 b = color.b;
433 end
434  
435 local frame = DEFAULT_CHAT_FRAME;
436 if (bSecondChatWindow) then
437 frame = ChatFrame2;
438 end
439  
440 if (frame) then
441 frame:AddMessage(msg,r,g,b);
442 end
443 end
444  
445 function DM_DUMP()
446 local table = DamageMeters_tables[DMT_ACTIVE];
447 DM_DUMP_RECURSIVE(table, "[root]", "");
448 end
449  
450 -- stolen from sky (assertEquals)
451 function DMASSERTEQUALS(expected, actual)
452 if actual ~= expected then
453 local function wrapValue( v )
454 if type(v) == 'string' then return "'"..v.."'" end
455 return tostring(v)
456 end
457 errorMsg = "expected: "..wrapValue(expected)..", actual: "..wrapValue(actual)
458 DMPrintD( errorMsg, 2 )
459 end
460 end
461 function DMASSERTNOTEQUALS(expected, actual)
462 if actual == expected then
463 local function wrapValue( v )
464 if type(v) == 'string' then return "'"..v.."'" end
465 return tostring(v)
466 end
467 errorMsg = "not expected: "..wrapValue(expected)..", actual: "..wrapValue(actual)
468 DMPrintD( errorMsg, 2 )
469 end
470 end
471  
472 function DMPrintD(msg, color, bSecondChatWindow)
473 if (DamageMeters_debugEnabled) then
474 --SendChatMessage(msg, "CHANNEL", nil, GetChannelName("dmdebug"));
475 DMPrint(msg, color, bSecondChatWindow);
476 end
477 end
478  
479 function DMVerbose(msg)
480 --DMPrint(msg);
481 end
482  
483 -------------------------------------------------------------------------------
484  
485 function DamageMetersFrame_OnLoad()
486 -- Initialize debug timers.
487 for timer = 1, DMPROF_COUNT do
488 DamageMeters_debugTimers[timer] = {};
489 DamageMeters_debugTimers[timer].time = 0;
490 DamageMeters_debugTimers[timer].count = 0;
491 DamageMeters_debugTimers[timer].peak = 0;
492 end
493  
494 -- Define DamageMeters_Quantity_MAX.
495 -- ALL QUANTITIES MUST BE DEFINED BEFORE THIS POINT.
496 DamageMeters_Quantity_MAX = table.getn(DM_QUANTDEFS);
497 DMPrintD("DamageMeters_Quantity_MAX = "..DamageMeters_Quantity_MAX);
498  
499 -- Inititalize quantity color codes.
500 for quant = 1, DamageMeters_Quantity_MAX do
501 local color = DM_QUANTDEFS[quant].defaultColor;
502 local code = string.format("|cFF%02X%02X%02X",
503 floor(color[1] * 255.0),
504 floor(color[2] * 255.0),
505 floor(color[3] * 255.0));
506 DamageMeters_quantityColorCodeDefault[quant] = code;
507 end
508  
509 -- Set default options. Variable loading from SavedVars happens after OnLoad.
510 DamageMeters_SetDefaultOptions();
511  
512 if (not DamageMetersFrame:IsUserPlaced()) then
513 DMPrintD("Not user placed: resetting pos.");
514 DamageMeters_ResetPos();
515 end
516  
517 -- Build arrays for easy reference of Bars and BarText, and initialize those elements.
518 local name = this:GetName();
519 local i;
520 for i = 1,DamageMeters_BARCOUNT_MAX do
521 DamageMeters_bars[i] = getglobal(name.."Bar"..i);
522 DamageMeters_bars[i]:SetID(i);
523 DamageMeters_bars[i]:Hide();
524 DamageMeters_text[i] = getglobal(name.."Text"..i);
525 SetTextStatusBarText(DamageMeters_bars[i], DamageMeters_text[i]);
526 -- Force text on always.
527 ShowTextStatusBarText(DamageMeters_bars[i]);
528 end
529  
530 -- Initialize the sync bars.
531 DamageMeters_sendMsgQueueBar = getglobal("DamageMetersFrame_SendMsgQueueBar");
532 DamageMeters_sendMsgQueueBarText = getglobal("DamageMetersFrame_SendMsgQueueBarText");
533 SetTextStatusBarText(DamageMeters_sendMsgQueueBar, DamageMeters_sendMsgQueueBarText);
534 DamageMeters_sendMsgQueueBar:SetMinMaxValues(0, 100);
535 DamageMeters_sendMsgQueueBar:SetValue(100);
536 DamageMeters_sendMsgQueueBar:SetStatusBarColor(1.00, 0.0, 0.00);
537 -- Force text on always.
538 ShowTextStatusBarText(DamageMeters_sendMsgQueueBar);
539 DamageMeters_sendMsgQueueBarText:SetPoint("CENTER", DamageMeters_sendMsgQueueBar:GetName(), "CENTER", 0, 0);
540 DamageMeters_sendMsgQueueBarText:SetText("");
541 DamageMeters_sendMsgQueueBar:Hide();
542  
543 DamageMeters_processMsgQueueBar = getglobal("DamageMetersFrame_ProcessMsgQueueBar");
544 DamageMeters_processMsgQueueBarText = getglobal("DamageMetersFrame_ProcessMsgQueueBarText");
545 SetTextStatusBarText(DamageMeters_processMsgQueueBar, DamageMeters_processMsgQueueBarText);
546 DamageMeters_processMsgQueueBar:SetMinMaxValues(0, 250);
547 DamageMeters_processMsgQueueBar:SetValue(0);
548 DamageMeters_processMsgQueueBar:SetStatusBarColor(1.00, 0.0, 0.00);
549 -- Force text on always.
550 ShowTextStatusBarText(DamageMeters_processMsgQueueBar);
551 DamageMeters_processMsgQueueBarText:SetPoint("CENTER", DamageMeters_processMsgQueueBar:GetName(), "CENTER", 0, 0);
552 DamageMeters_processMsgQueueBarText:SetText("");
553 DamageMeters_processMsgQueueBar:Hide();
554  
555 this:RegisterEvent("VARIABLES_LOADED");
556 -- Register these events, which will then cause us to register/unregister the rest.
557 this:RegisterEvent("PLAYER_ENTERING_WORLD");
558 this:RegisterEvent("PLAYER_LEAVING_WORLD");
559  
560 -- Console commands.
561 SlashCmdList["DAMAGEMETERSHELP"] = DamageMeters_Help;
562 SLASH_DAMAGEMETERSHELP1 = "/dmhelp";
563 SlashCmdList["DAMAGEMETERSCMD"] = DamageMeters_ListCommands;
564 SLASH_DAMAGEMETERSCMD1 = "/dmcmd";
565 SlashCmdList["DAMAGEMETERSSHOW"] = DamageMeters_ToggleShow;
566 SLASH_DAMAGEMETERSSHOW1 = "/dmshow";
567 SlashCmdList["DAMAGEMETERSHIDE"] = DamageMeters_Hide;
568 SLASH_DAMAGEMETERSHIDE1 = "/dmhide";
569 SlashCmdList["DAMAGEMETERSCLEAR"] = DamageMeters_Clear;
570 SLASH_DAMAGEMETERSCLEAR1 = "/dmclear";
571 SlashCmdList["DAMAGEMETERSREPORT"] = DamageMeters_Report;
572 SLASH_DAMAGEMETERSREPORT1 = "/dmreport";
573 SlashCmdList["DAMAGEMETERSSORT"] = DamageMeters_SetSort;
574 SLASH_DAMAGEMETERSSORT1 = "/dmsort";
575 SlashCmdList["DAMAGEMETERSCOUNT"] = DamageMeters_SetCount;
576 SLASH_DAMAGEMETERSCOUNT1 = "/dmcount";
577 SlashCmdList["DAMAGEMETERSSAVE"] = DamageMeters_Save;
578 SLASH_DAMAGEMETERSSAVE1 = "/dmsave";
579 SlashCmdList["DAMAGEMETERSRESTORE"] = DamageMeters_Restore;
580 SLASH_DAMAGEMETERSRESTORE1 = "/dmrestore";
581 SlashCmdList["DAMAGEMETERSMERGE"] = DamageMeters_Merge;
582 SLASH_DAMAGEMETERSMERGE1 = "/dmmerge";
583 SlashCmdList["DAMAGEMETERSSWAP"] = DamageMeters_Swap;
584 SLASH_DAMAGEMETERSSWAP1 = "/dmswap";
585 SlashCmdList["DAMAGEMETERSMEMCLEAR"] = DamageMeters_MemClear;
586 SLASH_DAMAGEMETERSMEMCLEAR1 = "/dmmemclear";
587 SlashCmdList["DAMAGEMETERSRESETPOS"] = DamageMeters_ResetPos;
588 SLASH_DAMAGEMETERSRESETPOS1 = "/dmresetpos";
589 SlashCmdList["DAMAGEMETERSSHOWTEXT"] = DamageMeters_SetTextOptions;
590 SLASH_DAMAGEMETERSSHOWTEXT1 = "/dmtext";
591 SlashCmdList["DAMAGEMETERSCOLORSCHEME"] = DamageMeters_SetColorScheme;
592 SLASH_DAMAGEMETERSCOLORSCHEME1 = "/dmcolor";
593 SlashCmdList["DAMAGEMETERSQUANTITY"] = DamageMeters_SetQuantity;
594 SLASH_DAMAGEMETERSQUANTITY1 = "/dmquant";
595 SlashCmdList["DAMAGEMETERSVISINPARTY"] = DamageMeters_SetVisibleInParty;
596 SLASH_DAMAGEMETERSVISINPARTY1 = "/dmvisinparty";
597 SlashCmdList["DAMAGEMETERSAUTOCOUNT"] = DamageMeters_SetAutoCount;
598 SLASH_DAMAGEMETERSAUTOCOUNT1 = "/dmautocount";
599 SlashCmdList["DAMAGEMETERSLISTBANNED"] = DamageMeters_ListBanned;
600 SLASH_DAMAGEMETERSLISTBANNED1 = "/dmlistbanned";
601 SlashCmdList["DAMAGEMETERSCLEARBANNED"] = DamageMeters_ClearBanned;
602 SLASH_DAMAGEMETERSCLEARBANNED1 = "/dmclearbanned";
603 SlashCmdList["DAMAGEMETERSSYNC"] = DamageMeters_Sync;
604 SLASH_DAMAGEMETERSSYNC1 = "/dmsync";
605 --SlashCmdList["DAMAGEMETERSSYNCCHAN"] = DamageMeters_SyncChan;
606 --SLASH_DAMAGEMETERSSYNCCHAN1 = "/dmsyncchan";
607 --SlashCmdList["DAMAGEMETERSSYNCLEAVE"] = DamageMeters_SyncLeaveChanCmd;
608 --SLASH_DAMAGEMETERSSYNCLEAVE1 = "/dmsyncleave";
609 SlashCmdList["DAMAGEMETERSSYNCSEND"] = DamageMeters_SyncReport;
610 SLASH_DAMAGEMETERSSYNCSEND1 = "/dmsyncsend";
611 SlashCmdList["DAMAGEMETERSSYNCREQUEST"] = DamageMeters_SyncRequest;
612 SLASH_DAMAGEMETERSSYNCREQUEST1 = "/dmsyncrequest";
613 SlashCmdList["DAMAGEMETERSSYNCCLEAR"] = DamageMeters_SyncClear;
614 SLASH_DAMAGEMETERSSYNCCLEAR1 = "/dmsyncclear";
615 SlashCmdList["DAMAGEMETERSSYNCMSG"] = DamageMeters_SendSyncMsg;
616 SLASH_DAMAGEMETERSSYNCMSG1 = "/dmsyncmsg";
617 SLASH_DAMAGEMETERSSYNCMSG2 = "/dmm";
618 --[[
619 SlashCmdList["DAMAGEMETERSSYNCBROADCASTCHAN"] = DamageMeters_SyncBroadcastChan;
620 SLASH_DAMAGEMETERSSYNCBROADCASTCHAN1 = "/dmsyncbroadcastchan";
621 SLASH_DAMAGEMETERSSYNCBROADCASTCHAN2 = "/dmsyncb";
622 ]]--
623 SlashCmdList["DAMAGEMETERSSYNCPING"] = DamageMeters_SyncPingRequest;
624 SLASH_DAMAGEMETERSSYNCPING1 = "/dmsyncping";
625 SlashCmdList["DAMAGEMETERSSYNCPAUSE"] = DamageMeters_SyncPause;
626 SLASH_DAMAGEMETERSSYNCPAUSE1 = "/dmsyncpause";
627 SlashCmdList["DAMAGEMETERSSYNCUNPAUSE"] = DamageMeters_SyncUnpause;
628 SLASH_DAMAGEMETERSSYNCUNPAUSE1 = "/dmsyncunpause";
629 SlashCmdList["DAMAGEMETERSSYNCREADY"] = DamageMeters_SyncReady;
630 SLASH_DAMAGEMETERSSYNCREADY1 = "/dmsyncready";
631 --SlashCmdList["DAMAGEMETERSSYNCKICK"] = DamageMeters_SyncKick;
632 --SLASH_DAMAGEMETERSSYNCKICK1 = "/dmsynckick";
633 SlashCmdList["DAMAGEMETERSSYNCLABEL"] = DamageMeters_SyncLabel;
634 SLASH_DAMAGEMETERSSYNCLABEL1 = "/dmsynclabel";
635 SlashCmdList["DAMAGEMETERSSYNCSTART"] = DamageMeters_SyncStart;
636 SLASH_DAMAGEMETERSSYNCSTART1 = "/dmsyncstart";
637 SlashCmdList["DAMAGEMETERSSYNCHALT"] = DamageMeters_SyncHalt;
638 SLASH_DAMAGEMETERSSYNCHALT1 = "/dmsynchalt";
639 --SlashCmdList["DAMAGEMETERSSYNCBOSSSTART"] = DamageMeters_SyncBossStart;
640 --SLASH_DAMAGEMETERSSYNCBOSSSTART1 = "/dmsyncbossstart";
641 --SlashCmdList["DAMAGEMETERSSYNCBOSSEND"] = DamageMeters_SyncBossEnd;
642 --SLASH_DAMAGEMETERSSYNCBOSSEND1 = "/dmsyncbossend";
643  
644 -- Undocumented atm.
645 SlashCmdList["DAMAGEMETERSSYNCEMOTE"] = DamageMeters_SyncEmote;
646 SLASH_DAMAGEMETERSSYNCEMOTE1 = "/dme";
647 SlashCmdList["DAMAGEMETERSRPS"] = DamageMeters_RPSChallenge;
648 SLASH_DAMAGEMETERSRPS1 = "/dmrps";
649 SlashCmdList["DAMAGEMETERSRPSR"] = DamageMeters_RPSResponse;
650 SLASH_DAMAGEMETERSRPSR1 = "/dmrpsr";
651  
652 SlashCmdList["DAMAGEMETERSPOPULATE"] = DamageMeters_Populate;
653 SLASH_DAMAGEMETERSPOPULATE1 = "/dmpop";
654 SlashCmdList["DAMAGEMETERSTOGGLELOCK"] = DamageMeters_ToggleLock;
655 SLASH_DAMAGEMETERSTOGGLELOCK1 = "/dmlock";
656 SlashCmdList["DAMAGEMETERSTOGGLEPAUSE"] = DamageMeters_TogglePause;
657 SLASH_DAMAGEMETERSTOGGLEPAUSE1 = "/dmpause";
658 SlashCmdList["DAMAGEMETERSSETREADY"] = DamageMeters_SetReady;
659 SLASH_DAMAGEMETERSSETREADY1 = "/dmready";
660 SlashCmdList["DAMAGEMETERSTOGGLELOCKPOS"] = DamageMeters_ToggleLockPos;
661 SLASH_DAMAGEMETERSTOGGLELOCKPOS1 = "/dmlockpos";
662 SlashCmdList["DAMAGEMETERSTOGGLEGROUPONLY"] = DamageMeters_ToggleGroupMembersOnly;
663 SLASH_DAMAGEMETERSTOGGLEGROUPONLY1 = "/dmgrouponly";
664 SlashCmdList["DAMAGEMETERSTOGGLEADDPETTOPLAYER"] = DamageMeters_ToggleAddPetToPlayer;
665 SLASH_DAMAGEMETERSTOGGLEADDPETTOPLAYER1 = "/dmaddpettoplayer";
666 SlashCmdList["DAMAGEMETERSTOGGLERESETWHENCOMBATSTARTS"] = DamageMeters_ToggleResetWhenCombatStarts;
667 SLASH_DAMAGEMETERSTOGGLERESETWHENCOMBATSTARTS1 = "/dmresetoncombat";
668 SlashCmdList["DAMAGEMETERSVERSION"] = DamageMeters_ShowVersion;
669 SLASH_DAMAGEMETERSVERSION1 = "/dmversion";
670 SLASH_DAMAGEMETERSVERSION2 = "/dmver";
671 SlashCmdList["DAMAGEMETERSTOGGLETOTAL"] = DamageMeters_ToggleTotal;
672 SLASH_DAMAGEMETERSTOGGLETOTAL1 = "/dmtotal";
673 SlashCmdList["DAMAGEMETERSTOGGLESHOWMAX"] = DamageMeters_ToggleMaxBars;
674 SLASH_DAMAGEMETERSTOGGLESHOWMAX1 = "/dmshowmax";
675  
676 -- Commands for testing.
677 -- ["reset"] = "/dmreset - (For Testing) Forces a re-layout of the visual elements.",
678 SlashCmdList["DAMAGEMETERSRESET"] = DamageMeters_Reset;
679 SLASH_DAMAGEMETERSRESET1 = "/dmreset";
680 -- ["test"] = "/dmtest [#] - (For Testing) Adds # test entries to the list. If no number specified, adds one entry for each visible bar.",
681 SlashCmdList["DAMAGEMETERSTEST"] = DamageMeters_Test;
682 SLASH_DAMAGEMETERSTEST1 = "/dmtest";
683 -- ["add"] = "/dmadd name - (For Testing) Simulates player 'name' doing 1 damage.",
684 SlashCmdList["DAMAGEMETERSADD"] = DamageMeters_Add;
685 SLASH_DAMAGEMETERSADD1 = "/dmadd";
686 -- ["dumptable"] = "/dmdumptable - (For Testing) Dumps the entire internal data table."
687 SlashCmdList["DAMAGEMETERSDUMPTABLE"] = DamageMeters_DumpTable;
688 SLASH_DAMAGEMETERSDUMPTABLE1 = "/dmdumptable";
689 SlashCmdList["DAMAGEMETERSDEBUGPRINT"] = DM_ToggleDMPrintD;
690 SLASH_DAMAGEMETERSDEBUGPRINT1 = "/dmdebug";
691 SlashCmdList["DAMAGEMETERSDUMPMSG"] = DM_DumpMsg;
692 SLASH_DAMAGEMETERSDUMPMSG1 = "/dmdumpmsg";
693 SlashCmdList["DAMAGEMETERSCONSOLEPRINT"] = DM_ConsolePrint;
694 SLASH_DAMAGEMETERSCONSOLEPRINT1 = "/dmp";
695 SlashCmdList["DAMAGEMETERSCONSOLEPRINTTABLE"] = DM_ConsolePrintTable;
696 SLASH_DAMAGEMETERSCONSOLEPRINTTABLE1 = "/dmpt";
697  
698 -- Tell the frame to rebuild itself.
699 DamageMeters_UpdateVisibility();
700 DamageMeters_frameNeedsToBeGenerated = true;
701  
702 DamageMeters_lastUpdateTime = GetTime();
703 DamageMeters_lastProcessQueueTime = DamageMeters_lastUpdateTime;
704 DamageMeters_lastEventTime = GetTime();
705  
706 DamageMeters_FixPatterns();
707 end
708  
709 function DamageMeters_RegisterEvents()
710 for index, event in DamageMeters_watchedEventsTable do
711 this:RegisterEvent(event);
712 end
713  
714 -- This is a hack--if the frame is initially hidden the stupid dropdown
715 -- menu doesn't work right and needs to be opened twice to be seen the first
716 -- time.
717 DMReportFrame:Hide();
718 end
719  
720 function DamageMeters_UnregisterEvents()
721 for index, event in DamageMeters_watchedEventsTable do
722 this:UnregisterEvent(event);
723 end
724 end
725  
726 function DamageMeters_DeleteDMIData(dmi, dmiCount)
727 for tableIx, table in DamageMeters_tables do
728 for playerIx, playerStruct in table do
729 local dmiTemp;
730 for dmiTemp = dmi, dmiCount do
731 playerStruct[dmiTemp] = playerStruct[dmiTemp - 1];
732 end
733 end
734 end
735 end
736  
737 -- This function should house code that needs to run after variables have been loaded
738 -- but before the mod starts updating.
739 function DamageMeters_OnLoadComplete()
740  
741 local dmiCount = DMI_MAX;
742 local plugin, savedDMI;
743 for plugin, savedDMI in DamageMeters_pluginDMITable do
744 if (savedDMI > dmiCount) then
745 dmiCount = savedDMI;
746 end
747 end
748  
749 local bPluginsMissing = false;
750  
751 --DMPrintD("DamageMeters_pluginDMITable loaded:");
752 --DM_DUMP_RECURSIVE(DamageMeters_pluginDMITable, "[root]", "");
753  
754 -- go through list of saved plugin data
755 for plugin, savedDMI in DamageMeters_pluginDMITable do
756 -- if no plugin for data
757 if (nil == DamageMeters_PLUGINS[plugin]) then
758 DMPrintD("Clearing saved data for not-loaded plugin "..plugin..", dmi = "..savedDMI);
759  
760 -- delete plugin data
761 DamageMeters_DeleteDMIData(savedDMI, dmiCount);
762 dmiCount = dmiCount - 1;
763  
764 -- renumber saved plugin indexes
765 DamageMeters_pluginDMITable[plugin] = nil;
766 for plugin2, savedDMI2 in DamageMeters_pluginDMITable do
767 DamageMeters_pluginDMITable[plugin2] = savedDMI2 - 1;
768 end
769  
770 bPluginsMissing = true;
771 else
772 DMPrintD("Plugin >"..plugin.."< has saved data and is assigned DMI "..savedDMI);
773  
774 -- save dmi into the plugin table
775 DamageMeters_PLUGINS[plugin].dmi = savedDMI;
776 end
777 end
778  
779 -- go through the list of plugins
780 DamageMeters_pluginDMITable = {};
781 for plugin, pluginStruct in DamageMeters_PLUGINS do
782 -- assign new dmis for any that still dont have any
783 if (pluginStruct.dmi == nil) then
784 dmiCount = dmiCount + 1;
785 pluginStruct.dmi = dmiCount;
786 DMPrintD("Plugin "..plugin.." has no saved data. Was assigned DMI "..dmiCount);
787 end
788  
789 -- build the new DamageMeters_pluginDMITable
790 DamageMeters_pluginDMITable[plugin] = pluginStruct.dmi;
791  
792 -- Inform the plugin of its new dmi.
793 pluginStruct.pfnAssignDMI(pluginStruct.dmi);
794 pluginStruct.quantDefs.dmi = pluginStruct.dmi;
795 end
796  
797 --DMPrintD("DamageMeters_pluginDMITable after load:");
798 --DM_DUMP_RECURSIVE(DamageMeters_pluginDMITable, "[root]", "");
799  
800 DMI_MAX = dmiCount;
801 DMPrintD("DMI_MAX after loading plugins = "..DMI_MAX);
802  
803 --------------
804  
805 -- Clean up other variables that may have depended on missing plugins.
806 if (bPluginsMissing) then
807 if (DamageMeters_quantity > DamageMeters_Quantity_MAX) then
808 DMPrintD("Plugins missing, and fixing out of range DamageMeters_quantity.");
809 DamageMeters_quantity = DamageMeters_Quantity_MAX;
810 else
811 DMPrintD("DamageMeters_quantity within range.");
812 end
813 end
814 end
815  
816 function DamageMeters_InParty()
817 local inParty = false;
818 local p = GetNumPartyMembers();
819 local r = GetNumRaidMembers();
820  
821 if ((p + r) > 0) then
822 inParty = true;
823 end
824  
825 return inParty;
826 end
827  
828 function DamageMeters_UpdateVisibility(userCaused)
829 local inParty = DamageMeters_InParty();
830 if (inParty and not DamageMeters_currentlyInParty) then
831 DMPrintD("DM: Joined party.");
832 if (DamageMeters_flags[DMFLAG_clearWhenJoinParty]) then
833 DamageMeters_Clear()
834 end
835 end
836 DamageMeters_currentlyInParty = inParty;
837  
838 if (DamageMeters_flags[DMFLAG_visibleOnlyInParty]) then
839 if (inParty and not DamageMetersFrame:IsVisible()) then
840 DMPrintD("DMFLAG_visibleOnlyInParty, inParty, and not DamageMetersFrame:IsVisible() - calling _Show()");
841 DamageMeters_Show();
842 elseif (not inParty and DamageMetersFrame:IsVisible()) then
843 DMPrintD("DMFLAG_visibleOnlyInParty, not inParty, and DamageMetersFrame:IsVisible() - calling _Hide()");
844 DamageMeters_Hide();
845 end
846 elseif (userCaused) then
847 if (not DamageMetersFrame:IsVisible()) then
848 DamageMeters_Show();
849 end
850 end
851 end
852  
853 function DamageMeters_UpdateCount()
854 local newCount = DamageMeters_barCount;
855 if (DMVIEW_MAX == DamageMeters_viewMode) then
856 newCount = DamageMeters_BARCOUNT_MAX;
857 elseif (DMVIEW_MIN == DamageMeters_viewMode) then
858 newCount = 1;
859 else
860 if (DamageMeters_autoCountLimit > 0) then
861 newCount = table.getn(DamageMeters_tables[DMT_VISIBLE]);
862 if (newCount > DamageMeters_autoCountLimit) then
863 newCount = DamageMeters_autoCountLimit;
864 elseif (newCount == 0) then
865 newCount = 1;
866 end
867 end
868 end
869  
870 if (newCount ~= DamageMeters_barCount) then
871 DamageMeters_barCount = newCount;
872 DMPrintD("Frame dirty: count changed.");
873 DamageMeters_frameNeedsToBeGenerated = true;
874 end
875 end
876  
877 function DamageMeters_UpdateDebugTimers()
878 local now = GetTime();
879  
880 -- /script DMPrint(GetTime().." - "..DamageMeters_lastDebugTime.." = "..(GetTime() - DamageMeters_lastDebugTime));
881 if (DamageMeters_lastDebugTime < 0) then
882 DamageMeters_lastDebugTime = now;
883  
884 local timer;
885 for timer = 1, DMPROF_COUNT do
886 DamageMeters_debugTimers[timer] = {};
887 DamageMeters_debugTimers[timer].time = 0;
888 DamageMeters_debugTimers[timer].count = 0;
889 DamageMeters_debugTimers[timer].peak = 0;
890 end
891 end
892  
893 local debugTime = now - DamageMeters_lastDebugTime;
894 if (debugTime > 1.0) then
895 DamageMeters_lastDebugTime = now;
896  
897 local timer;
898  
899 if (DamageMeters_debugEnabled) then
900 if (DMTIMERMODE == 1) then
901 local msg = string.format("(%.2f) ", debugTime);
902 for timer = 1, DMPROF_COUNT do
903 msg = msg..string.format("%s=%d(%d) ", DMPROF_NAMES[timer], DamageMeters_debugTimers[timer].time, DamageMeters_debugTimers[timer].count);
904 end
905 DMPrint(msg, nil, true);
906 elseif (DMTIMERMODE == 2) then
907 local msg = "";
908 local uCount = ceil(DamageMeters_debugTimers[DMPROF_UPDATE].time / 10);
909 local pCount = ceil(DamageMeters_debugTimers[DMPROF_PARSEMESSAGE].time / 10);
910 local aCount = ceil(DamageMeters_debugTimers[DMPROF_ADDVALUE].time / 10);
911 local bCount = ceil(DamageMeters_debugTimers[DMPROF_BARS].time / 10);
912 msg = msg.."|cFFFF0000"..string.rep("U", uCount);
913 msg = msg.."|cFF00FF00"..string.rep("P", pCount);
914 msg = msg.."|cFF60FF60"..string.rep("A", aCount);
915 msg = msg.."|cFF0000FF"..string.rep("B", bCount);
916 DMPrint(msg, nil, true);
917 elseif (DMTIMERMODE == 3) then
918 local msPerFrame = 1000 / GetFramerate();
919 local msg = string.format("Frames (%.2f) ", debugTime);
920 for timer = 1, DMPROF_COUNT do
921 msg = msg..string.format("%s=%.2f(%d) ",
922 DMPROF_NAMES[timer],
923 DamageMeters_debugTimers[timer].time / msPerFrame,
924 DamageMeters_debugTimers[timer].count);
925 end
926 DMPrint(msg, nil, true);
927 elseif (DMTIMERMODE == 4) then
928 local totalTime = 0;
929 local msPerFrame = 1000 / GetFramerate();
930 for timer = 1, DMPROF_COUNT do
931 totalTime = totalTime + DamageMeters_debugTimers[timer].time;
932 end
933 local debugMS = floor(debugTime * 1000);
934 local msg = string.format("%.2f Frames @ %.2f FPS | %4d / %4d ms = %.2f%%",
935 totalTime / msPerFrame,
936 GetFramerate(),
937 totalTime,
938 debugMS,
939 100 * totalTime / debugMS);
940 DMPrint(msg, nil, true);
941 end
942 end
943  
944 for timer = 1, DMPROF_COUNT do
945 if (DamageMeters_debugTimers[timer].peak < DamageMeters_debugTimers[timer].time) then
946 DamageMeters_debugTimers[timer].peak = DamageMeters_debugTimers[timer].time;
947 end
948 DamageMeters_debugTimers[timer].time = 0;
949 DamageMeters_debugTimers[timer].count = 0;
950 end
951 end
952 end
953  
954 function DMPEAKINFO()
955 local msg = "";
956 local timer;
957 local total = 0;
958 for timer = 1, DMPROF_COUNT do
959 msg = msg..string.format("%s=%d ", DMPROF_NAMES[timer], DamageMeters_debugTimers[timer].peak);
960 end
961 DMPrint(msg);
962 end
963  
964 -- Call this when the table is dirty to "clean" it.
965 -- Do sorting and such here.
966 function DamageMeters_UpdateTables()
967 if (DM_Bypass["Update Tables"] == true) then
968 return;
969 end
970  
971 --DMPrintD(GetTime()..": Update Tables called.", nil, true);
972  
973 DamageMeters_StartDebugTimer(DMPROF_SORT);
974  
975 -- Determine totals -first-, as some quantities (ie. Dande-Rating) require totals in order to
976 -- calculate their own values.
977 DamageMeters_DetermineTotals();
978  
979 -- Sort
980 DamageMeters_DoSort(DamageMeters_tables[DMT_VISIBLE], DamageMeters_quantity);
981 DamageMeters_tablesDirty = false;
982  
983 -- Determine ranks for Titan display.
984 -- Eventually the rank table could be used to index into the main table, rather than sorting the
985 -- main table itself. Would add some indirection but would keep us from having to shuffle that
986 -- table around. Dunno which way is faster, honestly.
987 DamageMeters_DetermineRanks(DMT_ACTIVE, true);
988  
989 DamageMeters_StopDebugTimer(DMPROF_SORT);
990 end
991  
992 function DamageMetersFrame_OnUpdate()
993 ----------------------
994  
995 if (DM_Bypass["Generate AddValues"] == true) then
996 DamageMeters_StartDebugTimer(DMPROF_PARSEMESSAGE);
997 DamageMeters_AddDamage("CHAT_MSG_COMBAT_SELF_HITS", UnitName("player"), "[Test]", 0, DM_HIT, DamageMeters_Relation_SELF, "[Stress Test]");
998  
999 DamageMeters_StartDebugTimer(DMPROF_PARSEMESSAGE);
1000 DamageMeters_AddHealing("CHAT_MSG_SPELL_SELF_BUFF", UnitName("player"), UnitName("player"), 0, DM_HIT, DamageMeters_Relation_SELF, DamageMeters_Relation_SELF, "[Stress Test]")
1001 end
1002  
1003 if (DM_Bypass["Generate Events"] == true) then
1004 --DamageMeters_ParseMessage("You hit Bob for 0.", "CHAT_MSG_COMBAT_SELF_HITS");
1005 --DamageMeters_ParseMessage("Bob hits you for 0.", "CHAT_MSG_COMBAT_CREATURE_VS_SELF_HITS");
1006  
1007 DamageMeters_ParseMessage("Your TestSpell heals you for 0.", "CHAT_MSG_SPELL_SELF_BUFF");
1008 DamageMeters_ParseMessage("Your TestSpell heals you for 0.", "CHAT_MSG_SPELL_SELF_BUFF");
1009 DamageMeters_ParseMessage("Your TestSpell heals you for 0.", "CHAT_MSG_SPELL_SELF_BUFF");
1010 end
1011  
1012 ----------------------
1013 -- Debug Start
1014 DamageMeters_StartDebugTimer(DMPROF_UPDATE);
1015  
1016 local updateBars = false;
1017  
1018 local currentTime = GetTime();
1019 local elapsed = currentTime - DamageMeters_lastUpdateTime;
1020  
1021 if (DamageMeters_debug4.showGCInfo) then
1022 local gcAmt, gcLimit = gcinfo();
1023  
1024 if (DM_Bypass["Constant Update"] == true) then
1025 DamageMeters_tablesDirty = 1;
1026 end
1027  
1028 local first = false;
1029 if (DM_lastgcAmt == nil) then
1030 DM_lastgcAmt = 0;
1031 DM_gcDelta = 0;
1032 first = true;
1033 end
1034 local delta = max(0, gcAmt - DM_lastgcAmt);
1035 DM_gcDelta = max(DM_gcDelta, delta);
1036 DM_gcDelta = min(DM_gcDelta, 50);
1037 DamageMeters_sendMsgQueueBar:Show();
1038 DamageMeters_sendMsgQueueBar:SetMinMaxValues(0, 50);
1039 DamageMeters_sendMsgQueueBar:SetValue(ceil(DM_gcDelta));
1040 DM_gcDelta = max(0, DM_gcDelta - 0.5);
1041 DM_lastgcAmt = gcAmt;
1042 if (first) then
1043 DM_gcDelta = 0;
1044 end
1045  
1046 DamageMeters_processMsgQueueBar:Show();
1047 DamageMeters_processMsgQueueBar:SetMinMaxValues(0, gcLimit);
1048 DamageMeters_processMsgQueueBar:SetValue(gcAmt);
1049 end
1050  
1051  
1052 -- If we have queued chain heals, process them now.
1053 if (DamageMeters_queuedChainHealCount > 0) then
1054 if (DamageMeters_queuedChainHealCount > 3) then
1055 -- If we have an unreasonable number, nuke them
1056 DamageMeters_queuedChainHealCount = 0;
1057 else
1058 --DMPrintD("Processing queued chain heals, total = "..DamageMeters_queuedChainHealCount);
1059 local activeIndex = DamageMeters_GetPlayerIndex(UnitName("Player"), DMT_ACTIVE);
1060 local fightIndex = DamageMeters_GetPlayerIndex(UnitName("Player"), DMT_FIGHT);
1061 if (not activeIndex or not fightIndex) then
1062 -- If the player has no index, maybe we had a clear happen between the heal being queued
1063 -- and this tick: just clear it.
1064 DamageMeters_queuedChainHealCount = 0;
1065 else
1066 local hitCount = 1;
1067 while (DamageMeters_queuedChainHealCount > 0) do
1068 -- Add events for the additional chain heals, but don't add the values again to
1069 -- the totals. Also, mark the events with a * at the end to tell other bits of
1070 -- code not to count this one.
1071 local spell = "Chain Heal "..hitCount.."*";
1072  
1073 -- index, quantity, spell, amount, crit, relationship
1074 DamageMeters_AddEvent(DMT_ACTIVE,
1075 activeIndex,
1076 DamageMeters_Quantity_HEALING,
1077 spell,
1078 DamageMeters_queuedChainHealValue[DamageMeters_queuedChainHealCount],
1079 DamageMeters_queuedChainHealCrit[DamageMeters_queuedChainHealCount],
1080 DamageMeters_Relation_SELF,
1081 nil );
1082 DamageMeters_AddEvent(DMT_FIGHT,
1083 fightIndex,
1084 DamageMeters_Quantity_HEALING,
1085 spell,
1086 DamageMeters_queuedChainHealValue[DamageMeters_queuedChainHealCount],
1087 DamageMeters_queuedChainHealCrit[DamageMeters_queuedChainHealCount],
1088 DamageMeters_Relation_SELF,
1089 nil );
1090  
1091 DamageMeters_queuedChainHealCount = DamageMeters_queuedChainHealCount - 1;
1092 hitCount = hitCount + 1;
1093 end
1094 end
1095 end
1096  
1097 DamageMeters_waitingForChainHeal = false;
1098 end
1099  
1100 ------------------
1101  
1102 if (DM_Bypass["Update All"] == true) then
1103 return;
1104 end
1105  
1106 -- Update quant cycling.
1107 if (DamageMeters_flags[DMFLAG_cycleVisibleQuantity]) then
1108 if (DamageMeters_textState < 1) then
1109 if (GetTime() - DamageMeters_currentQuantStartTime > DamageMeters_QUANTITYSHOWDURATION) then
1110 DamageMeters_CycleQuant(false, DamageMeters_flags[DMFLAG_applyFilterToAutoCycle]);
1111 DamageMeters_textStateStartTime = GetTime();
1112 updateBars = true;
1113 end
1114 end
1115 end
1116  
1117 -- Update visibility.
1118 DamageMeters_UpdateVisibility();
1119  
1120 -- Update count.
1121 DamageMeters_UpdateCount();
1122  
1123 -- Generate the frame if needed.
1124 local forceSort = false;
1125 if (DamageMeters_frameNeedsToBeGenerated) then
1126 DamageMetersFrame_GenerateFrame();
1127 DamageMeters_tablesDirty = true;
1128 updateBars = true;
1129 forceSort = true;
1130 end
1131  
1132 -- Update Background
1133 -- Determine if we are still in combat.
1134 local updateBackground = false;
1135 if (DamageMeters_inCombat) then
1136 if (DamageMeters_IsQuantityPS(DamageMeters_quantity)) then
1137 updateBackground = true;
1138 end
1139  
1140 -- If the player isn't in combat and we haven't received any messages
1141 -- in a while, automatically end combat.
1142 if (not DamageMeters_playerInCombat and
1143 DamageMeters_combatEndTime - DamageMeters_lastEventTime > DM_COMBAT_TIMEOUT_SECONDS) then
1144 --DMPrintD("Stopping combat due to inactivity.");
1145 DamageMeters_OnCombatEnd();
1146 end
1147 end
1148 if (DM_Pause_Not ~= DamageMeters_pauseState) then
1149 updateBackground = true;
1150 end
1151 if (updateBackground) then
1152 DamageMeters_SetBackgroundColor();
1153 end
1154  
1155 -- Start delayed Sync.
1156 if (DamageMeters_syncStartTime > 0) then
1157 if (currentTime > DamageMeters_syncStartTime) then
1158 DamageMeters_DoSync();
1159 DamageMeters_syncStartTime = -1;
1160 end
1161 end
1162  
1163 -- Update text state.
1164 if (DamageMeters_textState > 0) then
1165 local now = GetTime();
1166 if (now - DamageMeters_textStateStartTime > DamageMeters_TEXTSTATEDURATION) then
1167 local lastState = DamageMeters_textState;
1168 repeat
1169 DamageMeters_textState = DamageMeters_textState + 1;
1170  
1171 if (DamageMeters_textState > DamageMeters_Text_MAX) then
1172 DamageMeters_textState = 1;
1173 if (DamageMeters_flags[DMFLAG_cycleVisibleQuantity]) then
1174 DamageMeters_CycleQuant(false, DamageMeters_flags[DMFLAG_applyFilterToAutoCycle]);
1175 end
1176 end
1177  
1178 -- This is a safety to keep us from looping forever.
1179 if (DamageMeters_textState == lastState) then
1180 -- Unnecessary, just break. Stay with the last state.
1181 --DMPrintD("DamageMeters_textState infinite loop protection activated.");
1182 --DamageMeters_textOptions[DamageMeters_Text_NAME] = true;
1183 --DamageMeters_textState = DamageMeters_Text_NAME;
1184 break;
1185 end
1186 until (DamageMeters_textOptions[DamageMeters_textState])
1187 DamageMeters_textStateStartTime = now;
1188 updateBars = true;
1189 end
1190 end
1191  
1192 DamageMeters_StopDebugTimer(DMPROF_UPDATE);
1193  
1194 ----------------------------------
1195  
1196 local bSecondHasPassedSinceLastBarUpdate = (currentTime - DamageMeters_lastBarUpdateTime > 1.0);
1197  
1198 -- NOTE: DamageMeters_lastBarUpdateTime also means "last sort time". When the hidden frame
1199 -- takes over sorting duties when we are hidden it uses that variable, even though no bars are
1200 -- actually sorted.
1201 if (DamageMeters_flags[DMFLAG_constantVisualUpdate] or bSecondHasPassedSinceLastBarUpdate) then
1202 updateBars = true;
1203 DamageMeters_lastBarUpdateTime = currentTime;
1204 end
1205  
1206 -- Sort the table.
1207 if (forceSort or (DamageMeters_tablesDirty and (DamageMeters_flags[DMFLAG_constantVisualUpdate] or updateBars))) then
1208 DamageMeters_UpdateTables();
1209 end
1210  
1211 ----------------------------------
1212 -- Code which calculates and uses totals.
1213 -- Must come after Sorting, as some quantity's values are calculated from totals.
1214  
1215 -- Calculate totals. These are used by tooltips and reports, and should be
1216 -- calculated every update.
1217 local quantIndex;
1218 local totalValue = 0;
1219 local maxUnitIndex = 0;
1220 local maxUnitValue = 0;
1221 local playerValue = 0;
1222 local playerIndex = DamageMeters_GetPlayerIndex(UnitName("player"));
1223 for quantIndex = 1, DMI_MAX do
1224 DamageMeters_totals[quantIndex] = 0;
1225 end
1226 local dmi = DamageMeters_GetQuantityDMI(DamageMeters_quantity);
1227 local index, playerStruct;
1228 for index, playerStruct in DamageMeters_tables[DMT_VISIBLE] do
1229 local unitValue = DamageMeters_GetQuantityValue(DamageMeters_quantity, DMT_VISIBLE, index);
1230  
1231 if (playerIndex == index) then
1232 playerValue = unitValue;
1233 end
1234  
1235 if (unitValue > maxUnitValue) then
1236 maxUnitIndex = index;
1237 maxUnitValue = unitValue;
1238 end
1239  
1240 totalValue = totalValue + unitValue;
1241  
1242 for dmiIndex = 1, DMI_MAX do
1243 DamageMeters_totals[dmiIndex] = DamageMeters_totals[dmiIndex] + playerStruct.dmiData[dmiIndex].q;
1244 end
1245 end
1246  
1247 -- Total Button
1248 if (DamageMeters_flags[DMFLAG_showTotal]) then
1249 if (DamageMeters_quantity == DamageMeters_Quantity_TIME) then
1250 DamageMeters_TotalButtonText:SetText("-");
1251 elseif (DamageMeters_IsQuantityPS(DamageMeters_quantity)) then
1252 DamageMeters_TotalButtonText:SetText(string.format("T=%.1f", totalValue));
1253 else
1254 DamageMeters_TotalButtonText:SetText(string.format("T=%d", totalValue));
1255 end
1256 end
1257  
1258 -- Tooltip
1259 if (DamageMetersTooltip:IsOwned(this)) then
1260 DamageMeters_SetTooltipText();
1261 end
1262  
1263 ----------------------------------
1264  
1265 if (DM_Bypass["Update Bars"] == true) then
1266 return;
1267 end
1268  
1269 -- Bar updating.
1270 if (updateBars) then
1271 --DMPrintD(string.format("Updating bars. %.3f", currentTime - DamageMeters_lastBarUpdateTime), nil, true);
1272  
1273 DamageMeters_StartDebugTimer(DMPROF_BARS);
1274  
1275 -- Initialize and clear the bars.
1276 local i;
1277 for i = 1,DamageMeters_barCount do
1278 DamageMeters_bars[i]:SetMinMaxValues(0, maxUnitValue);
1279 DamageMeters_bars[i]:SetValue(0);
1280 DamageMeters_text[i]:SetText("");
1281 end
1282  
1283 -- Table index of first bar.
1284 DamageMeters_barStartIndex = 1;
1285 local playerIndex = DamageMeters_GetPlayerIndex(UnitName("Player"), DMT_VISIBLE);
1286 if (DMVIEW_MIN == DamageMeters_viewMode) then
1287 if (not playerIndex) then
1288 if (DMVIEW_MIN == DamageMeters_viewMode) then
1289 -- If we are in miniMode we need the player to be in the table:
1290 -- add her by giving her some dummy data.
1291 DamageMeters_AddValue(UnitName("Player"), 0, DM_DOT, DamageMeters_Relation_SELF, DamageMeters_Quantity_HEALINGRECEIVED, nil);
1292 playerIndex = DamageMeters_GetPlayerIndex(UnitName("Player"), DMT_VISIBLE);
1293 if (not playerIndex) then
1294 -- Could fail if the table was full.
1295 playerIndex = 1;
1296 end
1297 else
1298 playerIndex = 1;
1299 end
1300 end
1301 DamageMeters_barStartIndex = playerIndex;
1302  
1303 if (DamageMeters_lastPlayerPosition ~= DamageMeters_barStartIndex) then
1304 DMPrintD("Frame dirty: Player index changed..");
1305 DamageMeters_frameNeedsToBeGenerated = true;
1306 end
1307 elseif (DMVIEW_MAX ~= DamageMeters_viewMode and DamageMeters_flags[DMFLAG_playerAlwaysVisible] and (playerIndex ~= nil) and DamageMeters_barCount) then
1308 -- /script DMPrint(DamageMeters_flags[DMFLAG_playerAlwaysVisible] and "true" or "false");
1309 --DMPrint("yes", nil, true);
1310 local nonPlayerBars = DamageMeters_barCount - 1; -- 0
1311 local top = ceil(nonPlayerBars / 2); -- 0
1312 local first = playerIndex - top; -- 2
1313 local last = playerIndex + (nonPlayerBars - top); -- 2
1314 local totalBars = table.getn(DamageMeters_tables[DMT_VISIBLE]); -- 2
1315  
1316 if (last > totalBars) then
1317 first = totalBars - DamageMeters_barCount + 1;
1318 end
1319 if (first < 1) then
1320 first = 1;
1321 end
1322 DamageMeters_barStartIndex = first;
1323 end
1324 DamageMeters_lastPlayerPosition = playerIndex;
1325  
1326 --DMPrintD(string.format("setting bars %d to %d", DamageMeters_barStartIndex, table.getn(DamageMeters_tables[DMT_VISIBLE])));
1327  
1328 -- Set bar info.
1329 local barIndex = 1;
1330 local struct;
1331 for i,struct in DamageMeters_tables[DMT_VISIBLE] do
1332 if (i >= DamageMeters_barStartIndex) then
1333 if (barIndex <= DamageMeters_barCount) then
1334 -- Wonky special case for health.
1335 if (DamageMeters_Quantity_HEALTH == DamageMeters_quantity) then
1336 DamageMeters_bars[i]:SetMinMaxValues(0, struct.maxHealth);
1337 end
1338 DamageMetersFrame_SetBarInfo(barIndex, i, totalValue, maxUnitValue, p == maxUnitIndex, playerValue);
1339 barIndex = barIndex + 1;
1340 end
1341 end
1342 end
1343  
1344 DamageMeters_StopDebugTimer(DMPROF_BARS);
1345 end
1346  
1347 DamageMeters_lastUpdateTime = currentTime;
1348  
1349 ----------------------
1350 -- Debug End
1351 DamageMeters_UpdateDebugTimers();
1352 end
1353  
1354 function DamageMetersFrame_GenerateFrame(frame)
1355 if (not frame) then
1356 frame = DamageMetersFrame;
1357 if (not frame) then
1358 return;
1359 end
1360 end
1361  
1362 -- Hide the title button if mini mode.
1363 if (DMVIEW_MIN == DamageMeters_viewMode) then
1364 DamageMetersFrame_TitleButton:Hide();
1365 else
1366 DamageMetersFrame_TitleButton:Show();
1367 end
1368  
1369 -- Show/hide the total button.
1370 if (DamageMeters_flags[DMFLAG_showTotal] and not (DMVIEW_MIN == DamageMeters_viewMode)) then
1371 DamageMetersFrame_TotalButton:Show();
1372 else
1373 DamageMetersFrame_TotalButton:Hide();
1374 end
1375  
1376 -- Hide all bars: update will reshow those that need to be seen.
1377 local i;
1378 for i = 1,DamageMeters_BARCOUNT_MAX do
1379 DamageMeters_bars[i]:Hide();
1380 DamageMeters_bars[i]:SetValue(0);
1381 DamageMeters_text[i]:SetText("");
1382 -- Put all bars under the first bar.
1383 DamageMeters_bars[i]:SetPoint("TOPLEFT", frame:GetName(), "TOPLEFT", 5, -6);
1384 end
1385  
1386 --DMPrint("GenerateFrame : bar count = "..DamageMeters_barCount);
1387  
1388 -- Set the size of the frame.
1389 local rowCount = 0;
1390 local columnCount = 1;
1391 local newWidth = 0;
1392 if (DamageMeters_barCount > (DamageMeters_BARCOUNT_MAX / 2)) then
1393 rowCount = ceil(DamageMeters_barCount / 2);
1394 columnCount = 2;
1395 newWidth = DamageMeters_BARWIDTH * 2 + 10 + 2;
1396 else
1397 columnCount = 1;
1398 rowCount = DamageMeters_barCount;
1399 newWidth = DamageMeters_BARWIDTH + 10;
1400 end
1401 local newHeight = (DamageMeters_BARHEIGHT * rowCount) + 11;
1402  
1403 local oldWidth = frame:GetWidth();
1404 local oldHeight = frame:GetHeight();
1405  
1406 frame:SetWidth( newWidth );
1407 frame:SetHeight( newHeight );
1408  
1409 --if (DamageMeters_debugEnabled) then
1410 -- if (DamageMeters_firstGeneration) then
1411 -- DMPrintD("Initializing position to "..frame:GetLeft()..", "..frame:GetTop());
1412 -- end
1413 --end
1414  
1415 -- Update pos according to resize direction.
1416 if (not DamageMeters_firstGeneration) then
1417 if (DamageMeters_flags[DMFLAG_resizeLeft] or DamageMeters_flags[DMFLAG_resizeUp]) then
1418 --DMPrint("Resizing...");
1419 local xPos = frame:GetLeft();
1420 local yPos = frame:GetTop();
1421  
1422 if (DamageMeters_flags[DMFLAG_resizeLeft]) then
1423 xPos = xPos - (newWidth - oldWidth);
1424 end
1425 if (DamageMeters_flags[DMFLAG_resizeUp]) then
1426 yPos = yPos + (newHeight - oldHeight);
1427 end
1428  
1429 -- Note: anchoring to bottomleft since apparently the GetLeft and GetTop
1430 -- values are relative to that point.
1431 frame:SetPoint("TOPLEFT", "UIParent", "BOTTOMLEFT", xPos, yPos);
1432 end
1433 end
1434  
1435 --DMPrint("DamageMeters: "..rowCount.." rows, "..columnCount.." columns.");
1436  
1437 -- Position the bars.
1438 local name = frame:GetName();
1439 local row;
1440 local column;
1441 for row = 1, rowCount do
1442 for column = 1, columnCount do
1443 --DMPrint("Row = "..row..", column = "..column);
1444 local index = row + (column - 1) * rowCount;
1445 if (index <= DamageMeters_barCount) then
1446 local itemButton = DamageMeters_bars[index];
1447 local itemText = DamageMeters_text[index];
1448  
1449 itemButton:SetWidth(DamageMeters_BARWIDTH);
1450  
1451 local x = 5 + (column - 1) * (DamageMeters_BARWIDTH + 2);
1452 local y = -6 - (row - 1) * DamageMeters_BARHEIGHT;
1453 itemButton:SetPoint("TOPLEFT", name, "TOPLEFT", x, y);
1454  
1455 itemText:SetPoint("CENTER", itemButton:GetName(), "CENTER", 0, 0);
1456 itemText:SetPoint("LEFT", itemButton:GetName(), "LEFT", 0, 0);
1457 itemText:SetPoint("TOP", itemButton:GetName(), "TOP", 0, 0);
1458 itemText:SetPoint("RIGHT", itemButton:GetName(), "RIGHT", 0, 0);
1459 itemText:SetPoint("BOTTOM", itemButton:GetName(), "BOTTOM", 0, 0);
1460  
1461 -- Justify text
1462 if (DMVIEW_MIN == DamageMeters_viewMode or DamageMeters_flags[DMFLAG_justifyTextLeft]) then
1463 itemText:SetJustifyH("LEFT");
1464 else
1465 itemText:SetJustifyH("CENTER");
1466 end
1467 end
1468 end
1469 end
1470  
1471 DamageMeters_SetBackgroundColor();
1472  
1473 DamageMeters_frameNeedsToBeGenerated = false;
1474 DamageMeters_firstGeneration = false;
1475 end
1476  
1477 function DamageMetersFrame_SetBarInfo(barIndex, tableIndex, totalValue, maxValue, isMax, playerValue)
1478 if (DM_Bypass["SetBarInfo All"] == true) then
1479 return;
1480 end
1481  
1482 --DMPrintD("DamageMetersFrame_SetBarInfo, barIndex = "..barIndex..", totalValue = "..totalValue..", maxValue = "..maxValue);
1483  
1484 local red = 0.00;
1485 local green = 0.00;
1486 local blue = 0.00;
1487 local barString = "";
1488  
1489 local tableEntry = DamageMeters_tables[DMT_VISIBLE][tableIndex];
1490 local player = tableEntry.player;
1491 local dmi = DamageMeters_GetQuantityDMI(DamageMeters_quantity);
1492 local age;
1493 if (DamageMeters_Quantity_TIME == DamageMeters_quantity) then
1494 age = GetTime() - tableEntry.lastTime;
1495 elseif (dmi ~= nil) then
1496 age = GetTime() - tableEntry.dmiData[dmi].lastQuantTime;
1497 else
1498 -- This case covers quantities without dmis (and hence no last times).
1499 -- Could put a system in for calculating it, but I doubt we really care.
1500 age = 60;
1501 end
1502  
1503 local relationship = tableEntry.relationship;
1504 if (DMVIEW_MIN == DamageMeters_viewMode) then
1505 local color = DamageMeters_quantityColor[DamageMeters_quantity];
1506 red = color[1];
1507 green = color[2]
1508 blue = color[3];
1509 else
1510 if (DamageMeters_colorScheme == 1) then
1511 if (DamageMeters_Relation_SELF == relationship) then
1512 green = 1.00;
1513 elseif (DamageMeters_Relation_PET == relationship) then
1514 green = 0.80;
1515 elseif (DamageMeters_Relation_PARTY == relationship) then
1516 blue = 1.00;
1517 elseif (DamageMeters_Relation_FRIENDLY == relationship) then
1518 red = 1.00;
1519 green = 0.50;
1520 end
1521 else
1522 local class = tableEntry.class;
1523 if (class) then
1524 local color = DamageMeters_GetClassColor(class);
1525 red = color.r;
1526 green = color.g;
1527 blue = color.b;
1528 elseif (DamageMeters_Relation_PET == relationship) then
1529 red = 0.00;
1530 green = 0.80;
1531 blue = 0.00;
1532 else
1533 red = 0.70;
1534 green = 0.70;
1535 blue = 0.70;
1536 end
1537 end
1538 end
1539  
1540 -- Bar color pulse magnitude.
1541 local pulseMag = 0.00;
1542 if (DamageMeters_flags[DMFLAG_constantVisualUpdate]) then
1543 if (age < DamageMeters_PULSE_TIME) then
1544 pulseMag = 1.00 - age / DamageMeters_PULSE_TIME;
1545 end
1546 end
1547  
1548 -- Calc value
1549 local value;
1550 local dmi = DamageMeters_GetQuantityDMI(DamageMeters_quantity);
1551 if (DamageMeters_quantity == DamageMeters_Quantity_TIME) then
1552 value = age;
1553 else
1554 value = DamageMeters_GetQuantityValue(DamageMeters_quantity, DMT_VISIBLE, tableIndex);
1555 end
1556  
1557  
1558 -- TEXT --
1559 local stateAge = GetTime() - DamageMeters_textStateStartTime;
1560 local barAge = stateAge - (barIndex / DamageMeters_barCount) * (DamageMeters_BARFADEINMINTIME + DamageMeters_BARFADEINTIME * DamageMeters_barCount);
1561  
1562 if ((barAge > 0) or (not DamageMeters_flags[DMFLAG_constantVisualUpdate])) then
1563 -- DamageMeters_Text_MAX many entries.
1564 local rankString = nil;
1565 local nameString = nil;
1566 local totalPercentString = nil;
1567 local leaderPercentString = nil;
1568 local valueString = nil;
1569 local deltaString = nil;
1570  
1571 -- Rank
1572 if (DMVIEW_MIN == DamageMeters_viewMode or
1573 ((DamageMeters_textState > 0 and DamageMeters_textState == DamageMeters_Text_RANK) or
1574 (DamageMeters_textState <= 0 and DamageMeters_textOptions[DamageMeters_Text_RANK]))) then
1575 rankString = tostring(tableIndex);
1576 end
1577  
1578 -- Name
1579 if (not (DMVIEW_MIN == DamageMeters_viewMode)) then
1580 if ((DamageMeters_textState > 0 and DamageMeters_textState == DamageMeters_Text_NAME) or
1581 (DamageMeters_textState <= 0 and DamageMeters_textOptions[DamageMeters_Text_NAME])) then
1582 nameString = player;
1583 end
1584 end
1585  
1586 -- Total Percentage
1587 if (DamageMeters_Quantity_TIME ~= DamageMeters_quantity and totalValue ~= nil and (not DamageMeters_IsQuantityPS(DamageMeters_quantity) or (not DamageMeters_flags[DMFLAG_showFightAsPS]))) then
1588 if ((DamageMeters_textState > 0 and DamageMeters_textState == DamageMeters_Text_TOTALPERCENTAGE) or
1589 (DamageMeters_textState <= 0 and DamageMeters_textOptions[DamageMeters_Text_TOTALPERCENTAGE])) then
1590 local percent = (totalValue > 0) and ((value / totalValue) * 100) or 0;
1591 totalPercentString = string.format("%.2f%%", percent);
1592 end
1593 end
1594  
1595 -- Leader Percentage
1596 if (DamageMeters_Quantity_TIME ~= DamageMeters_quantity and totalValue ~= nil and (not DamageMeters_IsQuantityPS(DamageMeters_quantity) or (not DamageMeters_flags[DMFLAG_showFightAsPS]))) then
1597 if ((DamageMeters_textState > 0 and DamageMeters_textState == DamageMeters_Text_LEADERPERCENTAGE) or
1598 (DamageMeters_textState <= 0 and DamageMeters_textOptions[DamageMeters_Text_LEADERPERCENTAGE])) then
1599 local percent = (maxValue > 0) and ((value / maxValue) * 100) or 0;
1600 leaderPercentString = format("%.2f%%", percent);
1601 end
1602 end
1603  
1604 -- Value
1605 local buildValueString = false;
1606 if (DamageMeters_textState > 0 and DamageMeters_textState == DamageMeters_Text_VALUE) then
1607 buildValueString = true;
1608 elseif (DamageMeters_textState <= 0 and DamageMeters_textOptions[DamageMeters_Text_VALUE]) then
1609 buildValueString = true;
1610 elseif (DamageMeters_textState == 0 and
1611 (DamageMeters_quantity == DamageMeters_Quantity_TIME or DamageMeters_IsQuantityPS(DamageMeters_quantity))) then
1612 buildValueString = true;
1613 end
1614  
1615 -- Delta
1616 if (DamageMeters_Quantity_TIME ~= DamageMeters_quantity and totalValue ~= nil and (not DamageMeters_IsQuantityPS(DamageMeters_quantity) or (not DamageMeters_flags[DMFLAG_showFightAsPS]))) then
1617 if ((DamageMeters_textState > 0 and DamageMeters_textState == DamageMeters_Text_DELTA) or
1618 (DamageMeters_textState <= 0 and DamageMeters_textOptions[DamageMeters_Text_DELTA])) then
1619 local delta = value - playerValue;
1620 deltaString = string.format("%s%d", (delta >= 0 and "+" or ""), delta);
1621 end
1622 end
1623  
1624 if (buildValueString) then
1625 if (DamageMeters_quantity == DamageMeters_Quantity_TIME) then
1626 valueString = string.format("%d:%.2d", value / 60, math.mod(value, 60));
1627 elseif (DamageMeters_IsQuantityPS(DamageMeters_quantity)) then
1628 valueString = string.format("%.1f", value);
1629 else
1630 valueString = tostring(value);
1631 end
1632 end
1633  
1634 -- Concatenate strings.
1635 local strIx;
1636 local first = true;
1637 if (rankString) then
1638 barString = barString..rankString.." ";
1639 end
1640 if (nameString) then
1641 barString = barString..nameString.." ";
1642 end
1643 if (totalPercentString) then
1644 barString = barString..totalPercentString.." ";
1645 end
1646 if (leaderPercentString) then
1647 barString = barString..leaderPercentString.." ";
1648 end
1649 if (valueString) then
1650 barString = barString..valueString.." ";
1651 end
1652 if (deltaString) then
1653 barString = barString..deltaString;
1654 end
1655 if (string.sub(barString, -1) == " ") then
1656 barString = string.sub(barString, 1, -2);
1657 end
1658 end
1659  
1660 if (DamageMeters_flags[DMFLAG_constantVisualUpdate]) then
1661 -- Apply pulse.
1662 if (red == 1.00 and green == 1.00 and blue == 1.00) then
1663 red = 0.5 + 0.5 * (1.0 - pulseMag);
1664 green = red;
1665 blue = red;
1666 else
1667 red = pulseMag > red and pulseMag or red;
1668 green = pulseMag > green and pulseMag or green;
1669 blue = pulseMag > blue and pulseMag or blue;
1670 end
1671 end
1672  
1673 -------
1674  
1675 if (DamageMeters_flags[DMFLAG_constantVisualUpdate]) then
1676 if (barAge > 0) then
1677 local charsToShow = floor(barAge / DamageMeters_BARCHARTIME);
1678 local strLen = string.len(barString);
1679 if (strLen > charsToShow) then
1680 local charsToRemove = strLen - charsToShow;
1681 local leftToRemove, rightToRemove;
1682 if (DMVIEW_MIN == DamageMeters_viewMode) then
1683 leftToRemove = 0;
1684 rightToRemove = charsToRemove;
1685 else
1686 leftToRemove = floor(charsToRemove / 2);
1687 rightToRemove = charsToRemove - leftToRemove;
1688 end
1689  
1690 barString = string.sub(barString, leftToRemove, -rightToRemove);
1691 end
1692 end
1693 end
1694  
1695 if (DMVIEW_MIN == DamageMeters_viewMode) then
1696 local titleText = DamageMeters_GetPausedTitleText();
1697 if (titleText) then
1698 barString = titleText.." "..barString;
1699 end
1700 end
1701  
1702 DamageMeters_bars[barIndex]:Show();
1703 DamageMeters_bars[barIndex]:SetStatusBarColor(red, green, blue);
1704 DamageMeters_bars[barIndex]:SetValue(value);
1705 DamageMeters_text[barIndex]:SetText(barString);
1706 -- After 1300 patch text wouldn't appear without this.
1707 DamageMeters_text[barIndex]:Show();
1708 end
1709  
1710 -------------------------------------------------------------------------------
1711  
1712 function DamageMeters_Clear(leave, silent)
1713 -- Clear contributor list full: on a partical clear it is impossible to
1714 -- tell who contributed what.
1715 DamageMeters_contributorList = {};
1716 DamageMeters_flags[DMFLAG_haveContributors] = false;
1717  
1718 DamageMetersPlugin_Clear();
1719  
1720 DamageMeters_DoClear(DMT_ACTIVE, leave, silent)
1721 DamageMeters_DoClear(DMT_FIGHT, 0, true)
1722 end
1723  
1724 function DamageMeters_DoClear(tableIndex, leave, silent)
1725 --DMPrintD("DamageMeters_DoClear("..tableIndex..")");
1726  
1727 DamageMeters_tablesDirty = true;
1728  
1729 -- In case we get a clear call between ticks.
1730 DamageMeters_queuedChainHealCount = 0;
1731  
1732 local last = table.getn(DamageMeters_tables[tableIndex]);
1733 if (last == 0) then
1734 -- This line just to ensure its really wiped out.
1735 DamageMeters_tables[tableIndex] = {};
1736 return;
1737 end
1738  
1739 local first = 1;
1740 if (leave ~= nil) then
1741 --DMPrint("leave = '"..leave.."'");
1742 local c = tonumber(leave);
1743 if (c) then
1744 first = leave + 1;
1745 if (first < 1) then
1746 first = 1;
1747 end
1748 end
1749 end
1750  
1751 if (not silent) then
1752 DMPrint(format(DM_MSG_CLEAR, first, last));
1753 end
1754  
1755 local i;
1756 for i = last,first,-1 do
1757 if (DamageMeters_flags[DMFLAG_constantVisualUpdate]) then
1758 if (tableIndex == DMT_VISIBLE) then
1759 if (DamageMeters_bars[i]) then
1760 DamageMeters_bars[i]:SetValue(0);
1761 DamageMeters_text[i]:SetText("");
1762 end
1763 end
1764 end
1765  
1766 table.remove(DamageMeters_tables[tableIndex]);
1767 end
1768  
1769 --if (not silent) then
1770 -- DMPrint(format(DM_MSG_REMAINING, table.getn(DamageMeters_tables[DMT_ACTIVE])));
1771 --end
1772 end
1773  
1774  
1775 function DamageMeters_Test(countArg)
1776 DamageMeters_Clear();
1777  
1778 local count = DamageMeters_barCount;
1779 if (countArg) then
1780 count = tonumber(countArg);
1781 if (not count) then
1782 count = DamageMeters_barCount
1783 end
1784  
1785 if (count > DamageMeters_barCount) then
1786 count = DamageMeters_barCount;
1787 end
1788 end
1789  
1790 DamageMeters_lastEvent = {};
1791  
1792 DMPrintD("Adding "..count.." test entries...");
1793 local index;
1794 local groupMembersOnlySave = DamageMeters_flags[DMFLAG_groupMembersOnly];
1795 DamageMeters_flags[DMFLAG_groupMembersOnly] = false;
1796 for index = 1,count do
1797 DamageMeters_AddValue("Test"..index, 1*index, DM_HIT, DamageMeters_Relation_FRIENDLY, DamageMeters_Quantity_DAMAGE, "[Test]");
1798 DamageMeters_AddValue("Test"..index, 2*index, DM_HIT, DamageMeters_Relation_FRIENDLY, DamageMeters_Quantity_HEALING, "[Test]");
1799 DamageMeters_AddValue("Test"..index, 3*(count - index), DM_HIT, DamageMeters_Relation_FRIENDLY, DamageMeters_Quantity_DAMAGED, "[Test]");
1800 DamageMeters_AddValue("Test"..index, 4*(count - index), DM_HIT, DamageMeters_Relation_FRIENDLY, DamageMeters_Quantity_HEALINGRECEIVED, "[Test]");
1801 end
1802 DamageMeters_flags[DMFLAG_groupMembersOnly] = groupMembersOnlySave;
1803 end
1804  
1805 function DamageMeters_Add(player)
1806 if (player) then
1807 DamageMeters_AddDamage(player, 0, DM_HIT, DamageMeters_Relation_FRIENDLY, "[Test]");
1808 end
1809 end
1810  
1811 function DamageMeters_SetSort(sortArg)
1812 local usage = true;
1813 if (sortArg) then
1814 local sort = tonumber(sortArg);
1815 if (sort) then
1816 if (sort >= 1 and sort <= DamageMeters_Sort_MAX) then
1817 DamageMeters_sort = sort;
1818 DamageMeters_tablesDirty = true;
1819 DMPrint(DM_MSG_SORT..DamageMeters_sort);
1820 usage = false;
1821 else
1822 DMPrint(DM_ERROR_INVALIDARG);
1823 end
1824 end
1825 end
1826  
1827 if (usage) then
1828 DMPrint(DM_MSG_CURRENTSORT..DamageMeters_Sort_STRING[DamageMeters_sort]);
1829 local i;
1830 for i=1,DamageMeters_Sort_MAX do
1831 DMPrint(" "..i..": "..DamageMeters_Sort_STRING[i]);
1832 end
1833 end
1834 end
1835  
1836 function DamageMeters_SetQuantity(quantArg, bSilent)
1837 local usage = true;
1838 if (quantArg) then
1839 local quant = tonumber(quantArg);
1840 if (quant) then
1841 if (quant >= 1 and quant <= DamageMeters_Quantity_MAX) then
1842 DamageMeters_quantity = quant;
1843 if (not bSilent) then
1844 DMPrint(DM_MSG_SETQUANT..DM_QUANTDEFS[DamageMeters_quantity].name);
1845 end
1846 usage = false;
1847 else
1848 if (not bSilent) then
1849 DMPrint(DM_ERROR_INVALIDARG);
1850 end
1851 DamageMeters_quantity = 1;
1852 end
1853 end
1854 end
1855  
1856 if (usage) then
1857 DMPrint(DM_MSG_CURRENTQUANT..DM_QUANTDEFS[DamageMeters_quantity].name);
1858 local i;
1859 for i=1,DamageMeters_Quantity_MAX do
1860 DMPrint(" "..i..": "..DM_QUANTDEFS[i].name);
1861 end
1862 end
1863  
1864 DamageMeters_SetBackgroundColor();
1865 --DMPrintD("Frame dirty: quantity changed.");
1866 DamageMeters_frameNeedsToBeGenerated = true;
1867 DamageMeters_currentQuantStartTime = GetTime();
1868  
1869 -- If a Fight quantity, make the visible table the combat table.
1870 if (DamageMeters_IsQuantityFight(DamageMeters_quantity)) then
1871 --DMPrintD("Visible table set to Combat");
1872 DMT_VISIBLE = DMT_FIGHT;
1873 else
1874 --DMPrintD("Visible table set to Active");
1875 DMT_VISIBLE = DMT_ACTIVE;
1876 end
1877 end
1878  
1879 function DamageMeters_SetBackgroundColor()
1880 local frame = DamageMetersFrame;
1881 if (frame) then
1882 local color = DamageMeters_quantityColor[DamageMeters_quantity];
1883 local titleR, titleG, titleB, titleA = DamageMeters_GetTitleButtonColors();
1884  
1885 if (DMVIEW_MIN == DamageMeters_viewMode) then
1886 frame:SetBackdropColor(titleR, titleG, titleB, titleA);
1887 else
1888 frame:SetBackdropColor(color[1], color[2], color[3], color[4]);
1889 end
1890  
1891 -- Set title button text.
1892 local pausedText = DamageMeters_GetPausedTitleText();
1893 if (pausedText) then
1894 DamageMeters_TitleButtonText:SetText(pausedText);
1895 else
1896 if (DamageMeters_IsQuantityPS(DamageMeters_quantity)) then
1897 local title;
1898 local combatTime = DamageMeters_combatEndTime - DamageMeters_combatStartTime;
1899 if (combatTime > 60) then
1900 title = format("%s %d:%.2d", DM_QUANTDEFS[DamageMeters_quantity].psName, combatTime / 60, math.mod(combatTime, 60));
1901 else
1902 title = format("%s %.1fs", DM_QUANTDEFS[DamageMeters_quantity].psName, combatTime);
1903 end
1904 DamageMeters_TitleButtonText:SetText(title);
1905 else
1906 local title = DM_QUANTDEFS[DamageMeters_quantity].name;
1907 DamageMeters_TitleButtonText:SetText(title);
1908 end
1909 end
1910  
1911 -- Set title button color.
1912 DamageMetersFrame_TitleButton:SetBackdropColor(titleR, titleG, titleB, titleA);
1913  
1914 -- Set total button color.
1915 DamageMetersFrame_TotalButton:SetBackdropColor(color[1], color[2], color[3], color[4]);
1916 end
1917 end
1918  
1919 function DamageMeters_GetPausedTitleText()
1920 local time = GetTime();
1921 local showPausedText = false;
1922  
1923 if (DMVIEW_MIN ~= DamageMeters_viewMode) then
1924 if (DM_Pause_Not == DamageMeters_pauseState) then
1925 return nil;
1926 else
1927 local flooredTime = floor(time);
1928 if (math.mod(flooredTime, 4) > 1) then
1929 return nil;
1930 end
1931 end
1932 end
1933  
1934 if (DM_Pause_Paused == DamageMeters_pauseState) then
1935 return DM_MSG_PAUSEDTITLE;
1936 elseif (DM_Pause_Ready == DamageMeters_pauseState) then
1937 return DM_MSG_READYTITLE;
1938 end
1939  
1940 return nil;
1941 end
1942  
1943 function DamageMeters_GetTitleButtonColors()
1944 local color = DamageMeters_quantityColor[DamageMeters_quantity];
1945 if (DM_Pause_Ready == DamageMeters_pauseState) then
1946 local time = GetTime();
1947 local pulseFactor = 1.0 - (time * 0.5 - floor(time * 0.5));
1948 return color[1] * pulseFactor, color[2] * pulseFactor, color[3] * pulseFactor, 1.0;
1949 elseif (DM_Pause_Paused == DamageMeters_pauseState) then
1950 return 0.0, 0.0, 0.0, color[4];
1951 end
1952  
1953 return color[1], color[2], color[3], color[4];
1954 end
1955  
1956 function DamageMeters_SetRelationship(index, relationship)
1957 local player = DamageMeters_tables[DMT_ACTIVE][index].player;
1958 if (nil == relationship) then
1959 DMPrintD("DamageMeters_SetRelationship ("..player.."), relationship = nil.");
1960 relationship = DamageMeters_Relation_FRIENDLY;
1961 end
1962  
1963 relationship = tonumber(relationship);
1964 local unitID = nil;
1965  
1966 if (relationship < 1 or relationship > DamageMeters_Relation_MAX) then
1967 DMPrintD("DamageMeters_SetRelationship ("..player.."), relationship = "..relationship);
1968 relationship = DamageMeters_Relation_FRIENDLY;
1969 end
1970 DamageMeters_tables[DMT_ACTIVE][index].relationship = relationship;
1971 --Print("relationship = "..relationship);
1972  
1973 if (relationship == DamageMeters_Relation_SELF) then
1974 DamageMeters_tables[DMT_ACTIVE][index].class = UnitClass("player");
1975 --Print("Adding self, class = "..DamageMeters_tables[DMT_ACTIVE][index].class);
1976 unitID = "player";
1977 elseif (relationship == DamageMeters_Relation_PET) then
1978 unitID = "pet";
1979 elseif (relationship == DamageMeters_Relation_PARTY) then
1980 local i;
1981 for i=1,5 do
1982 unitID = "party"..i;
1983 local partyName = UnitName(unitID);
1984 if (partyName == player) then
1985 DamageMeters_tables[DMT_ACTIVE][index].class = UnitClass(unitID);
1986 --Print("Party member found: index = "..i..", class = "..DamageMeters_tables[DMT_ACTIVE][index].class);
1987 break;
1988 end
1989 end
1990 else
1991 --[[
1992 local i;
1993 for i=1,40 do
1994 unitID = "raid"..i;
1995 local partyName = UnitName(unitID);
1996 if (partyName == player) then
1997 DamageMeters_tables[DMT_ACTIVE][index].class = UnitClass(unitID);
1998 --Print("Raid member found: index = "..i..", class = "..DamageMeters_tables[DMT_ACTIVE][index].class);
1999 break;
2000 end
2001 end
2002 ]]--
2003  
2004 DamageMeters_UpdateRaidMemberClasses();
2005 end
2006  
2007  
2008 if (nil == unitID) then
2009 unitID = DamageMeters_GetUnitID(player, relationship);
2010 end
2011 if (unitID) then
2012 DamageMeters_tables[DMT_ACTIVE][index].health = UnitHealth(unitID);
2013 DamageMeters_tables[DMT_ACTIVE][index].maxHealth = UnitHealthMax(unitID);
2014 --DMPrint("New Player "..player.." has id <"..unitID.."> and health "..DamageMeters_tables[DMT_ACTIVE][index].health.."/"..DamageMeters_tables[DMT_ACTIVE][index].maxHealth, nil, true);
2015 else
2016 --DMPrint("New Player "..player.." unitID = nil.");
2017 DamageMeters_tables[DMT_ACTIVE][index].health = 0;
2018 DamageMeters_tables[DMT_ACTIVE][index].maxHealth = 0;
2019  
2020 --[[
2021 --DMPrint(GetNumRaidMembers().." raid members:");
2022 for index = 1, GetNumRaidMembers() do
2023 DMPrint(index.." "..GetRaidRosterInfo(index));
2024 unitId = "raid"..index;
2025 DMPrint(unitId.." = "..UnitName(unitId));
2026 end
2027 ]]--
2028 end
2029  
2030 return relationship;
2031 end
2032  
2033 function DamageMeters_AddValue(player, amount, crit, relationship, quantity, spell, damageType)
2034 if (DM_Bypass["AddValue"] == true) then
2035 return;
2036 end
2037  
2038 if (nil == player) then
2039 DMPrint("DamageMeters: INTERNAL ERROR! player = nil.");
2040 return 0;
2041 end
2042 if (nil == quantity) then
2043 DMPrint("DamageMeters: INTERNAL ERROR! quantity = nil.");
2044 end
2045  
2046 if (DM_UNKNOWNENTITY == player) then
2047 return 0;
2048 end
2049  
2050 if (DamageMeters_debugEnabled) then
2051 if (string.find(player, "Julie's") or
2052 string.find(player, "Night Dragon")) then
2053 DMPrintD(string.format("HEY!: Player = %s, spell = %s", player, spell));
2054 DMPrintD(string.format("[%s]: %s (%s)", DamageMeters_lastEvent.event, DamageMeters_lastEvent.fullMsg, DamageMeters_lastEvent.desc));
2055 end
2056 end
2057  
2058 if (DamageMeters_debug4.msgWatchMode) then
2059 if (spell ~= "[Msg]") then
2060 return 0;
2061 end
2062 end
2063  
2064 -- Because sometimes messages say "x dmg done by spell."/"x dmg done by spell (blah absorbed)", the
2065 -- spell sometimes appears as "spell.". This code strips it off.
2066 if (spell ~= nil and "." == string.sub(spell, -1)) then
2067 --DMPrint("Stripping period from spell "..spell);
2068 spell = string.sub(spell, 1, -2);
2069 end
2070  
2071 if (relationship == nil) then
2072 DMPrintD("Relationship = nil, player("..player.."), amount("..amount.."), quantity("..quantity..")");
2073 relationship = DamageMeters_Relation_FRIENDLY;
2074 end
2075  
2076 -- Fix pet relationship if necessary.
2077 if (DamageMeters_Relation_PET ~= relationship and player == UnitName("Pet")) then
2078 --DMPrintD("Fixing Pet Relationship: spell = "..spell, nil, true);
2079 relationship = DamageMeters_Relation_PET;
2080 end
2081  
2082 -- Assign to self if it is a pet and the option is set.
2083 if (DamageMeters_flags[DMFLAG_addPetToPlayer] and relationship == DamageMeters_Relation_PET) then
2084 relationship = DamageMeters_Relation_SELF;
2085 player = UnitName("Player");
2086 end
2087  
2088 amount = tonumber(amount);
2089 relationship = tonumber(relationship);
2090 local currentTime = GetTime();
2091  
2092 --DMPrint("DamageMeters_AddValue : relationship = "..relationship);
2093  
2094 local index = DamageMeters_GetPlayerIndex(player);
2095 local found = (index ~= nil);
2096 if (nil == index) then
2097  
2098 -- Reject if list locked.
2099 if (DamageMeters_listLocked) then
2100 return 0;
2101 end
2102  
2103 -- Reject if list full.
2104 if (table.getn(DamageMeters_tables[DMT_ACTIVE]) >= DamageMeters_TABLE_MAX) then
2105 return 0;
2106 end
2107  
2108 -- Reject if player is banned.
2109 if (DamageMeters_IsBanned(player)) then
2110 --DMPrintD("Rejecting banned player "..player);
2111 return 0;
2112 end
2113  
2114 -- Reject if we are excluding non-group members.
2115 -- This code lets the player's pets through, btw.
2116 if (DamageMeters_flags[DMFLAG_groupMembersOnly] and
2117 (DamageMeters_Relation_PARTY == relationship or DamageMeters_Relation_FRIENDLY == relationship)) then
2118 local foundRelation = DamageMeters_GetGroupRelation(player);
2119 if (foundRelation < 0) then
2120 --DMPrintD(player.." not in party or raid, rejecting.");
2121 return 0;
2122 end
2123 end
2124  
2125 -- ** At this point we've determined the value is ok to add to the table. **
2126  
2127 -- If we are "ready", unpause.
2128 if (DamageMeters_DoReadyCheck(quantity, spell)) then
2129 return;
2130 end
2131  
2132 if (quantity == DamageMeters_Quantity_DAMAGE and spell ~= DM_SYNCSPELLNAME) then
2133 if (DamageMeters_startCombatOnNextValue) then
2134 DamageMeters_startCombatOnNextValue = false;
2135 if (DamageMeters_flags[DMFLAG_resetWhenCombatStarts]) then
2136 DamageMeters_Clear(0, true);
2137 end
2138 DamageMeters_OnCombatStart();
2139 end
2140 end
2141  
2142 -- OK: Add the new player.
2143 index = DamageMeters_AddNewPlayer(DamageMeters_tables[DMT_ACTIVE], player);
2144 relationship = DamageMeters_SetRelationship(index, relationship);
2145  
2146 if (index <= DamageMeters_barCount) then
2147 DamageMeters_bars[index]:Show();
2148 end
2149 else
2150 -- If we are "ready", unpause.
2151 if (DamageMeters_DoReadyCheck(quantity, spell)) then
2152 return;
2153 end
2154  
2155 if (DamageMeters_startCombatOnNextValue and quantity == DamageMeters_Quantity_DAMAGE) then
2156 DamageMeters_startCombatOnNextValue = false;
2157 if (DamageMeters_flags[DMFLAG_resetWhenCombatStarts]) then
2158 DamageMeters_Clear(0, true);
2159 end
2160 DamageMeters_OnCombatStart();
2161  
2162 -- Very dangerous! Recursing here.
2163 DamageMeters_AddValue(player, amount, crit, relationship, quantity, spell);
2164 return;
2165 end
2166  
2167 if (relationship < DamageMeters_tables[DMT_ACTIVE][index].relationship) then
2168 DMPrintD("Updating "..player.."'s relationship from "..DamageMeters_tables[DMT_ACTIVE][index].relationship.." to "..relationship);
2169 relationship = DamageMeters_SetRelationship(index, relationship);
2170 end
2171 end
2172  
2173 if (DM_Bypass["AddValue 1"] == true) then
2174 return;
2175 end
2176  
2177 -----------------------------------------------------------------
2178 -- ADD THE DATA TO THE MAIN TABLE
2179 --DMPrintD("DamageMeters_UpdateTableEntry active");
2180 DamageMeters_UpdateTableEntry(DMT_ACTIVE, index, quantity, amount, crit, found, relationship, spell, damageType);
2181  
2182 -----------------------------------------------------------------
2183 -- This is where the data gets added to the combat table.
2184  
2185 if (DamageMeters_inCombat) then
2186 local combatIndex = DamageMeters_GetPlayerIndex(player, DMT_FIGHT);
2187 if (nil == combatIndex) then
2188 combatIndex = DamageMeters_AddNewPlayer(DamageMeters_tables[DMT_FIGHT], player);
2189 -- Relationship and class is tricky: copy it directly from the main table.
2190 DamageMeters_tables[DMT_FIGHT][combatIndex].relationship = relationship;
2191 DamageMeters_tables[DMT_FIGHT][combatIndex].class = DamageMeters_tables[DMT_ACTIVE][index].class;
2192 end
2193  
2194 -- ADD THE DATA TO THE COMBAT TABLE
2195 --DMPrintD("DamageMeters_UpdateTableEntry combat");
2196 DamageMeters_UpdateTableEntry(DMT_FIGHT, combatIndex, quantity, amount, crit, found, relationship, spell, damageType);
2197 end
2198  
2199 -----------------------------------------------------------------
2200 -- This is where data is accumulated to the memory table.
2201  
2202 if (DamageMeters_flags[DMFLAG_accumulateToMemory]) then
2203 local memIndex = DamageMeters_GetPlayerIndex(player, DMT_SAVED);
2204 if (nil == memIndex) then
2205 memIndex = DamageMeters_AddNewPlayer(DamageMeters_tables[DMT_SAVED], player);
2206 -- Relationship is tricky: copy it directly from the main table.
2207 DamageMeters_tables[DMT_SAVED][memIndex].relationship = relationship;
2208 DamageMeters_tables[DMT_SAVED][memIndex].class = DamageMeters_tables[DMT_ACTIVE][index].class;
2209 end
2210  
2211 DamageMeters_UpdateTableEntry(DMT_SAVED, memIndex, quantity, amount, crit, found, relationship, spell, damageType);
2212  
2213 -- Take time from master table.
2214 DamageMeters_tables[DMT_SAVED][memIndex].lastTime = DamageMeters_tables[DMT_ACTIVE][index].lastTime;
2215 end
2216  
2217 -----------------------------------------------------------------
2218  
2219 if (DamageMeters_Quantity_DAMAGE == quantity or DamageMeters_Quantity_DAMAGED == quantity) then
2220 DamageMeters_lastEventTime = currentTime;
2221 end
2222  
2223 if (DamageMeters_debug4.showValueChanges) then
2224 DMPrint(format("Added %d %s to %s from %s.", amount, DM_QUANTDEFS[quantity].name, DamageMeters_tables[DMT_ACTIVE][index].player, spell), nil, true);
2225 end
2226  
2227 --[[
2228 -- Debug info.
2229 if (DamageMeters_lastEvent.event and DamageMeters_lastEvent.event ~= "") then
2230 if (nil == DamageMeters_tables[DMT_ACTIVE][index].firstMsg) then
2231 DamageMeters_tables[DMT_ACTIVE][index].firstMsg = {};
2232 end
2233 DamageMeters_tables[DMT_ACTIVE][index].firstMsg.event = DamageMeters_lastEvent.event;
2234 DamageMeters_tables[DMT_ACTIVE][index].firstMsg.desc = DamageMeters_lastEvent.desc;
2235 DamageMeters_tables[DMT_ACTIVE][index].firstMsg.fullMsg = DamageMeters_lastEvent.fullMsg;
2236  
2237 DamageMeters_lastEvent.event = "";
2238 end
2239 ]]--
2240  
2241 return index;
2242 end
2243  
2244 function DamageMeters_UpdateTableEntry(destTableIndex, index, quantity, amount, crit, existingEntry, relationship, spell, damageType)
2245 if (DM_Bypass["UpdateTableEntry"] == true) then
2246 return;
2247 end
2248  
2249 DamageMeters_tablesDirty = true;
2250  
2251 local destTable = DamageMeters_tables[destTableIndex];
2252  
2253 -----------------------------------------------------------------
2254 -- This is where the table entry gets modified with the new data.
2255  
2256 if (index == nil) then
2257 DMPrintD("index = nil, spell = "..spell);
2258 end
2259 if (quantity == nil) then
2260 DMPrintD("quantity = nil, spell = "..spell);
2261 end
2262  
2263 -- Lookup the DMI.
2264 local dmi = DM_QUANTDEFS[quantity].dmi;
2265  
2266 -- Update quantity.
2267 --DMPrintD("index = "..index..", quantity = "..quantity);
2268 destTable[index].dmiData[dmi].q = destTable[index].dmiData[dmi].q + amount;
2269  
2270 -- Update crit count.
2271 if (crit ~= DM_DOT) then
2272 destTable[index].dmiData[dmi].hitCount = destTable[index].dmiData[dmi].hitCount + 1;
2273 if (crit == DM_CRT) then
2274 destTable[index].dmiData[dmi].critCount = destTable[index].dmiData[dmi].critCount + 1;
2275 end
2276 end
2277  
2278 -- We use amount = 0 just to add empty people to the list.
2279 -- Only update time if it was because of a player action.
2280 if (existingEntry and (amount > 0) and (dmi == DMI_DAMAGE or dmi == DMI_HEALING)) then
2281 destTable[index].lastTime = GetTime();
2282 end
2283 destTable[index].dmiData[dmi].lastQuantTime = GetTime();
2284  
2285 -----------------------------------------------------------------
2286 -- Event Data collection. --
2287  
2288 if (spell and
2289 spell ~= DM_SYNCSPELLNAME and
2290 ((DamageMeters_eventDataLevel == DamageMeters_EventData_ALL) or
2291 (DamageMeters_eventDataLevel == DamageMeters_EventData_SELF and (DamageMeters_Relation_SELF == relationship)))) then
2292  
2293 -- Special case for Chain Heal.
2294 -- If we get one, queue into a global array. Chain heal messages come in reverse order
2295 -- (smallest to biggest) and all in the same frame. At the next tick a bit of code in Update
2296 -- adds fake events for them (fake events have a * at the end and aren't counted towards
2297 -- totals.
2298 if (destTableIndex == DMT_ACTIVE and
2299 DamageMeters_Relation_SELF == relationship and
2300 "Chain Heal" == spell and
2301 DamageMeters_Quantity_HEALING == quantity and
2302 DamageMeters_waitingForChainHeal) then
2303  
2304 DamageMeters_queuedChainHealCount = DamageMeters_queuedChainHealCount + 1;
2305 DamageMeters_queuedChainHealValue[DamageMeters_queuedChainHealCount] = amount;
2306 DamageMeters_queuedChainHealCrit[DamageMeters_queuedChainHealCount] = crit;
2307  
2308 --DMPrintD("Chain Heal cast for "..amount);
2309 end
2310  
2311 DamageMeters_AddEvent(destTableIndex, index, quantity, spell, amount, crit, relationship, damageType);
2312 end
2313 end
2314  
2315 function DamageMeters_StartChainHeal()
2316 DamageMeters_queuedChainHealCount = 0;
2317 DamageMeters_waitingForChainHeal = true;
2318 end
2319  
2320 function DamageMeters_DebugError(msg)
2321 DMPrint(msg);
2322 DamageMeters_SendSyncMsg("ERROR: "..msg);
2323 end
2324  
2325 function DamageMeters_AddEvent(destTableIx, index, quantity, spell, amount, crit, relationship, damageType)
2326 if (DM_Bypass["AddEvent"] == true) then
2327 return;
2328 end
2329  
2330 local destTable = DamageMeters_tables[destTableIx];
2331 local countIndex = crit;
2332 if (crit == DM_DOT) then
2333 countIndex = DM_HIT;
2334  
2335 if ((string.sub(spell, 1, 1) ~= "[")) then
2336 if (quantity == DamageMeters_Quantity_HEALING or
2337 quantity == DamageMeters_Quantity_HEALINGRECEIVED) then
2338 spell = spell.." [HOT]";
2339 else
2340 spell = spell.." [DOT]";
2341 end
2342 end
2343 end
2344  
2345 -- Beta error handling--this shouldn't ever happen, think I fixed the bug elsewhere.
2346 -- (Calls to this function not using proper table's index).
2347 if (not index) then
2348 DamageMeters_DebugError("DamageMeters_AddEvent index = nil. Spell = "..spell);
2349 return;
2350 end
2351 if (index == 0) then
2352 DamageMeters_DebugError("DamageMeters_AddEvent index = 0. Spell = "..spell);
2353 return;
2354 end
2355 if (not quantity or quantity == 0) then
2356 DamageMeters_DebugError("DamageMeters_AddEvent bad quantity. Spell = "..spell);
2357 return;
2358 end
2359 if (not destTable[index]) then
2360 DamageMeters_DebugError("DamageMeters_AddEvent destTable["..index.."] = nil. Spell = "..spell);
2361 return;
2362 end
2363  
2364 -- Lookup the DMI.
2365 local dmi = DM_QUANTDEFS[quantity].dmi;
2366  
2367 if (not destTable[index].dmiData[dmi].events) then
2368 destTable[index].dmiData[dmi].events = {};
2369 destTable[index].dmiData[dmi].events.spellTable = {};
2370 destTable[index].dmiData[dmi].events.hash = {};
2371 destTable[index].dmiData[dmi].events.dirty = true;
2372 end
2373 if (not destTable[index].dmiData[dmi].events.spellTable[spell]) then
2374 --DMPrintD("EventTable: Adding spell "..spell);
2375 destTable[index].dmiData[dmi].events.spellTable[spell] = {};
2376 destTable[index].dmiData[dmi].events.spellTable[spell].value = 0;
2377 destTable[index].dmiData[dmi].events.spellTable[spell].counts = {0,0};
2378 destTable[index].dmiData[dmi].events.spellTable[spell].damageType = DM_DMGTYPE_DEFAULT;
2379 destTable[index].dmiData[dmi].events.spellTable[spell].resistanceSum = 0;
2380 destTable[index].dmiData[dmi].events.spellTable[spell].resistanceCount = 0;
2381 end
2382 destTable[index].dmiData[dmi].events.spellTable[spell].value = destTable[index].dmiData[dmi].events.spellTable[spell].value + amount;
2383 destTable[index].dmiData[dmi].events.spellTable[spell].counts[countIndex] = destTable[index].dmiData[dmi].events.spellTable[spell].counts[countIndex] + 1;
2384  
2385 if (DM_Bypass["AddEvent 1"] == true) then
2386 return;
2387 end
2388  
2389 if (relationship == DamageMeters_Relation_SELF and dmi == DMI_DAMAGED) then
2390 local dmgType = DM_DMGTYPE_DEFAULT;
2391 local resistance = 0;
2392 if (damageType) then
2393 if (damageType ~= DM_DMGTYPE_DEFAULT) then
2394 dmgType = DM_DMGNAMETOID[damageType];
2395  
2396 if (nil == dmgType) then
2397 DMPrintD("ERROR: Unrecognized damage type >"..damageType.."<, fixing.");
2398 dmgType = DM_DMGTYPE_DEFAULT;
2399 end
2400 end
2401  
2402 if (destTable[index].dmiData[dmi].events.spellTable[spell].damageType ~= DM_DMGTYPE_DEFAULT and
2403 destTable[index].dmiData[dmi].events.spellTable[spell].damageType ~= dmgType) then
2404 --DMPrintD("Switching types from "..destTable[index].dmiData[dmi].events.spellTable[spell].damageType .." to "..dmgType);
2405 end
2406  
2407 destTable[index].dmiData[dmi].events.spellTable[spell].damageType = dmgType;
2408 resistance = DamageMeters_GetResistance(dmgType);
2409  
2410 --DMPrintD(spell..": "..damageType.." damage, "..resistance.." resistance.");
2411  
2412 destTable[index].dmiData[dmi].events.spellTable[spell].resistanceSum = destTable[index].dmiData[dmi].events.spellTable[spell].resistanceSum + resistance;
2413 destTable[index].dmiData[dmi].events.spellTable[spell].resistanceCount = destTable[index].dmiData[dmi].events.spellTable[spell].resistanceCount + 1;
2414 end
2415 end
2416  
2417 if (DM_Bypass["AddEvent 2"] == true) then
2418 return;
2419 end
2420  
2421 destTable[index].dmiData[dmi].events.hash = nil;
2422 destTable[index].dmiData[dmi].events.dirty = true;
2423  
2424 if (crit == DM_CRT) then
2425 destTable[index].dmiData[dmi].events.spellTable[spell].counts[DM_HIT] = destTable[index].dmiData[dmi].events.spellTable[spell].counts[DM_HIT] + 1;
2426 end
2427 end
2428  
2429 function DamageMeters_DoReadyCheck(quantity, spell)
2430 if (DM_Pause_Ready == DamageMeters_pauseState) then
2431 if (DamageMeters_Quantity_DAMAGE == quantity or DamageMeters_Quantity_DAMAGED == quantity) then
2432 if (DM_DMG_FALLING == spell or DM_DMG_LAVA == spell or DM_SYNCSPELLNAME == spell) then
2433 return true;
2434 else
2435 if (DamageMeters_CheckSyncChan(true)) then
2436 DMPrint(DM_MSG_READYUNPAUSING, nil, true);
2437 end
2438 DamageMeters_SyncUnpause(true, spell);
2439 end
2440 else
2441 return true;
2442 end
2443 end
2444  
2445 return false;
2446 end
2447  
2448 function DamageMeters_AddNewPlayer(destTable, player)
2449 --DMPrintD("Adding player "..player);
2450  
2451 local now = GetTime();
2452  
2453 local index = table.getn(destTable) + 1;
2454 table.setn(destTable, index);
2455 destTable[index] = {};
2456 destTable[index].dmiData = {};
2457  
2458 local quant;
2459 for quant = 1, DMI_MAX do
2460 destTable[index].dmiData[quant] = {};
2461 destTable[index].dmiData[quant].q = 0;
2462 destTable[index].dmiData[quant].hitCount = 0;
2463 destTable[index].dmiData[quant].critCount = 0;
2464 destTable[index].dmiData[quant].lastQuantTime = now;
2465 end
2466 destTable[index].player = player;
2467 destTable[index].lastTime = now;
2468  
2469 return index;
2470 end
2471  
2472 function DamageMeters_GetResistance(resistId)
2473 if (resistId < DM_DMGTYPE_ARCANE or resistId > DM_DMGTYPE_SHADOW) then
2474 return 0;
2475 end
2476  
2477 local base, resistance, positive, negative;
2478 local frame = getglobal("MagicResFrame"..resistId);
2479 base, resistance, positive, negative = UnitResistance("player", frame:GetID());
2480 return resistance;
2481 end
2482  
2483 function DamageMeters_AddDamage(event, player, creatureName, amount, crit, relationship, spell, damageType)
2484 DamageMeters_StopDebugTimer(DMPROF_PARSEMESSAGE);
2485  
2486 DamageMeters_StartDebugTimer(DMPROF_ADDVALUE);
2487 DamageMeters_AddValue(player, amount, crit, relationship, DamageMeters_Quantity_DAMAGE, spell);
2488 DamageMeters_StopDebugTimer(DMPROF_ADDVALUE);
2489  
2490 DamageMetersPlugin_AddDamage(event, player, creatureName, amount, crit, relationship, spell, damageType)
2491 end
2492  
2493 function DamageMeters_AddDamageReceived(event, player, creatureName, amount, crit, relationship, spell, damageType, resisted)
2494 DamageMeters_StopDebugTimer(DMPROF_PARSEMESSAGE);
2495  
2496 DamageMeters_StartDebugTimer(DMPROF_ADDVALUE);
2497 local index = DamageMeters_AddValue(player, amount, crit, relationship, DamageMeters_Quantity_DAMAGED, spell, damageType);
2498 DamageMeters_StopDebugTimer(DMPROF_ADDVALUE);
2499  
2500 --[[
2501 -- Adjust the health value we're storing for this player
2502 if (index ~= nil and index > 0) then
2503 local playerStruct = DamageMeters_tables[DMT_ACTIVE][index];
2504 if ((playerStruct ~= nil) and (playerStruct.health ~= nil and playerStruct.health > 0)) then
2505 playerStruct.health = max(0, playerStruct.health - amount);
2506  
2507 if (DamageMeters_debug4.showHealthChanges) then
2508 DMPrintD(-amount.." to "..player.."'s health. New = "..playerStruct.health, {r=1,g=1,b=1}, true);
2509 end
2510 end
2511  
2512 if (playerStruct == nil) then
2513 DMPrintD("playerStruct = nil, index = "..index);
2514 end
2515 end
2516 ]]--
2517  
2518 DamageMetersPlugin_AddDamageReceived(event, player, creatureName, amount, crit, relationship, spell)
2519 end
2520  
2521 function DamageMeters_GetUnitID(entity, relationship)
2522 --DMPrintD("DamageMeters_GetUnitID "..entity.." "..relationship, nil, true);
2523  
2524 if (relationship == DamageMeters_Relation_SELF) then
2525 return "player";
2526 elseif (relationship == DamageMeters_Relation_PET) then
2527 return "pet";
2528 elseif (GetNumRaidMembers() > 0) then
2529 for index = 1, GetNumRaidMembers() do
2530 if (entity == GetRaidRosterInfo(index)) then
2531 return "raid"..index;
2532 end
2533 end
2534 elseif (GetNumPartyMembers() > 0) then
2535 for i=1,5 do
2536 local partyUnitName = "party"..i;
2537 local partyName = UnitName(partyUnitName);
2538 if (partyName and partyName ~= "" and partyName == entity) then
2539 return partyUnitName;
2540 end
2541 end
2542 end
2543  
2544 return nil;
2545 end
2546  
2547 function DamageMeters_AddHealing(event, player, target, amount, crit, relationship, targetRelationship, spell)
2548 DamageMeters_StopDebugTimer(DMPROF_PARSEMESSAGE);
2549  
2550 if (DM_UNKNOWNENTITY == player or DM_UNKNOWNENTITY == target) then
2551 return;
2552 end
2553  
2554 --DMPrintD(DamageMeters_Relation_STRING[relationship].." healed "..DamageMeters_Relation_STRING[targetRelationship].." for "..amount);
2555  
2556 -------------------------
2557 -- Absolute healing.
2558 DamageMeters_StartDebugTimer(DMPROF_ADDVALUE);
2559 DamageMeters_AddValue(player, amount, crit, relationship, DamageMeters_Quantity_ABSHEAL, spell);
2560 DamageMeters_StopDebugTimer(DMPROF_ADDVALUE);
2561  
2562 -------------------------
2563 -- Overheal stuff.
2564 -- using DMT_ACTIVE instead of DMT_VISIBLE since overhealing was always zero.
2565 local targetIndex = DamageMeters_GetPlayerIndex(target, DMT_ACTIVE);
2566 local health = nil;
2567 local maxHealth = nil;
2568 local playerStruct;
2569 if (targetIndex) then
2570 playerStruct = DamageMeters_tables[DMT_ACTIVE][targetIndex];
2571 if ((playerStruct.health ~= nil and playerStruct.health > 0) and (playerStruct.maxHealth ~= nil and playerStruct.maxHealth > 0)) then
2572 health = playerStruct.health;
2573 maxHealth = playerStruct.maxHealth;
2574 end
2575 else
2576 -- If the given player isn't already in the list we still want to know if they are being overhealed.
2577 -- Therefore, try to figure out their unitID.
2578 local unitID = DamageMeters_GetUnitID(player, relationship);
2579 if (unitID) then
2580 health = UnitHealth(unitID);
2581 maxHealth = UnitHealthMax(unitID);
2582 end
2583 end
2584  
2585 if (health ~= nil and maxHealth ~= nil) then
2586 local newHealth = health + amount;
2587 local overhealing = newHealth - maxHealth;
2588 if (overhealing > 0) then
2589 if (DamageMeters_debug4.showHealthChanges) then
2590 DMPrintD(player.." overhealed "..target.." by "..overhealing.." ("..health.."/"..maxHealth..")", nil, true);
2591 end
2592 DamageMeters_AddValue(player, overhealing, crit, relationship, DamageMeters_Quantity_OVERHEAL, spell);
2593  
2594 newHealth = maxHealth;
2595 amount = maxHealth - health;
2596 end
2597  
2598 if (targetIndex) then
2599 playerStruct.health = newHealth;
2600 end
2601 end
2602  
2603 -------------------------
2604 -- Healing Done & Healing Taken
2605  
2606 --DMPrint("AddHealing: "..player.." healed "..target.." for "..amount);
2607 DamageMeters_StartDebugTimer(DMPROF_ADDVALUE);
2608 DamageMeters_AddValue(player, amount, crit, relationship, DamageMeters_Quantity_HEALING, spell);
2609 DamageMeters_AddValue(target, amount, crit, targetRelationship, DamageMeters_Quantity_HEALINGRECEIVED, spell);
2610 DamageMeters_StopDebugTimer(DMPROF_ADDVALUE);
2611  
2612 -------------------------
2613  
2614 DamageMetersPlugin_AddHealing(event, player, target, amount, crit, relationship, targetRelationship, spell)
2615 end
2616  
2617 function DamageMeters_Report(arg1)
2618 local destChar = "c";
2619 local count = table.getn(DamageMeters_tables[DMT_ACTIVE]);
2620 local tellTarget = "";
2621 local params = arg1;
2622 local reportQuantity;
2623  
2624 local argsParsed = false;
2625  
2626 if ("help" == params) then
2627 DamageMeters_ShowReportHelp();
2628 return;
2629 end
2630  
2631 local totalStrLen = 5;
2632 if ("total" == string.lower(string.sub(params, 1, totalStrLen))) then
2633 reportQuantity = DamageMeters_ReportQuantity_Total;
2634 if (string.len(params) > totalStrLen) then
2635 params = string.sub(params, totalStrLen + 1);
2636 else
2637 params = "";
2638 end
2639 else
2640 reportQuantity = DamageMeters_quantity;
2641 end
2642  
2643 if (params == "") then
2644 argsParsed = true;
2645 end
2646  
2647 local a, b, c;
2648 if (not argsParsed) then
2649 for a, b, c in string.gfind(params, "(.)(%d+) (.+)") do
2650 destChar = a;
2651 count = tonumber(b);
2652 tellTarget = c;
2653 --DMPrint(1);
2654 argsParsed = true;
2655 end
2656 end
2657 if (not argsParsed) then
2658 for a, c in string.gfind(params, "(.) (%d+)") do
2659 destChar = a;
2660 --tellTarget = c;
2661 tellTarget = format("%d", c);
2662 --DMPrint(2);
2663 argsParsed = true;
2664 end
2665 end
2666 if (not argsParsed) then
2667 for a, b in string.gfind(params, "(.)(%d+)") do
2668 destChar = a;
2669 count = tonumber(b);
2670 --DMPrint(3);
2671 argsParsed = true;
2672 end
2673 end
2674 if (not argsParsed) then
2675 for a, c in string.gfind(params, "(.) (.+)") do
2676 destChar = a;
2677 tellTarget = c;
2678 --DMPrint(4);
2679 argsParsed = true;
2680 end
2681 end
2682 if (not argsParsed) then
2683 for a in string.gfind(params, "(.)") do
2684 destChar = a;
2685 --DMPrint(5);
2686 argsParsed = true;
2687 end
2688 end
2689 --DMPrint("."..destChar.."."..count.."."..tellTarget..".");
2690  
2691 if (not argsParsed) then
2692 DMPrint(DM_ERROR_INVALIDARG);
2693 DamageMeters_PrintHelp("report");
2694 end
2695  
2696 local destination;
2697 local invert = false;
2698 if (destChar) then
2699 --DMPrint("DamageMeters_Report("..params..")");
2700  
2701 local lowerDestChar = string.lower(destChar);
2702 if (lowerDestChar ~= destChar) then
2703 invert = true;
2704 destChar = lowerDestChar;
2705 end
2706  
2707 if (destChar == "c") then
2708 destination = "CONSOLE";
2709 elseif (destChar == "p") then
2710 destination = "PARTY";
2711 elseif (destChar == "s") then
2712 destination = "SAY";
2713 elseif (destChar == "r") then
2714 destination = "RAID";
2715 elseif (destChar == "w") then
2716 destination = "WHISPER";
2717 elseif (destChar == "h") then
2718 destination = "CHANNEL";
2719 elseif (destChar == "g") then
2720 destination = "GUILD";
2721 elseif (destChar == "o") then
2722 destination = "OFFICER";
2723 elseif (destChar == "f") then
2724 destination = "BUFFER";
2725  
2726 else
2727 DMPrint(DM_ERROR_BADREPORTTARGET..destChar);
2728 return;
2729 end
2730 end
2731  
2732 if (destination == "WHISPER" and tellTarget == "") then
2733 DMPrint(DM_ERROR_MISSINGWHISPERTARGET);
2734 return;
2735 elseif (destination == "CHANNEL" and tellTarget == "") then
2736 DMPrint(DM_ERROR_MISSINGCHANNEL);
2737 return;
2738 end
2739  
2740 DamageMeters_DoReport(reportQuantity, destination, invert, 1, count, tellTarget);
2741  
2742 if (destination == "BUFFER") then
2743 DamageMeters_OpenReportFrame();
2744 end
2745 end
2746  
2747 function DamageMeters_DumpTable()
2748 DMPrint(table.getn(DamageMeters_tables[DMT_ACTIVE]).." elements:");
2749  
2750 local index;
2751 local info;
2752 for index,info in DamageMeters_tables[DMT_ACTIVE] do
2753 DMPrint(index..": "..info.player);
2754 end
2755 end
2756  
2757 function DamageMeters_SendReportMsg(msg, destination, tellTarget)
2758 local editBox = DEFAULT_CHAT_FRAME.editBox;
2759 if (destination == "CONSOLE") then
2760 DMPrint(msg);
2761 elseif (destination == "TOOLTIP_TITLE") then
2762 DamageMetersTooltip:AddLine(msg, 1.0, 1.0, 1.0, 1);
2763 elseif (destination == "TOOLTIP") then
2764 DamageMetersTooltip:AddLine(msg, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 0);
2765 elseif (destination == "CHANNEL") then
2766 --DMPrint("Destination = "..destination..", tellTarget = "..tellTarget);
2767 SendChatMessage(msg, destination, editBox.language, GetChannelName(tellTarget));
2768 elseif (destination == "BUFFER") then
2769 DamageMeters_reportBuffer = DamageMeters_reportBuffer..msg.."\n";
2770 else
2771 SendChatMessage(msg, destination, editBox.language, tellTarget);
2772 end
2773 end
2774  
2775 function DamageMeters_SetCount(arg1, bSilent)
2776 local count = 0;
2777 if (not arg1 or arg1 == "") then
2778 DMPrint(DM_MSG_SETCOUNTTOMAX);
2779 count = DamageMeters_BARCOUNT_MAX;
2780 else
2781 count = tonumber(arg1);
2782 if (count > DamageMeters_BARCOUNT_MAX) then
2783 count = DamageMeters_BARCOUNT_MAX;
2784 end
2785 end
2786  
2787 DamageMeters_barCount = count;
2788 if (not bSilent) then
2789 DMPrint(DM_MSG_SETCOUNT..DamageMeters_barCount);
2790 end
2791 DMPrintD("Frame dirty: SetCount.");
2792 DamageMeters_frameNeedsToBeGenerated = true;
2793 DamageMeters_autoCountLimit = 0;
2794 DamageMeters_ForceNormalView();
2795 end
2796  
2797 function DamageMeters_Reset()
2798 DamageMeters_UpdateVisibility();
2799 DamageMeters_UpdateCount();
2800 DamageMeters_frameNeedsToBeGenerated = true;
2801 end
2802  
2803 function DamageMeters_ResetPos()
2804 local frame = DamageMetersFrame;
2805 if (not frame) then
2806 DMPrintD("DamageMetersFrame_Reset : Error getting frame.");
2807 return;
2808 end
2809  
2810 DMPrint(DM_MSG_RESETFRAMEPOS);
2811 local frameWidth = frame:GetWidth();
2812 local frameHeight = frame:GetHeight();
2813 frame:ClearAllPoints();
2814 frame:SetPoint("TOPLEFT", "UIParent", "RIGHT", -frameWidth, floor(frameHeight / 2));
2815  
2816 CloseMenus();
2817  
2818 -- Make sure the window is visible, too.
2819 DamageMeters_Show();
2820 end
2821  
2822 function DamageMeters_SetBarWidth(arg1, bSilent)
2823 if (arg1 == nil or arg1 == "") then
2824 DMPrint(string.format(DM_MSG_CURRENTBARWIDTH, DamageMeters_BARWIDTH));
2825 else
2826 if (string.lower(arg1) == "default") then
2827 DamageMeters_BARWIDTH = DamageMeters_DEFAULTBARWIDTH;
2828 else
2829 DamageMeters_BARWIDTH = tonumber(arg1);
2830 end
2831 if (not bSilent) then
2832 DMPrint(string.format(DM_MSG_NEWBARWIDTH, DamageMeters_BARWIDTH));
2833 end
2834 DamageMeters_frameNeedsToBeGenerated = true;
2835 end
2836 end
2837  
2838 function DamageMeters_ToggleShow()
2839 local frame = getglobal("DamageMetersFrame");
2840 DamageMeters_flags[DMFLAG_visibleOnlyInParty] = false;
2841 if (frame:IsVisible()) then
2842 DMPrintD("ToggleShow called - calling _Hide()");
2843 DamageMeters_Hide();
2844 else
2845 DMPrintD("ToggleShow called - calling _Show()");
2846 DamageMeters_Show();
2847 end
2848 end
2849  
2850 function DamageMeters_Show()
2851 DMPrintD("DamageMeters_Show called.");
2852 DamageMetersFrame:Show();
2853 DamageMeters_flags[DMFLAG_isVisible] = true;
2854 DamageMeters_frameNeedsToBeGenerated = true;
2855 end
2856  
2857 function DamageMeters_Hide()
2858 DamageMetersFrame:Hide();
2859 DamageMetersFrame_TitleButton:Hide();
2860 DamageMetersFrame_TotalButton:Hide();
2861 DamageMeters_flags[DMFLAG_isVisible] = false;
2862 end
2863  
2864 function DM_CountMsg(arg1, desc, event, filter)
2865 event = string.sub(event, 10);
2866  
2867 if (DamageMeters_debugEnabled) then
2868 DamageMeters_lastEvent.event = event;
2869 DamageMeters_lastEvent.desc = desc;
2870 DamageMeters_lastEvent.fullMsg = arg1;
2871  
2872 local filterOn = false;
2873 --if (DamageMeters_debug4.showParse) then
2874 -- if (not filterOn or filter) then
2875 -- DMPrint("Parsed("..event..") "..arg1.." ["..desc.."]", nil, true);
2876 -- end
2877 --end
2878  
2879 if (DamageMeters_msgCounts[desc]) then
2880 DamageMeters_msgCounts[desc] = DamageMeters_msgCounts[desc] + 1;
2881 else
2882 DamageMeters_msgCounts[desc] = 1;
2883 end
2884  
2885 if (DamageMeters_debug4.msgWatchMode) then
2886 DamageMeters_AddValue(desc, 1, DM_HIT, DamageMeters_Relation_PET, DamageMeters_Quantity_DAMAGE, "[Msg]");
2887 end
2888 end
2889 end
2890  
2891 function DM_DumpMsg()
2892 local i;
2893 local desc;
2894 for key,count in DamageMeters_msgCounts do
2895 DMPrintD(key.." : "..count)
2896 end;
2897 end
2898  
2899 function DM_ConsolePrint(arg1)
2900 local script = "DMPrint(("..arg1.."))";
2901 RunScript(script);
2902 end
2903  
2904 function DM_ConsolePrintTable(arg1)
2905 local script = "DM_DUMP_RECURSIVE(("..arg1.."), \"[root]\", \"\", \"CONSOLE\")";
2906 RunScript(script);
2907 end
2908  
2909 function DM_ToggleDMPrintD()
2910 DamageMeters_debugEnabled = not DamageMeters_debugEnabled;
2911 DMPrint("Debug mode enabled = "..(DamageMeters_debugEnabled and "true" or "false"));
2912 end
2913  
2914 -------------------------------------------------------------------------------
2915  
2916 function DamageMetersBarTemplate_OnEnter()
2917 if (not DamageMetersFrame:IsVisible()) then
2918 return;
2919 end
2920 -- Getting onenters for invisible bars. This doesn't seem to work :/
2921 if (not this:IsVisible()) then
2922 return;
2923 end
2924 -- This to work around above condition not working.
2925 if (this:GetID() > DamageMeters_barCount) then
2926 return;
2927 end
2928  
2929 -- no workee
2930 if (DamageMetersTooltip:IsVisible()) then
2931 return;
2932 end
2933  
2934 -- no workee
2935 if (DamageMetersFrameBarDropDown:IsVisible()) then
2936 --DMPrint("Not showing because drop down visible");
2937 return;
2938 end
2939  
2940 DamageMeters_tooltipBarIndex = this:GetID();
2941  
2942 -- Determine anchor.
2943 local anchorStyle = "ANCHOR_LEFT";
2944 local x,y = DamageMetersFrame:GetCenter();
2945 local screenWidth = UIParent:GetWidth();
2946 if (x~=nil and screenWidth~=nil) then
2947 if (x < (screenWidth / 2)) then
2948 anchorStyle = "ANCHOR_RIGHT";
2949 end
2950 end
2951  
2952 -- Set owner and anchor.
2953 DamageMetersTooltip:SetOwner(DamageMetersFrame, anchorStyle);
2954  
2955 -- added 2005-01-13 by arys
2956 -- makes clock tooltip scale correctly
2957 DamageMetersTooltip:SetScale(this:GetScale());
2958  
2959 -- Set text.
2960 DamageMeters_SetTooltipText();
2961 end
2962  
2963 function DamageMetersBarTemplate_OnLeave()
2964 DamageMeters_tooltipBarIndex = nil;
2965 DamageMetersTooltip:Hide();
2966 end
2967  
2968 function DamageMetersBarTemplate_OnClick()
2969 local index = this:GetID();
2970  
2971 --DMPrint("Click '"..arg1.."'");
2972 if ( arg1 == "LeftButton" ) then
2973 if (index <= table.getn(DamageMeters_tables[DMT_VISIBLE])) then
2974 --Print("Targetting "..DamageMeters_tables[DMT_VISIBLE][index].player);
2975 local tableIndex = DamageMeters_barStartIndex + index - 1;
2976 local targetName = DamageMeters_tables[DMT_VISIBLE][tableIndex].player;
2977 local targetID = DamageMeters_GetUnitID(targetName, DamageMeters_tables[DMT_VISIBLE][tableIndex].relationship)
2978  
2979 if (targetID) then
2980 TargetUnit(targetID);
2981 else
2982 TargetByName(targetName);
2983 end
2984 end
2985 elseif ( arg1 == "RightButton" ) then
2986 if (DMVIEW_MIN == DamageMeters_viewMode) then
2987 DamageMeters_ShowMainMenu();
2988 else
2989 if (index <= table.getn(DamageMeters_tables[DMT_VISIBLE])) then
2990 local frame = DamageMetersFrame;
2991  
2992 local distance;
2993 distance = ( UIParent:GetWidth() - frame:GetRight() );
2994  
2995 DamageMeters_clickedBarIndex = index + DamageMeters_barStartIndex - 1;
2996  
2997 --DMPrint("distance = "..distance);
2998 local menuMoveDist = -75;
2999 if ( distance <= menuMoveDist ) then
3000 local newOffset = distance - menuMoveDist;
3001 --DMPrint("Too close, new offset = "..newOffset);
3002 ToggleDropDownMenu(1, nil, DamageMetersFrameBarDropDown, "DamageMetersFrameBarDropDown", newOffset, 0);
3003 else
3004 ToggleDropDownMenu(1, nil, DamageMetersFrameBarDropDown, "DamageMetersFrameBarDropDown", 0, 0);
3005 end
3006 end
3007 end
3008 end
3009 end
3010  
3011 function DamageMeters_SetTooltipText()
3012 local tableIndex = DamageMeters_barStartIndex + DamageMeters_tooltipBarIndex - 1;
3013 local playerStruct = DamageMeters_tables[DMT_VISIBLE][tableIndex];
3014  
3015 if ((nil == playerStruct) or (not tableIndex) or (tableIndex > table.getn(DamageMeters_tables[DMT_VISIBLE]))) then
3016 -- (nil == struct.player) or
3017 DamageMeters_tooltipBarIndex = nil;
3018 DamageMetersTooltip:Hide();
3019 return;
3020 end
3021  
3022 local player = playerStruct.player;
3023 DamageMetersTooltip:SetText(player, 1.00, 1.00, 1.00);
3024  
3025 if (not IsControlKeyDown()) then
3026 local msg = DM_MSG_PRESSCONTROLEVENT;
3027 if (DamageMeters_flags[DMFLAG_showEventTooltipsFirst]) then
3028 msg = DM_MSG_PRESSCONTROLQUANTITY;
3029 end
3030 DamageMetersTooltip:AddLine(msg, 1.0, 0.5, 0.5, 1);
3031 end
3032  
3033 local tableIx = DMT_VISIBLE;
3034  
3035 if ((IsControlKeyDown() and not DamageMeters_flags[DMFLAG_showEventTooltipsFirst]) or (not IsControlKeyDown() and DamageMeters_flags[DMFLAG_showEventTooltipsFirst])) then
3036 local singleQuantity = nil;
3037 if (DamageMeters_quantity ~= DamageMeters_Quantity_TIME) then
3038 if (IsAltKeyDown()) then
3039 singleQuantity = DamageMeters_quantity;
3040 else
3041 DamageMetersTooltip:AddLine(DM_MSG_PRESSALTSINGLEQUANTITY, 1.0, 0.5, 0.5, 1);
3042 end
3043 end
3044 DamageMeters_DumpPlayerEvents(DamageMeters_tables[tableIx][tableIndex].player, "TOOLTIP", false, nil, nil, singleQuantity);
3045 else
3046 local percentages = {0, 0, 0, 0};
3047 local dmi;
3048 for dmi = 1, DMI_MAX do
3049 percentages[dmi] = (DamageMeters_totals[dmi] > 0) and (100 * playerStruct.dmiData[dmi].q / DamageMeters_totals[dmi]) or 0;
3050 end
3051  
3052 local text = "";
3053 for dmi = 1, DMI_MAX do
3054 local rank = (DamageMeters_rankTables[tableIx][player] and DamageMeters_rankTables[tableIx][player][dmi]) and " #"..tostring(DamageMeters_rankTables[tableIx][player][dmi]) or "";
3055 text = text..(format("%s = %d (%.2f%%)%s\n", DMI_NAMES[dmi], playerStruct.dmiData[dmi].q, percentages[dmi], rank));
3056 local critPercentage = (playerStruct.dmiData[dmi].hitCount > 0) and (playerStruct.dmiData[dmi].critCount / playerStruct.dmiData[dmi].hitCount) * 100 or 0;
3057 text = text..(format(" %d/%d (%.2f%%) %s\n", playerStruct.dmiData[dmi].critCount, playerStruct.dmiData[dmi].hitCount, critPercentage, DM_CRITSTR));
3058 end
3059  
3060 --DMPrint("relationship = "..playerStruct.relationship);
3061  
3062 text = text..format(DM_TOOLTIP,
3063 GetTime() - playerStruct.lastTime,
3064 DamageMeters_Relation_STRING[playerStruct.relationship]);
3065 if (playerStruct.class) then
3066 text = text.."\n"..DM_CLASS.." = "..playerStruct.class;
3067 end
3068  
3069 DamageMetersTooltip:AddLine(text, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1);
3070 end
3071  
3072 DamageMetersTooltip:Show();
3073 end
3074  
3075 function DamageMeters_DoPlayerReport(player, destination)
3076 local playerIndex = DamageMeters_GetPlayerIndex(player);
3077 if (not playerIndex) then
3078 return;
3079 end
3080 local playerStruct = DamageMeters_tables[DMT_ACTIVE][playerIndex];
3081  
3082 DamageMeters_SendReportMsg(string.format(DM_MSG_PLAYERREPORTHEADER, player), destination);
3083  
3084 local percentages = {0, 0, 0, 0};
3085 local quantIndex;
3086 for quantIndex = 1, DMI_MAX do
3087 percentages[quantIndex] = (DamageMeters_totals[quantIndex] > 0) and (100 * playerStruct.dmiData[quantIndex].q / DamageMeters_totals[quantIndex]) or 0;
3088 end
3089  
3090 local text = "";
3091 for quantIndex = 1, DMI_MAX do
3092 DamageMeters_SendReportMsg(format("%s = %d (%.2f%%)", DM_QUANTDEFS[quantIndex].name, playerStruct.dmiData[quantIndex].q, percentages[quantIndex]), destination);
3093 local critPercentage = (playerStruct.dmiData[quantIndex].hitCount > 0) and (playerStruct.dmiData[quantIndex].critCount / playerStruct.dmiData[quantIndex].hitCount) * 100 or 0;
3094 DamageMeters_SendReportMsg(format(" %d/%d (%.2f%%) %s", playerStruct.dmiData[quantIndex].critCount, playerStruct.dmiData[quantIndex].hitCount, critPercentage, DM_CRITSTR), destination);
3095 end
3096 end
3097  
3098 function DamageMeters_PrintHelp(command)
3099 local index, help;
3100 for index, help in DamageMeters_helpTable do
3101 if (1 == string.find(help, "dm"..command)) then
3102 DMPrint(help);
3103 return;
3104 end
3105 end
3106 end
3107  
3108 function DamageMeters_ListCommands()
3109 local index, help;
3110 for index, help in DamageMeters_helpTable do
3111 DMPrint(help);
3112 end
3113 end
3114  
3115 function DamageMeters_Help()
3116 DamageMeters_ShowVersion();
3117 DMPrint(DM_MSG_HELP);
3118 end
3119  
3120 -- /script DM_MemInfo();
3121 function DM_MemInfo()
3122 DMPrint("VISIBLE = "..DMT_VISIBLE);
3123 DMPrint("ACTIVE = "..DMT_ACTIVE..", "..table.getn(DamageMeters_tables[DMT_ACTIVE]).." entries.");
3124 DMPrint("SAVED = "..DMT_SAVED..", "..table.getn(DamageMeters_tables[DMT_SAVED]).." entries.");
3125 end
3126  
3127 function DamageMeters_Save()
3128 DMPrint(DM_MSG_SAVE);
3129  
3130 -- This makes the saved table just a reference to the active, so when the active
3131 -- is cleared it kills the saved.
3132 --DamageMeters_tables[DMT_SAVED] = DamageMeters_tables[DMT_ACTIVE];
3133  
3134 -- Clear the saved.
3135 DamageMeters_DoClear(DMT_SAVED, 0, true);
3136  
3137 -- Duplicate the table.
3138 DamageMeters_tables[DMT_SAVED] = DM_clone(DamageMeters_tables[DMT_ACTIVE]);
3139 end
3140  
3141 function DamageMeters_Restore()
3142 if (DamageMeters_tables[DMT_SAVED] and (table.getn(DamageMeters_tables[DMT_SAVED]) > 0)) then
3143 DMPrint(DM_MSG_RESTORE);
3144 DamageMeters_tables[DMT_ACTIVE] = DamageMeters_tables[DMT_SAVED];
3145 DamageMeters_tables[DMT_SAVED] = {};
3146 else
3147 DMPrint(DM_ERROR_NOSAVEDTABLE);
3148 end
3149 end
3150  
3151 function DamageMeters_Merge()
3152 local sourceTableIx = DMT_SAVED;
3153 local destTableIx = DMT_ACTIVE;
3154  
3155 for sourceIx, playerStruct in DamageMeters_tables[sourceTableIx] do
3156 local destIx = GetPlayerIndex(playerStruct.player, destTableIx);
3157 if (nil == destIx) then
3158  
3159 end
3160 end
3161 end
3162  
3163 function DamageMeters_Swap(silent)
3164 local tempTable = {};
3165  
3166 if (not silent) then
3167 DMPrint(format(DM_MSG_SWAP, table.getn(DamageMeters_tables[DMT_ACTIVE]), table.getn(DamageMeters_tables[DMT_SAVED])));
3168 DMPrintD("DMT_ACTIVE = "..DMT_ACTIVE..", DMT_SAVED = "..DMT_SAVED);
3169 end
3170  
3171 DMT_ACTIVE = DMT_SAVED;
3172 DMT_SAVED = (DMT_SAVED == DM_TABLE_B) and DM_TABLE_A or DM_TABLE_B;
3173 if (not DamageMeters_IsQuantityFight(DamageMeters_quantity)) then
3174 DMT_VISIBLE = DMT_ACTIVE;
3175 end
3176  
3177 -- Regen frame to hide any buttons now not needed.
3178 DamageMeters_frameNeedsToBeGenerated = true;
3179 --DMPrintD("Frame dirty: Swap.");
3180 end
3181  
3182 function DamageMeters_MemClear()
3183 DMPrint(DM_MSG_MEMCLEAR);
3184 DamageMeters_tables[DMT_SAVED] = {};
3185 end
3186  
3187 function DamageMeters_SetTextOptions(arg1)
3188 if (arg1 == "") then
3189 DMPrint(DM_ERROR_MISSINGARG);
3190 DamageMeters_PrintHelp("text");
3191 return;
3192 end
3193  
3194 DamageMeters_textOptions[DamageMeters_Text_RANK] = false;
3195 DamageMeters_textOptions[DamageMeters_Text_NAME] = false;
3196 DamageMeters_textOptions[DamageMeters_Text_TOTALPERCENTAGE] = false;
3197 DamageMeters_textOptions[DamageMeters_Text_LEADERPERCENTAGE] = false;
3198 DamageMeters_textOptions[DamageMeters_Text_VALUE] = false;
3199 DamageMeters_textOptions[DamageMeters_Text_DELTA] = false;
3200  
3201 if (arg1 == "0") then
3202 return;
3203 end
3204  
3205 local i;
3206 for i = 1, string.len(arg1) do
3207 local char = string.lower(string.sub(arg1, i, i));
3208  
3209 if (char == "n") then
3210 DamageMeters_textOptions[DamageMeters_Text_NAME] = true;
3211 elseif (char == "r") then
3212 DamageMeters_textOptions[DamageMeters_Text_RANK] = true;
3213 elseif (char == "p") then
3214 DamageMeters_textOptions[DamageMeters_Text_TOTALPERCENTAGE] = true;
3215 elseif (char == "l") then
3216 DamageMeters_textOptions[DamageMeters_Text_LEADERPERCENTAGE] = true;
3217 elseif (char == "v") then
3218 DamageMeters_textOptions[DamageMeters_Text_VALUE] = true;
3219 elseif (char == "d") then
3220 DamageMeters_textOptions[DamageMeters_Text_DELTA] = true;
3221 end
3222 end
3223 end
3224  
3225 function DamageMeters_SetColorScheme(arg1)
3226 local showUsage = false;
3227 local colorScheme;
3228 if (not arg1 or arg1 == "") then
3229 showUsage = true;
3230 else
3231 colorScheme = tonumber(arg1);
3232 if (colorScheme < 1 or colorScheme > DamageMeters_colorScheme_MAX) then
3233 showUsage = true;
3234 end
3235 end
3236  
3237 if (showUsage) then
3238 DamageMeters_PrintHelp("color");
3239  
3240 local i;
3241 for i=1, DamageMeters_colorScheme_MAX do
3242 DMPrint(i..": "..DamageMeters_colorScheme_STRING[i]);
3243 end
3244  
3245 return;
3246 end
3247  
3248 DMPrint(DM_MSG_SETCOLORSCHEME..DamageMeters_colorScheme_STRING[colorScheme]);
3249 DamageMeters_colorScheme = colorScheme;
3250 end
3251  
3252 function DamageMeters_UpdateRaidMemberClasses()
3253 local numRaidMembers = GetNumRaidMembers();
3254 local name, rank, subgroup, level, class, fileName, zone, online, isDead;
3255 local i;
3256 for i = 1,numRaidMembers do
3257 name, rank, subgroup, level, class, fileName, zone, online, isDead = GetRaidRosterInfo(i);
3258  
3259 local tableIndex = DamageMeters_GetPlayerIndex(name);
3260 if (tableIndex) then
3261 DamageMeters_tables[DMT_ACTIVE][tableIndex].class = class;
3262 end
3263  
3264 if (DMT_VISIBLE ~= DMT_ACTIVE) then
3265 tableIndex = DamageMeters_GetPlayerIndex(name, DMT_VISIBLE);
3266 if (tableIndex) then
3267 DamageMeters_tables[DMT_VISIBLE][tableIndex].class = class;
3268 end
3269 end
3270 end
3271 end
3272  
3273 function DamageMeters_GetGroupRelation(player)
3274  
3275 if (player == UnitName("Player")) then
3276 return DamageMeters_Relation_SELF;
3277 end
3278  
3279 local numPartyMembers = GetNumPartyMembers();
3280 if (numPartyMembers > 0) then
3281 for i=1,5 do
3282 local partyUnitName = "party"..i;
3283 local partyName = UnitName(partyUnitName);
3284 if (partyName == player) then
3285 return DamageMeters_Relation_PARTY;
3286 end
3287 end
3288 end
3289  
3290 local numRaidMembers = GetNumRaidMembers();
3291 if (numRaidMembers > 0) then
3292 local name, rank, subgroup, level, class, fileName, zone, online, isDead;
3293 local i;
3294 for i = 1,numRaidMembers do
3295 name, rank, subgroup, level, class, fileName, zone, online, isDead = GetRaidRosterInfo(i);
3296 if (name == player) then
3297 return DamageMeters_Relation_FRIENDLY;
3298 end
3299 end
3300 end
3301  
3302 return -1;
3303 end
3304  
3305 function DamageMeters_SetVisibleInParty(arg1)
3306 if (arg1 and arg1 ~= "") then
3307 local arg = string.lower(arg1);
3308 if (arg == "y") then
3309 DamageMeters_flags[DMFLAG_visibleOnlyInParty] = true;
3310 DamageMeters_UpdateVisibility(true);
3311 elseif (arg == "n") then
3312 DamageMeters_flags[DMFLAG_visibleOnlyInParty] = false;
3313 DamageMeters_UpdateVisibility(true);
3314 else
3315 DMPrint(DM_ERROR_INVALIDARGS);
3316 DamageMeters_PrintHelp("visinparty");
3317 end
3318 end
3319  
3320 DMPrint(DM_MSG_SETVISINPARTY..(DamageMeters_flags[DMFLAG_visibleOnlyInParty] and DM_MSG_TRUE or DM_MSG_FALSE));
3321 end
3322  
3323 function DamageMeters_SetAutoCount(arg1)
3324 if (not arg1 or arg1 == "") then
3325 DMPrint(DM_ERROR_MISSINGARG);
3326 DamageMeters_PrintHelp("autocount");
3327 return;
3328 end
3329  
3330 local newAutoCountLimit = tonumber(arg1);
3331 if (not newAutoCountLimit or newAutoCountLimit <= 0 or newAutoCountLimit > DamageMeters_BARCOUNT_MAX) then
3332 DMPrint(DM_ERROR_INVALIDARG);
3333 return;
3334 end
3335  
3336 DMPrint(DM_MSG_SETAUTOCOUNT..newAutoCountLimit);
3337 DamageMeters_autoCountLimit = newAutoCountLimit;
3338 DamageMeters_ForceNormalView();
3339 end
3340 --[[
3341 function DamageMeters_ToggleOnlySyncWithGroup()
3342 DamageMeters_flags[DMFLAG_onlySyncWithGroup] = not DamageMeters_flags[DMFLAG_onlySyncWithGroup];
3343 if (DamageMeters_flags[DMFLAG_onlySyncWithGroup]) then
3344 DMPrint(DM_MSG_SYNCINGROUPON);
3345 else
3346 DMPrint(DM_MSG_SYNCINGROUPOFF);
3347 end
3348 end
3349  
3350 function DamageMeters_TogglePermitAutoJoin()
3351 DamageMeters_flags[DMFLAG_permitAutoSyncChanJoin] = not DamageMeters_flags[DMFLAG_permitAutoSyncChanJoin];
3352 if (DamageMeters_flags[DMFLAG_permitAutoSyncChanJoin]) then
3353 DMPrint(DM_MSG_AUTOSYNCJOINON);
3354 else
3355 DMPrint(DM_MSG_AUTOSYNCJOINOFF);
3356 end
3357 end
3358 ]]--
3359  
3360 -----------------------------------------
3361  
3362 function DamageMeters_FrameDropDown_OnLoad()
3363 --DMPrint("this = "..this:GetName());
3364 UIDropDownMenu_Initialize(this, DamageMeters_FrameDropDown_Initialize, "MENU");
3365 end
3366  
3367 function DamageMeters_FrameDropDown_Initialize()
3368  
3369 -- If level 2
3370 if ( UIDROPDOWNMENU_MENU_LEVEL == 2 ) then
3371 -- If this is the sort style menu then create dropdown
3372 if ( UIDROPDOWNMENU_MENU_VALUE == DM_MENU_SORT ) then
3373 local index;
3374 for index = 1,DamageMeters_Sort_MAX do
3375 info = {};
3376 info.text = DamageMeters_Sort_STRING[index];
3377 info.value = index;
3378 info.func = DamageMetersFrame_TitleButton_SetSort;
3379 if ( index == DamageMeters_sort ) then
3380 info.checked = 1;
3381 end
3382 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3383 end
3384 return;
3385 end
3386  
3387 -- If this is the quantity menu then create dropdown
3388 if ( UIDROPDOWNMENU_MENU_VALUE == DM_MENU_VISIBLEQUANTITY ) then
3389 local index;
3390 for index = 1,DamageMeters_Quantity_MAX do
3391 info = {};
3392 info.text = DamageMeters_GetQuantityString(index);
3393 info.value = index;
3394 info.func = DamageMetersFrame_TitleButton_SetQuantity;
3395 if ( index == DamageMeters_quantity ) then
3396 info.checked = 1;
3397 end
3398 info.swatchFunc = DamageMeters_SetQuantityColor;
3399 -- Set the swatch color info
3400 info.hasColorSwatch = 1;
3401 info.r = DamageMeters_quantityColor[index][1];
3402 info.g = DamageMeters_quantityColor[index][2];
3403 info.b = DamageMeters_quantityColor[index][3];
3404 info.opacity = 1.0 - DamageMeters_quantityColor[index][4];
3405 info.cancelFunc = DamageMeters_CancelQuantityColorSettings;
3406 info.hasOpacity = 1;
3407 info.opacityFunc = DamageMeters_SetQuantityColorOpacity;
3408 --info.keepShownOnClick = 1;
3409 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3410 end
3411  
3412 -- Spacer
3413 info = {};
3414 info.disabled = 1;
3415 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3416  
3417 -- Show fight data as PS.
3418 info = {};
3419 info.text = DM_MENU_SHOWFIGHTASPS;
3420 if (DamageMeters_flags[DMFLAG_showFightAsPS]) then
3421 info.checked = 1;
3422 end
3423 info.func = DamageMeters_ToggleShowFightAsPS;
3424 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3425  
3426 -- Spacer
3427 info = {};
3428 info.disabled = 1;
3429 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3430  
3431 -- Set for all
3432 info = {};
3433 info.text = DM_MENU_SETCOLORFORALL;
3434 info.func = DamageMeters_SetQuantityColorAllOnClick;
3435 info.swatchFunc = DamageMeters_SetQuantityColorAll;
3436 info.hasColorSwatch = 1;
3437 info.r = DamageMeters_quantityColor[DamageMeters_quantity][1];
3438 info.g = DamageMeters_quantityColor[DamageMeters_quantity][2];
3439 info.b = DamageMeters_quantityColor[DamageMeters_quantity][3];
3440 info.hasOpacity = 1;
3441 info.opacity = 1.0 - DamageMeters_quantityColor[DamageMeters_quantity][4];
3442 info.opacityFunc = DamageMeters_SetQuantityColorOpacityAll;
3443 info.notCheckable = 1;
3444 info.keepShownOnClick = 1;
3445 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3446  
3447 -- Default Colors
3448 info = {};
3449 info.text = DM_MENU_DEFAULTCOLORS;
3450 info.notCheckable = 1;
3451 info.func = DamageMeters_SetDefaultColors;
3452 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3453  
3454 -- Spacer
3455 info = {};
3456 info.disabled = 1;
3457 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3458  
3459 -- Show Total
3460 info = {};
3461 info.text = DM_MENU_SHOWTOTAL;
3462 if (DamageMeters_flags[DMFLAG_showTotal]) then
3463 info.checked = 1;
3464 end
3465 info.keepShownOnClick = 1;
3466 info.value = DMFLAG_showTotal;
3467 info.func = DamageMetersMenu_ToggleVariableAndRegen;
3468 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3469  
3470 return;
3471 end
3472  
3473 if ( UIDROPDOWNMENU_MENU_VALUE == DM_MENU_QUANTITYFILTER ) then
3474 local index;
3475 for index = 1, DamageMeters_Quantity_MAX do
3476 info = {};
3477 info.text = DamageMeters_GetQuantityString(index);
3478 info.value = index;
3479 info.func = DamageMetersFrame_TitleButton_ToggleCycleQuantity;
3480 info.keepShownOnClick = 1;
3481 if ( DamageMeters_quantitiesFilter[index] ) then
3482 info.checked = 1;
3483 end
3484 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3485 end
3486  
3487 -- Spacer
3488 info = {};
3489 info.disabled = 1;
3490 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3491  
3492 -- Apply filter to auto-cycle
3493 info = {};
3494 info.text = DM_MENU_APPLYFILTERTOAUTOCYCLING;
3495 if (DamageMeters_flags[DMFLAG_applyFilterToAutoCycle]) then
3496 info.checked = 1;
3497 end
3498 info.keepShownOnClick = 1;
3499 info.value = DMFLAG_applyFilterToAutoCycle;
3500 info.func = DamageMetersMenu_ToggleVariable;
3501 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3502  
3503 -- Apply filter to manual-cycle
3504 info = {};
3505 info.text = DM_MENU_APPLYFILTERTOMANUALCYCLING;
3506 if (DamageMeters_flags[DMFLAG_applyFilterToManualCycle]) then
3507 info.checked = 1;
3508 end
3509 info.keepShownOnClick = 1;
3510 info.value = DMFLAG_applyFilterToManualCycle;
3511 info.func = DamageMetersMenu_ToggleVariable;
3512 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3513  
3514 -- Spacer
3515 info = {};
3516 info.disabled = 1;
3517 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3518  
3519 -- Cycle text
3520 info = {};
3521 info.text = DM_MENU_QUANTCYCLE;
3522 if (DamageMeters_flags[DMFLAG_cycleVisibleQuantity]) then
3523 info.checked = 1;
3524 end
3525 info.keepShownOnClick = 1;
3526 info.func = DamageMeters_ToggleCycleVisibleQuant;
3527 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3528  
3529 return;
3530 end
3531  
3532 --[[
3533 -- If this is the color scheme menu then create dropdown
3534 if ( UIDROPDOWNMENU_MENU_VALUE == DM_MENU_COLORSCHEME ) then
3535 local index;
3536 for index = 1, DamageMeters_colorScheme_MAX do
3537 info = {};
3538 info.text = DamageMeters_colorScheme_STRING[index];
3539 info.value = index;
3540 info.func = DamageMetersFrame_TitleButton_SetColorScheme;
3541 if ( index == DamageMeters_colorScheme ) then
3542 info.checked = 1;
3543 end
3544 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3545 end
3546 return;
3547 end
3548 ]]--
3549  
3550 local barCounts = {3,5,10,15,20,25,30,35,40};
3551  
3552 -- If this is the Bar count menu then create dropdown
3553 if ( UIDROPDOWNMENU_MENU_VALUE == DM_MENU_BARCOUNT ) then
3554 local index;
3555 for index = 1, table.getn(barCounts) do
3556 info = {};
3557 info.text = barCounts[index];
3558 info.value = barCounts[index];
3559 info.func = DamageMetersFrame_TitleButton_SetCount;
3560 if ( info.value == DamageMeters_barCount ) then
3561 info.checked = 1;
3562 end
3563 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3564 end
3565  
3566 -- Spacer
3567 info = {};
3568 info.disabled = 1;
3569 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3570  
3571 -- Show Max
3572 info = {};
3573 info.text = DM_MENU_SHOWMAX;
3574 if (DMVIEW_MAX == DamageMeters_viewMode) then
3575 info.checked = 1;
3576 end
3577 info.func = DamageMeters_ToggleMaxBars;
3578 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3579  
3580 return;
3581 end
3582  
3583 -- If this is the Bar auto count menu then create dropdown
3584 if ( UIDROPDOWNMENU_MENU_VALUE == DM_MENU_AUTOCOUNTLIMIT ) then
3585 local index;
3586 for index = 1, table.getn(barCounts) do
3587 info = {};
3588 info.text = barCounts[index];
3589 info.value = barCounts[index];
3590 info.func = DamageMetersFrame_TitleButton_SetAutoCount;
3591 if ( info.value == DamageMeters_autoCountLimit ) then
3592 info.checked = 1;
3593 end
3594 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3595 end
3596 return;
3597 end
3598  
3599 -- If this is the Bar auto count menu then create dropdown
3600 if ( UIDROPDOWNMENU_MENU_VALUE == DM_MENU_REPORT ) then
3601 local reportTypes = {"f", "c", "s", "p", "r", "g", "o"};
3602 local index;
3603 for index = 1, table.getn(reportTypes) do
3604 info = {};
3605 info.text = DM_MENU_REPORTNAMES[index];
3606 info.value = reportTypes[index];
3607 info.func = DamageMetersFrame_TitleButton_Report;
3608 info.notCheckable = 1;
3609 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3610 end
3611  
3612 info = {};
3613 info.text = DM_MENU_REPORTCHANNEL;
3614 info.notCheckable = 1;
3615 info.func = function() StaticPopup_Show("DM_REPORT_CHANNEL") end;
3616 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3617  
3618 info = {};
3619 info.text = DM_MENU_REPORTWHISPER;
3620 info.notCheckable = 1;
3621 info.func = function() StaticPopup_Show("DM_REPORT_WHISPER") end;
3622 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3623  
3624 -- Spacer
3625 info = {};
3626 info.disabled = 1;
3627 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3628  
3629 -- Reset Pos
3630 info = {};
3631 info.text = DM_MENU_HELP;
3632 info.notCheckable = 1;
3633 info.func = DamageMeters_ShowReportHelp;
3634 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3635  
3636 return;
3637 end
3638  
3639 if ( UIDROPDOWNMENU_MENU_VALUE == DM_MENU_MEMORY ) then
3640 -- Session
3641 if (DamageMeters_tableInfo[DMT_SAVED].sessionLabel) then
3642 info = {};
3643 info.isTitle = true;
3644 info.notCheckable = 1;
3645 info.text = DM_MENU_SAVEDSESSION..DamageMeters_tableInfo[DMT_SAVED].sessionLabel.." "..DamageMeters_tableInfo[DMT_SAVED].sessionIndex;
3646 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3647 end
3648  
3649 -- Save
3650 info = {};
3651 info.text = DM_MENU_SAVE;
3652 info.notCheckable = 1;
3653 info.func = DamageMeters_Save;
3654 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3655  
3656 -- Clear
3657 info = {};
3658 info.text = DM_MENU_CLEAR;
3659 info.notCheckable = 1;
3660 info.func = DamageMeters_MemClear;
3661 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3662  
3663 -- Restore
3664 info = {};
3665 info.text = DM_MENU_RESTORE;
3666 info.notCheckable = 1;
3667 info.func = DamageMeters_Restore;
3668 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3669  
3670 -- Swap
3671 info = {};
3672 info.text = DM_MENU_SWAP;
3673 info.notCheckable = 1;
3674 info.func = DamageMeters_Swap;
3675 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3676  
3677 -- Accumulate
3678 info = {};
3679 info.text = DM_MENU_ACCUMULATEINMEMORY;
3680 if (DamageMeters_flags[DMFLAG_accumulateToMemory]) then
3681 info.checked = 1;
3682 end
3683 info.keepShownOnClick = 1;
3684 info.func = DamageMeters_ToggleAccumulateToMemory;
3685 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3686  
3687 return;
3688 end
3689  
3690 if ( UIDROPDOWNMENU_MENU_VALUE == DM_MENU_POSITION ) then
3691 -- Reset Pos
3692 info = {};
3693 info.text = DM_MENU_RESETPOS;
3694 info.notCheckable = 1;
3695 info.func = DamageMeters_ResetPos;
3696 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3697  
3698 -- Lock Pos
3699 info = {};
3700 if (DamageMeters_flags[DMFLAG_positionLocked]) then
3701 info.text = DM_MENU_UNLOCKPOS;
3702 else
3703 info.text = DM_MENU_LOCKPOS;
3704 end
3705 info.notCheckable = 1;
3706 info.func = DamageMeters_ToggleLockPos;
3707 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3708  
3709 -- Resize left
3710 info = {};
3711 info.text = DM_MENU_RESIZELEFT;
3712 info.value = DamageMeters_Text_RANK;
3713 if (DamageMeters_flags[DMFLAG_resizeLeft]) then
3714 info.checked = 1;
3715 end
3716 info.keepShownOnClick = 1;
3717 info.value = DMFLAG_resizeLeft;
3718 info.func = DamageMetersMenu_ToggleVariable;
3719 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3720  
3721 -- Resize left
3722 info = {};
3723 info.text = DM_MENU_RESIZEUP;
3724 info.value = DamageMeters_Text_RANK;
3725 if (DamageMeters_flags[DMFLAG_resizeUp]) then
3726 info.checked = 1;
3727 end
3728 info.keepShownOnClick = 1;
3729 info.value = DMFLAG_resizeUp;
3730 info.func = DamageMetersMenu_ToggleVariable;
3731 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3732  
3733 return;
3734 end
3735  
3736 if ( UIDROPDOWNMENU_MENU_VALUE == DM_MENU_TEXT ) then
3737 local optionStrings =
3738 {
3739 "RANK",
3740 "NAME",
3741 "TOTALPERCENTAGE",
3742 "LEADERPERCENTAGE",
3743 "VALUE",
3744 "DELTA",
3745 };
3746  
3747 for index, optionString in optionStrings do
3748 info = {};
3749 info.text = getglobal("DM_MENU_TEXT_"..optionString);
3750 info.value = getglobal("DamageMeters_Text_"..optionString);
3751 if (DamageMeters_textOptions[info.value]) then
3752 info.checked = 1;
3753 end
3754 info.keepShownOnClick = 1;
3755 info.func = DamageMeters_ToggleTextOption;
3756 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3757 end
3758  
3759 -- Spacer
3760 info = {};
3761 info.disabled = 1;
3762 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3763  
3764 -- Cycle text
3765 info = {};
3766 info.text = DM_MENU_TEXTCYCLE;
3767 if (DamageMeters_textState > 0) then
3768 info.checked = 1;
3769 end
3770 info.func = DamageMeters_ToggleTextState;
3771 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3772  
3773 -- Left Justify Text
3774 info = {};
3775 info.text = DM_MENU_LEFTJUSTIFYTEXT;
3776 if (DamageMeters_flags[DMFLAG_justifyTextLeft]) then
3777 info.checked = 1;
3778 end
3779 info.value = DMFLAG_justifyTextLeft;
3780 info.func = DamageMetersMenu_ToggleVariableAndRegen;
3781 info.keepShownOnClick = 1;
3782 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3783  
3784 return;
3785 end
3786  
3787 if ( UIDROPDOWNMENU_MENU_VALUE == DM_MENU_EVENTDATA ) then
3788  
3789 -- No Data
3790 info = {};
3791 info.text = DM_MENU_EVENTDATA_NONE;
3792 if (DamageMeters_eventDataLevel == DamageMeters_EventData_NONE) then
3793 info.checked = 1;
3794 end
3795 info.value = DamageMeters_EventData_NONE;
3796 info.func = DamageMeters_ChangeEventDataLevel;
3797 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3798  
3799 -- Self Data
3800 info = {};
3801 info.text = DM_MENU_EVENTDATA_PLAYER;
3802 if (DamageMeters_eventDataLevel == DamageMeters_EventData_SELF) then
3803 info.checked = 1;
3804 end
3805 info.value = DamageMeters_EventData_SELF;
3806 info.func = DamageMeters_ChangeEventDataLevel;
3807 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3808  
3809 -- All Data
3810 info = {};
3811 info.text = DM_MENU_EVENTDATA_ALL;
3812 if (DamageMeters_eventDataLevel == DamageMeters_EventData_ALL) then
3813 info.checked = 1;
3814 end
3815 info.value = DamageMeters_EventData_ALL;
3816 info.func = DamageMeters_ChangeEventDataLevel;
3817 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3818  
3819 -- Spacer
3820 info = {};
3821 info.disabled = 1;
3822 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3823  
3824 -- Tooltip Default
3825 info = {};
3826 info.text = DM_MENU_SHOWEVENTDATATOOLTIP;
3827 if (DamageMeters_flags[DMFLAG_showEventTooltipsFirst]) then
3828 info.checked = 1;
3829 end
3830 info.keepShownOnClick = 1;
3831 info.value = DMFLAG_showEventTooltipsFirst;
3832 info.func = DamageMetersMenu_ToggleVariable;
3833 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3834  
3835 return;
3836 end
3837  
3838 if ( UIDROPDOWNMENU_MENU_VALUE == DM_MENU_SYNC ) then
3839 --[[
3840 -- Title
3841 info = {};
3842 info.isTitle = true;
3843 info.notCheckable = 1;
3844 if (DamageMeters_syncChannel == "") then
3845 info.text = DM_MENU_NOSYNCCHAN;
3846 else
3847 info.text = DM_MENU_SYNCCHAN..DamageMeters_syncChannel;
3848 end
3849 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3850 ]]--
3851 -- Session
3852 if (DamageMeters_tableInfo[DMT_ACTIVE].sessionLabel) then
3853 info = {};
3854 info.isTitle = true;
3855 info.notCheckable = 1;
3856 info.text = DM_MENU_SESSION..DamageMeters_tableInfo[DMT_ACTIVE].sessionLabel.." "..DamageMeters_tableInfo[DMT_ACTIVE].sessionIndex;
3857 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3858 end
3859  
3860 info = {};
3861 info.text = DM_MENU_STARTNEWSESSION;
3862 info.notCheckable = 1;
3863 info.func = function() StaticPopup_Show("DM_START_NEW_SESSION") end;
3864 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3865  
3866 info = {};
3867 info.text = DM_MENU_SYNCGROUPDATA;
3868 info.notCheckable = 1;
3869 info.func = DamageMeters_Sync;
3870 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3871  
3872 info = {};
3873 info.text = DM_MENU_SYNCREADY;
3874 info.notCheckable = 1;
3875 info.func = DamageMeters_SyncReady;
3876 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3877  
3878 info = {};
3879 info.text = DM_MENU_SYNCPAUSE;
3880 info.notCheckable = 1;
3881 info.func = DamageMeters_SyncPause;
3882 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3883  
3884 -- Spacer
3885 info = {};
3886 info.disabled = 1;
3887 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3888  
3889 info = {};
3890 info.text = DM_MENU_SYNCCLEAR;
3891 info.notCheckable = 1;
3892 info.func = DamageMeters_SyncClear;
3893 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3894  
3895 --[[
3896 -- Title 2
3897 info = {};
3898 info.isTitle = true;
3899 info.notCheckable = 1;
3900 info.text = DM_MENU_JOINSYNCCHAN;
3901 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3902  
3903 info = {};
3904 info.text = DM_MENU_SYNCLEAVECHAN;
3905 info.notCheckable = 1;
3906 info.func = DamageMeters_SyncLeaveChan;
3907 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3908  
3909 info = {};
3910 info.text = DM_MENU_SYNCBROADCASTCHAN;
3911 info.notCheckable = 1;
3912 info.func = DamageMeters_SyncBroadcastChan;
3913 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3914 ]]--
3915  
3916 -- Spacer
3917 info = {};
3918 info.disabled = 1;
3919 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3920  
3921 --[[
3922 info = {};
3923 info.text = DM_MENU_PERMITSYNCAUTOJOIN;
3924 if (DamageMeters_flags[DMFLAG_permitAutoSyncChanJoin]) then
3925 info.checked = 1;
3926 end
3927 info.func = DamageMeters_TogglePermitAutoJoin;
3928 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3929  
3930 info = {};
3931 info.text = DM_MENU_CLEARONAUTOJOIN;
3932 if (DamageMeters_flags[DMFLAG_autoClearOnChannelJoin]) then
3933 info.checked = 1;
3934 end
3935 info.value = DMFLAG_autoClearOnChannelJoin;
3936 info.func = DamageMetersMenu_ToggleVariable;
3937 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3938 ]]--
3939 info = {};
3940 info.text = DM_MENU_ENABLEDMM;
3941 if (DamageMeters_flags[DMFLAG_enableDMM]) then
3942 info.checked = 1;
3943 end
3944 info.keepShownOnClick = 1;
3945 info.value = DMFLAG_enableDMM;
3946 info.func = DamageMetersMenu_ToggleVariable;
3947 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3948 --[[
3949 info = {};
3950 info.text = DM_MENU_ONLYSYNCWITHGROUP;
3951 if (DamageMeters_flags[DMFLAG_onlySyncWithGroup]) then
3952 info.checked = 1;
3953 end
3954 info.func = DamageMeters_ToggleOnlySyncWithGroup;
3955 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3956 ]]--
3957 info = {};
3958 info.text = DM_MENU_AUTOSYNC;
3959 if (DamageMeters_flags[DMFLAG_autoSync]) then
3960 info.checked = 1;
3961 end
3962 info.keepShownOnClick = 1;
3963 info.value = DMFLAG_autoSync;
3964 info.func = DamageMetersMenu_ToggleVariable;
3965 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3966  
3967 -- Spacer
3968 info = {};
3969 info.disabled = 1;
3970 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3971  
3972 -- Help
3973 info = {};
3974 info.text = DM_MENU_HELP;
3975 info.notCheckable = 1;
3976 info.func = DamageMeters_ShowSyncHelp;
3977 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3978  
3979 return;
3980 end
3981  
3982 if ( UIDROPDOWNMENU_MENU_VALUE == "Debug" ) then
3983 local varName, value;
3984 for varName, value in DamageMeters_debug4 do
3985 info = {};
3986 info.text = varName;
3987 if (value) then
3988 info.checked = 1;
3989 end
3990 info.keepShownOnClick = 1;
3991 info.value = varName;
3992 info.func = DamageMeters_ToggleDebugVariable;
3993 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
3994 end
3995  
3996 return;
3997 end
3998  
3999 if ( UIDROPDOWNMENU_MENU_VALUE == "Debug Bypass" ) then
4000 for index, yesno in DM_Bypass do
4001 info = {};
4002 info.text = index;
4003 if (yesno) then
4004 info.checked = 1;
4005 end
4006 info.keepShownOnClick = 1;
4007 info.value = index;
4008 info.func = DamageMeters_ToggleBypass;
4009 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
4010 end
4011 end
4012  
4013 if ( UIDROPDOWNMENU_MENU_VALUE == DM_MENU_GENERAL ) then
4014 -- Player Always Visible
4015 info = {};
4016 info.text = DM_MENU_PLAYERALWAYSVISIBLE;
4017 if (DamageMeters_flags[DMFLAG_playerAlwaysVisible]) then
4018 info.checked = 1
4019 end
4020 info.keepShownOnClick = 1;
4021 info.value = DMFLAG_playerAlwaysVisible;
4022 info.func = DamageMetersMenu_ToggleVariableAndRegen;
4023 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
4024  
4025 -- visible in party
4026 info = {};
4027 info.text = DM_MENU_VISINPARTY;
4028 if (DamageMeters_flags[DMFLAG_visibleOnlyInParty]) then
4029 info.checked = 1;
4030 end
4031 info.keepShownOnClick = 1;
4032 info.func = DamageMeters_ToggleVisibleInParty;
4033 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
4034  
4035 -- Group members only
4036 info = {};
4037 info.text = DM_MENU_GROUPMEMBERSONLY;
4038 if (DamageMeters_flags[DMFLAG_groupMembersOnly]) then
4039 info.checked = 1;
4040 end
4041 info.keepShownOnClick = 1;
4042 info.value = DMFLAG_groupMembersOnly;
4043 info.func = DamageMetersMenu_ToggleVariable;
4044 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
4045  
4046 -- Add pet to player
4047 info = {};
4048 info.text = DM_MENU_ADDPETTOPLAYER;
4049 if (DamageMeters_flags[DMFLAG_addPetToPlayer]) then
4050 info.checked = 1;
4051 end
4052 info.keepShownOnClick = 1;
4053 info.func = DamageMeters_ToggleAddPetToPlayer;
4054 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
4055  
4056 -- Reset on combat
4057 info = {};
4058 info.text = DM_MENU_RESETONCOMBATSTARTS;
4059 if (DamageMeters_flags[DMFLAG_resetWhenCombatStarts]) then
4060 info.checked = 1;
4061 end
4062 info.keepShownOnClick = 1;
4063 info.func = DamageMeters_ToggleResetWhenCombatStarts;
4064 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
4065  
4066 -- Group DPS Mode
4067 info = {};
4068 info.text = DM_MENU_GROUPDPSMODE;
4069 if (DamageMeters_flags[DMFLAG_groupDPSMode]) then
4070 info.checked = 1
4071 end
4072 info.keepShownOnClick = 1;
4073 info.value = DMFLAG_groupDPSMode;
4074 info.func = DamageMetersMenu_ToggleVariable;
4075 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
4076  
4077 -- Constant Update
4078 info = {};
4079 info.text = DM_MENU_CONSTANTVISUALUPDATE;
4080 if (DamageMeters_flags[DMFLAG_constantVisualUpdate]) then
4081 info.checked = 1
4082 end
4083 info.keepShownOnClick = 1;
4084 info.value = DMFLAG_constantVisualUpdate;
4085 info.func = DamageMetersMenu_ToggleVariable;
4086 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
4087  
4088 -- Clear when joining party.
4089 info = {};
4090 info.text = DM_MENU_CLEARWHENJOINPARTY;
4091 if (DamageMeters_flags[DMFLAG_clearWhenJoinParty]) then
4092 info.checked = 1
4093 end
4094 info.keepShownOnClick = 1;
4095 info.value = DMFLAG_clearWhenJoinParty;
4096 info.func = DamageMetersMenu_ToggleVariable;
4097 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
4098  
4099 -- Spacer
4100 info = {};
4101 info.disabled = 1;
4102 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
4103  
4104 -- Restore defaults
4105 info = {};
4106 info.text = DM_MENU_RESTOREDEFAULTOPTIONS;
4107 info.notCheckable = 1;
4108 info.func = DamageMeters_DoRestoreDefaultOptions;
4109 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
4110  
4111 return;
4112 end
4113  
4114 DamageMetersPlugin_DropDownInitialize();
4115 return;
4116 end
4117  
4118 -- Title
4119 info = {};
4120 info.isTitle = true;
4121 info.text = "DamageMeters "..DamageMeters_VERSIONSTRING;
4122 UIDropDownMenu_AddButton(info);
4123  
4124 --[[
4125 -- Boss mode.
4126 if (DamageMeters_bInBossMode) then
4127 info = {};
4128 info.isTitle = true;
4129  
4130 info.text = "* In Boss Mode *";
4131 UIDropDownMenu_AddButton(info);
4132 end
4133 ]]--
4134  
4135 -- Hide
4136 info = {};
4137 if (DamageMetersFrame:IsVisible()) then
4138 info.text = DM_MENU_HIDE;
4139 else
4140 info.text = DM_MENU_SHOW;
4141 end
4142 info.notCheckable = 1;
4143 info.func = DamageMetersBar_ToggleShow;
4144 -- Just a test. These fields are only used if noob tooltips are enabled.
4145 --info.tooltipTitle = info.text;
4146 --info.tooltipText = "Hello!";
4147 UIDropDownMenu_AddButton(info);
4148  
4149 -- Clear
4150 info = {};
4151 info.text = DM_MENU_CLEAR;
4152 info.notCheckable = 1;
4153 info.func = DamageMeters_Clear;
4154 UIDropDownMenu_AddButton(info);
4155  
4156 -- Pause
4157 info = {};
4158 info.text = DM_MENU_PAUSE;
4159 if (DM_Pause_Not ~= DamageMeters_pauseState) then
4160 info.checked = 1;
4161 end
4162 info.keepShownOnClick = 1;
4163 info.func = DamageMeters_TogglePause;
4164 UIDropDownMenu_AddButton(info);
4165  
4166 -- Minimize
4167 info = {};
4168 info.text = DM_MENU_MINIMIZE;
4169 if (DMVIEW_MIN == DamageMeters_viewMode) then
4170 info.checked = 1;
4171 end
4172 --info.keepShownOnClick = 1;
4173 info.func = DamageMeters_ToggleMiniMode;
4174 UIDropDownMenu_AddButton(info);
4175  
4176 -- Spacer
4177 info = {};
4178 info.disabled = 1;
4179 UIDropDownMenu_AddButton(info);
4180  
4181 -- General
4182 info = {};
4183 info.text = DM_MENU_GENERAL;
4184 --info.notClickable = 1;
4185 info.hasArrow = 1;
4186 info.func = nil;
4187 info.notCheckable = 1;
4188 UIDropDownMenu_AddButton(info);
4189  
4190 -- Report
4191 info = {};
4192 info.text = DM_MENU_REPORT;
4193 --info.notClickable = 1;
4194 info.hasArrow = 1;
4195 info.func = nil;
4196 info.notCheckable = 1;
4197 UIDropDownMenu_AddButton(info);
4198  
4199 -- Position
4200 info = {};
4201 info.text = DM_MENU_POSITION;
4202 --info.notClickable = 1;
4203 info.hasArrow = 1;
4204 info.func = nil;
4205 info.notCheckable = 1;
4206 UIDropDownMenu_AddButton(info);
4207  
4208 -- Count
4209 info = {};
4210 info.text = DM_MENU_BARCOUNT;
4211 --info.notClickable = 1;
4212 info.hasArrow = 1;
4213 info.func = nil;
4214 info.notCheckable = 1;
4215 UIDropDownMenu_AddButton(info);
4216  
4217 -- AutoCount
4218 info = {};
4219 info.text = DM_MENU_AUTOCOUNTLIMIT;
4220 --info.notClickable = 1;
4221 info.hasArrow = 1;
4222 info.func = nil;
4223 info.notCheckable = 1;
4224 UIDropDownMenu_AddButton(info);
4225  
4226 -- Sort
4227 info = {};
4228 info.text = DM_MENU_SORT;
4229 --info.notClickable = 1;
4230 info.hasArrow = 1;
4231 info.func = nil;
4232 info.notCheckable = 1;
4233 UIDropDownMenu_AddButton(info);
4234  
4235 -- Quantity
4236 info = {};
4237 info.text = DM_MENU_VISIBLEQUANTITY;
4238 --info.notClickable = 1;
4239 info.hasArrow = 1;
4240 info.func = nil;
4241 info.notCheckable = 1;
4242 UIDropDownMenu_AddButton(info);
4243  
4244 -- Quantity Filter
4245 info = {};
4246 info.text = DM_MENU_QUANTITYFILTER;
4247 --info.notClickable = 1;
4248 info.hasArrow = 1;
4249 info.func = nil;
4250 info.notCheckable = 1;
4251 UIDropDownMenu_AddButton(info);
4252  
4253 --[[
4254 -- Bar Colors
4255 info = {};
4256 info.text = DM_MENU_COLORSCHEME;
4257 --info.notClickable = 1;
4258 info.hasArrow = 1;
4259 info.func = nil;
4260 info.notCheckable = 1;
4261 UIDropDownMenu_AddButton(info);
4262 ]]--
4263  
4264 -- Bar Colors
4265 info = {};
4266 info.text = DM_MENU_MEMORY;
4267 --info.notClickable = 1;
4268 info.hasArrow = 1;
4269 info.func = nil;
4270 info.notCheckable = 1;
4271 UIDropDownMenu_AddButton(info);
4272  
4273 -- text optionss
4274 info = {};
4275 info.text = DM_MENU_TEXT;
4276 --info.notClickable = 1;
4277 info.hasArrow = 1;
4278 info.func = nil;
4279 info.notCheckable = 1;
4280 UIDropDownMenu_AddButton(info);
4281  
4282 -- Event Options
4283 info = {};
4284 info.text = DM_MENU_EVENTDATA;
4285 --info.notClickable = 1;
4286 info.hasArrow = 1;
4287 info.func = nil;
4288 info.notCheckable = 1;
4289 UIDropDownMenu_AddButton(info);
4290  
4291 -- Sync Options
4292 info = {};
4293 info.text = DM_MENU_SYNC;
4294 --info.notClickable = 1;
4295 info.hasArrow = 1;
4296 info.func = nil;
4297 info.notCheckable = 1;
4298 UIDropDownMenu_AddButton(info);
4299  
4300 if (DamageMeters_debugEnabled) then
4301 -- Debug Menu
4302 info = {};
4303 info.text = "Debug";
4304 --info.notClickable = 1;
4305 info.hasArrow = 1;
4306 info.func = nil;
4307 info.notCheckable = 1;
4308 UIDropDownMenu_AddButton(info);
4309  
4310 -- Bypass Debug Menu
4311 info = {};
4312 info.text = "Debug Bypass";
4313 --info.notClickable = 1;
4314 info.hasArrow = 1;
4315 info.func = nil;
4316 info.notCheckable = 1;
4317 UIDropDownMenu_AddButton(info);
4318 end
4319  
4320 DamageMetersPlugin_DropDownInitialize();
4321 end
4322  
4323 --------------------------------------------
4324  
4325 function DamageMetersFrame_TitleButton_OnLoad()
4326 DamageMeters_TitleButtonText:SetText("Damage Meters");
4327 -- Color tables not initialized yet.
4328 --local color = DamageMeters_quantityColor[DamageMeters_quantity];
4329 --DamageMetersFrame_TitleButton:SetBackdropColor(color[1], color[2], color[3], color[4]);
4330 this:RegisterForClicks("LeftButtonDown", "LeftButtonUp", "RightButtonUp");
4331 end
4332  
4333 function DamageMetersFrame_TitleButton_OnClick()
4334 local button = arg1;
4335  
4336 --DMPrint("DamageMetersFrame_TitleButton_OnClick : "..button);
4337  
4338 if ( button == "LeftButton" ) then
4339 if ( this:GetButtonState() == "PUSHED" ) then
4340 DamageMetersFrame:StopMovingOrSizing();
4341 else
4342 if (not DamageMeters_flags[DMFLAG_positionLocked] and not DamageMetersFrame.isLocked) then
4343 DamageMetersFrame:StartMoving();
4344 end
4345 end
4346 elseif ( button == "RightButton" ) then
4347 DamageMeters_ShowMainMenu();
4348 end
4349 end
4350  
4351 function DamageMeters_ShowMainMenu()
4352 local frame = DamageMetersFrame_TitleButton;
4353 local distance;
4354 distance = ( UIParent:GetWidth() - frame:GetRight() );
4355  
4356 --DMPrint("distance = "..distance);
4357 local menuMoveDist = 250;
4358 if ( distance <= menuMoveDist ) then
4359 local newOffset = distance - menuMoveDist;
4360 --DMPrint("Too close, new offset = "..newOffset);
4361 ToggleDropDownMenu(1, nil, DamageMetersFrameDropDown, "DamageMetersFrameDropDown", newOffset, 0);
4362 else
4363 ToggleDropDownMenu(1, nil, DamageMetersFrameDropDown, "DamageMetersFrameDropDown", 0, 0);
4364 end
4365 end
4366  
4367 function DamageMetersFrame_TitleButton_SetSort()
4368 DamageMeters_SetSort(this.value);
4369 end
4370  
4371 function DamageMetersFrame_TitleButton_SetQuantity()
4372 DamageMeters_flags[DMFLAG_cycleVisibleQuantity] = false;
4373 DamageMeters_SetQuantity(this.value, true);
4374 end
4375  
4376 function DamageMetersFrame_TitleButton_ToggleCycleQuantity()
4377 DamageMeters_quantitiesFilter[this.value] = not DamageMeters_quantitiesFilter[this.value];
4378 end
4379  
4380 function DamageMetersFrame_TitleButton_SetColorScheme()
4381 DamageMeters_SetColorScheme(this.value);
4382 end
4383  
4384 function DamageMetersFrame_TotalButton_OnLoad()
4385 DamageMeters_TotalButtonText:SetText("Damage Meters");
4386 end
4387  
4388 function DamageMeters_ToggleTextOption()
4389 DamageMeters_textOptions[this.value] = not DamageMeters_textOptions[this.value];
4390  
4391 if (DamageMeters_textState > 0) then
4392 -- If we have turned off all text options, make sure we stop cycling.
4393 local option;
4394 for option = 1, DamageMeters_Text_MAX do
4395 if (DamageMeters_textOptions[option]) then
4396 return;
4397 end
4398 end
4399 -- Fell through...turn off cycling.
4400 DMPrintD("Turned off all text options: disabling text cycling.");
4401 DamageMeters_textState = 0;
4402 end
4403 end
4404  
4405 function DamageMeters_ToggleTextState()
4406 if (DamageMeters_textState < 1) then
4407 DamageMeters_textStateStartTime = GetTime();
4408  
4409 -- Set the text state to the first set option.
4410 local nextState;
4411 for nextState = 1, DamageMeters_Text_MAX do
4412 if (DamageMeters_textOptions[nextState]) then
4413 DamageMeters_textState = nextState;
4414 DMPrintD("Setting text state to "..DamageMeters_textState);
4415 return;
4416 end
4417 end
4418  
4419 -- Cycling enabled but no text options turned on: turn on the name option.
4420 DamageMeters_textOptions[DamageMeters_Text_NAME] = true;
4421 DamageMeters_textState = DamageMeters_Text_NAME;
4422 DMPrintD("Setting text state to (and enabling) "..DamageMeters_textState);
4423 else
4424 DamageMeters_textState = 0;
4425 DMPrintD("Setting text state to 0.");
4426 end
4427 end
4428  
4429 function DamageMeters_ToggleCycleVisibleQuant()
4430 if (DamageMeters_flags[DMFLAG_cycleVisibleQuantity]) then
4431 DamageMeters_flags[DMFLAG_cycleVisibleQuantity] = false;
4432 else
4433 DamageMeters_flags[DMFLAG_cycleVisibleQuantity] = true;
4434 DamageMeters_currentQuantStartTime = GetTime();
4435 end
4436 end
4437  
4438 function DamageMeters_CycleQuant(manual, useFilter)
4439 DamageMeters_flags[DMFLAG_cycleVisibleQuantity] = not manual;
4440 local newQuant = DamageMeters_quantity;
4441 repeat
4442 newQuant = newQuant + 1;
4443 if (newQuant > DamageMeters_Quantity_MAX) then
4444 newQuant = 1;
4445 end
4446  
4447 if (newQuant == DamageMeters_quantity) then
4448 newQuant = 1;
4449 DamageMeters_quantitiesFilter[newQuant] = true;
4450 DMPrintD("No quantities selected for cycling, aborting loop.");
4451 end
4452 until ((not useFilter) or DamageMeters_quantitiesFilter[newQuant]);
4453  
4454 DamageMeters_SetQuantity(newQuant, true);
4455 end
4456  
4457 function DamageMeters_CycleQuantBack(manual, useFilter)
4458 DamageMeters_flags[DMFLAG_cycleVisibleQuantity] = not manual;
4459 local newQuant = DamageMeters_quantity;
4460 repeat
4461 newQuant = newQuant - 1;
4462 if (newQuant < 1) then
4463 newQuant = DamageMeters_Quantity_MAX;
4464 end
4465  
4466 if (newQuant == DamageMeters_quantity) then
4467 newQuant = 1;
4468 DamageMeters_quantitiesFilter[newQuant] = true;
4469 DMPrintD("No quantities selected for cycling, aborting loop.");
4470 end
4471 until ((not useFilter) or DamageMeters_quantitiesFilter[newQuant]);
4472  
4473 DamageMeters_SetQuantity(newQuant, true);
4474 end
4475  
4476  
4477 function DamageMeters_ToggleVisibleInParty()
4478 DamageMeters_flags[DMFLAG_visibleOnlyInParty] = not DamageMeters_flags[DMFLAG_visibleOnlyInParty];
4479 DamageMeters_UpdateVisibility(true);
4480 end
4481  
4482 function DamageMeters_ToggleAddPetToPlayer()
4483 DamageMeters_flags[DMFLAG_addPetToPlayer] = not DamageMeters_flags[DMFLAG_addPetToPlayer];
4484 if (DamageMeters_flags[DMFLAG_addPetToPlayer]) then
4485 DMPrint(DM_MSG_ADDINGPETTOPLAYER);
4486 else
4487 DMPrint(DM_MSG_NOTADDINGPETTOPLAYER);
4488 return;
4489 end
4490  
4491 -- This code automatically merges pet information into player's.
4492  
4493 local playerName = UnitName("Player");
4494 local playerIndex = DamageMeters_GetPlayerIndex(playerName);
4495 if (not playerIndex or playerIndex < 1) then
4496 DamageMeters_AddValue(playerName, 0, DM_DOT, DamageMeters_Relation_SELF, DamageMeters_Quantity_DAMAGE, "[Pet]");
4497 playerIndex = DamageMeters_GetPlayerIndex(playerName);
4498 if (not playerIndex or playerIndex < 1) then
4499 DMPrint(DM_ERROR_NOROOMFORPLAYER);
4500 return;
4501 end
4502 end
4503 local target = DamageMeters_tables[DMT_ACTIVE][playerIndex];
4504  
4505 local index;
4506 local tableN = table.getn(DamageMeters_tables[DMT_ACTIVE]);
4507 for index = tableN, 1, -1 do
4508 local playerStruct = DamageMeters_tables[DMT_ACTIVE][index];
4509 if (DamageMeters_Relation_PET == playerStruct.relationship) then
4510 DMPrint(format(DM_MSG_PETMERGE, playerStruct.player));
4511  
4512 local quantIndex;
4513 for quantIndex = 1, DMI_MAX do
4514 target.dmiData[quantIndex].q = target.dmiData[quantIndex].q + playerStruct.dmiData[quantIndex].q;
4515 target.dmiData[quantIndex].hitCount = target.dmiData[quantIndex].hitCount + playerStruct.dmiData[quantIndex].hitCount;
4516 target.dmiData[quantIndex].critCount = target.dmiData[quantIndex].critCount + playerStruct.dmiData[quantIndex].critCount;
4517 end
4518  
4519 target.lastTime = (target.lastTime > playerStruct.lastTime) and target.lastTime or playerStruct.lastTime;
4520  
4521 table.remove(DamageMeters_tables[DMT_ACTIVE], index);
4522 DamageMeters_frameNeedsToBeGenerated = true;
4523 --DMPrintD("Frame dirty: Pet removed.");
4524 end
4525 end
4526 end
4527  
4528 function DamageMetersFrame_TitleButton_SetCount()
4529 DamageMeters_SetCount(this.value);
4530 CloseMenus();
4531 end
4532  
4533 function DamageMetersFrame_TitleButton_SetAutoCount()
4534 DamageMeters_SetAutoCount(this.value);
4535 end
4536  
4537 function DamageMetersFrame_TitleButton_Report()
4538 local command = format("%s%d", this.value, DamageMeters_barCount);
4539 DamageMeters_Report(command);
4540 CloseMenus();
4541 end
4542  
4543 --------------------------------------------
4544  
4545 function DamageMeters_BarDropDown_OnLoad()
4546 UIDropDownMenu_Initialize(this, DamageMeters_BarFrameDropDown_Initialize, "MENU");
4547 end
4548  
4549 function DamageMeters_BarFrameDropDown_Initialize()
4550 DamageMetersTooltip:Hide();
4551  
4552 -- Header
4553 info = {};
4554 if (DamageMeters_clickedBarIndex) then
4555 info.text = DamageMeters_tables[DMT_VISIBLE][DamageMeters_clickedBarIndex].player;
4556 else
4557 info.text = "";
4558 end
4559 info.notClickable = 1;
4560 info.isTitle = 1;
4561 UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
4562  
4563 -- Delete
4564 info = {};
4565 info.text = DM_MENU_DELETE;
4566 info.notCheckable = 1;
4567 info.func = DamageMetersBar_DeleteEntry;
4568 UIDropDownMenu_AddButton(info);
4569  
4570 -- Ban
4571 info = {};
4572 info.text = DM_MENU_BAN;
4573 info.notCheckable = 1;
4574 info.func = DamageMetersBar_BanEntry;
4575 UIDropDownMenu_AddButton(info);
4576  
4577 -- Clear above
4578 info = {};
4579 info.text = DM_MENU_CLEARABOVE;
4580 info.notCheckable = 1;
4581 info.func = DamageMetersBar_ClearAboveEntry;
4582 UIDropDownMenu_AddButton(info);
4583  
4584 -- Clear below
4585 info = {};
4586 info.text = DM_MENU_CLEARBELOW;
4587 info.notCheckable = 1;
4588 info.func = DamageMetersBar_ClearBelowEntry;
4589 UIDropDownMenu_AddButton(info);
4590  
4591 -- Event Data
4592 info = {};
4593 info.text = DM_MENU_PLAYERREPORT;
4594 info.notCheckable = 1;
4595 info.func = DamageMetersBar_DoPlayerReport;
4596 UIDropDownMenu_AddButton(info);
4597  
4598 -- Event Data
4599 info = {};
4600 info.text = DM_MENU_EVENTREPORT;
4601 info.notCheckable = 1;
4602 info.func = DamageMetersBar_DumpPlayerEvents;
4603 UIDropDownMenu_AddButton(info);
4604  
4605 -- Spacer
4606 info = {};
4607 info.disabled = 1;
4608 UIDropDownMenu_AddButton(info);
4609  
4610 -- Clear banned
4611 info = {};
4612 info.text = DM_MENU_CLEARBANNED;
4613 info.notCheckable = 1;
4614 info.func = DamageMeters_ClearBanned;
4615 UIDropDownMenu_AddButton(info);
4616 end
4617  
4618 function DamageMetersBar_DeleteEntry()
4619 --DMPrint("DamageMetersBar_DeleteEntry "..this:GetName());
4620  
4621 DamageMeters_DoDelete(DamageMeters_clickedBarIndex);
4622 end
4623  
4624 function DamageMetersBar_BanEntry()
4625 --DMPrint("DamageMetersBar_BanEntry "..this:GetID());
4626 DamageMeters_DoBan(DamageMeters_clickedBarIndex);
4627 DamageMeters_clickedBarIndex = nil;
4628 end
4629  
4630 function DamageMetersBar_ClearAboveEntry()
4631 --DMPrint("DamageMetersBar_ClearAboveEntry "..this:GetID());
4632  
4633 local index;
4634 for index = 1, (DamageMeters_clickedBarIndex - 1) do
4635 table.remove(DamageMeters_tables[DMT_VISIBLE], 1);
4636 end
4637  
4638 DamageMeters_frameNeedsToBeGenerated = true;
4639 DMPrintD("Frame dirty: ClearAboveEntry.");
4640 DamageMeters_clickedBarIndex = nil;
4641 end
4642  
4643 function DamageMetersBar_ClearBelowEntry()
4644 --DMPrint("DamageMetersBar_ClearBelowEntry");
4645 DamageMeters_Clear(DamageMeters_clickedBarIndex);
4646 DamageMeters_clickedBarIndex = nil;
4647 end
4648  
4649 function DamageMeters_DoDelete(index)
4650 table.remove(DamageMeters_tables[DMT_VISIBLE], index);
4651 DamageMeters_frameNeedsToBeGenerated = true;
4652 DamageMeters_clickedBarIndex = nil;
4653 end
4654  
4655 function DamageMeters_DoBan(index)
4656 if (index <= 0 or index > table.getn(DamageMeters_tables[DMT_VISIBLE])) then
4657 DMPrint(DM_ERROR_INVALIDARG);
4658 return;
4659 end
4660  
4661 DamageMeters_bannedTable[DamageMeters_tables[DMT_VISIBLE][index].player] = 1;
4662 DamageMeters_DoDelete(index);
4663 end
4664  
4665 function DamageMeters_ListBanned()
4666 local index, name, unused;
4667 index = 1;
4668 DMPrint(DM_MSG_LISTBANNED);
4669 for name, unused in DamageMeters_bannedTable do
4670 DMPrint(index..": "..name);
4671 index = index + 1;
4672 end
4673 end
4674  
4675 function DamageMeters_ClearBanned()
4676 DMPrint(DM_MSG_CLEARBANNED);
4677 DamageMeters_bannedTable = {};
4678 end
4679  
4680 function DamageMeters_IsBanned(newPlayer)
4681 local name, unused;
4682 for name, unused in DamageMeters_bannedTable do
4683 if (name == newPlayer) then
4684 return true;
4685 end
4686 end
4687  
4688 return false;
4689 end
4690  
4691 function DamageMetersBar_ToggleShow()
4692 if (DamageMetersFrame:IsVisible()) then
4693 DMPrint(DM_MSG_HOWTOSHOW);
4694 end
4695  
4696 DamageMeters_ToggleShow();
4697 end
4698  
4699 function DamageMeters_Sync(msg)
4700  
4701 if (not DamageMeters_CheckSyncChan()) then
4702 return;
4703 end
4704  
4705 DamageMeters_syncEvents = false;
4706 local delaySync = false;
4707 if (type(msg) == "string") then
4708 for optionLetter, optionValue in string.gfind(msg, "(%a)(%d*)") do
4709 if (optionLetter == "d") then
4710 --DMPrintD("d found");
4711 if (optionValue) then
4712 --DMPrintD("optionValue = "..optionValue);
4713 local timeUntilSync = tonumber(optionValue);
4714 if (timeUntilSync and timeUntilSync > 0) then
4715 DamageMeters_syncStartTime = GetTime() + timeUntilSync;
4716 DamageMeters_SendSyncMsg(string.format("<Sync incoming in %d seconds.>", timeUntilSync));
4717 delaySync = true;
4718 end
4719 end
4720 elseif (optionLetter == "e") then
4721 --DMPrintD("e found");
4722 DamageMeters_syncEvents = true;
4723 end
4724 end
4725 end
4726  
4727 if (not delaySync) then
4728 DamageMeters_DoSync();
4729 end
4730 end
4731  
4732 function DamageMeters_SyncStart(label)
4733 if (not label or label == "") then
4734 DMPrint(DM_ERROR_MISSINGARG);
4735 return;
4736 end
4737 if (not DamageMeters_CheckSyncChan()) then
4738 return;
4739 end
4740  
4741 DamageMeters_SyncLabel(label);
4742 if (DamageMeters_tableInfo[DMT_ACTIVE].sessionIndex == 1) then
4743 DamageMeters_tableInfo[DMT_ACTIVE].sessionIndex = 0;
4744 end
4745 DamageMeters_SyncPause();
4746 DamageMeters_SyncClear();
4747 end
4748  
4749 function DamageMeters_SyncLabel(label)
4750 if (not label or label == "") then
4751 DMPrint(DM_ERROR_MISSINGARG);
4752 return;
4753 end
4754  
4755 if (DamageMeters_tableInfo[DMT_ACTIVE].sessionLabel ~= label) then
4756 DamageMeters_tableInfo[DMT_ACTIVE].sessionIndex = 1;
4757 end
4758 DamageMeters_tableInfo[DMT_ACTIVE].sessionLabel = label;
4759 DMPrintD(label..", new label = "..DamageMeters_tableInfo[DMT_ACTIVE].sessionLabel);
4760  
4761 DMPrint(string.format(DM_MSG_SETLABEL, DamageMeters_tableInfo[DMT_ACTIVE].sessionLabel, DamageMeters_tableInfo[DMT_ACTIVE].sessionIndex));
4762 end
4763  
4764 function DamageMeters_DoSync()
4765 DamageMeters_SyncRequest();
4766 DamageMeters_SyncReport();
4767 --DamageMeters_requestSyncWhenReportDone = true;
4768 end
4769  
4770 function DamageMeters_SyncReport()
4771  
4772 if (not DamageMeters_CheckSyncChan()) then
4773 return;
4774 end
4775  
4776 if (table.getn(DamageMeters_syncMsgQueue) > 0) then
4777 DMPrintD("Already reporting.");
4778 return;
4779 end
4780  
4781 DamageMeters_LastSyncTime = GetTime();
4782  
4783 if (DamageMeters_syncEvents) then
4784 DMPrint(DM_MSG_SYNCEVENTS, nil, true);
4785 else
4786 DMPrint(DM_MSG_SYNC, nil, true);
4787 end
4788 --local channelName = GetChannelName(DamageMeters_syncChannel)
4789 --SendChatMessage(DamageMeters_SYNCSTART, "CHANNEL", nil, channelName);
4790 --Telepathy.sendMessage(DamageMeters_SYNC_ID, DamageMeters_SYNCSTART, "RAID");
4791 ChatThrottleLib:SendAddonMessage("NORMAL", DamageMeters_SYNC_ID, DamageMeters_SYNCSTART, "RAID");
4792  
4793 DamageMeters_DoSyncReport();
4794  
4795 -- Add finishing msg to queue, including any extra data.
4796 if (1) then
4797 local msg = string.format("%s", DamageMeters_SYNCEND);
4798 DamageMeters_AddMsgToSyncQueue(msg);
4799 end
4800 end
4801  
4802 function DamageMeters_DoSyncReport()
4803  
4804 if (not DamageMeters_CheckSyncChan()) then
4805 return;
4806 end
4807  
4808 local startIndex = 1;
4809 local endIndex = table.getn(DamageMeters_tables[DMT_ACTIVE]);
4810 --DMPrintD("sync indexes: "..startIndex.."->"..endIndex.."("..table.getn(DamageMeters_tables[DMT_ACTIVE])..")");
4811  
4812 --local channelName = GetChannelName(DamageMeters_syncChannel)
4813  
4814 local index;
4815 for index = startIndex, endIndex do
4816 local info = DamageMeters_tables[DMT_ACTIVE][index];
4817 local playerName = info.player;
4818 if (DamageMeters_debug4.syncSelfTestMode) then
4819 playerName = playerName.."x";
4820 end
4821  
4822 local msg = DamageMeters_GenerateQuantityString(playerName, info);
4823 DamageMeters_AddMsgToSyncQueue(msg);
4824 end
4825  
4826 -----
4827 if (DamageMeters_syncEvents) then
4828 -- Dump events for ourselves only.
4829  
4830 local index, playerStruct;
4831 for index, playerStruct in DamageMeters_tables[DMT_ACTIVE] do
4832 DamageMeters_SyncSendPlayerEvents(playerStruct);
4833 end
4834 end
4835 -- Reset variable: we are done with it.
4836 DamageMeters_syncEvents = false;
4837  
4838 -------------
4839  
4840 local queueSize = table.getn(DamageMeters_syncMsgQueue);
4841 DamageMeters_sendMsgQueueBar:Show();
4842 DamageMeters_sendMsgQueueBar:SetMinMaxValues(0, queueSize);
4843 DamageMeters_sendMsgQueueBar:SetValue(queueSize);
4844 DamageMeters_sendMsgQueueBarText:SetText(DM_MENU_SENDINGBAR);
4845 end
4846  
4847 function DamageMeters_GenerateQuantityString(playerName, info)
4848 local msg = DMSYNC_PREFIX.." "..playerName;
4849 for dmi = 1, DMI_BUILTIN_MAX do
4850 msg = msg.." "..info.dmiData[dmi].q.." "..info.dmiData[dmi].hitCount.." "..info.dmiData[dmi].critCount;
4851 end
4852 return msg;
4853 end
4854  
4855 function DamageMeters_SyncSendPlayerEvents(playerStruct)
4856 local playerName = playerStruct.player;
4857 if (DamageMeters_debug4.syncSelfTestMode) then
4858 playerName = playerName.."x";
4859 end
4860  
4861 local quantity;
4862 -- BUILTIN dmi's only--would have to name the plugin dmi explicitly because the numbers can
4863 -- be different on different machines.
4864 for quantity = 1, DMI_BUILTIN_MAX do
4865 local quantityStruct = playerStruct.dmiData[quantity].events;
4866 --DMPrintD(quantity.." hash n = "..table.getn(quantityStruct.hash));
4867  
4868 if (quantityStruct and quantityStruct.spellTable) then
4869 if (quantityStruct.dirty) then
4870 DamageMeters_BuildSpellHash(quantityStruct);
4871 end
4872  
4873 local hashCount = table.getn(quantityStruct.hash);
4874 for hashIndex = 1, hashCount do
4875 local formatStr = " %d <%s> %d %d %d %d %d %d; ";
4876 local msg = DMSYNC_EVENT_PREFIX.."["..playerName.."]";
4877 local msgLen = string.len(msg);
4878  
4879 local eventIx;
4880 -- 10 max events per msg.
4881 local eventCount = math.min(10, hashCount - hashIndex + 1);
4882 hashIndex = hashIndex - 1;
4883 for eventIx = 1, eventCount do
4884 hashIndex = hashIndex + 1;
4885 local spell = quantityStruct.hash[hashIndex].spell;
4886 spellStruct = quantityStruct.spellTable[spell];
4887  
4888 newMsgPart = string.format(formatStr, quantity, spell,
4889 spellStruct.value, spellStruct.counts[1], spellStruct.counts[2],
4890 spellStruct.damageType, spellStruct.resistanceSum, spellStruct.resistanceCount);
4891 local newPartLen = string.len(newMsgPart);
4892  
4893 local MAX_MSG_LEN = 255;
4894 if (newPartLen + msgLen >= MAX_MSG_LEN) then
4895 --DMPrintD("Aborting at eventIx = "..eventIx);
4896 hashIndex = hashIndex - 1;
4897 break;
4898 else
4899 msg = msg..newMsgPart;
4900 msgLen = msgLen + newPartLen;
4901 end
4902 end
4903  
4904 DamageMeters_AddMsgToSyncQueue(msg);
4905 end
4906 end
4907 end
4908 end
4909  
4910 --[[
4911 function DamageMeters_SyncChan(arg1)
4912 if (not arg1 or arg1 == "") then
4913 DMPrint(DM_ERROR_MISSINGARG);
4914 else
4915 local autobroadcast = false;
4916 local params = arg1;
4917 if (string.sub(params, 1, 3) == "-b ") then
4918 autobroadcast = true;
4919 params = string.sub(params, 4);
4920 end
4921  
4922 -- Leave the current channel if we are in a different one.
4923 if (params ~= DamageMeters_syncChannel) then
4924 if (DamageMeters_syncChannel and (GetChannelName(DamageMeters_syncChannel) ~= 0)) then
4925 LeaveChannelByName(DamageMeters_syncChannel);
4926 end
4927 end
4928  
4929 DamageMeters_syncChannel = params;
4930 DMPrint(DM_MSG_SYNCCHAN..DamageMeters_syncChannel);
4931  
4932 if (0 == GetChannelName(DamageMeters_syncChannel)) then
4933 -- Autojoin the channel.
4934 JoinChannelByName(DamageMeters_syncChannel, nil, DEFAULT_CHAT_FRAME:GetID());
4935 end
4936  
4937 -- Automatically remove channel from the frame's list.
4938 ChatFrame_RemoveChannel(DEFAULT_CHAT_FRAME, DamageMeters_syncChannel);
4939  
4940 if (autobroadcast) then
4941 DamageMeters_SyncBroadcastChan();
4942 end
4943 end
4944 end
4945 ]]--
4946 --[[
4947 function DamageMeters_SyncBroadcastChan()
4948 if (not DamageMeters_CheckSyncChan()) then
4949 --DMPrint(DM_ERROR_NOSYNCCHANNEL);
4950 return;
4951 end
4952  
4953 local targetChannel = "";
4954 if (GetNumRaidMembers() > 0) then
4955 targetChannel = "RAID";
4956 elseif (GetNumPartyMembers() > 0) then
4957 targetChannel = "PARTY";
4958 else
4959 DMPrint(DM_ERROR_BROADCASTNOGROUP);
4960 return;
4961 end
4962  
4963 local msg = DM_MSG_SYNCCHANBROADCAST..DamageMeters_syncChannel;
4964 SendChatMessage(msg, targetChannel, nil, nil);
4965 end
4966  
4967  
4968 function DamageMeters_SyncLeaveChanCmd()
4969 DamageMeters_SyncLeaveChan(true);
4970 end
4971  
4972  
4973 function DamageMeters_SyncLeaveChan(bVerbose)
4974  
4975 if (GetChannelName(DamageMeters_syncChannel) ~= 0) then
4976 if (bVerbose) then
4977 DMPrint(string.format(DM_MSG_LEAVECHAN, DamageMeters_syncChannel));
4978 end
4979  
4980 LeaveChannelByName(DamageMeters_syncChannel);
4981 end
4982  
4983 DamageMeters_syncChannel = "";
4984 end
4985 ]]--
4986  
4987 function DamageMeters_SyncRequest()
4988 if (not DamageMeters_CheckSyncChan()) then
4989 return;
4990 end
4991  
4992 local msg = DamageMeters_SYNCREQUEST;
4993 if (DamageMeters_syncEvents) then
4994 msg = msg.." E";
4995 end
4996 if (DamageMeters_tableInfo[DMT_ACTIVE].sessionLabel) then
4997 msg = string.format("%s <%s %d>", msg, DamageMeters_tableInfo[DMT_ACTIVE].sessionLabel, DamageMeters_tableInfo[DMT_ACTIVE].sessionIndex);
4998 end
4999 --SendChatMessage(msg, "CHANNEL", nil, GetChannelName(DamageMeters_syncChannel));
5000 --Telepathy.sendMessage(DamageMeters_SYNC_ID, msg, "RAID");
5001 ChatThrottleLib:SendAddonMessage("NORMAL", DamageMeters_SYNC_ID, msg, "RAID");
5002 end
5003  
5004 function DamageMeters_SyncClear()
5005 if (not DamageMeters_CheckSyncChan()) then
5006 return;
5007 end
5008  
5009 DMPrint(DM_MSG_SYNCCLEARREQ);
5010 DamageMeters_Clear(0, true);
5011  
5012 local msg = DamageMeters_SYNCCLEARREQUEST;
5013 if (DamageMeters_tableInfo[DMT_ACTIVE].sessionLabel) then
5014 DamageMeters_tableInfo[DMT_ACTIVE].sessionIndex = DamageMeters_tableInfo[DMT_ACTIVE].sessionIndex + 1;
5015 DMPrintD("Incremented DamageMeters_tableInfo[DMT_ACTIVE].sessionIndex to "..DamageMeters_tableInfo[DMT_ACTIVE].sessionIndex);
5016 msg = string.format("%s %s %d", msg, DamageMeters_tableInfo[DMT_ACTIVE].sessionLabel, DamageMeters_tableInfo[DMT_ACTIVE].sessionIndex);
5017 end
5018 --SendChatMessage(msg, "CHANNEL", nil, GetChannelName(DamageMeters_syncChannel));
5019 --Telepathy.sendMessage(DamageMeters_SYNC_ID, msg, "RAID");
5020 ChatThrottleLib:SendAddonMessage("NORMAL", DamageMeters_SYNC_ID, msg, "RAID");
5021 end
5022  
5023 function DamageMeters_CheckSyncChan(bSilent)
5024 if (GetNumRaidMembers() > 1 or GetNumPartyMembers() > 1) then
5025 return true;
5026 end
5027  
5028 return false;
5029 end
5030  
5031 function DamageMeters_SyncPingRequest()
5032 DMPrint(DM_MSG_PINGING);
5033 --SendChatMessage(DamageMeters_SYNCPINGREQ, "CHANNEL", nil, GetChannelName(DamageMeters_syncChannel));
5034 --Telepathy.sendMessage(DamageMeters_SYNC_ID, DamageMeters_SYNCPINGREQ, "RAID");
5035 ChatThrottleLib:SendAddonMessage("NORMAL", DamageMeters_SYNC_ID, DamageMeters_SYNCPINGREQ, "RAID");
5036 end
5037  
5038 function DamageMeters_SyncPause()
5039 DMPrint(DM_MSG_SYNCPAUSEREQ);
5040 --SendChatMessage(DamageMeters_SYNCPAUSEREQ, "CHANNEL", nil, GetChannelName(DamageMeters_syncChannel));
5041 --Telepathy.sendMessage(DamageMeters_SYNC_ID, DamageMeters_SYNCPAUSEREQ, "RAID");
5042 ChatThrottleLib:SendAddonMessage("NORMAL", DamageMeters_SYNC_ID, DamageMeters_SYNCPAUSEREQ, "RAID");
5043  
5044 if (DM_Pause_Pause ~= DamageMeters_pauseState) then
5045 DamageMeters_pauseState = DM_Pause_Paused;
5046 DamageMeters_CompletePauseChange();
5047 end
5048 end
5049  
5050 function DamageMeters_SyncUnpause(silent, details)
5051 if (not silent) then
5052 DMPrint(DM_MSG_SYNCUNPAUSEREQ);
5053 end
5054 local msg = DamageMeters_SYNCUNPAUSEREQ;
5055 if (details) then
5056 msg = msg.." "..details;
5057 end
5058 --SendChatMessage(msg, "CHANNEL", nil, GetChannelName(DamageMeters_syncChannel));
5059 --Telepathy.sendMessage(DamageMeters_SYNC_ID, msg, "RAID");
5060 ChatThrottleLib:SendAddonMessage("NORMAL", DamageMeters_SYNC_ID, msg, "RAID");
5061  
5062 if (DM_Pause_Not ~= DamageMeters_pauseState) then
5063 DamageMeters_pauseState = DM_Pause_Not;
5064 DamageMeters_CompletePauseChange(silent);
5065 end
5066 end
5067  
5068 function DamageMeters_SyncReady()
5069 DamageMeters_SetReady();
5070 if (DamageMeters_CheckSyncChan(true)) then
5071 DMPrint(DM_MSG_SYNCREADYREQ);
5072 --SendChatMessage(DamageMeters_SYNCREADYREQ, "CHANNEL", nil, GetChannelName(DamageMeters_syncChannel));
5073 --Telepathy.sendMessage(DamageMeters_SYNC_ID, DamageMeters_SYNCREADYREQ, "RAID");
5074 ChatThrottleLib:SendAddonMessage("NORMAL", DamageMeters_SYNC_ID, DamageMeters_SYNCREADYREQ, "RAID");
5075 end
5076 end
5077 --[[
5078 function DamageMeters_SyncKick(arg1)
5079 if (not DamageMeters_CheckSyncChan()) then
5080 return;
5081 end
5082  
5083 if (nil == arg1 or "" == arg1) then
5084 DMPrint(DM_ERROR_MISSINGARG);
5085 return;
5086 end
5087  
5088 --SendChatMessage(DamageMeters_SYNCKICK.." "..arg1, "CHANNEL", nil, GetChannelName(DamageMeters_syncChannel));
5089 --Telepathy.sendMessage(DamageMeters_SYNC_ID, DamageMeters_SYNCKICK.." "..arg1, "RAID");
5090 ChatThrottleLib:SendAddonMessage("NORMAL", DamageMeters_SYNC_ID, DamageMeters_SYNCKICK.." "..arg1, "RAID");
5091 end
5092 ]]--
5093 function DamageMeters_SyncEmote(arg1)
5094 if (not DamageMeters_CheckSyncChan()) then
5095 return;
5096 end
5097  
5098 if (not arg1) then
5099 return;
5100 end
5101  
5102 local player = nil;
5103 local message = arg1;
5104 if (string.sub(arg1, 1, 1) == "@") then
5105 local a,b;
5106 for a, b in string.gfind(arg1, "@(%a+) (.+)") do
5107 player = a;
5108 message = b;
5109 end
5110 end
5111  
5112 -- Do target replacement.
5113 local target = UnitName("Target");
5114 if (nil == target) then
5115 target = "nobody";
5116 end
5117 local repStart, repEnd = string.find(message, "%%t");
5118 while (repStart ~= nil) do
5119 message = string.sub(message, 1, repStart - 1)..target..string.sub(message, repEnd + 1);
5120 repStart, repEnd = string.find(message, "%%t");
5121 end
5122  
5123 --------
5124  
5125 -- Send the message.
5126 if (nil == player) then player = ""; end
5127 local msg = DamageMeters_SYNCEMOTE.." <"..player.."> "..message;
5128 --SendChatMessage(msg, "CHANNEL", nil, GetChannelName(DamageMeters_syncChannel));
5129 --Telepathy.sendMessage(DamageMeters_SYNC_ID, msg, "RAID");
5130 ChatThrottleLib:SendAddonMessage("NORMAL", DamageMeters_SYNC_ID, msg, "RAID");
5131  
5132 if (player ~= "") then
5133 DMPrint("[DME -> "..player.."] "..UnitName("Player").." "..message, DamageMeters_SYNCEMOTECOLOR);
5134 else
5135 DMPrint("[DME] "..UnitName("Player").." "..message, DamageMeters_SYNCEMOTECOLOR);
5136 end
5137 end
5138  
5139 function DamageMeters_DecodeEmote(source, msg)
5140 for target, message in string.gfind(msg, "<(.*)> (.+)") do
5141  
5142 if (target ~= "") then
5143 local target = string.lower(target);
5144 local ourName = string.lower(UnitName("Player"));
5145 if (target ~= ourName) then
5146 return;
5147 end
5148  
5149 DMPrint("[DME "..WHISPER.."] "..source.." "..message, DamageMeters_SYNCEMOTECOLOR);
5150 else
5151 DMPrint(source.." "..message, DamageMeters_SYNCEMOTECOLOR);
5152 end
5153 end
5154 end
5155  
5156 function DamageMeters_SyncPingReply(pinger)
5157 local msg = DamageMeters_SYNCPING.." <"..pinger.."> <"..DamageMeters_VERSIONSTRING;
5158 if (DamageMeters_tableInfo[DMT_ACTIVE].sessionLabel) then
5159 msg = string.format("%s [%s #%d]", msg, DamageMeters_tableInfo[DMT_ACTIVE].sessionLabel, DamageMeters_tableInfo[DMT_ACTIVE].sessionIndex);
5160 end
5161 msg = msg..">";
5162 --SendChatMessage(msg, "CHANNEL", nil, GetChannelName(DamageMeters_syncChannel));
5163 --Telepathy.sendMessage(DamageMeters_SYNC_ID, msg, "RAID");
5164 ChatThrottleLib:SendAddonMessage("NORMAL", DamageMeters_SYNC_ID, msg, "RAID");
5165 end
5166  
5167 function DamageMeters_AddNewPlayerComplete(tableIndex, playerName, relationship)
5168 local index = DamageMeters_GetPlayerIndex(playerName, tableIndex);
5169 if (nil == index) then
5170 index = DamageMeters_AddNewPlayer(DamageMeters_tables[tableIndex], playerName);
5171 DamageMeters_SetRelationship(index, relationship);
5172 end
5173  
5174 return index;
5175 end
5176  
5177 function DamageMeters_Populate()
5178 local numPartyMembers = GetNumPartyMembers();
5179 local numRaidMembers = GetNumRaidMembers();
5180  
5181 local oldLocked = DamageMeters_listLocked;
5182 DamageMeters_listLocked = false;
5183  
5184 if (numRaidMembers > 0) then
5185 DamageMeters_AddNewPlayerComplete(DMT_ACTIVE, UnitName("Player"), DamageMeters_Relation_SELF);
5186  
5187 local name, rank, subgroup, level, class, fileName, zone, online, isDead;
5188 local i;
5189 for i = 1,numRaidMembers do
5190 name, rank, subgroup, level, class, fileName, zone, online, isDead = GetRaidRosterInfo(i);
5191 DamageMeters_AddNewPlayerComplete(DMT_ACTIVE, name, DamageMeters_Relation_FRIENDLY);
5192 end
5193 elseif (numPartyMembers > 0) then
5194 DamageMeters_AddNewPlayerComplete(DMT_ACTIVE, UnitName("Player"), DamageMeters_Relation_SELF);
5195  
5196 for i=1,5 do
5197 local partyUnitName = "party"..i;
5198 local partyName = UnitName(partyUnitName);
5199 if (partyName and partyName ~= "") then
5200 DamageMeters_AddNewPlayerComplete(DMT_ACTIVE, partyName, DamageMeters_Relation_PARTY);
5201 end
5202 end
5203 else
5204 DMPrint(DM_ERROR_POPNOPARTY);
5205 end
5206  
5207 DamageMeters_listLocked = oldLocked;
5208 end
5209  
5210 function DamageMeters_ToggleLock()
5211 DamageMeters_listLocked = not DamageMeters_listLocked;
5212 if (DamageMeters_listLocked) then
5213 DMPrint(DM_MSG_LOCKED);
5214 else
5215 DMPrint(DM_MSG_NOTLOCKED);
5216 end
5217 end
5218  
5219 function DamageMeters_CompletePauseChange(silent)
5220 if (not silent) then
5221 if (DM_Pause_Not ~= DamageMeters_pauseState) then
5222 DMPrint(DM_MSG_PAUSED);
5223 else
5224 DMPrint(DM_MSG_UNPAUSED);
5225 end
5226 end
5227 DamageMeters_SetBackgroundColor();
5228  
5229 if (DM_Pause_Not == DamageMeters_pauseState) then
5230 if (DamageMeters_playerInCombat) then
5231 --DMPrintD("Starting combat via unpausing.");
5232 DamageMeters_OnCombatStart();
5233 end
5234 else
5235 if (DamageMeters_inCombat) then
5236 DamageMeters_OnCombatEnd();
5237 end
5238 end
5239 end
5240  
5241 function DamageMeters_TogglePause(silent)
5242 if (DM_Pause_Not ~= DamageMeters_pauseState) then
5243 DamageMeters_pauseState = DM_Pause_Not;
5244 else
5245 DamageMeters_pauseState = DM_Pause_Paused;
5246 end
5247  
5248 DamageMeters_CompletePauseChange(silent);
5249 end
5250  
5251 function DamageMeters_SetReady()
5252 if (DamageMeters_pauseState ~= DM_Pause_Ready) then
5253 DamageMeters_pauseState = DM_Pause_Ready;
5254 DamageMeters_CompletePauseChange(true);
5255 --DMPrint("DamageMeters: Ready state activated; DM will automatically unpause on the next damage event.");
5256 end
5257 end
5258  
5259 function DamageMeters_ToggleLockPos()
5260 DamageMeters_flags[DMFLAG_positionLocked] = not DamageMeters_flags[DMFLAG_positionLocked];
5261 if (DamageMeters_flags[DMFLAG_positionLocked]) then
5262 DamageMetersFrame:StopMovingOrSizing();
5263 DamageMetersFrame:EnableMouse(0);
5264 DMPrint(DM_MSG_POSLOCKED);
5265 else
5266 DamageMetersFrame:EnableMouse(1);
5267 DMPrint(DM_MSG_POSNOTLOCKED);
5268 end
5269 CloseMenus();
5270 end
5271  
5272 function DamageMeters_SetQuantityColor()
5273 local r,g,b = ColorPickerFrame:GetColorRGB();
5274 DamageMeters_quantityColor[UIDROPDOWNMENU_MENU_VALUE][1] = r;
5275 DamageMeters_quantityColor[UIDROPDOWNMENU_MENU_VALUE][2] = g;
5276 DamageMeters_quantityColor[UIDROPDOWNMENU_MENU_VALUE][3] = b;
5277 DamageMeters_flags[DMFLAG_cycleVisibleQuantity] = false;
5278 DamageMeters_frameNeedsToBeGenerated = true;
5279 DamageMeters_tablesDirty = true;
5280 end
5281  
5282 function DamageMeters_SetQuantityColorOpacity()
5283 local alpha = 1.0 - OpacitySliderFrame:GetValue();
5284 DamageMeters_quantityColor[UIDROPDOWNMENU_MENU_VALUE][4] = alpha;
5285 DamageMeters_frameNeedsToBeGenerated = true;
5286 end
5287  
5288 function DamageMeters_CancelQuantityColorSettings(previousValues)
5289 if ( previousValues.r ) then
5290 DamageMeters_quantityColor[UIDROPDOWNMENU_MENU_VALUE][1] = previousValues.r;
5291 DamageMeters_quantityColor[UIDROPDOWNMENU_MENU_VALUE][2] = previousValues.g;
5292 DamageMeters_quantityColor[UIDROPDOWNMENU_MENU_VALUE][3] = previousValues.b;
5293 if (previousValues.opacity) then
5294 --DMPrint("previousValues.opacity = "..previousValues.opacity);
5295 DamageMeters_quantityColor[UIDROPDOWNMENU_MENU_VALUE][4] = 1.0 - previousValues.opacity
5296 end
5297 end
5298 DamageMeters_frameNeedsToBeGenerated = true;
5299 end
5300  
5301 function DamageMeters_SetQuantityColorAllOnClick()
5302 local frame = this:GetParent();
5303  
5304 frame.text = DM_MENU_SETCOLORFORALL;
5305 frame.func = DamageMeters_SetQuantityColorAll;
5306 frame.swatchFunc = DamageMeters_SetQuantityColorAll;
5307 frame.hasColorSwatch = 1;
5308 frame.r = DamageMeters_quantityColor[DamageMeters_quantity][1];
5309 frame.g = DamageMeters_quantityColor[DamageMeters_quantity][2];
5310 frame.b = DamageMeters_quantityColor[DamageMeters_quantity][3];
5311 frame.hasOpacity = 1;
5312 frame.opacity = 1.0 - DamageMeters_quantityColor[DamageMeters_quantity][4];
5313 frame.opacityFunc = DamageMeters_SetQuantityColorOpacityAll;
5314 frame.notCheckable = 1;
5315  
5316 ColorPickerFrame.frame = frame;
5317 CloseMenus();
5318 UIDropDownMenuButton_OpenColorPicker(frame);
5319 end
5320  
5321 function DamageMeters_SetDefaultColors()
5322 DamageMeters_quantityColor = {};
5323 local quant;
5324 for quant = 1, DamageMeters_Quantity_MAX do
5325 DamageMeters_quantityColor[quant] = DM_clone(DM_QUANTDEFS[quant].defaultColor);
5326 end
5327 DamageMeters_frameNeedsToBeGenerated = true;
5328 end
5329  
5330 function DamageMeters_SetQuantityColorAll()
5331 local r,g,b = ColorPickerFrame:GetColorRGB();
5332 local index;
5333 for index = 1, DamageMeters_Quantity_MAX do
5334 DamageMeters_quantityColor[index][1] = r;
5335 DamageMeters_quantityColor[index][2] = g;
5336 DamageMeters_quantityColor[index][3] = b;
5337 end
5338 DamageMeters_frameNeedsToBeGenerated = true;
5339 end
5340  
5341 function DamageMeters_SetQuantityColorOpacityAll()
5342 local alpha = 1.0 - OpacitySliderFrame:GetValue();
5343 local index;
5344 for index = 1, DamageMeters_Quantity_MAX do
5345 DamageMeters_quantityColor[index][4] = alpha;
5346 end
5347 DamageMeters_frameNeedsToBeGenerated = true;
5348 end
5349  
5350 function DamageMeters_ToggleResetWhenCombatStarts()
5351 DamageMeters_flags[DMFLAG_resetWhenCombatStarts] = not DamageMeters_flags[DMFLAG_resetWhenCombatStarts];
5352 -- Only print message if we weren't called from the menu option.
5353 if (not this.value) then
5354 DMPrint(DM_MSG_RESETWHENCOMBATSTARTSCHANGE..(DamageMeters_flags[DMFLAG_resetWhenCombatStarts] and DM_MSG_TRUE or DM_MSG_FALSE));
5355 end
5356 end
5357  
5358 function DamageMeters_ToggleShowFightAsPS()
5359 DamageMeters_flags[DMFLAG_showFightAsPS] = not DamageMeters_flags[DMFLAG_showFightAsPS];
5360 -- Only print message if we weren't called from the menu option.
5361 if (this and not this.value) then
5362 DMPrint(DM_MSG_SHOWFIGHTASPS..(DamageMeters_flags[DMFLAG_showFightAsPS] and DM_MSG_TRUE or DM_MSG_FALSE));
5363 end
5364 DamageMeters_SetQuantity(DamageMeters_quantity, true);
5365 end
5366  
5367 function DamageMeters_ToggleNormalAndFight()
5368 local newQuant = DM_QUANTDEFS[DamageMeters_quantity].toggleQuant;
5369 if (newQuant ~= nil) then
5370 DamageMeters_SetQuantity(newQuant, true);
5371 end
5372 end
5373  
5374 function DamageMeters_OnCombatStart()
5375 DamageMeters_combatStartTime = GetTime();
5376 DamageMeters_combatEndTime = DamageMeters_combatStartTime;
5377 DamageMeters_inCombat = true;
5378 --DMPrintD("Starting combat...");
5379  
5380 -- Clear the combat table.
5381 DamageMeters_DoClear(DMT_FIGHT, 0, true);
5382 end
5383  
5384 function DamageMeters_OnCombatEnd()
5385 DamageMeters_combatEndTime = GetTime();
5386 --DMPrintD("Ending combat, duration = "..(DamageMeters_combatEndTime - DamageMeters_combatStartTime));
5387 DamageMeters_inCombat = false;
5388  
5389 -- This is...complicated.
5390 --DamageMeters_tableInfo[DMT_ACTIVE].totalCombatTime = (DamageMeters_combatEndTime - DamageMeters_combatStartTime) + DamageMeters_tableInfo[DMT_ACTIVE].totalCombatTime;
5391  
5392 if ( DamageMeters_flags[DMFLAG_autoSync] and not DamageMeters_GroupInCombat() ) then
5393 if (not DamageMeters_LastSyncTime or GetTime() - DamageMeters_LastSyncTime > 180) then
5394 DamageMeters_DoSync();
5395 end
5396 end
5397  
5398 DamageMeters_startCombatOnNextValue = true;
5399 end
5400  
5401 function DamageMeters_GroupInCombat()
5402 if (DamageMeters_inCombat) then
5403 return true;
5404 end
5405  
5406 local num = GetNumRaidMembers();
5407 if ( num > 1 ) then
5408 for i=1, num do
5409 if ( UnitAffectingCombat("raid"..i) ) then
5410 return true;
5411 end
5412 end
5413 else
5414 num = GetNumPartyMembers();
5415 if ( num > 1 ) then
5416 for i=1, num do
5417 if ( UnitAffectingCombat("party"..i) ) then
5418 return true;
5419 end
5420 end
5421 end
5422 end
5423  
5424 return false;
5425 end
5426  
5427 function DamageMeters_GetCombatValuePS(combatValue)
5428 local combatTime = DamageMeters_combatEndTime - DamageMeters_combatStartTime;
5429 if (combatTime <= 1.0) then
5430 combatTime = 1.0;
5431 end
5432 return combatValue / combatTime;
5433 end
5434  
5435 function DamageMeters_OpenReportFrame()
5436 CloseDropDownMenus();
5437  
5438 ShowUIPanel(DMReportFrame);
5439 DMReportFrame:SetBackdropColor(0, 0, 0, 1);
5440 DMSendMailScrollFrame:SetBackdropColor(0, 0, 0, 1);
5441 DamageMeters_UpdateReportText();
5442 end
5443  
5444 function DamageMeters_UpdateReportText()
5445 DMReportFrame_SendMailBodyEditBox:SetText(DamageMeters_reportBuffer);
5446 DMReportFrame_SendMailBodyEditBox:SetFocus("");
5447 DMReportFrame_SendMailBodyEditBox:HighlightText();
5448 end
5449  
5450 function DamageMeters_ReportTypeDropDown_OnLoad()
5451 UIDropDownMenu_Initialize(this, DamageMeters_ReportTypeDropDown_Initialize, "MENU");
5452 end
5453  
5454 function DamageMeters_ReportTypeDropDown_Initialize()
5455 local index;
5456 for index = 1,DamageMeters_Quantity_MAX do
5457 info = {};
5458 info.text = DM_QUANTDEFS[index].name;
5459 info.value = index;
5460 info.func = DamageMeters_ReportFrame_DoReport;
5461 info.notCheckable = 1
5462 UIDropDownMenu_AddButton(info);
5463 end
5464  
5465 info = {};
5466 info.text = DM_MENU_TOTAL;
5467 info.value = DamageMeters_ReportQuantity_Total;
5468 info.func = DamageMeters_ReportFrame_DoReport;
5469 info.notCheckable = 1
5470 UIDropDownMenu_AddButton(info);
5471  
5472 info = {};
5473 info.text = DM_MENU_LEADERS;
5474 info.value = DamageMeters_ReportQuantity_Leaders;
5475 info.func = DamageMeters_ReportFrame_DoReport;
5476 info.notCheckable = 1
5477 UIDropDownMenu_AddButton(info);
5478  
5479 local index;
5480 for index = 1, 3 do
5481 info = {};
5482 info.text = getglobal("DM_MENU_EVENTS"..index);
5483 info.value = index;
5484 info.func = DamageMeters_ReportFrame_DoEventReport;
5485 info.notCheckable = 1
5486 UIDropDownMenu_AddButton(info);
5487 end
5488  
5489 if (DamageMeters_debugEnabled) then
5490 info = {};
5491 info.text = "Missed Messages";
5492 info.func = DamageMeters_ReportMissed;
5493 info.notCheckable = 1
5494 UIDropDownMenu_AddButton(info);
5495 end
5496 end
5497  
5498 function DamageMeters_ReportFrame_DoReport()
5499 DamageMeters_DoReport(this.value, "BUFFER", false, 1, DamageMeters_TABLE_MAX, "");
5500 DamageMeters_UpdateReportText();
5501 end
5502  
5503 function DamageMeters_ReportFrame_DoEventReport()
5504 local start = ((this.value - 1) * 20) + 1;
5505 DamageMeters_DoReport(DamageMeters_ReportQuantity_Events, "BUFFER", false, start, 20, "");
5506 DamageMeters_UpdateReportText();
5507 end
5508  
5509 function DamageMeters_ReportTypeButton_OnClick()
5510 ToggleDropDownMenu(1, nil, DMReportTypeDropDown, "DMReportTypeDropDown", 0, 0);
5511 end
5512  
5513 function DamageMeters_ShowReportFrame()
5514 DamageMeters_Report("f");
5515 end
5516  
5517 function DamageMeters_DumpContributors()
5518 local playerName, unused;
5519 DMPrint(table.getn(DamageMeters_contributorList).." contributors:");
5520 for playerName, unused in DamageMeters_contributorList do
5521 DMPrint(" "..playerName);
5522 end
5523 end
5524  
5525 function DamageMetersBar_DoPlayerReport()
5526 local destination = "BUFFER";
5527 DamageMeters_reportBuffer = "";
5528  
5529 DamageMeters_DoPlayerReport(DamageMeters_tables[DMT_VISIBLE][DamageMeters_clickedBarIndex].player, destination);
5530  
5531 if (destination == "BUFFER") then
5532 DamageMeters_OpenReportFrame();
5533 end
5534 end
5535  
5536 function DamageMetersBar_DumpPlayerEvents()
5537 local destination = "BUFFER";
5538 DamageMeters_reportBuffer = "";
5539  
5540 DamageMeters_DumpPlayerEvents(DamageMeters_tables[DMT_VISIBLE][DamageMeters_clickedBarIndex].player, destination, true);
5541  
5542 if (destination == "BUFFER") then
5543 DamageMeters_OpenReportFrame();
5544 end
5545 end
5546  
5547 function DamageMeters_ShowVersion()
5548 DMPrint(string.format(DM_MSG_VERSION, DamageMeters_VERSIONSTRING));
5549 end
5550  
5551 function DamageMeters_ShowReportHelp()
5552 DamageMeters_reportBuffer = DM_MSG_REPORTHELP;
5553 DamageMeters_OpenReportFrame();
5554 DMReportFrame_SendMailBodyEditBox:HighlightText(0, 0)
5555 end
5556  
5557 function DamageMeters_ShowSyncHelp()
5558 DamageMeters_reportBuffer = DM_MSG_SYNCHELP;
5559 DamageMeters_OpenReportFrame();
5560 DMReportFrame_SendMailBodyEditBox:HighlightText(0, 0)
5561 end
5562  
5563 function DamageMeters_ToggleAccumulateToMemory()
5564 DamageMeters_flags[DMFLAG_accumulateToMemory] = not DamageMeters_flags[DMFLAG_accumulateToMemory];
5565 DMPrintD("Accumulate = "..(DamageMeters_flags[DMFLAG_accumulateToMemory] and "true" or "false"));
5566 end
5567  
5568 function DamageMeters_SendSyncMsg(arg1)
5569 if (not DamageMeters_CheckSyncChan()) then
5570 return;
5571 end
5572  
5573 if (not arg1 or arg1 == "") then
5574 DMPrint(DM_ERROR_MISSINGARG);
5575 return;
5576 end
5577  
5578 -- "|HPlayer:%s|h[%s]|h"
5579 DMPrint(format(DM_MSG_SYNCMSG, UnitName("Player"), UnitName("Player"), arg1), DamageMeters_SYNCMSGCOLOR);
5580  
5581 local msg = DamageMeters_SYNCMSG.." "..arg1;
5582 --SendChatMessage(msg, "CHANNEL", nil, GetChannelName(DamageMeters_syncChannel));
5583 --Telepathy.sendMessage(DamageMeters_SYNC_ID, msg, "RAID", nil, "BULK")
5584 ChatThrottleLib:SendAddonMessage("BULK", DamageMeters_SYNC_ID, msg, "RAID");
5585 end
5586  
5587 function DamageMeters_ToggleMaxBars(bSilent)
5588 DamageMeters_ToggleViewMode(DMVIEW_MAX);
5589  
5590 DamageMeters_frameNeedsToBeGenerated = true;
5591 if (not bSilent) then
5592 DMPrint(format(DM_MSG_MAXBARS, ((DMVIEW_MAX == DamageMeters_viewMode) and DM_MSG_TRUE or DM_MSG_FALSE)));
5593 end
5594 end
5595  
5596 function DamageMeters_ToggleViewMode(toggleMode)
5597 if (toggleMode == DamageMeters_viewMode) then
5598 DMPrintD("Setting viewmode to normal.");
5599 DamageMeters_viewMode = DMVIEW_NORMAL;
5600 DamageMeters_barCount = DamageMeters_savedBarCount;
5601 else
5602 if (DMVIEW_NORMAL == DamageMeters_viewMode) then
5603 DMPrintD("Setting saved bar count to "..DamageMeters_barCount);
5604 DamageMeters_savedBarCount = DamageMeters_barCount;
5605 end
5606 DMPrintD("Setting viewmode to "..toggleMode);
5607 DamageMeters_viewMode = toggleMode;
5608 end
5609 end
5610  
5611 function DamageMeters_ForceNormalView()
5612 if (DMVIEW_NORMAL ~= DamageMeters_viewMode) then
5613 DamageMeters_barCount = DamageMeters_savedBarCount;
5614 DMPrintD("Setting viewmode to normal.");
5615 DamageMeters_viewMode = DMVIEW_NORMAL;
5616 end
5617 end
5618  
5619 function DamageMeters_ChangeEventDataLevel()
5620 DamageMeters_eventDataLevel = this.value;
5621 DMPrint(DM_MSG_EVENTDATALEVEL[DamageMeters_eventDataLevel]);
5622 end
5623  
5624 function DamageMeters_ChangeSyncEventDataLevel()
5625 DamageMeters_syncEventDataLevel = this.value;
5626 DMPrint(DM_MSG_SYNCEVENTDATALEVEL[DamageMeters_syncEventDataLevel]);
5627 end
5628  
5629 function DamageMeters_ReportMissed()
5630 local destination = "BUFFER";
5631 DamageMeters_reportBuffer = "";
5632  
5633 local msg = table.getn(DamageMeters_missedMessages).." missed messages:";
5634 DamageMeters_SendReportMsg(msg, destination);
5635  
5636 local index;
5637 for index = 1, table.getn(DamageMeters_missedMessages) do
5638 DamageMeters_SendReportMsg(DamageMeters_missedMessages[index], destination);
5639 end
5640  
5641 if (destination == "BUFFER") then
5642 DamageMeters_OpenReportFrame();
5643 end
5644 end
5645  
5646 function DamageMeters_ToggleDebugVariable()
5647 DamageMeters_debug4[this.value] = not DamageMeters_debug4[this.value];
5648 end
5649  
5650 function DamageMeters_ToggleBypass()
5651 DM_Bypass[this.value] = not DM_Bypass[this.value];
5652 end
5653  
5654 function DamageMeters_ProcessSyncMsg(msg, arg2)
5655 local dmi;
5656 local formatStr = DMSYNC_PREFIX.." (.+)";
5657 for dmi = 1, DMI_BUILTIN_MAX do
5658 formatStr = formatStr.." (%d+) (%d+) (%d+)";
5659 end
5660  
5661 local incQuant = {};
5662 local incHitCount = {};
5663 local incCritCount = {};
5664 local found;
5665 found, _, player,
5666 incQuant[1], incHitCount[1], incCritCount[1],
5667 incQuant[2], incHitCount[2], incCritCount[2],
5668 incQuant[3], incHitCount[3], incCritCount[3],
5669 incQuant[4], incHitCount[4], incCritCount[4],
5670 incQuant[5], incHitCount[5], incCritCount[5],
5671 incQuant[6], incHitCount[6], incCritCount[6],
5672 incQuant[7], incHitCount[7], incCritCount[7]
5673 = string.find(msg, formatStr);
5674  
5675 if (found) then
5676 for dmi = 1, DMI_BUILTIN_MAX do
5677 incQuant[dmi] = tonumber(incQuant[dmi]);
5678 incHitCount[dmi] = tonumber(incHitCount[dmi]);
5679 incCritCount[dmi] = tonumber(incCritCount[dmi]);
5680 end
5681  
5682 -- We have recieved data from a contributor: add him/her to the list.
5683 DamageMeters_contributorList[arg2] = true;
5684 DamageMeters_flags[DMFLAG_haveContributors] = true;
5685  
5686 local index = DamageMeters_GetPlayerIndex(player);
5687 if (not index) then
5688 -- There is a problem: if the other player is parsing damage for our pet
5689 -- we could erroneously add it again to our own if we have the option turned
5690 -- on. This condition attempts to fix that problem.
5691 if (DamageMeters_flags[DMFLAG_addPetToPlayer] and player == UnitName("Pet")) then
5692 return;
5693 end
5694  
5695 index = DamageMeters_AddNewPlayer(DamageMeters_tables[DMT_ACTIVE], player);
5696 DamageMeters_SetRelationship(index, DamageMeters_Relation_FRIENDLY);
5697  
5698 if (not index) then
5699 DMPrintD("Couldn't add new player from sync'ing.");
5700 return;
5701 end
5702 if (DamageMeters_debug4.showSyncChanges) then
5703 DMPrintD("DMSYNC("..arg2.."): Adding new player, "..player..".", nil, true);
5704 end
5705 end
5706  
5707 local localStruct = DamageMeters_tables[DMT_ACTIVE][index];
5708  
5709 local quantIndex;
5710 for quantIndex = 1, DMI_BUILTIN_MAX do
5711 if (incQuant[quantIndex] > localStruct.dmiData[quantIndex].q) then
5712 if (DamageMeters_debug4.showSyncChanges) then
5713 DMPrintD("DMSYNC("..arg2.."): "..player.."["..DM_QUANTDEFS[quantIndex].name.."] "..localStruct.dmiData[quantIndex].q.." -> "..incQuant[quantIndex], nil, true);
5714 end
5715 localStruct.dmiData[quantIndex].q = incQuant[quantIndex];
5716 DamageMeters_tablesDirty = true;
5717 end
5718  
5719 if (incHitCount[quantIndex] > localStruct.dmiData[quantIndex].hitCount) then
5720 if (DamageMeters_debug4.showSyncChanges) then
5721 DMPrintD("DMSYNC("..arg2.."): "..player.."["..DM_QUANTDEFS[quantIndex].name.." hits] "..localStruct.dmiData[quantIndex].hitCount.." -> "..incHitCount[quantIndex], nil, true);
5722 end
5723 localStruct.dmiData[quantIndex].hitCount = incHitCount[quantIndex];
5724 DamageMeters_tablesDirty = true;
5725 end
5726 if (incCritCount[quantIndex] > localStruct.dmiData[quantIndex].critCount) then
5727 if (DamageMeters_debug4.showSyncChanges) then
5728 DMPrintD("DMSYNC("..arg2.."): "..player.."["..DM_QUANTDEFS[quantIndex].name.." crits] "..localStruct.dmiData[quantIndex].critCount.." -> "..incCritCount[quantIndex], nil, true);
5729 end
5730 localStruct.dmiData[quantIndex].critCount = incCritCount[quantIndex];
5731 DamageMeters_tablesDirty = true;
5732 end
5733 end
5734  
5735 return;
5736 end
5737  
5738 ----------------------
5739  
5740 local prefixLen = string.len(DMSYNC_EVENT_PREFIX);
5741 if (strsub(msg, 1, prefixLen) == DMSYNC_EVENT_PREFIX) then
5742 msg = strsub(msg, prefixLen + 2);
5743 local originalMsg = msg;
5744 local msgLeft = "";
5745  
5746 local quantity, spell, total, hit1, hit2, hit3, misc1, misc2;
5747 -- name quant spell val c1 c2;
5748  
5749 local endName = string.find(msg, "]");
5750 local player = string.sub(msg, 1, endName - 1);
5751  
5752 -- may not be an index for this player if it is someone's totem or something
5753 local index = DamageMeters_GetPlayerIndex(player);
5754 if (index) then
5755 msg = string.sub(msg, endName + 1);
5756  
5757 local parsed;
5758 repeat
5759 local semicolonIndex = string.find(msg, ";");
5760 if (semicolonIndex) then
5761 msgLeft = string.sub(msg, semicolonIndex + 3); -- 1 for semicolon, 1 for following space
5762 msg = string.sub(msg, 1, semicolonIndex - 1);
5763 end
5764  
5765 --DMPrint("Parsing '"..msg.."'");
5766  
5767 local formatStr = "(%d+) <(.+)> (%d+) (%d+) (%d+) (%d+) (%d+) (%d+)";
5768 parsed = false;
5769 for quantity, spell, total, hit1, hit2, misc1, misc2, misc3 in string.gfind(msg, formatStr) do
5770 parsed = true;
5771 --DMPrint("Parsed! "..player..","..quantity..","..spell..","..total..","..hit1..","..hit2);
5772 if (DamageMeters_debugEnabled) then
5773 if (string.sub(player, 1, 1) == " ") then
5774 DMPrintD("ERROR: Player <"..player.."> starts with space: fixing.");
5775 DMPrintD("org = >"..originalMsg.."<");
5776 DMPrintD("msg = >"..msg.."<");
5777 player = string.sub(player, 2);
5778 end
5779 end
5780  
5781 if ((DamageMeters_EventData_ALL == DamageMeters_eventDataLevel) or
5782 ((DamageMeters_EventData_SELF == DamageMeters_eventDataLevel) and (player == UnitName("Player")))) then
5783 --DMPrintD("Accepting >"..spell.."< event for player "..player, nil, true)
5784  
5785 quantity = tonumber(quantity);
5786 total = tonumber(total);
5787 hit1 = tonumber(hit1);
5788 hit2 = tonumber(hit2);
5789 misc1 = tonumber(misc1);
5790 misc2 = tonumber(misc2);
5791 misc3 = tonumber(misc3);
5792  
5793 local bMsgFromPlayer = (string.lower(player) == string.lower(arg2));
5794  
5795 local playerEventStruct = DamageMeters_tables[DMT_ACTIVE][index].dmiData[quantity].events;
5796 if (nil == playerEventStruct) then
5797 if (DamageMeters_debug4.showSyncChanges) then
5798 DMPrintD("DMSYNCE("..arg2.."): Adding new player, <"..player..">.", nil, true);
5799 end
5800 DMPrintD("EventTable: Adding player <"..player..">.");
5801  
5802 DamageMeters_tables[DMT_ACTIVE][index].dmiData[quantity].events = {};
5803 playerEventStruct = DamageMeters_tables[DMT_ACTIVE][index].dmiData[quantity].events;
5804  
5805 playerEventStruct.spellTable = {};
5806 playerEventStruct.hash = {};
5807 playerEventStruct.dirty = true;
5808 end
5809  
5810 if (nil == playerEventStruct.spellTable[spell]) then
5811 if (DamageMeters_debug4.showSyncChanges) then
5812 DMPrintD("DMSYNCE("..arg2.."): Adding spell "..spell.." to player <"..player..">.", nil, true);
5813 end
5814 playerEventStruct.spellTable[spell] = {};
5815 playerEventStruct.spellTable[spell].value = 0;
5816 playerEventStruct.spellTable[spell].counts = {0,0};
5817 playerEventStruct.spellTable[spell].damageType = DM_DMGTYPE_DEFAULT;
5818 playerEventStruct.spellTable[spell].resistanceSum = 0;
5819 playerEventStruct.spellTable[spell].resistanceCount = 0;
5820 end
5821  
5822 if (playerEventStruct.spellTable[spell].counts[DM_HIT] < hit1 or
5823 (playerEventStruct.spellTable[spell].counts[DM_HIT] == hit1 and bMsgFromPlayer)) then
5824 if (DamageMeters_debug4.showSyncChanges) then
5825 DMPrintD(string.format("DMSYNCE("..arg2.."): %s %s: %d -> %d", player, spell, playerEventStruct.spellTable[spell].value, total), nil, true);
5826 end
5827 playerEventStruct.spellTable[spell].value = total;
5828 playerEventStruct.spellTable[spell].counts = {hit1, hit2};
5829 playerEventStruct.spellTable[spell].damageType = misc1;
5830 playerEventStruct.spellTable[spell].resistanceSum = misc2;
5831 playerEventStruct.spellTable[spell].resistanceCount = misc3;
5832 end
5833  
5834 DamageMeters_tablesDirty = true;
5835 else
5836 --DMPrintD("Rejecting >"..spell.."< event for player "..player, nil, true)
5837 end
5838 end
5839  
5840 msg = msgLeft;
5841 msgLeft = "";
5842 until ((msg == "") or (msg == " ") or (not parsed));
5843  
5844 return;
5845 end
5846 end
5847 end
5848  
5849 function DamageMeters_AddMsgToSyncQueue(msg, bAddToFront)
5850 if (bAddToFront == true) then
5851 table.insert(DamageMeters_syncMsgQueue, 1, msg);
5852 else
5853 table.insert(DamageMeters_syncMsgQueue, msg);
5854 end
5855 end
5856  
5857 function DamageMeters_ProcessMessages()
5858 local now = GetTime();
5859  
5860 -- In the case of lag spikes the time can be very large.
5861 local numToSend = DamageMeters_MAXSYNCMSGPERFRAME;
5862  
5863 local sent = 0;
5864 local toSend = getn(DamageMeters_syncMsgQueue);
5865 if ( getn(DamageMeters_syncMsgQueue) > 0 ) then
5866 while ( now - DamageMeters_lastSyncMsgTime > DamageMeters_SYNCMSGSENDDELAY) do
5867 if ( getn(DamageMeters_syncMsgQueue) > 0 ) then
5868 sent = sent + 1;
5869 --SendChatMessage(DamageMeters_syncMsgQueue[1], "CHANNEL", nil, GetChannelName(DamageMeters_syncChannel));
5870 --Telepathy.sendMessage(DamageMeters_SYNC_ID, DamageMeters_syncMsgQueue[1], "RAID", nil, "BULK");
5871 ChatThrottleLib:SendAddonMessage("BULK", DamageMeters_SYNC_ID, DamageMeters_syncMsgQueue[1], "RAID");
5872 table.remove(DamageMeters_syncMsgQueue, 1);
5873  
5874 numToSend = numToSend - 1;
5875 if (numToSend <= 0) then
5876 DamageMeters_lastSyncMsgTime = now;
5877 break;
5878 end
5879 else
5880 DamageMeters_lastSyncMsgTime = now;
5881 break;
5882 end
5883  
5884 DamageMeters_lastSyncMsgTime = DamageMeters_lastSyncMsgTime + DamageMeters_SYNCMSGSENDDELAY;
5885 end
5886 else
5887 DamageMeters_lastSyncMsgTime = now;
5888 end
5889  
5890 if (not DamageMeters_debug4.showGCInfo) then
5891 local leftToSend = getn(DamageMeters_syncMsgQueue);
5892 -- Note: Using 2 here so periodic update messages don't cause the text to show up.
5893 if (leftToSend < 2) then
5894 DamageMeters_sendMsgQueueBar:Hide();
5895 DamageMeters_sendMsgQueueBarText:SetText("");
5896 else
5897 DamageMeters_sendMsgQueueBar:SetValue(leftToSend);
5898 DamageMeters_sendMsgQueueBarText:SetText(DM_MENU_SENDINGBAR);
5899 end
5900 end
5901  
5902 -------------------------
5903  
5904 local processed = 0;
5905 local toProcess = getn(DamageMeters_syncIncMsgQueue);
5906 local initialElapsed = now - DamageMeters_lastSyncIncMsgTime;
5907  
5908 if (toProcess > 0) then
5909 DamageMeters_lastProcessQueueTime = now;
5910 end
5911  
5912 if ( getn(DamageMeters_syncIncMsgQueue) > 0 ) then
5913 while (now - DamageMeters_lastSyncIncMsgTime > DamageMeters_SYNCMSGPROCESSDELAY) do
5914 if ( getn(DamageMeters_syncIncMsgQueue) > 0 ) then
5915 processed = processed + 1;
5916 DamageMeters_ProcessSyncMsg(DamageMeters_syncIncMsgQueue[1], DamageMeters_syncIncMsgSourceQueue[1]);
5917  
5918 table.remove(DamageMeters_syncIncMsgQueue, 1);
5919 table.remove(DamageMeters_syncIncMsgSourceQueue, 1);
5920 else
5921 DamageMeters_lastSyncIncMsgTime = now;
5922 break;
5923 end
5924  
5925 DamageMeters_lastSyncIncMsgTime = DamageMeters_lastSyncIncMsgTime + DamageMeters_SYNCMSGPROCESSDELAY;
5926 end
5927 else
5928 DamageMeters_lastSyncIncMsgTime = now;
5929 end
5930  
5931 -- GCInfo doesn't show if this code runs. Hope this doesn't break anything.
5932 if (not DamageMeters_debug4.showGCInfo) then
5933 local leftToProcess = getn(DamageMeters_syncIncMsgQueue);
5934 if ((now - DamageMeters_lastProcessQueueTime) < 1.0) then
5935 DamageMeters_processMsgQueueBar:Show();
5936 DamageMeters_processMsgQueueBar:SetValue(leftToProcess);
5937 DamageMeters_processMsgQueueBarText:SetText(DM_MENU_PROCESSINGBAR);
5938 elseif (DamageMeters_processMsgQueueBar:IsVisible()) then
5939 DamageMeters_processMsgQueueBar:Hide();
5940 DamageMeters_processMsgQueueBarText:SetText("");
5941 end
5942 end
5943  
5944 if (DamageMeters_debug4.showSyncQueueInfo) then
5945 if (sent > 0 or processed > 0) then
5946 DMPrint(string.format("%.4f: sent = %d/%d, processed = %d/%d", initialElapsed, sent, toSend, processed, toProcess));
5947 end
5948 end
5949 end
5950  
5951  
5952 function DamageMeters_ToggleVariable(varName)
5953 DamageMeters_flags[varName] = not DamageMeters_flags[varName];
5954 end
5955  
5956 function DamageMeters_ToggleMiniMode(bSilent)
5957 DamageMeters_ToggleViewMode(DMVIEW_MIN);
5958  
5959 DamageMeters_frameNeedsToBeGenerated = true;
5960 if (not bSilent) then
5961 DMPrint(format(DM_MSG_MINBARS, ((DMVIEW_MIN == DamageMeters_viewMode) and DM_MSG_TRUE or DM_MSG_FALSE)));
5962 end
5963 end
5964  
5965 function DamageMeters_DoRestoreDefaultOptions()
5966 DamageMeters_SetDefaultOptions();
5967 DamageMeters_frameNeedsToBeGenerated = true;
5968 end
5969  
5970 function DamageMetersMenu_ToggleVariable()
5971 DamageMeters_ToggleVariable(this.value);
5972 end
5973  
5974 function DamageMetersMenu_ToggleVariableAndRegen()
5975 DamageMeters_ToggleVariable(this.value);
5976 DamageMeters_frameNeedsToBeGenerated = true;
5977 end
5978  
5979 -- Put updating here that must happen even when the meters are hidden.
5980 -- Note that this mostly is for TitanPanel's benefit, as we still need values
5981 -- updated and sorted when hidden because of the titan plugin.
5982 function DamageMetersHiddenFrame_OnUpdate()
5983 -- Process the message queue.
5984 DamageMeters_ProcessMessages(elapsed);
5985  
5986 -- Update combat end time so that the Titan DPS display can be accurate.
5987 if (DamageMeters_inCombat) then
5988 DamageMeters_combatEndTime = GetTime();
5989 end
5990  
5991 -- If we aren't visible then we fire off the table updating (sorting) here.
5992 if (not DamageMeters_flags[DMFLAG_isVisible]) then
5993 local bSecondHasPassedSinceLastBarUpdate = (GetTime() - DamageMeters_lastBarUpdateTime) > 1.0;
5994 if (DamageMeters_tablesDirty and (DamageMeters_flags[DMFLAG_constantVisualUpdate] or bSecondHasPassedSinceLastBarUpdate)) then
5995 DamageMeters_lastBarUpdateTime = GetTime();
5996 DamageMeters_UpdateTables();
5997 end
5998 end
5999  
6000 DamageMetersFrame_DragUpdate();
6001 end
6002  
6003 function DamageMeters_SyncHalt()
6004 if (DamageMeters_CheckSyncChan()) then
6005 --SendChatMessage(DamageMeters_SYNCHALT, "CHANNEL", nil, GetChannelName(DamageMeters_syncChannel));
6006 --Telepathy.sendMessage(DamageMeters_SYNC_ID, DamageMeters_SYNCHALT, "RAID");
6007 ChatThrottleLib:SendAddonMessage("NORMAL", DamageMeters_SYNC_ID, DamageMeters_SYNCHALT, "RAID");
6008  
6009 DMPrint(DM_MSG_SYNCHALTSENT);
6010  
6011 -- Clear the message queues.
6012 DamageMeters_syncMsgQueue = {};
6013 DamageMeters_syncIncMsgQueue = {};
6014 DamageMeters_syncIncMsgSourceQueue = {};
6015 end
6016 end
6017  
6018 function DamageMeters_CheckSession(tableIndex, sessionLabel, sessionIndex)
6019 if (sessionLabel ~= DamageMeters_tableInfo[tableIndex].sessionLabel or
6020 sessionIndex ~= DamageMeters_tableInfo[tableIndex].sessionIndex) then
6021 DMPrint(string.format("Local = <%s> #%d. Incoming = <%s> #%d.",
6022 DamageMeters_tableInfo[tableIndex].sessionLabel,
6023 DamageMeters_tableInfo[tableIndex].sessionIndex,
6024 sessionLabel,
6025 sessionIndex));
6026 DamageMeters_Clear();
6027 DamageMeters_tableInfo[tableIndex].sessionLabel = sessionLabel;
6028 DamageMeters_tableInfo[tableIndex].sessionIndex = sessionIndex;
6029 return false;
6030 else
6031 return true;
6032 end
6033 end
6034  
6035 --[[
6036 function DamageMeters_SyncBossStart(arg1)
6037 if (DamageMeters_CheckSyncChan()) then
6038 if (nil == arg1 or "" == arg1) then
6039 DMPrint(DM_ERROR_MISSINGARG);
6040 return;
6041 end
6042  
6043 local bossLabel = arg1;
6044 DamageMeters_DoSyncBossStart(DamageMeters_tableInfo[DMT_ACTIVE].sessionLabel, DamageMeters_tableInfo[DMT_ACTIVE].sessionIndex, bossLabel);
6045  
6046 local message = DamageMeters_SYNCBOSSSTART.." "..label;
6047 SendChatMessage(message, "CHANNEL", nil, GetChannelName(DamageMeters_syncChannel));
6048 end
6049 end
6050  
6051 function DamageMeters_DoSyncBossStart(mainLabel, mainIndex, bossLabel)
6052 if (DamageMeters_bInBossMode) then
6053 --!
6054 DMPrint("Warning: Already in boss mode, replacing current boss table with new one.");
6055 else
6056 DamageMeters_Swap();
6057 end
6058  
6059 DamageMeters_pauseState = DM_Pause_Paused;
6060 DamageMeters_CompletePauseChange(true);
6061  
6062 DamageMeters_flags[DMFLAG_accumulateToMemory] = true;
6063  
6064 -- SyncLabel
6065 DamageMeters_tableInfo[DMT_ACTIVE].sessionIndex = 1;
6066 DamageMeters_tableInfo[DMT_ACTIVE].sessionLabel = label;
6067  
6068 DamageMeters_bInBossMode = true;
6069 end
6070  
6071 function DamageMeters_SyncBossEnd()
6072 if (DamageMeters_CheckSyncChan()) then
6073 DamageMeters_DoSyncBossEnd();
6074  
6075 local message = DamageMeters_SYNCBOSSEND;
6076 SendChatMessage(message, "CHANNEL", nil, GetChannelName(DamageMeters_syncChannel));
6077 end
6078 end
6079  
6080 function DamageMeters_DoSyncBossEnd()
6081 if (DamageMeters_bInBossMode) then
6082 DamageMeters_pauseState = DM_Pause_Paused;
6083 DamageMeters_CompletePauseChange(true);
6084  
6085 DamageMeters_Swap();
6086 DamageMeters_flags[DMFLAG_accumulateToMemory] = false;
6087 DamageMeters_bInBossMode = false;
6088 else
6089 --!
6090 DMPrint("Warning: Not in boss mode, but instructed to end boss mode. Doing nothing.");
6091 end
6092 end
6093 ]]--
6094  
6095 -------------------------------------------------------------------------------
6096 -- Dragging
6097  
6098 -- Drag global variables
6099 DamageMeters_dragStartX = nil;
6100 DamageMeters_dragStartY = nil;
6101 DamageMeters_widthAtDragStart = nil;
6102 DamageMeters_draggingRight = nil;
6103 DamageMeters_draggingBottom = nil;
6104 DamageMeters_barCountAtStart = nil;
6105 DamageMeters_resizeLeftAtDragStart = nil;
6106 DamageMeters_resizeUpAtDragStart = nil;
6107  
6108 function DamageMetersFrame_OnMouseDown()
6109 local xLoc, yLoc = GetCursorPosition();
6110 --DMPrintD("local = "..xLoc..", "..yLoc);
6111  
6112 local effectiveScale = this:GetEffectiveScale();
6113 local left = this:GetLeft() * effectiveScale;
6114 local top = this:GetTop() * effectiveScale;
6115 local right = this:GetRight() * effectiveScale;
6116 local bottom = this:GetBottom() * effectiveScale;
6117 --DMPrintD("Frame: x = ("..left.."->"..right.."), y = ("..top.."->"..bottom..")");
6118  
6119 if (abs(xLoc - left) < 10) then
6120 DamageMeters_draggingRight = false;
6121 elseif (abs(xLoc - right) < 10) then
6122 DamageMeters_draggingRight = true;
6123 end
6124  
6125 if (abs(yLoc - bottom) < 10) then
6126 DamageMeters_draggingBottom = true;
6127 elseif (abs(yLoc - top) < 10) then
6128 DamageMeters_draggingBottom = false;
6129 end
6130  
6131 if (not DamageMeters_flags[DMFLAG_positionLocked]) then
6132 if (nil ~= DamageMeters_draggingRight or nil ~= DamageMeters_draggingBottom) then
6133 if (DMVIEW_MAX == DamageMeters_viewMode or
6134 (DMVIEW_MIN == DamageMeters_viewMode and DamageMeters_draggingBottom ~= nil)) then
6135 -- Do Moving.
6136 this:StartMoving();
6137 this.isMoving = true;
6138  
6139 --DMPrintD("Moving");
6140 DamageMeters_draggingRight = nil;
6141 DamageMeters_draggingBottom = nil;
6142 else
6143 DamageMeters_dragStartX, DamageMeters_dragStartY = GetCursorPosition(UIParent);
6144 --DMPrintD("Dragging");
6145 end
6146 end
6147 end
6148 end
6149  
6150 function DamageMetersFrame_OnMouseUp()
6151 if (this.isMoving == true) then
6152 -- Stop dragging.
6153 this:StopMovingOrSizing();
6154 this.isMoving = false;
6155 end
6156 end
6157  
6158 function DamageMetersFrame_OnDragStart()
6159 if ((not DamageMeters_flags[DMFLAG_positionLocked]) and this.isMoving ~= true and (DamageMeters_dragStartX ~= nil)) then
6160 DamageMeters_widthAtDragStart = DamageMeters_BARWIDTH;
6161 DamageMeters_barCountAtStart = DamageMeters_barCount;
6162 DamageMeters_resizeLeftAtDragStart = DamageMeters_flags[DMFLAG_resizeLeft];
6163 DamageMeters_resizeUpAtDragStart = DamageMeters_flags[DMFLAG_resizeUp];
6164  
6165 DMPrintD("DamageMetersFrame: OnDragStart ("..DamageMeters_dragStartX..", "..DamageMeters_dragStartY..")");
6166 DMPrintD("Effective Scale = "..this:GetEffectiveScale());
6167  
6168 if (DamageMeters_draggingRight) then
6169 DamageMeters_flags[DMFLAG_resizeLeft] = false;
6170 elseif (not DamageMeters_draggingRight) then
6171 DamageMeters_flags[DMFLAG_resizeLeft] = true;
6172 end
6173  
6174 if (DMVIEW_MIN == DamageMeters_viewMode) then
6175  
6176 else
6177 if (DamageMeters_draggingBottom) then
6178 DamageMeters_flags[DMFLAG_resizeUp] = false;
6179 elseif(not DamageMeters_draggingBottom) then
6180 DamageMeters_flags[DMFLAG_resizeUp] = true;
6181 end
6182 end
6183 end
6184 end
6185  
6186 function DamageMetersFrame_OnDragStop()
6187 if (this.isMoving ~= true and (DamageMeters_dragStartX ~= nil)) then
6188 local endX, endY = GetCursorPosition(UIParent);
6189 --DMPrintD("DamageMetersFrame: OnDragStop ("..endX..", "..endY..")");
6190 local deltaX = endX - DamageMeters_dragStartX;
6191 local deltaY = endY - DamageMeters_dragStartY;
6192 --DMPrintD("Delta = ("..deltaX..", "..deltaY..")");
6193  
6194 DamageMeters_flags[DMFLAG_resizeLeft] = DamageMeters_resizeLeftAtDragStart
6195 DamageMeters_flags[DMFLAG_resizeUp] = DamageMeters_resizeUpAtDragStart;
6196  
6197 DamageMeters_dragStartX = nil;
6198 DamageMeters_dragStartY = nil;
6199 DamageMeters_widthAtDragStart = nil;
6200 DamageMeters_draggingRight = nil;
6201 DamageMeters_draggingBottom = nil;
6202 DamageMeters_barCountAtStart = nil;
6203 end
6204 end
6205  
6206 function DamageMetersFrame_DragUpdate()
6207 if ((not DamageMeters_flags[DMFLAG_positionLocked]) and not this.isMoving) then
6208 if (DamageMeters_widthAtDragStart ~= nil) then
6209 local endX, endY = GetCursorPosition(UIParent);
6210 local deltaX = (endX - DamageMeters_dragStartX) / this:GetEffectiveScale();
6211 local deltaY = (endY - DamageMeters_dragStartY) / this:GetEffectiveScale();
6212  
6213 if (DamageMeters_draggingRight ~= nil) then
6214 if (not DamageMeters_draggingRight) then
6215 deltaX = -deltaX;
6216 end
6217 if (DamageMeters_barCount > 20) then
6218 deltaX = deltaX / 2;
6219 end
6220  
6221 local newWidth = max(50, DamageMeters_widthAtDragStart + deltaX);
6222 newWidth = min(600, newWidth);
6223 DamageMeters_SetBarWidth(newWidth, true);
6224 end
6225  
6226 if (DamageMeters_draggingBottom ~= nil) then
6227 if (DamageMeters_draggingBottom) then
6228 deltaY = -deltaY;
6229 end
6230 local barDelta = deltaY / DamageMeters_BARHEIGHT;
6231 barDelta = floor(barDelta);
6232 if (DamageMeters_barCount > 20) then
6233 barDelta = barDelta * 2;
6234 end
6235 if (barDelta ~= 0) then
6236 local newBarCount = DamageMeters_barCountAtStart + barDelta;
6237 if (((DamageMeters_barCount < 20) and newBarCount < 20 and newBarCount > 0 and DamageMeters_barCount ~= newBarCount) or
6238 ((DamageMeters_barCount > 20) and newBarCount > 20 and newBarCount < 40 and DamageMeters_barCount ~= newBarCount)) then
6239 DamageMeters_SetCount(newBarCount, true);
6240 end
6241 else
6242 end
6243 end
6244 end
6245 end
6246 end
6247  
6248 -------------------------------------------------------------------------------
6249  
6250 DMRPS_PREFIX = "DMRPS: ";
6251  
6252 DamageMeters_RPSChallengedList = {};
6253 DamageMeters_RPSChallengedByList = {};
6254  
6255 function DamageMeters_RPSChallenge(arg)
6256 if (not DamageMeters_CheckSyncChan()) then
6257 return;
6258 end
6259  
6260 if (arg == nil or arg == "") then
6261 DMPrint(DM_ERROR_MISSINGARG);
6262 return;
6263 end
6264  
6265 local found, player, move;
6266 found,_,player,move = string.find(arg, "(.+) (.)");
6267 if (not found) then
6268 DMPrint(DM_ERROR_INVALIDARG);
6269 return;
6270 end
6271  
6272 move = string.lower(move);
6273 if (move ~= "r" and move ~= "p" and move ~= "s") then
6274 DMPrint(DM_ERROR_INVALIDARG);
6275 return;
6276 end
6277  
6278 if (player == nil or player == "") then
6279 DMPrint(DM_ERROR_MISSINGARG);
6280 return;
6281 end
6282  
6283 player = string.lower(player);
6284 player = string.upper(string.sub(player, 1, 1))..string.sub(player, 2);
6285 DamageMeters_RPSChallengedList[player] = move;
6286  
6287 DMPrint(string.format(DMRPS_PREFIX..DM_MSG_RPS_CHALLENGE, player, DamageMeters_RPSmoveStrings[move]), DamageMeters_RPSCOLOR);
6288  
6289 local moveNumber = string.byte(move);
6290 DamageMeters_AddMsgToSyncQueue(string.format("%s %s", DamageMeters_SYNCRPS, player));
6291 end
6292  
6293 function DamageMeters_RPSChallengeReceived(player, arg)
6294 local defender = arg;
6295 if (string.lower(UnitName("Player")) == string.lower(defender)) then
6296 DMPrint(string.format(DMRPS_PREFIX..DM_MSG_RPS_CHALLENGED, player), DamageMeters_RPSCOLOR);
6297  
6298 local struct = {player = player, move = ""};
6299 table.insert(DamageMeters_RPSChallengedByList, struct);
6300 end
6301 end
6302  
6303 function DamageMeters_RPSResponse(arg)
6304 if (not DamageMeters_CheckSyncChan()) then
6305 return;
6306 end
6307  
6308 if (arg == nil or arg == "") then
6309 DMPrint(DM_ERROR_MISSINGARG);
6310 return;
6311 end
6312  
6313 local found, player, move;
6314 found,_,player,move = string.find(arg, "(.+) (.+)");
6315 if (not found) then
6316 found,_,move = string.find(arg, "(.+)");
6317 if (found) then
6318 if (table.getn(DamageMeters_RPSChallengedByList) == 1) then
6319 local index, struct;
6320 for index, struct in DamageMeters_RPSChallengedByList do
6321 player = struct.player;
6322 break;
6323 end
6324 else
6325 DMPrint(table.getn(DamageMeters_RPSChallengedByList));
6326 for _player, unused in DamageMeters_RPSChallengedByList do
6327 DMPrint(player);
6328 break;
6329 end
6330  
6331 DMPrint(DM_MSG_RPS_MISSING_PLAYER, DamageMeters_RPSCOLOR);
6332 end
6333 else
6334 DMPrint(DM_ERROR_INVALIDARG);
6335 return;
6336 end
6337 end
6338 if (move == nil or move == "") then
6339 DMPrint(DM_ERROR_MISSINGARG);
6340 return;
6341 end
6342 if (player == nil or player == "") then
6343 DMPrint(DM_ERROR_MISSINGARG);
6344 return;
6345 end
6346 player = string.lower(player);
6347 player = string.upper(string.sub(player, 1, 1))..string.sub(player, 2);
6348  
6349 move = string.lower(move);
6350 if (move ~= "r" and move ~= "p" and move ~= "s") then
6351 DMPrint(DM_ERROR_INVALIDARG);
6352 return;
6353 end
6354  
6355 local playerListIndex = nil;
6356 for index, struct in DamageMeters_RPSChallengedByList do
6357 if (struct.player == player) then
6358 playerListIndex = index;
6359 break;
6360 end
6361 end
6362  
6363 if (playerListIndex == nil) then
6364 DMPrint(string.format(DM_MSG_RPS_NOTCHALLENGED, player), DamageMeters_RPSCOLOR);
6365 return;
6366 end
6367  
6368 DMPrint(string.format(DMRPS_PREFIX..DM_MSG_RPS_YOUPLAY, DamageMeters_RPSmoveStrings[move]), DamageMeters_RPSCOLOR);
6369  
6370 DamageMeters_RPSChallengedByList[playerListIndex].move = move;
6371  
6372 local moveNumber = string.byte(move);
6373 DamageMeters_AddMsgToSyncQueue(string.format("%s %s %d", DamageMeters_SYNCRPSRESPONSE, player, moveNumber));
6374 end
6375  
6376 function DamageMeters_RPSResponseReceived(sourcePlayer, arg)
6377 local found, player, moveNumber;
6378 found,_,player,moveNumber = string.find(arg, "(.+) (%d+)");
6379 if (not found) then
6380 DMPrint("Error parsing RPS response.");
6381 return;
6382 end
6383  
6384 if (string.lower(player) ~= string.lower(UnitName("player"))) then
6385 -- Not for us.
6386 return;
6387 end
6388  
6389 if (DamageMeters_RPSChallengedList[sourcePlayer] ~= nil) then
6390 -- We were the attacker.
6391 local move = string.char(tonumber(moveNumber));
6392 DamageMeters_RPSPrintResult(DamageMeters_RPSChallengedList[sourcePlayer], move, sourcePlayer);
6393  
6394 -- Send our move
6395 local moveNumber = string.byte(DamageMeters_RPSChallengedList[sourcePlayer]);
6396 DamageMeters_AddMsgToSyncQueue(string.format("%s %s %d", DamageMeters_SYNCRPSCOUNTERRESPONSE, sourcePlayer, moveNumber));
6397  
6398 -- Game over for us.
6399 DamageMeters_RPSChallengedList[sourcePlayer] = nil;
6400 end
6401 end
6402  
6403 function DamageMeters_RPSCounterresponseRecieved(sourcePlayer, arg)
6404 local found, player, moveNumber;
6405 found,_,player,moveNumber = string.find(arg, "(.+) (%d+)");
6406 if (not found) then
6407 DMPrint("Error parsing RPS response.");
6408 return;
6409 end
6410  
6411 if (string.lower(player) ~= string.lower(UnitName("player"))) then
6412 -- Not for us.
6413 return;
6414 end
6415  
6416 local move = string.char(tonumber(moveNumber));
6417  
6418 if (DamageMeters_RPSChallengedByList[sourcePlayer] ~= nil) then
6419 -- We were the defender.
6420 local move = string.char(tonumber(moveNumber));
6421 DamageMeters_RPSPrintResult(DamageMeters_RPSChallengedByList[sourcePlayer], move, sourcePlayer);
6422  
6423 -- Game over.
6424 DamageMeters_RPSChallengedByList[sourcePlayer] = nil;
6425 end
6426 end
6427  
6428 function DamageMeters_RPSPrintResult(myMove, opponentsMove, opponent)
6429 DMPrint(string.format(DMRPS_PREFIX..DM_MSG_RPS_PLAYS, opponent, DamageMeters_RPSmoveStrings[opponentsMove]), DamageMeters_RPSCOLOR);
6430  
6431 if (myMove == opponentsMove) then
6432 DMPrint(string.format(DM_MSG_RPS_TIE, opponent), DamageMeters_RPSCOLOR);
6433 elseif ((opponentsMove == "r" and myMove == "s") or
6434 (opponentsMove == "p" and myMove == "r") or
6435 (opponentsMove == "s" and myMove == "p")) then
6436 DMPrint(string.format(DMRPS_PREFIX..DM_MSG_RPS_DEFEATED, opponent), DamageMeters_RPSCOLOR);
6437 else
6438 DMPrint(string.format(DMRPS_PREFIX..DM_MSG_RPS_VICTORIOUS, opponent), DamageMeters_RPSCOLOR);
6439 end
6440 end
6441  
6442 function DamageMeters_RPSReset()
6443 DamageMeters_queuedRPSMove = nil;
6444 DamageMeters_queuedRPSOpponent = nil;
6445 DamageMeters_bRPSAttacker = false;
6446 end
6447  
6448 -------------------------------------------------------------------------------
6449  
6450 --DM_useEventCaseTableDebug = true;
6451  
6452 local function convertPattern(patternString, patternInfo)
6453 -- Add % to escape all magic characters used in LUA pattern matching, except $ and %
6454 patternString = string.gsub(patternString,"([%^%(%)%.%[%]%*%+%-%?])","%%%1")
6455  
6456 -- Do these AFTER escaping the magic characters.
6457 patternString = string.gsub(patternString,"%%s","(.-)") -- %s to (.-)
6458 patternString = string.gsub(patternString,"%%d","(%%d+)") -- %d to (%d+)
6459  
6460 if string.find(patternString, "%$") then
6461 local field = { } -- fills with ordered list of $s as they appear
6462 local idx = 1 -- incremental index into field[]
6463  
6464 for i in string.gfind(patternString,"%%(%d)%$.") do
6465 field[idx] = tonumber(i)
6466 idx = idx + 1
6467 end
6468  
6469 for k in field do
6470 for j in patternInfo do
6471 if patternInfo[j] == field[k] then
6472 patternInfo[j] = tostring(k)
6473 end
6474 end
6475 end
6476  
6477 -- Convert them back to number, if they are number (6 will not be converted), tonumber() will not change their values.
6478 for j in patternInfo do
6479 if tonumber(patternInfo[j]) then
6480 patternInfo[j] = tonumber(patternInfo[j])
6481 end
6482 end
6483  
6484 patternString = string.gsub(patternString,"%%%d%$s","(.-)") -- %1$s to (.-)
6485 patternString = string.gsub(patternString,"%%%d%$d","(%%d+)") -- %1$d to (%d+)
6486  
6487 end
6488  
6489 -- Escape $ now.
6490 patternString = string.gsub(patternString,"%$","%%$")
6491  
6492 -- If the pattern ends with (.-), libace it with (.+), or the capsule will be lost.
6493 if string.sub(patternString, -4) == "(.-)" then
6494 pattern = string.sub(patternString, 0, -5) .. "(.+)"
6495 end
6496  
6497 return "^"..patternString;
6498 end
6499  
6500  
6501  
6502 function DamageMeters_FixPatterns()
6503 for messageID, msgInfo in DamageMeters_msgInfo do
6504 if (not msgInfo.custom) then
6505 local pattern = msgInfo.pattern;
6506 if (nil == pattern) then
6507 DMPrint("INTERNAL ERROR: Pattern for "..messageID.." = nil.");
6508 else
6509 pattern = convertPattern(pattern, msgInfo);
6510 DMPrintD(msgInfo.pattern.." -> "..pattern, nil, true);
6511 msgInfo.pattern = pattern;
6512 end
6513 end
6514 end
6515  
6516 --[[function DamageMeters_FixPatterns()
6517 for messageID, msgInfo in DamageMeters_msgInfo do
6518 if (not msgInfo.custom) then
6519 local pattern = msgInfo.pattern;
6520 if (nil == pattern) then
6521 DMPrint("INTERNAL ERROR: Pattern for "..messageID.." = nil.");
6522 else
6523 --AmbigousFix, needed?--
6524 --pattern = string.gsub(string.gsub(pattern, "(%%%d%$s)s", "%1\'s"), "%%ss", "%%s\'s")
6525  
6526 --Strip string format indicators, might seriously mess parsing up if arguments are not in the same order as in enGB/enUS
6527 --pattern = string.gsub(pattern, "%%%d%$(%a)", "%%%1")
6528  
6529 pattern = string.gsub(pattern, "%.", "%%.");
6530 pattern = string.gsub(pattern, "%%s", "(.+)");
6531 pattern = string.gsub(pattern, "%%d", "(%%d+)");
6532 DMPrintD(msgInfo.pattern.." -> "..pattern, nil, true);
6533 msgInfo.pattern = pattern;
6534 end
6535 end
6536 end]]
6537  
6538 -- Dand: Note that if you set this variable to true then all kinds of crazy stuff
6539 -- will be stored in this DamageMeters_eventCaseTable variable--namely, which messages
6540 -- where parsed how and which messages weren't parsed. The system is pretty crude atm
6541 -- so you'll have to figure this out on your own, I'm afraid.
6542 --if (DM_useEventCaseTableDebug) then
6543 if (false) then
6544 DM_eventCaseTableDebug = DM_clone(DamageMeters_eventCaseTable);
6545 for msgType, msgTypeTable in DM_eventCaseTableDebug do
6546 for event, eventTable in msgTypeTable do
6547 for caseIx, case in eventTable do
6548 case.hitCount = 0;
6549 end
6550  
6551 eventTable.hitCount = 0;
6552 eventTable.parseCount = 0;
6553 end
6554 end
6555 end
6556 end
6557  
6558 -- This made global to keep it from hammering the GC.
6559 DM_elem = {"", "", "", "", "", ""};
6560  
6561 function DamageMeters_CheckMsgInfoAndProcess(event, message, msgInfoName, msgInfo, msgType, sourceRelationOverride, destRelationOverride)
6562 if (DM_Bypass["CheckMsgInfoAndProcess"] == true) then
6563 return;
6564 end
6565  
6566 if (nil == msgInfo.pattern) then
6567 DMPrint("INTERNAL ERROR: msgInfo "..msgInfoName.." has a nil pattern.");
6568  
6569 DM_DUMP_TABLE(msgInfo);
6570  
6571 return false;
6572 end
6573  
6574 if (DM_Bypass["CheckMsgInfoAndProcess 1"] == true) then
6575 return;
6576 end
6577  
6578 local found;
6579 DMPrintD("message: "..message);
6580 DMPrintD("msgInfo.pattern: "..msgInfo.pattern);
6581 found, _, DM_elem[1], DM_elem[2], DM_elem[3], DM_elem[4], DM_elem[5], DM_elem[6] = string.find(message, msgInfo.pattern)
6582 if (found) then
6583 local sourceRelation = msgInfo.relationship;
6584  
6585 local sourceName;
6586 if (msgInfo.source == 0) then
6587 sourceRelation = DamageMeters_Relation_SELF;
6588 sourceName = UnitName("Player");
6589 else
6590 sourceRelation = DamageMeters_Relation_FRIENDLY;
6591 sourceName = DM_elem[msgInfo.source];
6592 if (sourceName == nil) then
6593 DMPrintD("INTERNAL ERROR: msgInfo "..msgInfoName.." has source = nil.");
6594 return true;
6595 end
6596 end
6597 if (sourceRelationOverride ~= nil) then
6598 sourceRelation = sourceRelationOverride;
6599 end
6600  
6601 local destRelation = DamageMeters_Relation_FRIENDLY;
6602 local destName;
6603 if (nil == msgInfo.dest) then
6604 destName = "";
6605 elseif (0 == msgInfo.dest) then
6606 destRelation = DamageMeters_Relation_SELF
6607 destName = UnitName("Player");
6608 else
6609 destName = DM_elem[msgInfo.dest];
6610 end
6611 if (nil == destName) then
6612 DMPrint("ERROR: destName = nil. msgInfo.dest = "..msgInfo.dest..", event = "..event);
6613 destName = "";
6614 end
6615 if (destRelationOverride ~= nil) then
6616 destRelation = destRelationOverride;
6617 end
6618  
6619 local amount = 0;
6620 if (msgInfo.amount > 0) then
6621 amount = tonumber(DM_elem[msgInfo.amount]);
6622 if (nil == amount) then
6623 if (msgInfo.amount == nil) then
6624 DMPrint("INTERNAL ERROR: msgInfo.amount == nil");
6625 else
6626 DMPrint("INTERNAL ERROR: DM_elem[msgInfo.amount] == nil");
6627 end
6628 return true;
6629 end
6630 end
6631  
6632 local crit = msgInfo.crit;
6633 if (crit == nil) then
6634 DMPrintD("CRIT = NIL", {r=1, g=0, b=0}, true);
6635 DM_DUMP_TABLE(msgInfo);
6636 crit = DM_HIT;
6637 end
6638  
6639 local spell;
6640 if (nil == msgInfo.spell) then
6641 spell = DM_DMG_MELEE;
6642 elseif (type(msgInfo.spell) == "string") then
6643 spell = msgInfo.spell;
6644 elseif (0 == msgInfo.spell) then
6645 spell = DM_DMG_MELEE;
6646 else
6647 spell = DM_elem[msgInfo.spell];
6648 if (nil == spell) then
6649 DMPrintD("INTERNAL ERROR: ("..msgInfoName..") DM_elem "..msgInfo.spell.." is nil in: "..message);
6650 end
6651 end
6652  
6653 local damageType;
6654 if (msgInfo.damageType == 0 or msgInfo.damageType == nil) then
6655 damageType = DM_DMGTYPE_DEFAULT;
6656 else
6657 damageType = DM_elem[msgInfo.damageType];
6658 if (nil == damageType) then
6659 DMPrint("INTERNAL ERROR: "..msgInfoName.." damageType = nil. (msgInfo.damageType = "..msgInfo.damageType..")");
6660 return true;
6661 end
6662 end
6663  
6664 local resisted = 0;
6665 --if (msgInfo.resisted) then
6666 -- resisted = DM_elem[msgInfo.resisted];
6667 --end
6668  
6669 --[[
6670 DMPrintD(event.."->"..msgInfoName.." ("..msgType..")", {r=0, g=1.0, b=0}, true);
6671 DMPrintD(string.format("source = %s, dest = %s, amount = %d, crit = %d, sourceRelation = %s, targetRelation = %s, spell = %s, damageType = %s",
6672 sourceName, destName, amount, crit, DamageMeters_Relation_STRING[sourceRelation], DamageMeters_Relation_STRING[destRelation], spell, damageType), nil, true);
6673 ]]--
6674 if (DamageMeters_debug4.showParse) then
6675 DMPrintD("["..event.."] ["..msgInfoName.."]:", {r=0,g=1,b=0}, true);
6676 DMPrintD(": "..message, {r=1,g=1,b=1}, true);
6677 end
6678  
6679 --DM_CountMsg(message, msgInfoName, event);
6680 if (msgType == DM_MSGTYPE_DAMAGE) then
6681 DamageMeters_AddDamage (event, sourceName, destName, amount, crit, sourceRelation, spell, damageType);
6682 elseif (msgType == DM_MSGTYPE_DAMAGERECEIVED) then
6683 DamageMeters_AddDamageReceived (event, destName, sourceName, amount, crit, destRelation, spell, damageType, resisted)
6684 elseif (msgType == DM_MSGTYPE_HEALING) then
6685 DamageMeters_AddHealing (event, sourceName, destName, amount, crit, sourceRelation, destRelation, spell)
6686 else
6687 DMPrintD("INTERNAL ERROR: invalid msgType "..msgType);
6688 end
6689  
6690 return true;
6691 end
6692  
6693 return false;
6694 end
6695  
6696 function DamageMeters_ParseMessage(arg1, event)
6697  
6698 ----------------------
6699 -- CURING MESSAGES --
6700 ----------------------
6701  
6702 if (event == "CHAT_MSG_SPELL_SELF_BUFF" or
6703 event == "CHAT_MSG_SPELL_HOSTILEPLAYER_BUFF" or
6704 event == "CHAT_MSG_SPELL_FRIENDLYPLAYER_BUFF") then
6705  
6706 for i in DM_Spellometer_Patterns do
6707 local caster, spell, target;
6708 local matches = {};
6709 local found;
6710  
6711 found,_,matches[1],matches[2],matches[3] = string.find(arg1, DM_Spellometer_Patterns[i].pattern);
6712  
6713 if found then
6714 local casterRelationship = DamageMeters_Relation_FRIENDLY;
6715  
6716 caster = matches[DM_Spellometer_Patterns[i].caster];
6717 spell = matches[DM_Spellometer_Patterns[i].spell];
6718 if DM_Spellometer_Patterns[i].target ~= nil then
6719 target = matches[DM_Spellometer_Patterns[i].target];
6720 else
6721 target = UnitName("player");
6722 end
6723 if caster == "You" then
6724 caster = UnitName("player");
6725 casterRelationship = DamageMeters_Relation_SELF;
6726 end
6727  
6728 local spellFound = false;
6729 for index, cureSpell in DM_CURESPELLS do
6730 if (cureSpell == spell) then
6731 spellFound = true;
6732 break;
6733 end
6734 end
6735  
6736 if (spellFound == true) then
6737 DamageMeters_AddValue(caster, 1, DM_HIT, casterRelationship, DamageMeters_Quantity_CURING, spell);
6738 end
6739 return;
6740 end
6741 end
6742 end
6743  
6744 ----------------------
6745 -- REGULAR MESSAGES --
6746 ----------------------
6747  
6748 DamageMeters_StartDebugTimer(DMPROF_PARSEMESSAGE);
6749  
6750 --DMPrint("["..event.."]: "..arg1, nil, true);
6751  
6752 local eventCase = nil;
6753 local msgType;
6754 for _msgType, msgTypeTable in DamageMeters_eventCaseTable do
6755 eventCase = msgTypeTable[event];
6756 msgType = _msgType;
6757 if (eventCase ~= nil) then
6758 break;
6759 end
6760 end
6761  
6762 if (DM_useEventCaseTableDebug) then
6763 DM_eventCaseTableDebug[msgType][event].hitCount = DM_eventCaseTableDebug[msgType][event].hitCount + 1;
6764 end
6765  
6766 if (nil == eventCase) then
6767 DMPrintD("INTERNAL ERROR: Attempted to parse message but no handler for it. event = "..event);
6768 else
6769 for msgInfoIndex, msgInfoDetails in eventCase do
6770 local msgInfoName = msgInfoDetails.n;
6771 local msgInfo = DamageMeters_msgInfo[msgInfoName];
6772 if (nil == msgInfo) then
6773 DMPrintD("INTERNAL ERROR: msgInfoName "..msgInfoName.." invalid.");
6774 return;
6775 end
6776 local sourceRelation = msgInfoDetails.sourceRelation;
6777 local destRelation = msgInfoDetails.destRelation;
6778  
6779 local adjustedMsgType = msgType;
6780 if (nil ~= msgInfoDetails.msgType) then
6781 adjustedMsgType = msgInfoDetails.msgType;
6782 end
6783  
6784 if (DamageMeters_CheckMsgInfoAndProcess(event, arg1, msgInfoName, msgInfo, adjustedMsgType, sourceRelation, destRelation)) then
6785 if (DM_useEventCaseTableDebug) then
6786 DM_eventCaseTableDebug[msgType][event].parseCount = DM_eventCaseTableDebug[msgType][event].parseCount + 1;
6787  
6788 local debugCase = DM_eventCaseTableDebug[msgType][event][msgInfoIndex];
6789 if (nil == debugCase) then
6790 DMPrintD("debugCase = nil, msgType = "..msgType..", event = "..event..", msgInfoIndex = "..msgInfoIndex);
6791 else
6792 if (nil == debugCase.parsed) then
6793 debugCase.parsed = {};
6794 end
6795 debugCase.hitCount = debugCase.hitCount + 1;
6796 if (table.getn(debugCase.parsed) < 10) then
6797 local parsedMsg = arg1;
6798 table.insert(debugCase.parsed, parsedMsg);
6799 end
6800 end
6801 end
6802  
6803 return;
6804 end
6805 end
6806  
6807 if (DM_useEventCaseTableDebug) then
6808 -- If the message had a number in it we are probably interested in it.
6809 for amount in string.gfind(arg1, "(%d+)") do
6810  
6811 -- Eliminate numeric messages we aren't interested in:
6812 -- Wierd (#) messages (buffs)
6813 for player, amount, type in string.gfind(arg1, "%(%d+%)") do return; end
6814 -- GENERICPOWERGAIN_OTHER
6815 -- GENERICPOWERGAIN_SELF
6816 for player, amount, type in string.gfind(arg1, "(.+) gains (%d+) (.+)%.") do return; end
6817 for player, amount, type in string.gfind(arg1, "You gain (%d+) (.+)%.") do return; end
6818 -- SPELLEXTRAATTACKSOTHER_SINGULAR etc
6819 if (string.find(arg1, "extra attack")) then return; end
6820 -- ITEMENCHANTMENTADDOTHEROTHER, etc
6821 for player in string.gfind(arg1, "(.+) casts (.+) on (.+)'s (.+)%.") do return; end
6822 for player in string.gfind(arg1, "(.+) casts (.+) on your (.+)%.") do return; end
6823 for player in string.gfind(arg1, "You cast (.+) on (.+)'s (.+)%.") do return; end
6824 for player in string.gfind(arg1, "You cast (.+) on your (.+)%.") do return; end
6825 -- VSENVIRONMENTALDAMAGE_DROWNING_OTHER etc.
6826 for player in string.gfind(arg1, "You are drowning and lose (%d+) health.") do return; end
6827 for player in string.gfind(arg1, "(.+) is exhausted and and loses (%d+) health.") do return; end
6828 for player in string.gfind(arg1, "You are exhausted and lose (%d+) health.") do return; end
6829 for player in string.gfind(arg1, "(.+) suffers (%d+) points of fire damage.") do return; end
6830 for player in string.gfind(arg1, "You suffer (%d+) points of fire damage.") do return; end
6831 for player in string.gfind(arg1, "(.+) loses (%d+) health for swimming in (.+)%.") do return; end
6832 for player in string.gfind(arg1, "You lose (%d+) health for swimming in (.+)%.") do return; end
6833 -- SPELLPOWERDRAINOTHEROTHER etc
6834 for player in string.gfind(arg1, "(.+) drains (%d+) Mana from you.") do return; end
6835 for player in string.gfind(arg1, "(.+) drains (%d+) Mana from (.+)%.") do return; end
6836 for player in string.gfind(arg1, "You drain (%d+) Mana from (.+)%.") do return; end
6837 for player in string.gfind(arg1, "(.+) drains (%d+) Mana from you and gains (%d+)") do return; end
6838 for player in string.gfind(arg1, "You drain (%d+) Mana from (.+) and gain (%d+)") do return; end
6839  
6840 if (DamageMeters_debugEnabled) then
6841 DMPrintD("["..event.."]:", {r=1,g=0.25,b=0.25});
6842 DMPrintD(": "..arg1, {r=1,g=0.75,b=0.75});
6843 end
6844  
6845 local debugCase = DM_eventCaseTableDebug[msgType][event];
6846 if (nil == debugCase.unparsed) then
6847 debugCase.unparsed = {};
6848 end
6849 if (table.getn(debugCase.unparsed) < 10) then
6850 local unparsedMsg = arg1;
6851 table.insert(debugCase.unparsed, unparsedMsg);
6852 end
6853 return;
6854 end
6855 end
6856 end
6857  
6858 --? Right?
6859 DamageMeters_StopDebugTimer(DMPROF_PARSEMESSAGE);
6860 return;
6861 end
6862  
6863  
6864 -------------------------------------------------------------------------------
6865 -- Message Parsing
6866  
6867 function DamageMeters_ParseSyncMessage(msg, sender, method)
6868  
6869 -- Ignore messages from ourself.
6870 if (not DamageMeters_debug4.syncSelf) then
6871 if (sender == UnitName("Player")) then
6872 return;
6873 end
6874 end
6875  
6876 local firstSpace = string.find(msg, " ");
6877 local command, commandArgs;
6878 if (firstSpace ~= nil) then
6879 command = string.sub(msg, 1, firstSpace - 1);
6880 commandArgs = string.sub(msg, firstSpace + 1);
6881 else
6882 command = msg;
6883 commandArgs = "";
6884 end
6885  
6886 if ((strsub(msg, 1, string.len(DMSYNC_PREFIX)) == DMSYNC_PREFIX) or
6887 ((strsub(msg, 1, string.len(DMSYNC_EVENT_PREFIX)) == DMSYNC_EVENT_PREFIX))) then
6888 if (DamageMeters_debug4.syncSelf) then
6889 for index = 1, DamageMeters_debug_syncTestFactor do
6890 table.insert(DamageMeters_syncIncMsgQueue, msg);
6891 table.insert(DamageMeters_syncIncMsgSourceQueue, sender);
6892 end
6893 else
6894 table.insert(DamageMeters_syncIncMsgQueue, msg);
6895 table.insert(DamageMeters_syncIncMsgSourceQueue, sender);
6896 end
6897 return;
6898 elseif (command == DamageMeters_SYNCREQUEST) then
6899 -- Note: +1 doesn't allow for a space between prefix and params.
6900 local params = commandArgs;
6901 --DMPrintD("Incoming sync params = >"..params.."<");
6902 --SendChatMessage("Incoming sync params = >"..params.."<", "CHANNEL", nil, GetChannelName(DamageMeters_syncChannel));
6903 if (string.sub(params, 1, 1) == "E") then
6904 --SendChatMessage("E detected: syncing events.", "CHANNEL", nil, GetChannelName(DamageMeters_syncChannel));
6905 DamageMeters_syncEvents = true;
6906 params = string.sub(params, 3);
6907 end
6908 if (params) then
6909 for syncLabel, syncIndex in string.gfind(params, "<(.+) (%d+)>") do
6910 syncLabel = tostring(syncLabel);
6911 syncIndex = tonumber(syncIndex);
6912 -- Potential error: local sessionLabel can be nil. UPDATE: I think this is fixed.
6913 local currentLabel = DamageMeters_tableInfo[DMT_ACTIVE].sessionLabel;
6914 local currentIndex = DamageMeters_tableInfo[DMT_ACTIVE].sessionIndex;
6915 if (false == DamageMeters_CheckSession(DMT_ACTIVE, syncLabel, syncIndex)) then
6916 DMPrint(DM_MSG_SESSIONMISMATCH);
6917 local mismatchMsg = DamageMeters_SYNCSESSIONMISMATCH.." "..currentLabel.." "..currentIndex;
6918 --SendChatMessage(mismatchMsg, "CHANNEL", nil, GetChannelName(DamageMeters_syncChannel));
6919 --Telepathy.sendMessage(DamageMeters_SYNC_ID, mismatchMsg, "RAID");
6920 ChatThrottleLib:SendAddonMessage("NORMAL", DamageMeters_SYNC_ID, mismatchMsg, "RAID");
6921  
6922 else
6923 DMPrintD("Sync request recieved, session matches our own.");
6924 end
6925 end
6926 end
6927  
6928 local now = GetTime();
6929 if (now - DamageMeters_lastSyncTime > DamageMeters_MINSYNCCOOLDOWN) then
6930 local ackmsg = DamageMeters_syncEvents and DM_MSG_SYNCREQUESTACKEVENTS or DM_MSG_SYNCREQUESTACK;
6931 DMPrint(ackmsg.. sender, nil, true);
6932 DamageMeters_lastSyncTime = now;
6933 DamageMeters_SyncReport();
6934 else
6935 DMPrint(DM_ERROR_SYNCTOOSOON);
6936 end
6937 return;
6938 elseif (command == DamageMeters_SYNCCLEARREQUEST) then
6939 DMPrint(DM_MSG_CLEARRECEIVED.. sender, nil, true);
6940 --SendChatMessage(DamageMeters_SYNCCLEARACK, "CHANNEL", nil, GetChannelName(DamageMeters_syncChannel));
6941 --Telepathy.sendMessage(DamageMeters_SYNC_ID, DamageMeters_SYNCCLEARACK, "RAID");
6942 ChatThrottleLib:SendAddonMessage("NORMAL", DamageMeters_SYNC_ID, DamageMeters_SYNCCLEARACK, "RAID");
6943 DamageMeters_Clear();
6944  
6945 -- Check for session information, and update ours if it is there.
6946 for newLabel, newIndex in string.gfind(commandArgs, "(.+) (%d+)") do
6947 DamageMeters_tableInfo[DMT_ACTIVE].sessionLabel = tostring(newLabel);
6948 DamageMeters_tableInfo[DMT_ACTIVE].sessionIndex = tonumber(newIndex);
6949 break;
6950 end
6951  
6952 return;
6953 elseif (command == DamageMeters_SYNCCLEARACK) then
6954 --DMPrint(format(DM_MSG_CLEARACKNOWLEDGED, sender), nil, true);
6955 return;
6956 elseif (command == DamageMeters_SYNCJOINED) then
6957 local version = commandArgs;
6958 DMPrint(string.format(DM_MSG_PLAYERJOINEDSYNCCHAN, sender, version), nil, true);
6959 return;
6960 elseif (command == DamageMeters_SYNCSTART) then
6961 DMPrint(format(DM_MSG_RECEIVEDSYNCDATA, sender), nil, true);
6962 return;
6963 elseif (command == DamageMeters_SYNCEND) then
6964 -- Nothing atm.
6965 return;
6966 elseif (command == DamageMeters_SYNCPINGREQ) then
6967 DamageMeters_SyncPingReply(sender);
6968 return;
6969 elseif (msg == DamageMeters_SYNCHALT) then
6970 DMPrint(string.format(DM_MSG_SYNCHALTRECEIVED, sender), nil, true);
6971 -- Clear the message queues.
6972 DamageMeters_syncMsgQueue = {};
6973 DamageMeters_syncIncMsgQueue = {};
6974 DamageMeters_syncIncMsgSourceQueue = {};
6975 return;
6976 elseif (command == DamageMeters_SYNCPAUSEREQ) then
6977 DMPrint(string.format(DM_MSG_SYNCPAUSE, sender), nil, true);
6978 DamageMeters_pauseState = DM_Pause_Paused;
6979 DamageMeters_CompletePauseChange(true);
6980 return;
6981 elseif (command == DamageMeters_SYNCUNPAUSEREQ) then
6982 local unpauseMsg = DM_MSG_SYNCUNPAUSE;
6983 local additionalInfo = strsub(msg, string.len(DamageMeters_SYNCUNPAUSEREQ) + 2);
6984 if (additionalInfo and string.len(additionalInfo) > 0) then
6985 unpauseMsg = unpauseMsg.." ("..additionalInfo..")";
6986 end
6987  
6988 DMPrint(string.format(unpauseMsg, sender), nil, true);
6989 if (DamageMeters_pauseState ~= DM_Pause_Not) then
6990 DamageMeters_pauseState = DM_Pause_Not;
6991 DamageMeters_CompletePauseChange(true);
6992 end
6993 return;
6994 elseif (command == DamageMeters_SYNCREADYREQ) then
6995 DMPrint(string.format(DM_MSG_SYNCREADY, sender), nil, true);
6996 DamageMeters_SetReady();
6997 return;
6998 elseif (command == DamageMeters_SYNCPING) then
6999 for pinger, additionalInfo in string.gfind(msg, DamageMeters_SYNCPING.." <(.+)> <(.+)>") do
7000 if (pinger == UnitName("Player")) then
7001 DMPrint("DMSYNCPING: ".. sender..", "..additionalInfo.."");
7002 end
7003 end
7004 return;
7005 elseif (command == DamageMeters_SYNCSESSIONMISMATCH) then
7006 local badSession, badIndex;
7007 for badSession, badIndex in string.gfind(msg, DamageMeters_SYNCSESSIONMISMATCH.." (.+) (%d+)") do
7008 local mismatchMsg = string.format(DM_MSG_SYNCSESSIONMISMATCH,
7009 sender,
7010 badSession,
7011 badIndex);
7012 DMPrint(mismatchMsg, nil, true);
7013 return;
7014 end
7015 return;
7016 elseif (command == DamageMeters_SYNCMSG) then
7017 if (DamageMeters_flags[DMFLAG_enableDMM]) then
7018 local syncMsg = commandArgs;
7019 DMPrint(format(DM_MSG_SYNCMSG, sender, sender, syncMsg), DamageMeters_SYNCMSGCOLOR);
7020 end
7021 return;
7022 elseif (command == DamageMeters_SYNCEMOTE) then
7023 DamageMeters_DecodeEmote(sender, strsub(msg, string.len(DamageMeters_SYNCEMOTE) + 1));
7024 return;
7025  
7026 elseif (command == DamageMeters_SYNCRPS) then
7027 DamageMeters_RPSChallengeReceived(sender, strsub(msg, string.len(DamageMeters_SYNCRPS) + 2));
7028 return;
7029 elseif (command == DamageMeters_SYNCRPSRESPONSE) then
7030 DamageMeters_RPSResponseReceived(sender, strsub(msg, string.len(DamageMeters_SYNCRPSRESPONSE) + 2));
7031 return;
7032 elseif (command == DamageMeters_SYNCRPSCOUNTERRESPONSE) then
7033 DamageMeters_RPSCounterresponseRecieved(sender, strsub(msg, string.len(DamageMeters_SYNCRPSCOUNTERRESPONSE) + 2));
7034 return;
7035 --[[
7036 elseif (command == DamageMeters_SYNCKICK) then
7037 local kicked = string.lower(string.sub(msg, string.len(DamageMeters_SYNCKICK) + 2));
7038 DMPrintD("kicked = >"..kicked.."<");
7039 if (string.lower(UnitName("Player")) == kicked) then
7040 DMPrint(string.format(DM_MSG_KICKED, sender));
7041 DamageMeters_SyncLeaveChan();
7042 end
7043 return;
7044 elseif (command == DamageMeters_SYNCBOSSSTART) then
7045 local label = commandArgs;
7046 --!
7047 DMPrint(string.format("DamageMeters: Received Boss (%s) Start command from %s.", label, sender));
7048 DamageMeters_DoSyncBossStart(label);
7049 return;
7050 elseif (command == DamageMeters_SYNCBOSSEND) then
7051 DamageMeters_DoSyncBossEnd();
7052 return;
7053 ]]--
7054 end
7055  
7056 end
7057  
7058  
7059  
7060  
7061 -------------------------------------------------------------------------------
7062 -- OnEvent
7063  
7064 function DamageMetersFrame_OnEvent()
7065  
7066 if (event == "PLAYER_ENTERING_WORLD") then
7067 DamageMeters_RegisterEvents();
7068 return;
7069 elseif (event == "PLAYER_LEAVING_WORLD") then
7070 DamageMeters_UnregisterEvents();
7071 return;
7072 end
7073  
7074 --[[
7075 if (event == "CHAT_MSG_CHANNEL_NOTICE") then
7076 if (arg1 == "YOU_JOINED" and
7077 string.lower(arg9) == string.lower(DamageMeters_syncChannel)) then
7078  
7079 -- Broadcast that we've joined.
7080 --SendChatMessage(DamageMeters_SYNCJOINED.." "..DamageMeters_VERSIONSTRING, "CHANNEL", nil, GetChannelName(DamageMeters_syncChannel));
7081 --Telepathy.sendMessage(DamageMeters_SYNC_ID, DamageMeters_SYNCJOINED.." "..DamageMeters_VERSIONSTRING, "RAID");
7082 ChatThrottleLib:SendAddonMessage("NORMAL", DamageMeters_SYNC_ID, DamageMeters_SYNCJOINED.." "..DamageMeters_VERSIONSTRING, "RAID");
7083 end
7084 return;
7085 end
7086 ]]--
7087  
7088 if (event == "VARIABLES_LOADED") then
7089 -- If a variable table is nil, reset to defaults
7090 local reset = (not DamageMeters_flags or not DamageMeters_quantitiesFilter or not DamageMeters_debug4)
7091 if (reset) then
7092 DamageMeters_SetDefaultOptions()
7093 end
7094  
7095 -- If the saved data is of a different version clear the table.
7096 if (DamageMeters_loadedDataVersion ~= DamageMeters_VERSION) then
7097 DMPrintD("Saved data version mismatch: loaded = "..DamageMeters_loadedDataVersion..", current = "..DamageMeters_VERSION);
7098 DamageMeters_pluginDMITable = {};
7099  
7100 if (not reset) then
7101 DamageMeters_InitTables();
7102 if (DamageMeters_loadedDataVersion < 4500) then
7103 DMPrintD("Restoring default colors.");
7104 DamageMeters_SetDefaultColors();
7105 end
7106 end
7107  
7108 DamageMeters_loadedDataVersion = DamageMeters_VERSION;
7109 end
7110  
7111 --Telepathy.registerListener(DamageMeters_SYNC_ID, { "RAID", "PARTY" }, DamageMeters_ParseSyncMessage);
7112  
7113 -- Reset the ages, as age values from old sessions are pointless.
7114 -- Reset the combat dmg too.
7115 local index, value;
7116 local now = GetTime();
7117 for tableIndex = 1, DMT_MAX do
7118 for index, value in DamageMeters_tables[tableIndex] do
7119 value.lastTime = now;
7120 for quantIx = 1, DMI_MAX do
7121 value.dmiData[quantIx].lastQuantTime = now;
7122 end
7123 end
7124 end
7125  
7126 DamageMeters_Reset();
7127  
7128 DamageMeters_textStateStartTime = GetTime();
7129 DamageMeters_currentQuantStartTime = DamageMeters_textStateStartTime;
7130  
7131 if (not DamageMeters_flags[DMFLAG_isVisible]) then
7132 DamageMeters_Hide();
7133 end
7134  
7135 -- Intro text.
7136 DamageMeters_ShowVersion();
7137 if (DamageMeters_flags[DMFLAG_accumulateToMemory]) then
7138 DMPrint(DM_MSG_ACCUMULATING);
7139 end
7140 if (DamageMeters_debugEnabled) then
7141 DMPrintD("DamageMeters: Debug enabled.");
7142 end
7143 --if (not DamageMeters_takeOnlyPlayerData) then
7144 -- DMPrint(DM_MSG_PLAYERONLYEVENTDATAOFF);
7145 --end
7146  
7147 DMPrintD("Loading DM into mode "..DamageMeters_viewMode..", count = "..DamageMeters_barCount..", saved = "..DamageMeters_savedBarCount);
7148  
7149  
7150 -- This is a hack--if the frame is initially hidden the stupid dropdown
7151 -- menu doesn't work right and needs to be opened twice to be seen the first
7152 -- time.
7153 DMReportFrame:Hide();
7154  
7155 -- Make sure this is called last.
7156 DamageMeters_OnLoadComplete();
7157  
7158 -- This needs to know that DamageMeters_quantity is valid.
7159 DamageMeters_SetQuantity(DamageMeters_quantity, true);
7160  
7161 return;
7162 end
7163  
7164 -----------------------
7165  
7166 if ( event == "PARTY_MEMBERS_CHANGED" ) then
7167 DamageMeters_UpdateVisibility();
7168 return;
7169 end
7170  
7171 if ( event == "RAID_ROSTER_UPDATE" ) then
7172 DamageMeters_UpdateVisibility();
7173 DamageMeters_UpdateRaidMemberClasses();
7174 return;
7175 end
7176  
7177 if ( event == "PLAYER_REGEN_DISABLED" ) then
7178 --DamageMeters_startCombatOnNextValue = true;
7179 DamageMeters_playerInCombat = true;
7180  
7181 if (not DamageMeters_flags[DMFLAG_groupDPSMode]) then
7182 DamageMeters_OnCombatStart();
7183 end
7184 return;
7185 end
7186 if ( event == "PLAYER_REGEN_ENABLED" ) then
7187 DamageMeters_playerInCombat = false;
7188  
7189 if (DamageMeters_flags[DMFLAG_groupDPSMode]) then
7190 if (DamageMeters_inCombat) then
7191 if (DamageMeters_InParty() and UnitIsDead("Player")) then
7192 -- Dont stop combat: the party could be continuing combat.
7193 else
7194 --DMPrintD("In Combat, but either not In Party or Not Dead: Ending Combat.");
7195 DamageMeters_OnCombatEnd();
7196 end
7197 end
7198 --BAD DamageMeters_startCombatOnNextValue = true;
7199 else
7200 if (DamageMeters_inCombat) then
7201 DamageMeters_OnCombatEnd();
7202 end
7203 end
7204 return;
7205 end
7206  
7207 if (DM_Bypass["Event All"] == true) then
7208 return;
7209 end
7210  
7211 -----------------------
7212  
7213 if ( event == "UNIT_HEALTH" or event == "UNIT_MAXHEALTH" ) then
7214 local unitName = UnitName(arg1);
7215 --DMPrintD(event..": "..arg1.." "..unitName, nil, true);
7216  
7217 local playerIndex = DamageMeters_GetPlayerIndex(unitName, DMT_ACTIVE);
7218 if (playerIndex) then
7219 local field, value;
7220 if (event == "UNIT_HEALTH") then
7221 field = "health";
7222 value = UnitHealth(arg1);
7223 else
7224 field = "maxHealth";
7225 value = UnitHealthMax(arg1);
7226 end
7227 -- Debug Spam.
7228 if (DamageMeters_debug4.showHealthChanges) then
7229 if (value ~= DamageMeters_tables[DMT_ACTIVE][playerIndex][field]) then
7230 local delta = value - DamageMeters_tables[DMT_ACTIVE][playerIndex][field];
7231 local color = (delta >= 0) and ({r=0.25,g=1.00,b=0.25}) or ({r=1.00,g=0.25,b=0.25});
7232 DMPrintD(delta..": Updating "..field.." for "..DamageMeters_tables[DMT_ACTIVE][playerIndex].player.." from "..DamageMeters_tables[DMT_ACTIVE][playerIndex][field].." to "..value, color, true);
7233 end
7234 end
7235 DamageMeters_tables[DMT_ACTIVE][playerIndex][field] = value;
7236  
7237 DamageMeters_tablesDirty = true;
7238 end
7239  
7240 return;
7241 end
7242  
7243 -----------------------
7244 --[[
7245 if (event == "CHAT_MSG_RAID" or event == "CHAT_MSG_PARTY") then
7246 if (DamageMeters_flags[DMFLAG_permitAutoSyncChanJoin]) then
7247  
7248 local first, last = string.find(arg1, DM_MSG_SYNCCHANBROADCAST);
7249 if (last) then
7250 local sub = string.sub(arg1, last+1);
7251 DMPrint(sub);
7252  
7253 local newChan;
7254 local newLabel = nil;
7255 for newChan, newLabel in string.gfind(sub, "(.+) %((.+)%)") do
7256 end
7257 if (newLabel == nil) then
7258 newChan = sub;
7259 end
7260  
7261 local changeChan = false;
7262 if (string.lower(newChan) ~= string.lower(DamageMeters_syncChannel)) then
7263 changeChan = true;
7264 elseif (0 == GetChannelName(newChan)) then
7265 changeChan = true;
7266 end
7267  
7268 if (changeChan) then
7269 DamageMeters_SyncChan(newChan);
7270 if (DamageMeters_flags[DMFLAG_autoClearOnChannelJoin]) then
7271 DamageMeters_Clear();
7272 end
7273 end
7274 return;
7275 end
7276 return;
7277 end
7278  
7279 return;
7280 end
7281 ]]--
7282  
7283 if (event == "CHAT_MSG_ADDON") then
7284 --[[
7285 arg1 - id
7286 arg2 - message
7287 arg3 - "PARTY","RAID", "GUILD" or "BATTLEGROUND"
7288 arg4 - sender
7289 ]]--
7290 if (arg1 == DamageMeters_SYNC_ID and (arg3 == "PARTY" or arg3 == "RAID") ) then
7291 DamageMeters_ParseSyncMessage(arg2, arg4, arg3);
7292 end
7293 return;
7294 end
7295  
7296 --[[
7297 if (event == "CHAT_MSG_CHANNEL") then
7298 local type = strsub(event, 10);
7299 local info = ChatTypeInfo[type];
7300  
7301 if (DamageMeters_flags[DMFLAG_onlySyncWithGroup] and DamageMeters_GetGroupRelation(arg2) < 0) then
7302 return;
7303 end
7304  
7305 local channelLength = strlen(arg4);
7306 if ( (strsub(type, 1, 7) == "CHANNEL") and (type ~= "CHANNEL_LIST") and (arg1 ~= "INVITE") ) then
7307  
7308 if (info and (string.lower(arg9) == string.lower(DamageMeters_syncChannel))) then
7309 -- arg2 = source, arg9 = channel name
7310 --DMPrint("arg2 = "..arg2..", arg3 = "..arg3..", arg4 = "..arg4);
7311 --DMPrint("arg5 = "..arg5..", arg6 = "..arg6..", arg7 = "..arg7);
7312 --DMPrint("arg8 = "..arg8..", arg9 = "..arg9);
7313 --DMPrint("arg7 = "..arg7..", arg9 = "..arg9);
7314  
7315 local sender = string.lower(arg2);
7316  
7317  
7318 -- Ignore messages from ourself.
7319 if (not DamageMeters_debug4.syncSelf) then
7320 if (arg2 == UnitName("Player")) then
7321 return;
7322 end
7323 end
7324  
7325 local msg = arg1;
7326  
7327 local firstSpace = string.find(msg, " ");
7328 local command, commandArgs;
7329 if (firstSpace ~= nil) then
7330 command = string.sub(msg, 1, firstSpace - 1);
7331 commandArgs = string.sub(msg, firstSpace + 1);
7332 else
7333 command = msg;
7334 commandArgs = "";
7335 end
7336  
7337 if ((strsub(msg, 1, string.len(DMSYNC_PREFIX)) == DMSYNC_PREFIX) or
7338 ((strsub(msg, 1, string.len(DMSYNC_EVENT_PREFIX)) == DMSYNC_EVENT_PREFIX))) then
7339 if (DamageMeters_debug4.syncSelf) then
7340 for index = 1, DamageMeters_debug_syncTestFactor do
7341 table.insert(DamageMeters_syncIncMsgQueue, msg);
7342 table.insert(DamageMeters_syncIncMsgSourceQueue, arg2);
7343 end
7344 else
7345 table.insert(DamageMeters_syncIncMsgQueue, msg);
7346 table.insert(DamageMeters_syncIncMsgSourceQueue, arg2);
7347 end
7348 return;
7349 elseif (command == DamageMeters_SYNCREQUEST) then
7350 -- Note: +1 doesn't allow for a space between prefix and params.
7351 local params = commandArgs;
7352 --DMPrintD("Incoming sync params = >"..params.."<");
7353 --SendChatMessage("Incoming sync params = >"..params.."<", "CHANNEL", nil, GetChannelName(DamageMeters_syncChannel));
7354 if (string.sub(params, 1, 1) == "E") then
7355 --SendChatMessage("E detected: syncing events.", "CHANNEL", nil, GetChannelName(DamageMeters_syncChannel));
7356 DamageMeters_syncEvents = true;
7357 params = string.sub(params, 3);
7358 end
7359 if (params) then
7360 for syncLabel, syncIndex in string.gfind(params, "<(.+) (%d+)>") do
7361 syncLabel = tostring(syncLabel);
7362 syncIndex = tonumber(syncIndex);
7363 -- Potential error: local sessionLabel can be nil. UPDATE: I think this is fixed.
7364 local currentLabel = DamageMeters_tableInfo[DMT_ACTIVE].sessionLabel;
7365 local currentIndex = DamageMeters_tableInfo[DMT_ACTIVE].sessionIndex;
7366 if (false == DamageMeters_CheckSession(DMT_ACTIVE, syncLabel, syncIndex)) then
7367 DMPrint(DM_MSG_SESSIONMISMATCH);
7368 local mismatchMsg = DamageMeters_SYNCSESSIONMISMATCH.." "..currentLabel.." "..currentIndex;
7369 --SendChatMessage(mismatchMsg, "CHANNEL", nil, GetChannelName(DamageMeters_syncChannel));
7370 --Telepathy.sendMessage(DamageMeters_SYNC_ID, mismatchMsg, "RAID");
7371 ChatThrottleLib:SendAddonMessage("NORMAL", DamageMeters_SYNC_ID, mismatchMsg, "RAID");
7372  
7373 else
7374 DMPrintD("Sync request recieved, session matches our own.");
7375 end
7376 end
7377 end
7378  
7379 local now = GetTime();
7380 if (now - DamageMeters_lastSyncTime > DamageMeters_MINSYNCCOOLDOWN) then
7381 local ackmsg = DamageMeters_syncEvents and DM_MSG_SYNCREQUESTACKEVENTS or DM_MSG_SYNCREQUESTACK;
7382 DMPrint(ackmsg..arg2, nil, true);
7383 DamageMeters_lastSyncTime = now;
7384 DamageMeters_SyncReport();
7385 else
7386 DMPrint(DM_ERROR_SYNCTOOSOON);
7387 end
7388 return;
7389 elseif (command == DamageMeters_SYNCCLEARREQUEST) then
7390 DMPrint(DM_MSG_CLEARRECEIVED..arg2, nil, true);
7391 --SendChatMessage(DamageMeters_SYNCCLEARACK, "CHANNEL", nil, GetChannelName(DamageMeters_syncChannel));
7392 --Telepathy.sendMessage(DamageMeters_SYNC_ID, DamageMeters_SYNCCLEARACK, "RAID");
7393 ChatThrottleLib:SendAddonMessage("NORMAL", DamageMeters_SYNC_ID, DamageMeters_SYNCCLEARACK, "RAID");
7394 DamageMeters_Clear();
7395  
7396 -- Check for session information, and update ours if it is there.
7397 for newLabel, newIndex in string.gfind(commandArgs, "(.+) (%d+)") do
7398 DamageMeters_tableInfo[DMT_ACTIVE].sessionLabel = tostring(newLabel);
7399 DamageMeters_tableInfo[DMT_ACTIVE].sessionIndex = tonumber(newIndex);
7400 break;
7401 end
7402  
7403 return;
7404 elseif (command == DamageMeters_SYNCCLEARACK) then
7405 --DMPrint(format(DM_MSG_CLEARACKNOWLEDGED, arg2), nil, true);
7406 return;
7407 elseif (command == DamageMeters_SYNCJOINED) then
7408 local version = commandArgs;
7409 DMPrint(string.format(DM_MSG_PLAYERJOINEDSYNCCHAN, arg2, version), nil, true);
7410 return;
7411 elseif (command == DamageMeters_SYNCSTART) then
7412 DMPrint(format(DM_MSG_RECEIVEDSYNCDATA, arg2), nil, true);
7413 return;
7414 elseif (command == DamageMeters_SYNCEND) then
7415 -- Nothing atm.
7416 return;
7417 elseif (command == DamageMeters_SYNCPINGREQ) then
7418 DamageMeters_SyncPingReply(arg2);
7419 return;
7420 elseif (msg == DamageMeters_SYNCHALT) then
7421 DMPrint(string.format(DM_MSG_SYNCHALTRECEIVED, arg2), nil, true);
7422 -- Clear the message queues.
7423 DamageMeters_syncMsgQueue = {};
7424 DamageMeters_syncIncMsgQueue = {};
7425 DamageMeters_syncIncMsgSourceQueue = {};
7426 return;
7427 elseif (command == DamageMeters_SYNCPAUSEREQ) then
7428 DMPrint(string.format(DM_MSG_SYNCPAUSE, arg2), nil, true);
7429 DamageMeters_pauseState = DM_Pause_Paused;
7430 DamageMeters_CompletePauseChange(true);
7431 return;
7432 elseif (command == DamageMeters_SYNCUNPAUSEREQ) then
7433 local unpauseMsg = DM_MSG_SYNCUNPAUSE;
7434 local additionalInfo = strsub(msg, string.len(DamageMeters_SYNCUNPAUSEREQ) + 2);
7435 if (additionalInfo and string.len(additionalInfo) > 0) then
7436 unpauseMsg = unpauseMsg.." ("..additionalInfo..")";
7437 end
7438  
7439 DMPrint(string.format(unpauseMsg, arg2), nil, true);
7440 if (DamageMeters_pauseState ~= DM_Pause_Not) then
7441 DamageMeters_pauseState = DM_Pause_Not;
7442 DamageMeters_CompletePauseChange(true);
7443 end
7444 return;
7445 elseif (command == DamageMeters_SYNCREADYREQ) then
7446 DMPrint(string.format(DM_MSG_SYNCREADY, arg2), nil, true);
7447 DamageMeters_SetReady();
7448 return;
7449 elseif (command == DamageMeters_SYNCPING) then
7450 for pinger, additionalInfo in string.gfind(msg, DamageMeters_SYNCPING.." <(.+)> <(.+)>") do
7451 if (pinger == UnitName("Player")) then
7452 DMPrint("DMSYNCPING: "..arg2..", "..additionalInfo.."");
7453 end
7454 end
7455 return;
7456 elseif (command == DamageMeters_SYNCSESSIONMISMATCH) then
7457 local badSession, badIndex;
7458 for badSession, badIndex in string.gfind(msg, DamageMeters_SYNCSESSIONMISMATCH.." (.+) (%d+)") do
7459 local mismatchMsg = string.format(DM_MSG_SYNCSESSIONMISMATCH,
7460 arg2,
7461 badSession,
7462 badIndex);
7463 DMPrint(mismatchMsg, nil, true);
7464 return;
7465 end
7466 return;
7467 elseif (command == DamageMeters_SYNCMSG) then
7468 if (DamageMeters_flags[DMFLAG_enableDMM]) then
7469 local syncMsg = commandArgs;
7470 DMPrint(format(DM_MSG_SYNCMSG, arg2, arg2, syncMsg), DamageMeters_SYNCMSGCOLOR);
7471 end
7472 return;
7473 elseif (command == DamageMeters_SYNCEMOTE) then
7474 DamageMeters_DecodeEmote(arg2, strsub(msg, string.len(DamageMeters_SYNCEMOTE) + 1));
7475 return;
7476  
7477 elseif (command == DamageMeters_SYNCRPS) then
7478 DamageMeters_RPSChallengeReceived(arg2, strsub(msg, string.len(DamageMeters_SYNCRPS) + 2));
7479 return;
7480 elseif (command == DamageMeters_SYNCRPSRESPONSE) then
7481 DamageMeters_RPSResponseReceived(arg2, strsub(msg, string.len(DamageMeters_SYNCRPSRESPONSE) + 2));
7482 return;
7483 elseif (command == DamageMeters_SYNCRPSCOUNTERRESPONSE) then
7484 DamageMeters_RPSCounterresponseRecieved(arg2, strsub(msg, string.len(DamageMeters_SYNCRPSCOUNTERRESPONSE) + 2));
7485 return;
7486  
7487 elseif (command == DamageMeters_SYNCKICK) then
7488 local kicked = string.lower(string.sub(msg, string.len(DamageMeters_SYNCKICK) + 2));
7489 DMPrintD("kicked = >"..kicked.."<");
7490 if (string.lower(UnitName("Player")) == kicked) then
7491 DMPrint(string.format(DM_MSG_KICKED, arg2));
7492 DamageMeters_SyncLeaveChan();
7493 end
7494 return;
7495 elseif (command == DamageMeters_SYNCBOSSSTART) then
7496 local label = commandArgs;
7497 --!
7498 DMPrint(string.format("DamageMeters: Received Boss (%s) Start command from %s.", label, arg2));
7499 DamageMeters_DoSyncBossStart(label);
7500 return;
7501 elseif (command == DamageMeters_SYNCBOSSEND) then
7502 DamageMeters_DoSyncBossEnd();
7503 return;
7504 end
7505 end
7506 end
7507  
7508 return;
7509 end
7510 ]]--
7511  
7512 ---------------------------
7513  
7514 if (DamageMeters_pauseState == DM_Pause_Paused) then
7515 return;
7516 end
7517  
7518 if (DamageMeters_debug4.showAll) then
7519 local subEvent = string.sub(event, 9);
7520 DMPrintD("("..subEvent.."): "..arg1, nil, true);
7521 end
7522  
7523 DamageMeters_ParseMessage(arg1, event);
7524  
7525 ---------------------------
7526 end
7527  
7528 function DamageMeters_StartDebugTimer(index)
7529 DamageMeters_activeDebugTimer = index;
7530 debugprofilestart();
7531 end
7532  
7533 function DamageMeters_StopDebugTimer(index)
7534 if (DamageMeters_activeDebugTimer ~= index) then
7535 DMPrintD("DM DEBUG ERROR: Wrong debug timer stopped. "..(DamageMeters_activeDebugTimer and DMPROF_NAMES[DamageMeters_activeDebugTimer] or "[none]").." expected, got "..DMPROF_NAMES[index]);
7536 debugprofilestop()
7537 DamageMeters_activeDebugTimer = 0;
7538 return;
7539 end
7540  
7541 DamageMeters_debugTimers[index].time = DamageMeters_debugTimers[index].time + debugprofilestop();
7542 DamageMeters_debugTimers[index].count = DamageMeters_debugTimers[index].count + 1;
7543 DamageMeters_activeDebugTimer = 0;
7544 end
7545  
7546 ---------------------------
7547 StaticPopupDialogs["DM_START_NEW_SESSION"] = {
7548 text = DM_NEWSESSIONID,
7549 button1 = ACCEPT,
7550 button2 = CANCEL,
7551 hasEditBox = 1,
7552 maxLetters = 12,
7553 OnAccept = function()
7554 local editBox = getglobal(this:GetParent():GetName().."EditBox");
7555 DamageMeters_SyncStart(editBox:GetText());
7556 end,
7557 OnShow = function()
7558 getglobal(this:GetName().."EditBox"):SetFocus();
7559 end,
7560 OnHide = function()
7561 getglobal(this:GetName().."EditBox"):SetText("");
7562 end,
7563 EditBoxOnEnterPressed = function()
7564 local editBox = getglobal(this:GetParent():GetName().."EditBox");
7565 DamageMeters_SyncStart(editBox:GetText());
7566 this:GetParent():Hide();
7567 end,
7568 EditBoxOnEscapePressed = function()
7569 this:GetParent():Hide();
7570 end,
7571 timeout = 0,
7572 exclusive = 1,
7573 whileDead = 1,
7574 hideOnEscape = 1
7575 };
7576  
7577 StaticPopupDialogs["DM_REPORT_CHANNEL"] = {
7578 text = DM_REPORTCHANNEL,
7579 button1 = ACCEPT,
7580 button2 = CANCEL,
7581 hasEditBox = 1,
7582 maxLetters = 12,
7583 OnAccept = function()
7584 local editBox = getglobal(this:GetParent():GetName().."EditBox");
7585 local command = format("%s%d %s", "h", DamageMeters_barCount, editBox:GetText());
7586 DamageMeters_Report(command);
7587 end,
7588 OnShow = function()
7589 getglobal(this:GetName().."EditBox"):SetFocus();
7590 end,
7591 OnHide = function()
7592 getglobal(this:GetName().."EditBox"):SetText("");
7593 end,
7594 EditBoxOnEnterPressed = function()
7595 local editBox = getglobal(this:GetParent():GetName().."EditBox");
7596 local command = format("%s%d %s", "h", DamageMeters_barCount, editBox:GetText());
7597 DamageMeters_Report(command);
7598 this:GetParent():Hide();
7599 end,
7600 EditBoxOnEscapePressed = function()
7601 this:GetParent():Hide();
7602 end,
7603 timeout = 0,
7604 exclusive = 1,
7605 whileDead = 1,
7606 hideOnEscape = 1
7607 };
7608  
7609 StaticPopupDialogs["DM_REPORT_WHISPER"] = {
7610 text = DM_REPORTWHISPER,
7611 button1 = ACCEPT,
7612 button2 = CANCEL,
7613 hasEditBox = 1,
7614 maxLetters = 12,
7615 OnAccept = function()
7616 local editBox = getglobal(this:GetParent():GetName().."EditBox");
7617 local command = format("%s%d %s", "w", DamageMeters_barCount, editBox:GetText());
7618 DamageMeters_Report(command);
7619 end,
7620 OnShow = function()
7621 getglobal(this:GetName().."EditBox"):SetFocus();
7622 end,
7623 OnHide = function()
7624 getglobal(this:GetName().."EditBox"):SetText("");
7625 end,
7626 EditBoxOnEnterPressed = function()
7627 local editBox = getglobal(this:GetParent():GetName().."EditBox");
7628 local command = format("%s%d %s", "w", DamageMeters_barCount, editBox:GetText());
7629 DamageMeters_Report(command);
7630 this:GetParent():Hide();
7631 end,
7632 EditBoxOnEscapePressed = function()
7633 this:GetParent():Hide();
7634 end,
7635 timeout = 0,
7636 exclusive = 1,
7637 whileDead = 1,
7638 hideOnEscape = 1
7639 };
7640  
7641 ---------------------------
7642 function DamageMetersPlugin_Register(pinfo)
7643 if pinfo and pinfo.name then
7644 DamageMeters_PLUGINS[pinfo.name] = pinfo;
7645 end
7646  
7647 -- fix up DMI
7648 -- DMI_MAX = DMI_MAX + 1;
7649  
7650 -- insert into quant thingy
7651 table.insert(DM_QUANTDEFS, pinfo.quantDefs);
7652 DamageMeters_Quantity_MAX = table.getn(DM_QUANTDEFS);
7653 --DM_QUANTDEFS[DamageMeters_Quantity_MAX].dmi = DMI_MAX;
7654  
7655 -- Assume that if they went to the trouble of loading the plugin they want to see the quantity by default.
7656 DamageMeters_quantitiesFilter[DamageMeters_Quantity_MAX] = true;
7657  
7658 table.insert(DMI_NAMES, pinfo.name);
7659  
7660 -- insert quantity color code.
7661 local color = DM_QUANTDEFS[DamageMeters_Quantity_MAX].defaultColor;
7662 local code = string.format("|cFF%02X%02X%02X",
7663 floor(color[1] * 255.0),
7664 floor(color[2] * 255.0),
7665 floor(color[3] * 255.0));
7666 DamageMeters_quantityColorCodeDefault[DamageMeters_Quantity_MAX] = code;
7667 DamageMeters_quantityColor[DamageMeters_Quantity_MAX] = DM_clone(DM_QUANTDEFS[DamageMeters_Quantity_MAX].defaultColor);
7668  
7669 -- PC: Made this unnecessary.
7670 --DamageMeters_Clear(0, true);
7671  
7672 DMPrintD("Plugin >"..pinfo.name.."< registered, quantity = "..DamageMeters_Quantity_MAX);
7673  
7674 --return DMI_MAX, DamageMeters_Quantity_MAX;
7675 return DamageMeters_Quantity_MAX;
7676 end
7677  
7678  
7679 ---------------------------
7680 function DamageMetersPlugin_Unregister(pname)
7681 DamageMeters_PLUGINS[pname] = nil;
7682 end
7683  
7684  
7685 ---------------------------
7686 function DamageMetersPlugin_AddHealing(event, player, target, amount, crit, relationship, targetRelationship, spell)
7687 for k, v in DamageMeters_PLUGINS do
7688 if v.pfnAddHealing ~= nil then
7689 v.pfnAddHealing(event, player, target, amount, crit, relationship, targetRelationship, spell);
7690 end
7691 end
7692 end
7693  
7694  
7695 ---------------------------
7696 function DamageMetersPlugin_AddDamage(event, player, creatureName, amount, crit, relationship, spell, damageType)
7697 for k, v in DamageMeters_PLUGINS do
7698 if v.pfnAddDamage ~= nil then
7699 v.pfnAddDamage(event, player, creatureName, amount, crit, relationship, spell, damageType);
7700 end
7701 end
7702 end
7703  
7704  
7705 ---------------------------
7706 function DamageMetersPlugin_AddDamageReceived(event, player, creatureName, amount, crit, relationship, spell, damageType, resisted)
7707 for k, v in DamageMeters_PLUGINS do
7708 if v.pfnAddDamageReceived ~= nil then
7709 v.pfnAddDamageReceived(event, player, creatureName, amount, crit, relationship, spell, damageType, resisted);
7710 end
7711 end
7712 end
7713  
7714  
7715  
7716 ---------------------------
7717 function DamageMetersPlugin_Clear()
7718 for k, v in DamageMeters_PLUGINS do
7719 if v.pfnClear ~= nil then
7720 v.pfnClear();
7721 end
7722 end
7723 end
7724  
7725  
7726 ---------------------------
7727 function DamageMetersPlugin_DropDownInitialize()
7728 for k, v in DamageMeters_PLUGINS do
7729 if v.pfnDropDownInitialize ~= nil then
7730 v.pfnDropDownInitialize();
7731 end
7732 end
7733 end