WoWInterface SVN MikScrollingBattleText

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /tags
    from Rev 1 to Rev 4
    Reverse comparison

Rev 1 → Rev 4

MSBT5_13/MikScrollingBattleText/Sounds/LowMana.mp3 Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes : Added: svn:mime-type + application/octet-stream
MSBT5_13/MikScrollingBattleText/Sounds/LowHealth.mp3 Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes : Added: svn:mime-type + application/octet-stream
MSBT5_13/MikScrollingBattleText/API.html New file
0,0 → 1,923
<!-- Author: Mik -->
<html>
<head>
<title>Mik's Scrolling Battle Text API</title>
<style type="text/css">
body { font-size : 10pt; font-family : verdana,arial,helvetica,sans-serif; }
hr { color : #e0e0e0; }
 
a:link { color : #000060; text-decoration : none; }
a:visited { color : #000060; text-decoration : none; }
a:hover { text-decoration : underline; }
 
div.TOCTitle { font-weight : bold; font-size : 12pt; }
div.TOC { margin : 2ex 1ex 2ex 2ex; }
div.TOCSection { margin : 1ex 1ex 2ex 2ex; }
 
div.SectionTitle { margin-top : 6ex; font-weight : bold; font-size : 14pt; }
div.SectionDesc { margin-top : 1ex; margin-bottom : 2ex; }
div.SubsectionTitle { font-weight : bold; }
div.SubsectionBody { margin : 2ex 10ex 2ex 5ex; }
div.Syntax { background-color : #e0e0e0; padding-left : 1ex; }
 
td.ParameterName { font-size : 10pt; background-color : #e0e0e0; vertical-align : top; }
td.ParameterDesc { font-size : 10pt; background-color : #e0e0e0; text-align : left; }
</style>
</head>
<body>
<div>
This file contains a reference for all of MSBT's publicly accessible functions and structures.<br /><br />
<div class="TOCTitle"><a name="TOC">Table of Contents:</a></div>
</div>
<div class="TOC">
<b>Mod State:</b>
<div class="TOCSection">
<a href="#MikSBT.IsModDisabled">MikSBT.IsModDisabled</a><br />
 
</div>
<b>Displaying Messages:</b>
<div class="TOCSection">
<a href="#DisplayOverview">Displaying Messages Overview</a><br />
<a href="#MikSBT.RegisterFont">MikSBT.RegisterFont</a><br />
<a href="#MikSBT.DisplayMessage">MikSBT.DisplayMessage</a><br />
<a href="#MikSBT.IterateFonts">MikSBT.IterateFonts</a><br />
<a href="#MikSBT.IterateScrollAreas">MikSBT.IterateScrollAreas</a><br />
<span style="color : red;">MikSBT.GetRegisteredFontList - DEPRECATED</span><br />
<span style="color : red;">MikSBT.GetScrollAreaList - DEPRECATED</span><br />
 
</div>
<b>Sounds:</b>
<div class="TOCSection">
<a href="#SoundsOverview">Sounds Overview</a><br />
<a href="#MikSBT.RegisterSound">MikSBT.RegisterSound</a><br />
<a href="#MikSBT.IterateSounds">MikSBT.IterateSounds</a><br />
 
</div>
<b>Custom Animation Styles:</b>
<div class="TOCSection">
<a href="#CustomAnimationStylesOverview">Custom Animation Styles Overview</a><br />
<a href="#MikSBT.RegisterAnimationStyle">MikSBT.RegisterAnimationStyle</a><br />
<a href="#MikSBT.RegisterStickyAnimationStyle">MikSBT.RegisterStickyAnimationStyle</a><br />
<a href="#InitDisplayEventCallback">InitDisplayEvent Callback</a><br />
<a href="#AnimationCallback">Animation Callback</a><br />
<a href="#DisplayEventTable">DisplayEvent Table</a><br />
</div>
</div>
 
 
<div class="SectionTitle"><a name="MikSBT.IsModDisabled">MikSBT.IsModDisabled</a></div>
<hr size="1" />
<a href="#TOC">Return to TOC</a><br /><br />
<div class="SectionDesc">
Returns a flag indicating if the mod is disabled.
</div>
<div class="SubsectionTitle">Syntax</div>
<div class="SubsectionBody">
<div class="Syntax"><i>isDisabled</i> = <b>MikSBT.IsModDisabled()</b></div>
</div>
 
<div class="SubsectionTitle">Parameters</div>
<div class="SubsectionBody">
None.
</div>
 
<div class="SubsectionTitle">Return Values</div>
<div class="SubsectionBody">
<table cellspacing="3">
<tr>
<td class="ParameterName" nowrap="nowrap"><i>isDisabled</i></td>
<td class="ParameterDesc">
A flag that indicates if the mod is disabled. The return value will be one of the following:<br /><br />
<ul>
<li>true - The mod is disabled.</li>
<li>nil - The mod is enabled.</li>
</ul>
</td>
</tr>
</table>
</div>
 
<div class="SubsectionTitle">Example</div>
<div class="SubsectionBody">
<div class="Syntax">
-- Do something special if MSBT is disabled.<br />
if MikSBT.IsModDisabled() then<br />
&nbsp;-- Do something special here.<br />
end
</div>
</div>
 
<div class="SubsectionTitle">Remarks</div>
<div class="SubsectionBody">
None.
</div>
 
 
<div class="SectionTitle"><a name="DisplayOverview">Displaying Messages Overview</a></div>
<hr size="1" />
<a href="#TOC">Return to TOC</a><br /><br />
<div class="SectionDesc">
MSBT allows you to output messages via the <a href="#MikSBT.DisplayMessage">MikSBT.DisplayMessage</a> function.
You can either output the messages using one of the existing fonts, which can be obtained with the <a href="#MikSBT.IterateFonts">MikSBT.IterateFonts</a> function, or first use the
<a href="#MikSBT.RegisterFont">MikSBT.RegisterFont</a> function to use your own custom font.<br /><br />
Additionally, you may call the <a href="#MikSBT.IterateScrollAreas">MikSBT.IterateScrollAreas</a> function to get an iterator for the valid scroll areas in which the message
may be displayed.
</div>
 
 
<div class="SectionTitle"><a name="MikSBT.RegisterFont">MikSBT.RegisterFont</a></div>
<hr size="1" />
<a href="#TOC">Return to TOC</a><br /><br />
<div class="SectionDesc">
Registers a font with MSBT.<br /><br />
Font registration is not permanent. It must be done each load. In this manner if the user were to remove
a mod that registers custom fonts, the fonts would simply no longer be available. If anything in MSBT has a
custom font selected that is no longer registered, MSBT will recognize that an invalid font is specified and
use the default font accordingly.
</div>
<div class="SubsectionTitle">Syntax</div>
<div class="SubsectionBody">
<div class="Syntax"><b>MikSBT.RegisterFont(</b><i>fontName</i><b>,</b> <i>fontPath</i><b>)</b></div>
</div>
 
<div class="SubsectionTitle">Parameters</div>
<div class="SubsectionBody">
<table cellspacing="3">
<tr>
<td class="ParameterName" nowrap="nowrap"><i>fontName</i> (Required)</td>
<td class="ParameterDesc">
The name to use for the font. This name will be displayed in the font selection
dialogs, and also is the name to be referenced when displaying messages via the
<a href="#MikSBT.DisplayMessage">MikSBT.DisplayMessage</a> function.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><i>fontPath</i> (Required)</td>
<td class="ParameterDesc">The filesystem path to where the font resides.</td>
</tr>
</table>
</div>
 
<div class="SubsectionTitle">Return Values</div>
<div class="SubsectionBody">
None.
</div>
 
<div class="SubsectionTitle">Example</div>
<div class="SubsectionBody">
<div class="Syntax">
-- Registers a font named "MyUberFont" with MSBT.<br />
MikSBT.RegisterFont("MyUberFont", "Interface\\AddOns\\MyModName\\Fonts\\MyUberFont.ttf");
</div>
</div>
 
<div class="SubsectionTitle">Remarks</div>
<div class="SubsectionBody">
If you attempt to register a font name that already exists, the function will quietly fail.
</div>
 
 
<div class="SectionTitle"><a name="MikSBT.DisplayMessage">MikSBT.DisplayMessage</a></div>
<hr size="1" />
<a href="#TOC">Return to TOC</a><br /><br />
<div class="SectionDesc">Displays the passed message with the passed formatting options.</div>
<div class="SubsectionTitle">Syntax</div>
<div class="SubsectionBody">
<div class="Syntax"><b>MikSBT.DisplayMessage(</b><i>message</i> <b>[,</b> <i>scrollArea</i><b>,</b> <i>isSticky</i><b>,</b> <i>colorR</i><b>,</b> <i>colorG</i><b>,</b> <i>colorB</i><b>,</b> <i>fontSize</i><b>,</b> <i>fontName</i><b>,</b> <i>outlineIndex</i><b>,</b> <i>texturePath</i><b>])</b></div>
</div>
 
<div class="SubsectionTitle">Parameters</div>
<div class="SubsectionBody">
<table cellspacing="3">
<tr>
<td class="ParameterName" nowrap="nowrap"><i>message</i> (Required)</td>
<td class="ParameterDesc">The string to display.</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><i>scrollArea</i> (Optional)</td>
<td class="ParameterDesc">
Specifies the scroll area key or scroll area name in which to display the message.
<br /><br />
You can get an iterator for the available scroll areas with the
<a href="#MikSBT.IterateScrollAreas">MikSBT.IterateScrollAreas</a> function, or use one of the following predefined values:<br /><br />
 
MikSBT.DISPLAYTYPE_INCOMING<br />
MikSBT.DISPLAYTYPE_OUTGOING<br />
MikSBT.DISPLAYTYPE_NOTIFICATION<br />
MikSBT.DISPLAYTYPE_STATIC<br /><br />
 
If the parameter is omitted or invalid, a default of MikSBT.DISPLAYTYPE_NOTIFICATION will be used.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><i>isSticky</i> (Optional)</td>
<td class="ParameterDesc">
Specifies whether or not the message should be displayed sticky style. This must be either true or false.<br /><br />
If the parameter is omitted, a default of false will be used.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><i>colorR</i> (Optional)</td>
<td class="ParameterDesc">
The red component of the color to display the message with. Value range is 0-255.<br /><br />
If the parameter is omitted, a default of 255 will be used.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><i>colorG</i> (Optional)</td>
<td class="ParameterDesc">
The green component of the color to display the message with. Value range is 0-255.<br /><br />
If the parameter is omitted, a default of 255 will be used.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><i>colorB</i> (Optional)</td>
<td class="ParameterDesc">
The blue component of the color to display the message with. Value range is 0-255.<br /><br />
If the parameter is omitted, a default of 255 will be used.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><i>fontSize</i> (Optional)</td>
<td class="ParameterDesc">
The font size to use. Value range is 4-38.<br /><br />
If this value is omitted or an invalid value is passed, the settings for the scroll area will be used.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><i>fontName</i> (Optional)</td>
<td class="ParameterDesc">
The name of the font to use.
<br /><br />
You can get a list of available font names with the
<a href="#MikSBT.IterateFonts">MikSBT.IterateFonts</a> function.<br /><br />
If the parameter is omitted or an invalid font name is passed, the font for the scroll area will be used.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><i>outlineIndex</i> (Optional)</td>
<td class="ParameterDesc">
The index of the outline to use. The valid values are:
<ul>
<li>1 - No Outline</li>
<li>2 - Thin</li>
<li>3 - Thick</li>
</ul>
If the parameter is omitted or an invalid index is passed, the outline index for the scroll area will be used.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><i>texturePath</i> (Optional)</td>
<td class="ParameterDesc">
The path to a texture file to display.<br /><br />
If the parameter is omitted or an invalid path is passed, no texture will be displayed.
</td>
</tr>
</table>
</div>
 
<div class="SubsectionTitle">Return Values</div>
<div class="SubsectionBody">None.</div>
 
<div class="SubsectionTitle">Examples</div>
<div class="SubsectionBody">
<div class="Syntax">
-- Displays "Test Message" in the notification scroll area in white.<br />
MikSBT.DisplayMessage("Test Message");<br /><br />
 
-- Displays "Another Message" in the incoming scroll area in white as a sticky.<br />
MikSBT.DisplayMessage("Another Message", MikSBT.DISPLAYTYPE_INCOMING, true);<br /><br />
 
-- Displays "Uber Damage!" in the outgoing scroll area in blue.<br />
MikSBT.DisplayMessage("Uber Damage!", MikSBT.DISPLAYTYPE_OUTGOING, false, 0, 0, 255);<br /><br />
 
-- Displays "Enemy begins to flee in fear" in the notification scroll area in green with the<br />
-- scroll area's font size, the font set to Yellowjacket, no outline, and the icon for fear.<br />
MikSBT.DisplayMessage("Enemy begins to flee in fear", nil, false, 0, 255, 0, nil, "Yellowjacket", 1, "Interface\\Icons\\Spell_Shadow_Possession");
</div>
</div>
 
<div class="SubsectionTitle">Remarks</div>
<div class="SubsectionBody">
Since this function specifies the font name to use, you can use custom fonts by first registering them via the
<a href="#MikSBT.RegisterFont">MikSBT.RegisterFont</a> function.
</div>
 
 
<div class="SectionTitle"><a name="MikSBT.IterateFonts">MikSBT.IterateFonts</a></div>
<hr size="1" />
<a href="#TOC">Return to TOC</a><br /><br />
<div class="SectionDesc">
Returns an iterator function for the table containing the registered fonts.
</div>
<div class="SubsectionTitle">Syntax</div>
<div class="SubsectionBody">
<div class="Syntax"><i>for fontName, fontPath in</i> <b>MikSBT.IterateFonts()</b> <i>do</i></div>
</div>
 
<div class="SubsectionTitle">Parameters</div>
<div class="SubsectionBody">None.</div>
 
<div class="SubsectionTitle">Return Values</div>
<div class="SubsectionBody">
<table cellspacing="3">
<tr>
<td class="ParameterName" nowrap="nowrap"><i>iterator</i></td>
<td class="ParameterDesc">
An iterator function for the table containing the registered fonts.<br /><br />
The format of the table is as follows:<br /><br />
&nbsp;&nbsp;["FontName1"] = "Font Path 1"<br />
&nbsp;&nbsp;["FontName2"] = "Font Path 2"<br />
</td>
</tr>
</table>
</div>
 
<div class="SubsectionTitle">Examples</div>
<div class="SubsectionBody">
<div class="Syntax">
-- Print the font names registered with MSBT.<br />
for fontName, fontPath in MikSBT.IterateFonts() do<br />
&nbsp;DEFAULT_CHAT_FRAME:AddMessage(fontName);<br />
end<br />
</div>
</div>
 
<div class="SubsectionTitle">Remarks</div>
<div class="SubsectionBody">
This function has superseded the <span style="color : red;">MikSBT.GetRegisteredFontList</span> function. The
old function created a new table and returned it every time it was called which was wasteful.
</div>
 
 
<div class="SectionTitle"><a name="MikSBT.IterateScrollAreas">MikSBT.IterateScrollAreas</a></div>
<hr size="1" />
<a href="#TOC">Return to TOC</a><br /><br />
<div class="SectionDesc">
Returns an iterator function for the table containing the available scroll areas.
</div>
<div class="SubsectionTitle">Syntax</div>
<div class="SubsectionBody">
<div class="Syntax"><i>for scrollAreaKey, scrollAreaName in</i> <b>MikSBT.IterateScrollAreas()</b> <i>do</i></div>
</div>
 
<div class="SubsectionTitle">Parameters</div>
<div class="SubsectionBody">None.</div>
 
<div class="SubsectionTitle">Return Values</div>
<div class="SubsectionBody">
<table cellspacing="3">
<tr>
<td class="ParameterName" nowrap="nowrap"><i>iterator</i></td>
<td class="ParameterDesc">
An iterator function for the table containing the available scroll areas.<br /><br />
The format of the table is as follows:<br /><br />
&nbsp;&nbsp;["FirstKey"] = "First Scroll Area Name"<br />
&nbsp;&nbsp;["SecondKey"] = "Second Scroll Area Name"<br />
</td>
</tr>
</table>
</div>
 
<div class="SubsectionTitle">Examples</div>
<div class="SubsectionBody">
<div class="Syntax">
-- Print MSBT's available scroll area names.<br />
for scrollAreaKey, scrollAreaName in MikSBT.IterateScrollAreas() do<br />
&nbsp;DEFAULT_CHAT_FRAME:AddMessage(scrollAreaName);<br />
end
</div>
</div>
 
<div class="SubsectionTitle">Remarks</div>
<div class="SubsectionBody">
This function has superseded the <span style="color : red;">MikSBT.GetScrollAreaList</span> function. The
old function created a new table and returned it every time it was called which was wasteful.
</div>
 
 
<div class="SectionTitle"><a name="SoundsOverview">Sounds Overview</a></div>
<hr size="1" />
<a href="#TOC">Return to TOC</a><br /><br />
<div class="SectionDesc">
MSBT allows you to register sounds which the user can assign to be played when events and triggers occur.<br /><br />
 
The <a href="#MikSBT.RegisterSound">MikSBT.RegisterSound</a> function is used to register the sounds, and the
registered sounds may be obtained by using the <a href="#MikSBT.IterateSounds">MikSBT.IterateSounds</a> function.
</div>
 
 
<div class="SectionTitle"><a name="MikSBT.RegisterSound">MikSBT.RegisterSound</a></div>
<hr size="1" />
<a href="#TOC">Return to TOC</a><br /><br />
<div class="SectionDesc">
Registers a sound with MSBT.<br /><br />
Sound registration is not permanent. It must be done each load. In this manner if the user were to remove
a mod that registers custom sounds, the sounds would simply no longer be available.
</div>
<div class="SubsectionTitle">Syntax</div>
<div class="SubsectionBody">
<div class="Syntax"><b>MikSBT.RegisterSound(</b><i>soundName</i><b>,</b> <i>soundPath</i><b>)</b></div>
</div>
 
<div class="SubsectionTitle">Parameters</div>
<div class="SubsectionBody">
<table cellspacing="3">
<tr>
<td class="ParameterName" nowrap="nowrap"><i>soundName</i> (Required)</td>
<td class="ParameterDesc">
The name to use for the sound. This name will be displayed in the sound selection
dialogs.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><i>soundPath</i> (Required)</td>
<td class="ParameterDesc">The filesystem path to where the sound resides.</td>
</tr>
</table>
</div>
 
<div class="SubsectionTitle">Return Values</div>
<div class="SubsectionBody">
None.
</div>
 
<div class="SubsectionTitle">Example</div>
<div class="SubsectionBody">
<div class="Syntax">
-- Registers a sound named "MyUberSound" with MSBT.<br />
MikSBT.RegisterSound("MyUberSound", "Interface\\AddOns\\MyModName\\Sounds\\MyUberSound.mp3");
</div>
</div>
 
<div class="SubsectionTitle">Remarks</div>
<div class="SubsectionBody">
If you attempt to register a sound name that already exists, the function will quietly fail.
</div>
 
 
<div class="SectionTitle"><a name="MikSBT.IterateSounds">MikSBT.IterateSounds</a></div>
<hr size="1" />
<a href="#TOC">Return to TOC</a><br /><br />
<div class="SectionDesc">
Returns an iterator function for the table containing the registered sounds.
</div>
<div class="SubsectionTitle">Syntax</div>
<div class="SubsectionBody">
<div class="Syntax"><i>for soundName, soundPath in</i> <b>MikSBT.IterateSounds()</b> <i>do</i></div>
</div>
 
<div class="SubsectionTitle">Parameters</div>
<div class="SubsectionBody">None.</div>
 
<div class="SubsectionTitle">Return Values</div>
<div class="SubsectionBody">
<table cellspacing="3">
<tr>
<td class="ParameterName" nowrap="nowrap"><i>iterator</i></td>
<td class="ParameterDesc">
An iterator function for the table containing the registered sounds.<br /><br />
The format of the table is as follows:<br /><br />
&nbsp;&nbsp;["SoundName1"] = "Sound Path 1"<br />
&nbsp;&nbsp;["SoundName2"] = "Sound Path 2"<br />
</td>
</tr>
</table>
</div>
 
<div class="SubsectionTitle">Examples</div>
<div class="SubsectionBody">
<div class="Syntax">
-- Print the sound names registered with MSBT.<br />
for soundName, soundPath in MikSBT.IterateSounds() do<br />
&nbsp;DEFAULT_CHAT_FRAME:AddMessage(soundName);<br />
end<br />
</div>
</div>
 
<div class="SubsectionTitle">Remarks</div>
<div class="SubsectionBody">None.</div>
 
 
<div class="SectionTitle"><a name="CustomAnimationStylesOverview">Custom Animation Styles Overview</a></div>
<hr size="1" />
<a href="#TOC">Return to TOC</a><br /><br />
<div class="SectionDesc">
MSBT has a custom animation style registration system that allows other mod authors to create new animation styles.
<br /><br />
The system works by allowing an initialization callback handler, directions, and behaviors for an animation style to be
registered with the <a href="#MikSBT.RegisterAnimationStyle">MikSBT.RegisterAnimationStyle</a> and
<a href="#MikSBT.RegisterStickyAnimationStyle">MikSBT.RegisterStickyAnimationStyle</a> functions. The supplied initialization
handler then sets the appropriate animation handler for each new <a href="#DisplayEventTable">DisplayEvent</a> it receives.
<br /><br />
 
The callback handlers receive recycled <a href="#DisplayEventTable">DisplayEvent</a> tables that contain information about an animating event
such as its x and y position, its alpha (opacity), the height of the scroll area it's animating in, how long it's been animating, and the user
specified animation speed.
<br /><br />
 
There are two callback handlers:
<table cellspacing="3">
<tr>
<td class="ParameterName" nowrap="nowrap"><a href="#InitDisplayEventCallback">InitDisplayEvent</a></td>
<td class="ParameterDesc">
This function receives a new <a href="#DisplayEventTable">DisplayEvent</a> table, an array of <a href="#DisplayEventTable">DisplayEvent</a>s that are
currently active for the scroll area using the same animation style, and the currently selected direction and behavior for the scroll area.
<br /><br />
The most important thing for this function to do is set the <i>.animationHandler</i> field for the new
<a href="#DisplayEventTable">DisplayEvent</a> to an appropriate <a href="#AnimationCallback">Animation</a> callback handler.
The handler <b>MUST</b> be set.
<br /><br />
Other things to be done are to establish the initial settings for the new <a href="#DisplayEventTable">DisplayEvent</a> table,
create any additional fields you need for your animation code, and move the active <a href="#DisplayEventTable">DisplayEvent</a>s
that are now colliding due to the newly added event if your animation style should avoid overlaps.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><a href="#AnimationCallback">Animation</a></td>
<td class="ParameterDesc">
This function moves the <a href="#DisplayEventTable">DisplayEvent</a> at each update interval by modifying the <i>.positionX</i> and <i>.positionY</i> fields.
The opacity is controlled by modifying the <i>.alpha</i> field.
<br /><br />
Once the animation has completed the function <b>MUST</b> return true so that the objects in use for the
animation may be reused and the mod stops calling the function.
</td>
</tr>
</table>
</div>
 
 
<div class="SectionTitle"><a name="MikSBT.RegisterAnimationStyle">MikSBT.RegisterAnimationStyle</a></div>
<hr size="1" />
<a href="#TOC">Return to TOC</a><br /><br />
<div class="SectionDesc">
Registers a new animation style with MSBT.
<br /><br />
Custom animation style registration is not permanent. It must be done each load. In order to remove a custom
animation style, all that needs to be done is no longer register it on subsequent loads. If any of the scroll
areas have a custom animation style selected that is no longer registered, MSBT will recognize that an invalid
animation style is specified and use the default animation style accordingly.<br /><br />
</div>
<div class="SubsectionTitle">Syntax</div>
<div class="SubsectionBody">
<div class="Syntax"><b>MikSBT.RegisterAnimationStyle(</b><i>styleID</i><b>,</b> <i>initHandler</i><b>,</b> <i>availableDirections</i><b> [,</b> <i>availableBehaviors</i><b>,</b> <i>localizationTable</i><b>])</b></div>
</div>
 
<div class="SubsectionTitle">Parameters</div>
<div class="SubsectionBody">
<table cellspacing="3">
<tr>
<td class="ParameterName" nowrap="nowrap"><i>styleID</i> (Required)</td>
<td class="ParameterDesc">
A unique string that identifies the animation style.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><i>initHandler</i> (Required)</td>
<td class="ParameterDesc">
Your <a href="#InitDisplayEventCallback">InitDisplayEvent</a> callback handler.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><i>availableDirections</i> (Required)</td>
<td class="ParameterDesc">
A string that contains a semicolon separated list of the available directions for the animation style.<br /><br />
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><i>availableBehaviors</i> (Optional)</td>
<td class="ParameterDesc">
A string that contains a semicolon separated list of the available behaviors for the animation style.<br /><br />
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><i>localizationTable</i> (Optional)</td>
<td class="ParameterDesc">
A table that contains translations.<br /><br />
The strings provided in the <i>styleID</i>, <i>availableDirections</i>, and <i>availableBehaviors</i> parameters
will by used as the key into this table to find an appropriate translation.
</td>
</tr>
</table>
</div>
 
<div class="SubsectionTitle">Return Values</div>
<div class="SubsectionBody">None.</div>
 
<div class="SubsectionTitle">Examples</div>
<div class="SubsectionBody">
<div class="Syntax">
-- Register a new animation style with MSBT.<br />
MikSBT.RegisterAnimationStyle("MyModNameUberAnimation", myInitHandler, "Up;Down", "Implode;Explode", myLocalizationTable);
</div>
</div>
 
<div class="SubsectionTitle">Remarks</div>
<div class="SubsectionBody">
If you attempt to register a <i>styleID</i> that already exists, the function will quietly fail.
An easy way to make sure you have a unique <i>styleID</i> is to preprend your mod's name to it as demonstrated in the example.
</div>
 
 
<div class="SectionTitle"><a name="MikSBT.RegisterStickyAnimationStyle">MikSBT.RegisterStickyAnimationStyle</a></div>
<hr size="1" />
<a href="#TOC">Return to TOC</a><br /><br />
<div class="SectionDesc">
Registers a new sticky animation style with MSBT.
<br /><br />
Custom animation style registration is not permanent. It must be done each load. In order to remove a custom animation style, all that needs to be done is
no longer register it on subsequent loads. If any of the scroll areas have a custom animation style selected that is no longer registered, MSBT will recognize that an invalid
animation style is specified and use the default animation style accordingly.<br /><br />
</div>
<div class="SubsectionTitle">Syntax</div>
<div class="SubsectionBody">
<div class="Syntax"><b>MikSBT.RegisterStickyAnimationStyle(</b><i>styleID</i><b>,</b> <i>initHandler</i><b>,</b> <i>availableDirections</i><b> [,</b> <i>availableBehaviors</i><b>,</b> <i>localizationTable</i><b>])</b></div>
</div>
 
<div class="SubsectionTitle">Parameters</div>
<div class="SubsectionBody">
<table cellspacing="3">
<tr>
<td class="ParameterName" nowrap="nowrap"><i>styleID</i> (Required)</td>
<td class="ParameterDesc">
A unique string that identifies the animation style.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><i>initHandler</i> (Required)</td>
<td class="ParameterDesc">
Your <a href="#InitDisplayEventCallback">InitDisplayEvent</a> callback handler.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><i>availableDirections</i> (Required)</td>
<td class="ParameterDesc">
A string that contains a semicolon separated list of the available directions for the animation style.<br /><br />
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><i>availableBehaviors</i> (Optional)</td>
<td class="ParameterDesc">
A string that contains a semicolon separated list of the available behaviors for the animation style.<br /><br />
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><i>localizationTable</i> (Optional)</td>
<td class="ParameterDesc">
A table that contains translations.<br /><br />
The strings provided in the <i>styleID</i>, <i>availableDirections</i>, and <i>availableBehaviors</i> parameters
will by used as the key into this table to find an appropriate translation.
</td>
</tr>
</table>
</div>
 
<div class="SubsectionTitle">Return Values</div>
<div class="SubsectionBody">None.</div>
 
<div class="SubsectionTitle">Examples</div>
<div class="SubsectionBody">
<div class="Syntax">
-- Register a new sticky animation style with MSBT.<br />
MikSBT.RegisterStickyAnimationStyle("MyModNameUberStickyAnimation", myInitHandler, "Up;Down", "Jiggle;Normal", myLocalizationTable);
</div>
</div>
 
<div class="SubsectionTitle">Remarks</div>
<div class="SubsectionBody">
If you attempt to register a <i>styleID</i> that already exists, the function will quietly fail.
An easy way to make sure you have a unique <i>styleID</i> is to preprend your mod's name to it as demonstrated in the example.
</div>
 
 
<div class="SectionTitle"><a name="InitDisplayEventCallback">InitDisplayEvent Callback</a></div>
<hr size="1" />
<a href="#TOC">Return to TOC</a><br /><br />
<div class="SectionDesc">
Each time a new <a href="#DisplayEventTable">DisplayEvent</a> is added to a scroll area, this function is called with it, an array of
other <a href="#DisplayEventTable">DisplayEvent</a>s that are currently active for the scroll area, and the currently selected direction
and behavior for the scroll area.
<br /><br />
The most important thing for this function to do is set the <i>.animationHandler</i> field for the new <a href="#DisplayEventTable">DisplayEvent</a>
to an appropriate <a href="#AnimationCallback">Animation</a> callback handler.
<br /><br />
The other purpose of this function is to initialize the starting position, alpha, and any other information you need for the new
<a href="#DisplayEventTable">DisplayEvent</a>, and to move any other <a href="#DisplayEventTable">DisplayEvent</a>s that are now colliding due to the new event.
<br /><br />
<b>This function MUST set the <i>.animationHandler</i> field of the <i>newDisplayEvent</i> parameter to a valid <a href="#AnimationCallback">Animation</a> callback handler.</b>
</div>
<div class="SubsectionTitle">Syntax</div>
<div class="SubsectionBody">
<div class="Syntax"><b>function myInitHandler(</b><i>newDisplayEvent</i><b>,</b> <i>activeDisplayEvents</i><b> [,</b> <i>direction</i><b>,</b> <i>behavior</i><b>])</b></div>
</div>
 
<div class="SubsectionTitle">Parameters</div>
<div class="SubsectionBody">
<table cellspacing="3">
<tr>
<td class="ParameterName" nowrap="nowrap"><i>newDisplayEvent</i> (Required)</td>
<td class="ParameterDesc">
A <a href="#DisplayEventTable">DisplayEvent</a> table that represents a new event.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><i>activeDisplayEvents</i> (Required)</td>
<td class="ParameterDesc">
An array of <a href="#DisplayEventTable">DisplayEvent</a> tables that represent the other events
that are currently active for the scroll area.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><i>direction</i> (Optional)</td>
<td class="ParameterDesc">
A string that is the currently selected direction for the scroll area.<br /><br />
The default animation direction should be used when this parameter is invalid.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><i>behavior</i> (Optional)</td>
<td class="ParameterDesc">
A string that is the currently selected behavior for the scroll area.<br /><br />
The default animation behavior should be used when this parameter is invalid.
</td>
</tr>
</table>
</div>
 
<div class="SubsectionTitle">Return Values</div>
<div class="SubsectionBody">None.</div>
 
<div class="SubsectionTitle">Examples</div>
<div class="SubsectionBody">
<div class="Syntax">
-- Create an InitDisplayEvent callback handler.<br />
local function myInitHandler(newDisplayEvent, activeDisplayEvents, direction, behavior)<br />
&nbsp;-- Do stuff in here to initialize the newDisplayEvent and move any activeDisplayEvents that are colliding according to your custom animation style.<br />
end<br />
</div>
</div>
 
<div class="SubsectionTitle">Remarks</div>
<div class="SubsectionBody">
Take a look at the init functions in the MSBTAnimationStyles.lua file that comes with the mod for an example of how MSBT initializes the default animation styles.<br /><br />
</div>
 
 
<div class="SectionTitle"><a name="AnimationCallback">Animation Callback</a></div>
<hr size="1" />
<a href="#TOC">Return to TOC</a><br /><br />
<div class="SectionDesc">
This function is called continously (typically every 15 or so milliseconds) for every active <a href="#DisplayEventTable">DisplayEvent</a> that is animating
until the function returns true to indicate the animation is complete.
<br /><br />
The <a href="#DisplayEventTable">DisplayEvent</a> is positioned by setting its <i>.positionX</i> and <i>.positionY</i> fields, and its opacity is controlled by setting its <i>.alpha</i> field.
<br /><br />
The x and y positions should be calculated based upon how much time it has been animating, which is available in the <i>.elapsedTime</i> field, and the height and width of the scroll area available
in the <i>.scrollHeight</i> and <i>.scrollWidth</i> fields.
Additionally, the <i>.animationSpeed</i> field should be used to scale the speed of the animation.
<br /><br />
By basing your calculations on the elapsed time, the animation will remain consistent under diverse performance situations. If you were to base it simply on moving a set number of pixels
each update then the actual scroll speed would vary greatly. These fields are further described in the <a href="#DisplayEventTable">DisplayEvent</a> Table section.
<br /><br />
<b>This function MUST return true when the animation is complete.</b>
</div>
<div class="SubsectionTitle">Syntax</div>
<div class="SubsectionBody">
<div class="Syntax"><i>animationComplete</i><b> = function myAnimationHandler(</b><i>displayEvent</i><b>)</b></div>
</div>
 
<div class="SubsectionTitle">Parameters</div>
<div class="SubsectionBody">
<table cellspacing="3">
<tr>
<td class="ParameterName" nowrap="nowrap"><i>displayEvent</i> (Required)</td>
<td class="ParameterDesc">
A <a href="#DisplayEventTable">DisplayEvent</a> table that represents the animating event.
</td>
</tr>
</table>
</div>
 
<div class="SubsectionTitle">Return Values</div>
<div class="SubsectionBody">
<table cellspacing="3">
<tr>
<td class="ParameterName" nowrap="nowrap"><i>animationComplete</i> (Required)</td>
<td class="ParameterDesc">
Return true if the animation is complete and false if it is not.
</td>
</tr>
</table>
</div>
 
<div class="SubsectionTitle">Examples</div>
<div class="SubsectionBody">
<div class="Syntax">
-- Create an Animation callback handler.<br />
local function myAnimationHandler(displayEvent)<br />
&nbsp;-- Do stuff in here to animate the displayEvent.<br />
end<br />
</div>
</div>
 
<div class="SubsectionTitle">Remarks</div>
<div class="SubsectionBody">
Take a look at the scroll functions in the MSBTAnimationStyles.lua file that comes with the mod for an example of how MSBT animates the default animation styles.
</div>
 
 
 
<div class="SectionTitle"><a name="DisplayEventTable">DisplayEvent Table</a></div>
<hr size="1" />
<a href="#TOC">Return to TOC</a><br /><br />
<div class="SectionDesc">
This table respresents an animating event.
</div>
 
<div class="SubsectionTitle">Fields</div>
<div class="SubsectionBody">
<table cellspacing="3">
<tr>
<td class="ParameterName" nowrap="nowrap"><i>.scrollHeight</i> (Read-Only)</td>
<td class="ParameterDesc">
This field contains the height of the scroll area the event is animating in.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><i>.scrollWidth</i> (Read-Only)</td>
<td class="ParameterDesc">
This field contains the width of the scroll area the event is animating in.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><i>.fontSize</i> (Read-Only)</td>
<td class="ParameterDesc">
This field contains the size of the font used for the event.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><i>.fontString</i> (Read-Only)</td>
<td class="ParameterDesc">
This field contains the &lt;FontString&gt; object that the event is using to display the text.<br /><br />
A dynamic pool of font strings is maintained and reused by MSBT.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><i>.anchorPoint</i> (Read-Only)</td>
<td class="ParameterDesc">
This field contains anchor point for &lt;FontString&gt; that the event is using to display the text.<br /><br />
It will be "BOTTOMLEFT", "BOTTOM", or "BOTTOMRIGHT", corresponding to left, center, and right text alignment.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><i>.animationSpeed</i> (Read-Only)</td>
<td class="ParameterDesc">
The user selected animation speed. This is a decimal representation of a percentage.
<br /><br />
For example, 0.5 means that the animation should animate at 50% of the normal speed,
1.0 means it should animate at normal speed, and 2.5 means it should animate at 250% of normal speed.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><i>.positionX</i> (Read-Write)</td>
<td class="ParameterDesc">
The x position of the event to be set once the function returns.
<br /><br />
MSBT handles all scroll area offsetting. x = 0 refers to the text's attachment point (left, right, or center).
Negative values for x move the text to the left, and positive values moves the text to the right.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><i>.positionY</i> (Read-Write)</td>
<td class="ParameterDesc">
The y position of the event to be set once the function returns.
<br /><br />
MSBT handles all scroll area offsetting. y = 0 refers to the bottom point of the scroll area and increases upward.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><i>.alpha</i> (Read-Write)</td>
<td class="ParameterDesc">
The opacity of the event to be set once the function returns.
<br /><br />
The value range is from 0 (invisible) to 1 (fully visible).
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><i>.elapsedTime</i> (Read-Write)</td>
<td class="ParameterDesc">
The amount of time the event has been animating.
</td>
</tr>
</table>
</div>
 
<div class="SubsectionTitle">Remarks</div>
<div class="SubsectionBody">
Technically the fields marked as read-only are normal fields just like the rest, however they should be treated as read-only. Altering them can cause unexpected behavior.
I didn't want to add the extra overhead it would take to truly make them read-only. There are also a few other internal fields that should not be altered.
</div>
 
 
</body>
</html>
\ No newline at end of file
MSBT5_13/MikScrollingBattleText/MSBTCooldowns.lua New file
0,0 → 1,253
-------------------------------------------------------------------------------
-- Title: Mik's Scrolling Battle Text Cooldowns
-- Author: Mik
-------------------------------------------------------------------------------
 
-- Create module and set its name.
local module = {};
local moduleName = "Cooldowns";
MikSBT[moduleName] = module;
 
-------------------------------------------------------------------------------
-- Constants.
-------------------------------------------------------------------------------
 
-- The minimum amount of time to delay between checking cooldowns.
local MIN_COOLDOWN_UPDATE_INTERVAL = 0.1;
 
-- Spell names.
local SPELL_COLD_SNAP = GetSpellInfo(11958);
local SPELL_PREPARATION = GetSpellInfo(14185);
local SPELL_READINESS = GetSpellInfo(23989);
 
 
-------------------------------------------------------------------------------
-- Private variables.
-------------------------------------------------------------------------------
 
-- Dynamically created frame for receiving events.
local eventFrame;
 
-- Cooldown information.
local activeCooldowns = {};
local delayedCooldowns = {};
local resetAbilities = {};
local cooldownSpellName;
 
-- Holds the shortest remaining cooldown time.
local shortestRemaining = MIN_COOLDOWN_UPDATE_INTERVAL;
 
-- Used for timing between updates.
local lastUpdate = 0;
 
 
-------------------------------------------------------------------------------
-- Imports.
-------------------------------------------------------------------------------
 
-- Local references to certain MSBT modules for faster access.
local MSBTLocale = MikSBT.Locale;
local MSBTProfiles = MikSBT.Profiles;
 
-- Local references to certain functions for faster access.
local string_gsub = string.gsub;
local string_find = string.find;
local string_format = string.format;
local EraseTable = MikSBT.EraseTable;
local DisplayEvent = MikSBT.Animations.DisplayEvent;
 
 
-------------------------------------------------------------------------------
-- Event handlers.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Called when the player successfully casts a spell.
-- ****************************************************************************
local function OnSpellCast(spellName)
-- Ignore the cast if the spell name is excluded.
if (MSBTProfiles.currentProfile.cooldownExclusions[spellName]) then return; end
 
-- An ability that resets cooldowns was cast.
if (resetAbilities[spellName]) then
-- Remove cooldowns that still have an internal timer, but the game is reporting otherwise.
for spellName, cooldownRemaining in pairs(activeCooldowns) do
local startTime, duration = GetSpellCooldown(spellName);
if (duration <= 1.5 and (cooldownRemaining - lastUpdate) > 1.5) then activeCooldowns[spellName] = nil; end
 
-- Set the shortest remaining cooldown to the minimum update interval so it will be recalculated.
shortestRemaining = MIN_COOLDOWN_UPDATE_INTERVAL;
end
end
 
-- Set the cooldown spell name to be checked on the next cooldown update event.
cooldownSpellName = spellName;
end
 
 
-- ****************************************************************************
-- Called when the OnUpdate event occurs.
-- ****************************************************************************
local function OnUpdate(this, elapsed)
-- Increment the amount of time passed since the last update.
lastUpdate = lastUpdate + elapsed;
 
-- Check if it's time for an update.
if (lastUpdate >= shortestRemaining) then
-- Reset the shortest remaining cooldown.
shortestRemaining = 65535;
 
-- Loop through all of the active cooldowns.
for spellName, cooldownRemaining in pairs(activeCooldowns) do
cooldownRemaining = cooldownRemaining - lastUpdate;
 
-- Cooldown completed.
if (cooldownRemaining <= 0) then
local eventSettings = MSBTProfiles.currentProfile.events.NOTIFICATION_COOLDOWN;
if (eventSettings) then
local message = eventSettings.message;
message = string_gsub(message, "%%e", string_format("|cffff0000%s|r", string_gsub(spellName, "%(.+%)%(%)$", "")));
DisplayEvent(eventSettings, message, GetSpellTexture(spellName));
end
 
-- Remove the cooldown from the active cooldowns list.
activeCooldowns[spellName] = nil;
 
-- Cooldown NOT completed.
else
activeCooldowns[spellName] = cooldownRemaining;
if (cooldownRemaining < shortestRemaining) then shortestRemaining = cooldownRemaining; end
end
end
 
-- Set the shortest cooldown to the min update interval if it's less.
if (shortestRemaining < MIN_COOLDOWN_UPDATE_INTERVAL) then shortestRemaining = MIN_COOLDOWN_UPDATE_INTERVAL; end
 
-- Hide the event frame if there are no active cooldowns so the OnUpdate events stop firing.
-- This is done to keep the number of OnUpdate events down to a minimum for better performance.
if (not next(activeCooldowns)) then eventFrame:Hide(); end
 
-- Reset the time since last update.
lastUpdate = 0;
end
end
 
 
-- ****************************************************************************
-- Called when the events the module registered for occur.
-- ****************************************************************************
local function OnEvent(this, event, arg1, arg2)
-- Successful spell casts.
if (event == "UNIT_SPELLCAST_SUCCEEDED") then
if (arg1 == "player") then OnSpellCast(arg2); end
 
-- Cooldown updates.
elseif (event == "SPELL_UPDATE_COOLDOWN") then
-- Start delayed cooldowns once they have been used.
for spellName in pairs(delayedCooldowns) do
-- Check if the spell is enabled yet.
local _, duration, enabled = GetSpellCooldown(spellName);
if (enabled == 1) then
-- Add the spell to the active cooldowns list if the cooldown is longer than the cooldown threshold.
if (duration >= MSBTProfiles.currentProfile.cooldownThreshold) then
activeCooldowns[spellName] = duration + lastUpdate;
 
-- Set the shortest remaining cooldown to the minimum update interval so it will be recalculated.
shortestRemaining = MIN_COOLDOWN_UPDATE_INTERVAL;
 
-- Check if the event frame is not visible and make it visible so the OnUpdate events start firing.
-- This is done to keep the number of OnUpdate events down to a minimum for better performance.
if (not eventFrame:IsVisible()) then eventFrame:Show(); end
end
 
-- Remove the spell from the delayed cooldowns list.
delayedCooldowns[spellName] = nil;
end
end
 
-- Add the last successful spell to the active cooldowns if necessary.
if (cooldownSpellName) then
-- Append empty rank syntax to spell names with parentheses in them to avoid confusing Blizzard's API.
if string_find(cooldownSpellName, "%(.+%)$") then cooldownSpellName = cooldownSpellName .. "()"; end
 
-- Make sure the spell cooldown is enabled.
local _, duration, enabled = GetSpellCooldown(cooldownSpellName);
if (enabled == 1) then
-- Add the spell to the active cooldowns list if the cooldown is longer than the cooldown threshold.
if (duration >= MSBTProfiles.currentProfile.cooldownThreshold) then
activeCooldowns[cooldownSpellName] = duration + lastUpdate;
 
-- Set the shortest remaining cooldown to the minimum update interval so it will be recalculated.
shortestRemaining = MIN_COOLDOWN_UPDATE_INTERVAL;
 
-- Check if the event frame is not visible and make it visible so the OnUpdate events start firing.
-- This is done to keep the number of OnUpdate events down to a minimum for better performance.
if (not eventFrame:IsVisible()) then eventFrame:Show(); end
end
 
-- Spell cooldown is NOT enabled so add it to the delayed cooldowns list.
else
delayedCooldowns[cooldownSpellName] = true;
end
 
cooldownSpellName = nil;
end -- cooldownSpellName?
end -- SPELL_UPDATE_COOLDOWN
end
 
 
-- ****************************************************************************
-- Enables the module.
-- ****************************************************************************
local function Enable()
eventFrame:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED");
eventFrame:RegisterEvent("SPELL_UPDATE_COOLDOWN");
end
 
 
-- ****************************************************************************
-- Disables the module.
-- ****************************************************************************
local function Disable()
-- Stop receiving updates.
eventFrame:Hide();
eventFrame:UnregisterAllEvents();
 
-- Clear the active and delayed cooldowns.
EraseTable(activeCooldowns);
EraseTable(delayedCooldowns);
end
 
 
-- ****************************************************************************
-- Called when the module is loaded.
-- ****************************************************************************
local function OnLoad()
-- Create a frame to receive events.
eventFrame = CreateFrame("Frame");
eventFrame:Hide();
eventFrame:SetScript("OnEvent", OnEvent);
eventFrame:SetScript("OnUpdate", OnUpdate);
 
-- Specify the abilities that reset cooldowns.
resetAbilities[SPELL_COLD_SNAP] = true;
resetAbilities[SPELL_PREPARATION] = true;
resetAbilities[SPELL_READINESS] = true;
end
 
 
 
 
-------------------------------------------------------------------------------
-- Module interface.
-------------------------------------------------------------------------------
 
-- Protected Functions.
module.Enable = Enable;
module.Disable = Disable;
 
-------------------------------------------------------------------------------
-- Load.
-------------------------------------------------------------------------------
 
OnLoad();
\ No newline at end of file
MSBT5_13/MikScrollingBattleText/localization.fr.lua New file
0,0 → 1,66
-------------------------------------------------------------------------------
-- Title: Mik's Scrolling Battle Text French Localization
-- Author: Mik
-- French Translation by: Calthas
-------------------------------------------------------------------------------
 
-- Don't do anything if the locale isn't French.
if (GetLocale() ~= "frFR") then return; end
 
-------------------------------------------------------------------------------
-- French localization
-------------------------------------------------------------------------------
 
-- Local reference for faster access.
local MSBTLocale = MikSBT.Locale;
 
 
MSBTLocale.COMMAND_USAGE = {
"Usage: " .. MikSBT.COMMAND .. " <commande> [params]",
" Commande:",
" " .. MSBTLocale.COMMAND_RESET .. " - Restaure les param\195\168tres par d\195\169faut.",
" " .. MSBTLocale.COMMAND_DISABLE .. " - D\195\169sactive l'addon.",
" " .. MSBTLocale.COMMAND_ENABLE .. " - Active l'addon.",
" " .. MSBTLocale.COMMAND_SHOWVER .. " - Affiche la version actuelle.",
" " .. MSBTLocale.COMMAND_HELP .. " - Affiche l'aide des commandes.",
};
 
 
------------------------------
-- Output messages
------------------------------
 
MSBTLocale.MSG_SEARCH_ENABLE = "Mode de recherche d'\195\169v\195\168nements activ\195\169e. Recherche de: ";
MSBTLocale.MSG_SEARCH_DISABLE = "Mode de recherche d'\195\169v\195\168nements d\195\169sactiv\195\169e.";
MSBTLocale.MSG_DISABLE = "Addon d\195\169sactiv\195\169.";
MSBTLocale.MSG_ENABLE = "Addon activ\195\169.";
MSBTLocale.MSG_PROFILE_RESET = "Profil r\195\169initialis\195\169";
MSBTLocale.MSG_HITS = "Coups";
--MSBTLocale.MSG_CRIT = "Crit";
--MSBTLocale.MSG_CRITS = "Crits";
MSBTLocale.MSG_MULTIPLE_TARGETS = "Multiples";
MSBTLocale.MSG_READY_NOW = "Disponible";
 
 
------------------------------
-- Scroll area messages
------------------------------
 
MSBTLocale.MSG_INCOMING = "Entrant";
MSBTLocale.MSG_OUTGOING = "Sortant";
MSBTLocale.MSG_NOTIFICATION = "Alertes";
MSBTLocale.MSG_STATIC = "Statique";
 
 
---------------------------------------
-- Master profile event output messages
---------------------------------------
 
--MSBTLocale.MSG_COMBAT = "Combat";
MSBTLocale.MSG_DISPEL = "Dissiper";
--MSBTLocale.MSG_CP = "CP";
--MSBTLocale.CP_FULL = "Finish It";
MSBTLocale.MSG_KILLING_BLOW = "Coup Fatal";
MSBTLocale.MSG_TRIGGER_LOW_HEALTH = "Vie Faible";
MSBTLocale.MSG_TRIGGER_LOW_MANA = "Mana Faible";
MSBTLocale.MSG_TRIGGER_LOW_PET_HEALTH = "Vie du fam faible";
\ No newline at end of file
MSBT5_13/MikScrollingBattleText/MSBTSounds.lua New file
0,0 → 1,24
-------------------------------------------------------------------------------
-- Title: Mik's Scrolling Battle Text Sounds
-- Author: Mik
-------------------------------------------------------------------------------
 
-------------------------------------------------------------------------------
-- Private constants.
-------------------------------------------------------------------------------
 
-- The sound files to use.
local SOUND_FILES = {
LowHealth = "Interface\\Addons\\MikScrollingBattleText\\Sounds\\LowHealth.mp3",
LowMana = "Interface\\Addons\\MikScrollingBattleText\\Sounds\\LowMana.mp3",
}
 
 
-------------------------------------------------------------------------------
-- Load.
-------------------------------------------------------------------------------
 
-- Loop through all of the sounds and register them.
for soundName, soundPath in pairs(SOUND_FILES) do
MikSBT.RegisterSound(soundName, soundPath);
end
\ No newline at end of file
MSBT5_13/MikScrollingBattleText/MikScrollingBattleText.toc New file
0,0 → 1,22
## Interface: 20400
## Version: 5.13
## Title: Mik's Scrolling Battle Text
## Author: Mik
## Notes: Scrolls battle information around the character model.
## SavedVariables: MSBTProfiles_SavedVars
## SavedVariablesPerCharacter: MSBTProfiles_SavedVarsPerChar
MikSBT.lua
localization.lua
localization.de.lua
localization.fr.lua
localization.zhcn.lua
MSBTProfiles.lua
MSBTParser.lua
MSBTAnimations.lua
MSBTTriggers.lua
MSBTCooldowns.lua
MSBTMain.lua
MSBTFonts.lua
MSBTSounds.lua
MSBTAnimationStyles.lua
MSBTLegacy.lua
\ No newline at end of file
MSBT5_13/MikScrollingBattleText/Fonts/porky.ttf Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes : Added: svn:mime-type + application/octet-stream
MSBT5_13/MikScrollingBattleText/Fonts/transformers.ttf Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes : Added: svn:mime-type + application/octet-stream
MSBT5_13/MikScrollingBattleText/Fonts/bazooka.ttf Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes : Added: svn:mime-type + application/octet-stream
MSBT5_13/MikScrollingBattleText/Fonts/ginko.ttf Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes : Added: svn:mime-type + application/octet-stream
MSBT5_13/MikScrollingBattleText/Fonts/cooline.ttf Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes : Added: svn:mime-type + application/octet-stream
MSBT5_13/MikScrollingBattleText/Fonts/talisman.ttf Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes : Added: svn:mime-type + application/octet-stream
MSBT5_13/MikScrollingBattleText/Fonts/heroic.ttf Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes : Added: svn:mime-type + application/octet-stream
MSBT5_13/MikScrollingBattleText/Fonts/adventure.ttf Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes : Added: svn:mime-type + application/octet-stream
MSBT5_13/MikScrollingBattleText/Fonts/diogenes.ttf Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes : Added: svn:mime-type + application/octet-stream
MSBT5_13/MikScrollingBattleText/Fonts/yellowjacket.ttf Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes : Added: svn:mime-type + application/octet-stream
MSBT5_13/MikScrollingBattleText/Fonts/zephyr.ttf Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes : Added: svn:mime-type + application/octet-stream
MSBT5_13/MikScrollingBattleText/MSBTAnimationStyles.lua New file
0,0 → 1,807
-------------------------------------------------------------------------------
-- Title: Mik's Scrolling Battle Text Default Animation Styles
-- Author: Mik
-------------------------------------------------------------------------------
 
-------------------------------------------------------------------------------
-- Private constants.
-------------------------------------------------------------------------------
 
-- How long to show stickies before they are faded.
local STICKY_FADE_IN_TIME = 0.17;
local STICKY_DISPLAY_TIME = 1.5;
local STICKY_FADE_OUT_TIME = 0.5;
 
-- How long to show static messages before they are faded.
local STATIC_DISPLAY_TIME = 3.15;
local STATIC_FADE_OUT_TIME = 0.5;
 
-- How long to wait between jiggles.
local JIGGLE_DELAY_TIME = 0.05;
 
-- The delta to use for the pow effect.
local POW_TEXT_DELTA = 0.7;
 
-- Default movement speed. (260 pixels every 3 seconds)
local MOVEMENT_SPEED = (3 / 260);
 
-- Minimum amount of space allowed between two strings.
local MIN_VERTICAL_SPACING = 8;
local MIN_HORIZONTAL_SPACING = 10;
 
 
-------------------------------------------------------------------------------
-- Private variables.
-------------------------------------------------------------------------------
 
-- Last used horizontal Y position and direction.
local lastHorizontalPositionY = {};
local lastHorizontalDirection = {};
 
 
-------------------------------------------------------------------------------
-- Imports.
-------------------------------------------------------------------------------
 
-- Local references to certain functions for faster access.
local math_floor = math.floor;
local math_ceil = math.ceil;
local math_random = math.random;
local math_max = math.max;
local math_abs = math.abs;
 
 
-------------------------------------------------------------------------------
-- Pow Sticky functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Animates the passed display event using using the zoom style.
-- ****************************************************************************
local function AnimatePowNormal(displayEvent)
-- Local references for faster access.
local displayTime = displayEvent.displayTime;
local fadeOutTime = displayEvent.fadeOutTime;
local elapsedTime = displayEvent.elapsedTime;
 
-- Scale the text height.
if (elapsedTime <= STICKY_FADE_IN_TIME) then
local textDelta = displayEvent.fontSize * ((1 - (elapsedTime / STICKY_FADE_IN_TIME)) * POW_TEXT_DELTA);
displayEvent.fontString:SetTextHeight(displayEvent.fontSize + textDelta);
return false;
 
-- Leave the text displayed.
elseif (elapsedTime <= (STICKY_FADE_IN_TIME + displayTime)) then
displayEvent.fontString:SetTextHeight(displayEvent.fontSize);
return false;
 
-- Fade out.
elseif (elapsedTime <= (STICKY_FADE_IN_TIME + displayTime + fadeOutTime)) then
displayEvent.alpha = 1 - ((elapsedTime - STICKY_FADE_IN_TIME - displayTime) / fadeOutTime);
return false;
end
 
-- Return true to indicate the animation is complete.
return true;
end
 
 
-- ****************************************************************************
-- Animates the passed display event using using the pow style.
-- ****************************************************************************
local function AnimatePowJiggle(displayEvent)
-- Local references for faster access.
local displayTime = displayEvent.displayTime;
local fadeOutTime = displayEvent.fadeOutTime;
local elapsedTime = displayEvent.elapsedTime;
 
-- Scale the text height.
if (elapsedTime <= STICKY_FADE_IN_TIME) then
local textDelta = displayEvent.fontSize * ((1 - (elapsedTime / STICKY_FADE_IN_TIME)) * POW_TEXT_DELTA);
displayEvent.fontString:SetTextHeight(displayEvent.fontSize + textDelta);
return false;
 
-- Jiggle the text around.
elseif (elapsedTime <= (STICKY_FADE_IN_TIME + displayTime)) then
if (elapsedTime - displayEvent.timeLastJiggled > JIGGLE_DELAY_TIME) then
displayEvent.positionX = displayEvent.originalPositionX + math_ceil(math_random(-1, 1));
displayEvent.positionY = displayEvent.originalPositionY + math_ceil(math_random(-1, 1));
displayEvent.timeLastJiggled = elapsedTime;
end
 
displayEvent.fontString:SetTextHeight(displayEvent.fontSize);
return false;
 
-- Fade out.
elseif (elapsedTime <= (STICKY_FADE_IN_TIME + displayTime + fadeOutTime)) then
displayEvent.alpha = 1 - ((elapsedTime - STICKY_FADE_IN_TIME - displayTime) / fadeOutTime);
return false;
end
 
-- Return true to indicate the animation is complete.
return true;
end
 
 
-- ****************************************************************************
-- Initialize the passed display event and reposition the ones that are
-- currently animating in the scroll area to prevent overlaps.
-- ****************************************************************************
local function InitPow(newDisplayEvent, activeDisplayEvents, direction, behavior)
-- Choose the correct animation function.
newDisplayEvent.animationHandler = (behavior == "Jiggle") and AnimatePowJiggle or AnimatePowNormal;
 
-- Set the new event's starting position.
local anchorPoint = newDisplayEvent.anchorPoint;
if (anchorPoint == "BOTTOMLEFT") then
newDisplayEvent.positionX = 0;
elseif (anchorPoint == "BOTTOM") then
newDisplayEvent.positionX = math_ceil(newDisplayEvent.scrollWidth / 2);
elseif (anchorPoint == "BOTTOMRIGHT") then
newDisplayEvent.positionX = newDisplayEvent.scrollWidth;
end
newDisplayEvent.positionY = math_ceil(newDisplayEvent.scrollHeight / 2);
 
-- Save the original x and y positions for calculating the jiggle effect.
newDisplayEvent.originalPositionX = newDisplayEvent.positionX;
newDisplayEvent.originalPositionY = newDisplayEvent.positionY;
newDisplayEvent.timeLastJiggled = 0;
 
-- Scale the display and fade out times based on the animation speed.
newDisplayEvent.displayTime = STICKY_DISPLAY_TIME * (1/newDisplayEvent.animationSpeed);
newDisplayEvent.fadeOutTime = STICKY_FADE_OUT_TIME * (1/newDisplayEvent.animationSpeed);
 
-- Set the initial alpha of the new display event to fully visible.
newDisplayEvent.alpha = 1;
 
-- Get the number of sticky display events that are currently animating.
local numActiveAnimations = #activeDisplayEvents;
 
-- Exit if there is no need to check for collisions.
if (numActiveAnimations == 0) then return; end
 
 
-- Check if the text is scrolling down.
if (direction == "Down") then
-- Get the middle sticky.
local middleSticky = math_floor((numActiveAnimations + 2) / 2);
 
-- Set the middle sticky to the center of the scroll area.
activeDisplayEvents[middleSticky].originalPositionY = newDisplayEvent.scrollHeight / 2;
activeDisplayEvents[middleSticky].positionY = activeDisplayEvents[middleSticky].originalPositionY;
 
-- Loop backwards from the middle sticky and move the animating display events so they don't collide.
for x = middleSticky - 1, 1, -1 do
activeDisplayEvents[x].originalPositionY = activeDisplayEvents[x+1].originalPositionY - activeDisplayEvents[x].fontSize - MIN_VERTICAL_SPACING;
activeDisplayEvents[x].positionY = activeDisplayEvents[x].originalPositionY
end
 
-- Loop forwards from the middle sticky and move the animating display events so they don't collide.
for x = middleSticky + 1, numActiveAnimations do
activeDisplayEvents[x].originalPositionY = activeDisplayEvents[x-1].originalPositionY + activeDisplayEvents[x-1].fontSize + MIN_VERTICAL_SPACING;
activeDisplayEvents[x].positionY = activeDisplayEvents[x].originalPositionY
end
 
-- Move the new display event so it doesn't collide.
newDisplayEvent.originalPositionY = activeDisplayEvents[numActiveAnimations].originalPositionY + activeDisplayEvents[numActiveAnimations].fontSize + MIN_VERTICAL_SPACING;
newDisplayEvent.positionY = newDisplayEvent.originalPositionY;
 
-- Text is scrolling up.
else
-- Get the middle sticky.
local middleSticky = math_ceil(numActiveAnimations / 2);
 
-- Set the middle sticky to the center of the scroll area.
activeDisplayEvents[middleSticky].originalPositionY = newDisplayEvent.scrollHeight / 2;
activeDisplayEvents[middleSticky].positionY = activeDisplayEvents[middleSticky].originalPositionY;
 
-- Loop backwards from the middle sticky and move the animating display events so they don't collide.
for x = middleSticky - 1, 1, -1 do
activeDisplayEvents[x].originalPositionY = activeDisplayEvents[x+1].originalPositionY + activeDisplayEvents[x+1].fontSize + MIN_VERTICAL_SPACING;
activeDisplayEvents[x].positionY = activeDisplayEvents[x].originalPositionY
end
 
-- Loop forwards from the middle sticky and move the animating display events so they don't collide.
for x = middleSticky + 1, numActiveAnimations do
activeDisplayEvents[x].originalPositionY = activeDisplayEvents[x-1].originalPositionY - activeDisplayEvents[x].fontSize - MIN_VERTICAL_SPACING;
activeDisplayEvents[x].positionY = activeDisplayEvents[x].originalPositionY
end
 
-- Move the new display event so it doesn't collide.
newDisplayEvent.originalPositionY = activeDisplayEvents[numActiveAnimations].originalPositionY - activeDisplayEvents[numActiveAnimations].fontSize - MIN_VERTICAL_SPACING;
newDisplayEvent.positionY = newDisplayEvent.originalPositionY;
end
end
 
 
-------------------------------------------------------------------------------
-- Straight scroll functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Scrolls the passed display event upwards.
-- ****************************************************************************
local function ScrollUp(displayEvent)
-- Local references for faster access.
local scaledScrollTime = displayEvent.scaledScrollTime;
local elapsedTime = displayEvent.elapsedTime;
 
-- Calculate the fade effect start time to be halfway through the animation.
local fadeStartTime = scaledScrollTime / 2;
 
-- Set the y position based on the elapsed time.
displayEvent.positionY = math_floor(displayEvent.scrollHeight * (elapsedTime / scaledScrollTime));
 
-- Fade the text out once enough time has passed.
if (elapsedTime >= fadeStartTime) then
local alpha = 1 - ((elapsedTime - fadeStartTime) / (scaledScrollTime - fadeStartTime));
displayEvent.alpha = math_max(alpha, 0);
end
 
-- Return true to indicate that the animation is complete when enough time has passed.
if (elapsedTime >= scaledScrollTime) then return true; end
 
-- Return false to indicate the animation is NOT complete.
return false;
end
 
 
-- ****************************************************************************
-- Scrolls the passed display event downwards.
-- ****************************************************************************
local function ScrollDown(displayEvent)
-- Local references for faster access.
local scaledScrollTime = displayEvent.scaledScrollTime;
local elapsedTime = displayEvent.elapsedTime;
 
-- Calculate the fade effect start time to be halfway through the animation.
local fadeStartTime = scaledScrollTime / 2;
 
-- Set the y position based on the elapsed time.
displayEvent.positionY = displayEvent.scrollHeight - math_floor(displayEvent.scrollHeight * (elapsedTime / scaledScrollTime));
 
-- Fade the text out once enough time has passed.
if (elapsedTime >= fadeStartTime) then
local alpha = 1 - ((elapsedTime - fadeStartTime) / (scaledScrollTime - fadeStartTime));
displayEvent.alpha = math_max(alpha, 0);
end
 
-- Return true to indicate that the animation is complete when enough time has passed.
if (elapsedTime >= scaledScrollTime) then return true; end
 
-- Return false to indicate the animation is NOT complete.
return false;
end
 
 
-- ****************************************************************************
-- Initialize the passed display event and reposition the ones that are
-- currently scrolling in the scroll area to prevent overlaps.
-- ****************************************************************************
local function InitStraight(newDisplayEvent, activeDisplayEvents, direction, behavior)
-- Set the new event's starting X position.
local anchorPoint = newDisplayEvent.anchorPoint;
if (anchorPoint == "BOTTOMLEFT") then
newDisplayEvent.positionX = 0;
elseif (anchorPoint == "BOTTOM") then
newDisplayEvent.positionX = math_ceil(newDisplayEvent.scrollWidth / 2);
elseif (anchorPoint == "BOTTOMRIGHT") then
newDisplayEvent.positionX = newDisplayEvent.scrollWidth;
end
 
-- Calculate how long the animation should take based on the height of the scroll area
-- and scaled by the animation speed.
newDisplayEvent.scaledScrollTime = newDisplayEvent.scrollHeight * MOVEMENT_SPEED * (1/newDisplayEvent.animationSpeed);
 
-- Set the initial alpha of the new display event to fully visible.
newDisplayEvent.alpha = 1;
 
-- Get the number of display events that are currently scrolling for this style.
local numActiveAnimations = #activeDisplayEvents;
 
-- Scroll text down.
if (direction == "Down") then
-- Choose the correct animation function.
newDisplayEvent.animationHandler = ScrollDown;
 
-- Exit if there is no need to check for collisions.
if (numActiveAnimations == 0) then return; end
 
-- Scale the per pixel time based on the animation speed.
local perPixelTime = MOVEMENT_SPEED * (1/newDisplayEvent.animationSpeed);
local currentDisplayEvent = newDisplayEvent;
local prevDisplayEvent, topTimeCurrent;
 
-- Move events that are colliding.
for x = numActiveAnimations, 1, -1 do
prevDisplayEvent = activeDisplayEvents[x];
 
-- Calculate the elapsed time for the top point of the current display event.
topTimeCurrent = currentDisplayEvent.elapsedTime + (currentDisplayEvent.fontSize + MIN_VERTICAL_SPACING) * perPixelTime;
 
-- Adjust the elapsed time of the previous display event if the current one is colliding with it.
if (prevDisplayEvent.elapsedTime < topTimeCurrent) then
prevDisplayEvent.elapsedTime = topTimeCurrent;
else
-- Don't continue checking if there is no need.
break;
end
 
currentDisplayEvent = prevDisplayEvent;
end
 
-- Scroll text up.
else
-- Choose the correct animation function.
newDisplayEvent.animationHandler = ScrollUp;
 
-- Exit if there is no need to check for collisions.
if (numActiveAnimations == 0) then return; end
 
-- Scale the per pixel time based on the animation speed.
local perPixelTime = MOVEMENT_SPEED * (1/newDisplayEvent.animationSpeed);
local currentDisplayEvent = newDisplayEvent;
local prevDisplayEvent, topTimePrev;
 
-- Move events that are colliding.
for x = numActiveAnimations, 1, -1 do
prevDisplayEvent = activeDisplayEvents[x];
 
-- Calculate the elapsed time for the top point of the previous display event.
topTimePrev = prevDisplayEvent.elapsedTime - (prevDisplayEvent.fontSize + MIN_VERTICAL_SPACING) * perPixelTime;
 
-- Adjust the elapsed time of the previous display event if the current one is colliding with it.
if (topTimePrev < currentDisplayEvent.elapsedTime) then
prevDisplayEvent.elapsedTime = currentDisplayEvent.elapsedTime + (prevDisplayEvent.fontSize + MIN_VERTICAL_SPACING) * perPixelTime;
else
-- Exit if there is no need to continue checking for collisions.
return;
end
 
currentDisplayEvent = prevDisplayEvent;
end
end -- Direction.
end
 
 
-------------------------------------------------------------------------------
-- Parabola scroll functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Scrolls the passed display event in a left parabola upwards.
-- ****************************************************************************
local function ScrollLeftParabolaUp(displayEvent)
-- Leverage the scroll up logic.
local animationComplete = ScrollUp(displayEvent);
 
-- Calculate the new x position based on equation of a parabola.
-- Equation of a parabola at vertex 0,0: x = y^2 / 4a
local y = displayEvent.positionY - displayEvent.midPoint;
displayEvent.positionX = (y * y) / displayEvent.fourA;
 
-- Return whether or not the animation is complete.
return animationComplete;
end
 
 
-- ****************************************************************************
-- Scrolls the passed display event in a left parabola downwards.
-- ****************************************************************************
local function ScrollLeftParabolaDown(displayEvent)
-- Leverage the scroll up logic.
local animationComplete = ScrollDown(displayEvent);
 
-- Calculate the new x position based on equation of a parabola.
-- Equation of a parabola at vertex 0,0: x = y^2 / 4a
local y = displayEvent.positionY - displayEvent.midPoint;
displayEvent.positionX = (y * y) / displayEvent.fourA;
 
-- Return whether or not the animation is complete.
return animationComplete;
end
 
 
-- ****************************************************************************
-- Scrolls the passed display event in a right parabola upwards.
-- ****************************************************************************
local function ScrollRightParabolaUp(displayEvent)
-- Leverage the scroll up logic.
local animationComplete = ScrollUp(displayEvent);
 
-- Calculate the new x position based on equation of a parabola.
-- Equation of a parabola at vertex 0,0: x = y^2 / 4a
local y = displayEvent.positionY - displayEvent.midPoint;
displayEvent.positionX = displayEvent.scrollWidth - ((y * y) / displayEvent.fourA);
 
-- Return whether or not the animation is complete.
return animationComplete;
end
 
 
-- ****************************************************************************
-- Scrolls the passed display event in a right parabola downwards.
-- ****************************************************************************
local function ScrollRightParabolaDown(displayEvent)
-- Leverage the scroll down logic.
local animationComplete = ScrollDown(displayEvent);
 
-- Calculate the new x position based on equation of a parabola.
-- Equation of a parabola at vertex 0,0: x = y^2 / 4a
local y = displayEvent.positionY - displayEvent.midPoint;
displayEvent.positionX = displayEvent.scrollWidth - ((y * y) / displayEvent.fourA);
 
-- Return whether or not the animation is complete.
return animationComplete;
end
 
 
-- ****************************************************************************
-- Initialize the passed display event and reposition the ones that are
-- currently scrolling in the scroll area to prevent overlaps.
-- ****************************************************************************
local function InitParabola(newDisplayEvent, activeDisplayEvents, direction, behavior)
-- Leverage the straight logic.
InitStraight(newDisplayEvent, activeDisplayEvents, direction, behavior);
 
-- Choose correction animation function.
if (direction == "Down") then
newDisplayEvent.animationHandler = (behavior == "CurvedRight") and ScrollRightParabolaDown or ScrollLeftParabolaDown;
else
newDisplayEvent.animationHandler = (behavior == "CurvedRight") and ScrollRightParabolaUp or ScrollLeftParabolaUp;
end
 
-- Calculate the scroll area midpoint.
local midPoint = newDisplayEvent.scrollHeight / 2;
newDisplayEvent.midPoint = midPoint;
 
-- Calculate the parabola focal point.
-- Equation of a parabola at vertex 0,0: x = y^2 / 4a
newDisplayEvent.fourA = (midPoint * midPoint) / newDisplayEvent.scrollWidth;
end
 
 
-------------------------------------------------------------------------------
-- Horizontal scroll functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Scrolls the passed display event horizontally left.
-- ****************************************************************************
local function ScrollLeft(displayEvent)
-- Local references for faster access.
local scaledScrollTime = displayEvent.scaledScrollTime;
local elapsedTime = displayEvent.elapsedTime;
 
-- Calculate the fade effect start time to be halfway through the animation.
local fadeStartTime = scaledScrollTime / 2;
 
-- Set the x position based on the elapsed time.
displayEvent.positionX = displayEvent.scrollWidth - math_floor(displayEvent.scrollWidth * (elapsedTime / scaledScrollTime));
 
 
-- Fade the text out once enough time has passed.
if (elapsedTime >= fadeStartTime) then
local alpha = 1 - ((elapsedTime - fadeStartTime) / (scaledScrollTime - fadeStartTime));
displayEvent.alpha = math_max(alpha, 0);
end
 
-- Return true to indicate that the animation is complete when enough time has passed.
if (elapsedTime >= scaledScrollTime) then return true; end
end
 
 
-- ****************************************************************************
-- Scrolls the passed display event horizontally right.
-- ****************************************************************************
local function ScrollRight(displayEvent)
-- Local references for faster access.
local scaledScrollTime = displayEvent.scaledScrollTime;
local elapsedTime = displayEvent.elapsedTime;
 
-- Calculate the fade effect start time to be halfway through the animation.
local fadeStartTime = scaledScrollTime / 2;
 
-- Set the x position based on the elapsed time.
displayEvent.positionX = math_floor(displayEvent.scrollWidth * (elapsedTime / scaledScrollTime));
 
-- Fade the text out once enough time has passed.
if (elapsedTime >= fadeStartTime) then
local alpha = 1 - ((elapsedTime - fadeStartTime) / (scaledScrollTime - fadeStartTime));
displayEvent.alpha = math_max(alpha, 0);
end
 
-- Return true to indicate that the animation is complete when enough time has passed.
if (elapsedTime >= scaledScrollTime) then return true; end
end
 
 
-- ****************************************************************************
-- Reposition the passed display events to prevent overlaps.
-- ****************************************************************************
local function RepositionHorizontalRight(currentDisplayEvent, activeDisplayEvents, startEvent)
-- Scale the per pixel time based on the animation speed.
local perPixelTime = MOVEMENT_SPEED * (1/currentDisplayEvent.animationSpeed);
 
-- Get the top and bottom points of the current display events.
local topCurrent = currentDisplayEvent.positionY + currentDisplayEvent.fontSize;
local bottomCurrent = currentDisplayEvent.positionY;
 
local prevDisplayEvent, topPrev, bottomPrev;
local leftTimePrev, rightTimeCurrent;
for x = startEvent, 1, -1 do
-- Get the top and bottom points of the previous display event.
prevDisplayEvent = activeDisplayEvents[x];
topPrev = prevDisplayEvent.positionY + prevDisplayEvent.fontSize;
bottomPrev = prevDisplayEvent.positionY;
 
-- Check for a vertical collision.
if ((topCurrent >= bottomPrev and topCurrent <= topPrev) or (bottomCurrent >= bottomPrev and bottomCurrent <= topPrev)) then
-- Calculate the elapsed time for the left and right points.
leftTimePrev = prevDisplayEvent.elapsedTime + (prevDisplayEvent.offsetLeft or 0) * perPixelTime;
rightTimeCurrent = currentDisplayEvent.elapsedTime + ((currentDisplayEvent.offsetRight or 0) + MIN_HORIZONTAL_SPACING) * perPixelTime;
 
-- Adjust the elapsed time of the previous display event if the current one is colliding with it.
if (leftTimePrev <= rightTimeCurrent) then
prevDisplayEvent.elapsedTime = rightTimeCurrent + math_abs((prevDisplayEvent.offsetLeft or 0) * perPixelTime);
 
-- Move events that are now colliding as a result of moving this one.
RepositionHorizontalRight(prevDisplayEvent, activeDisplayEvents, x - 1);
end -- Horizontal collision.
end -- Vertical collision.
end
end
 
 
-- ****************************************************************************
-- Reposition the passed display events to prevent overlaps.
-- ****************************************************************************
local function RepositionHorizontalLeft(currentDisplayEvent, activeDisplayEvents, startEvent)
-- Scale the per pixel time based on the animation speed.
local perPixelTime = MOVEMENT_SPEED * (1/currentDisplayEvent.animationSpeed);
 
-- Get the top and bottom points of the current display events.
local topCurrent = currentDisplayEvent.positionY + currentDisplayEvent.fontSize;
local bottomCurrent = currentDisplayEvent.positionY;
 
local prevDisplayEvent, topPrev, bottomPrev;
local rightTimePrev, leftTimeCurrent;
for x = startEvent, 1, -1 do
-- Get the top and bottom points of the previous display event.
prevDisplayEvent = activeDisplayEvents[x];
topPrev = prevDisplayEvent.positionY + prevDisplayEvent.fontSize;
bottomPrev = prevDisplayEvent.positionY;
 
-- Check for a vertical collision.
if ((topCurrent >= bottomPrev and topCurrent <= topPrev) or (bottomCurrent >= bottomPrev and bottomCurrent <= topPrev)) then
-- Calculate the elapsed time for the left and right points.
rightTimePrev = prevDisplayEvent.elapsedTime - ((prevDisplayEvent.offsetRight or 0) + MIN_HORIZONTAL_SPACING) * perPixelTime;
leftTimeCurrent = currentDisplayEvent.elapsedTime - (currentDisplayEvent.offsetLeft or 0) * perPixelTime;
 
-- Adjust the elapsed time of the previous display event if the current one is colliding with it.
if (rightTimePrev <= leftTimeCurrent) then
prevDisplayEvent.elapsedTime = leftTimeCurrent + ((prevDisplayEvent.offsetRight or 0) + MIN_HORIZONTAL_SPACING) * perPixelTime;
 
-- Move events that are now colliding as a result of moving this one.
RepositionHorizontalLeft(prevDisplayEvent, activeDisplayEvents, x - 1);
end -- Horizontal collision.
end -- Vertical collision.
end
end
 
 
-- ****************************************************************************
-- Initialize the passed display event and reposition the ones that are
-- currently scrolling in the scroll area to prevent overlaps.
-- ****************************************************************************
local function InitHorizontal(newDisplayEvent, activeDisplayEvents, direction, behavior)
-- Calculate how long the animation should take based on the width of the scroll area
-- and scaled by the animation speed.
newDisplayEvent.scaledScrollTime = newDisplayEvent.scrollWidth * MOVEMENT_SPEED * (1/newDisplayEvent.animationSpeed);
 
-- Modify the direction and anchor if the direction is alternating.
local anchorPoint = newDisplayEvent.anchorPoint;
if (direction ~= "Left" and direction ~= "Right") then
-- Select direction and anchor point based on the last event.
direction = (lastHorizontalDirection[activeDisplayEvents] == "Left") and "Right" or "Left";
lastHorizontalDirection[activeDisplayEvents] = direction;
anchorPoint = (direction == "Left") and "BOTTOMRIGHT" or "BOTTOMLEFT";
newDisplayEvent.anchorPoint = anchorPoint;
 
-- Start at the scroll area's mid point.
newDisplayEvent.elapsedTime = newDisplayEvent.scaledScrollTime / 2;
end
 
-- Calculate the left and right offsets from the anchor point.
local fontStringWidth = newDisplayEvent.fontString:GetStringWidth();
if (anchorPoint == "BOTTOMLEFT") then
newDisplayEvent.offsetLeft = 0;
newDisplayEvent.offsetRight = fontStringWidth;
elseif (anchorPoint == "BOTTOM") then
local halfWidth = fontStringWidth / 2;
newDisplayEvent.offsetLeft = -halfWidth;
newDisplayEvent.offsetRight = halfWidth;
elseif (anchorPoint == "BOTTOMRIGHT") then
newDisplayEvent.offsetLeft = -fontStringWidth;
newDisplayEvent.offsetRight = 0;
end
 
-- Set the initial alpha of the new display event to fully visible.
newDisplayEvent.alpha = 1;
 
 
-- Check if the text is growing down.
local positionY;
if (behavior == "GrowDown") then
-- Calculate the y position based on the last event.
positionY = lastHorizontalPositionY[activeDisplayEvents] or newDisplayEvent.scrollHeight;
positionY = positionY - newDisplayEvent.fontSize - MIN_VERTICAL_SPACING;
if (positionY < 0) then positionY = newDisplayEvent.scrollHeight; end
 
-- Text is growing up.
else
-- Calculate the y position based on the last event.
positionY = lastHorizontalPositionY[activeDisplayEvents] or 0;
positionY = positionY + newDisplayEvent.fontSize + MIN_VERTICAL_SPACING;
if (positionY > newDisplayEvent.scrollHeight) then positionY = 0; end
end
 
-- Set the y position to the calculated value and save it for the next event.
newDisplayEvent.positionY = positionY;
lastHorizontalPositionY[activeDisplayEvents] = positionY;
 
-- Get the number of display events that are currently scrolling for this style.
local numActiveAnimations = #activeDisplayEvents;
 
-- Scroll text right.
if (direction == "Right") then
-- Choose the correct animation function.
newDisplayEvent.animationHandler = ScrollRight;
 
-- Exit if there is no need to check for collisions.
if (numActiveAnimations == 0) then return; end
 
-- Move events that are colliding.
RepositionHorizontalRight(newDisplayEvent, activeDisplayEvents, numActiveAnimations);
 
-- Scroll text left.
else
-- Choose the correct animation function.
newDisplayEvent.animationHandler = ScrollLeft;
 
-- Exit if there is no need to check for collisions.
if (numActiveAnimations == 0) then return; end
 
-- Move events that are colliding.
RepositionHorizontalLeft(newDisplayEvent, activeDisplayEvents, numActiveAnimations);
end
end
 
 
-------------------------------------------------------------------------------
-- Static scroll functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Animates the passed display event using the static style.
-- ****************************************************************************
local function ScrollStatic(displayEvent)
-- Local references for faster access.
local displayTime = displayEvent.displayTime;
local fadeOutTime = displayEvent.fadeOutTime;
local elapsedTime = displayEvent.elapsedTime;
 
-- Leave the text displayed.
if (elapsedTime <= displayTime) then
return false;
 
-- Fade out.
elseif (elapsedTime <= displayTime + fadeOutTime) then
displayEvent.alpha = 1 - ((elapsedTime - displayTime) / fadeOutTime);
return false;
end
 
-- Return true to indicate the animation is complete.
return true;
end
 
 
-- ****************************************************************************
-- Initialize the passed display event and reposition the ones that are
-- currently scrolling in the scroll area to prevent overlaps.
-- ****************************************************************************
local function InitStatic(newDisplayEvent, activeDisplayEvents, direction, behavior)
-- Set the animation function.
newDisplayEvent.animationHandler = ScrollStatic;
 
-- Set the new event's starting X position.
local anchorPoint = newDisplayEvent.anchorPoint;
if (anchorPoint == "BOTTOMLEFT") then
newDisplayEvent.positionX = 0;
elseif (anchorPoint == "BOTTOM") then
newDisplayEvent.positionX = math_ceil(newDisplayEvent.scrollWidth / 2);
elseif (anchorPoint == "BOTTOMRIGHT") then
newDisplayEvent.positionX = newDisplayEvent.scrollWidth;
end
 
-- Scale the display and fade out times based on the animation speed.
newDisplayEvent.displayTime = STATIC_DISPLAY_TIME * (1/newDisplayEvent.animationSpeed);
newDisplayEvent.fadeOutTime = STATIC_FADE_OUT_TIME * (1/newDisplayEvent.animationSpeed);
 
-- Set the initial alpha of the new display event to fully visible.
newDisplayEvent.alpha = 1;
 
-- Get the number of display events that are currently animating for this style.
local numActiveAnimations = #activeDisplayEvents;
local positionY;
 
-- Static display is growing downwards.
if (direction == "Down") then
positionY = newDisplayEvent.scrollHeight;
 
-- Offset the new display event correctly if there are already animating events.
if (numActiveAnimations > 0) then
-- Set the next y position to after the last display event.
positionY = activeDisplayEvents[numActiveAnimations].positionY - newDisplayEvent.fontSize - MIN_VERTICAL_SPACING;
 
-- Wrap the y position if it is outside the scroll area's height.
if (positionY < 0) then positionY = newDisplayEvent.scrollHeight; end
end
 
-- Static display is growing upwards.
else
positionY = 0;
 
-- Offset the new display event correctly if there are already animating events.
if (numActiveAnimations > 0) then
-- Set the next y position to before the last display event.
positionY = activeDisplayEvents[numActiveAnimations].positionY + newDisplayEvent.fontSize + MIN_VERTICAL_SPACING;
 
-- Wrap the y position if it is outside the scroll area's height.
if (positionY > newDisplayEvent.scrollHeight) then positionY = 0; end
 
end
end
 
 
-- Check if there are already animating events.
if (numActiveAnimations > 0) then
-- Get the top and bottom points of the new display event.
local topNew = positionY + newDisplayEvent.fontSize;
local bottomNew = positionY;
 
-- Loop through all the old display events to force old animations that the new one overlaps to complete.
local oldDisplayEvent, topOld, bottomOld;
for x = 1, numActiveAnimations - 1 do
-- Get the top and bottom points of the old display event.
oldDisplayEvent = activeDisplayEvents[x];
bottomOld = oldDisplayEvent.positionY;
topOld = bottomOld + oldDisplayEvent.fontSize;
 
-- Force the old animation to complete if the new display event is overlapping it.
if ((topNew >= bottomOld and topNew <= topOld) or (bottomNew >= bottomOld and bottomNew <= topOld)) then
oldDisplayEvent.elapsedTime = (STATIC_DISPLAY_TIME + STATIC_FADE_OUT_TIME) * (1/oldDisplayEvent.animationSpeed);
end
end
end
 
-- Set the y position to the calculated value.
newDisplayEvent.positionY = positionY;
end
 
 
 
 
-------------------------------------------------------------------------------
-- Load.
-------------------------------------------------------------------------------
 
-- Register the default animation styles.
MikSBT.RegisterAnimationStyle("Straight", InitStraight, "Up;Down", nil);
MikSBT.RegisterAnimationStyle("Parabola", InitParabola, "Up;Down", "CurvedLeft;CurvedRight");
MikSBT.RegisterAnimationStyle("Horizontal", InitHorizontal, "Alternate;Left;Right", "GrowUp;GrowDown");
MikSBT.RegisterAnimationStyle("Static", InitStatic, "Up;Down", nil);
 
-- Register the default sticky animation styles.
MikSBT.RegisterStickyAnimationStyle("Pow", InitPow, "Up;Down", "Normal;Jiggle");
MikSBT.RegisterStickyAnimationStyle("Static", InitStatic, "Up;Down", nil);
\ No newline at end of file
MSBT5_13/MikScrollingBattleText/MSBTProfiles.lua New file
0,0 → 1,1489
-------------------------------------------------------------------------------
-- Title: Mik's Scrolling Battle Text Profiles
-- Author: Mik
-------------------------------------------------------------------------------
 
-- Create module and set its name.
local module = {};
local moduleName = "Profiles";
MikSBT[moduleName] = module;
 
 
-------------------------------------------------------------------------------
-- Private constants.
-------------------------------------------------------------------------------
 
local DEFAULT_PROFILE_NAME = "Default";
 
-- The .toc entries for saved variables.
local SAVED_VARS_NAME = "MSBTProfiles_SavedVars";
local SAVED_VARS_PER_CHAR_NAME = "MSBTProfiles_SavedVarsPerChar";
 
-- Localized pet name followed by a space.
local PET_SPACE = PET .. " ";
 
-- Spell IDs.
local SPELLID_COUNTER_ATTACK = 19306;
local SPELLID_EXECUTE = 5308;
local SPELLID_HAMMER_OF_WRATH = 24275;
local SPELLID_KILL_COMMAND = 34026;
local SPELLID_MONGOOSE_BITE = 1495;
local SPELLID_RAMPAGE = 29801;
local SPELLID_REVENGE = 6572;
local SPELLID_RIPOSTE = 14251;
local SPELLID_OVERPOWER = 7384;
local SPELLID_VICTORY_RUSH = 34428
 
-- Spell names.
local SPELL_BACKLASH = GetSpellInfo(34935);
local SPELL_BLACKOUT = GetSpellInfo(15268);
local SPELL_CLEARCASTING = GetSpellInfo(12536);
local SPELL_COUNTER_ATTACK = GetSpellInfo(SPELLID_COUNTER_ATTACK);
local SPELL_EXECUTE = GetSpellInfo(SPELLID_EXECUTE);
local SPELL_FROSTBITE = GetSpellInfo(11071);
local SPELL_HAMMER_OF_WRATH = GetSpellInfo(SPELLID_HAMMER_OF_WRATH);
local SPELL_IMPACT = GetSpellInfo(11103);
local SPELL_KILL_COMMAND = GetSpellInfo(SPELLID_KILL_COMMAND);
local SPELL_MONGOOSE_BITE = GetSpellInfo(SPELLID_MONGOOSE_BITE);
local SPELL_NIGHTFALL = GetSpellInfo(18094);
local SPELL_SHADOW_TRANCE = GetSpellInfo(17941);
local SPELL_RAMPAGE = GetSpellInfo(SPELLID_RAMPAGE);
local SPELL_REVENGE = GetSpellInfo(SPELLID_REVENGE);
local SPELL_RIPOSTE = GetSpellInfo(SPELLID_RIPOSTE);
local SPELL_OVERPOWER = GetSpellInfo(SPELLID_OVERPOWER);
local SPELL_VICTORY_RUSH = GetSpellInfo(SPELLID_VICTORY_RUSH);
local SPELL_DRAIN_LIFE = GetSpellInfo(689);
local SPELL_MANA_SPRING = GetSpellInfo(5677);
local SPELL_SHADOWMEND = GetSpellInfo(39373);
local SPELL_SIPHON_LIFE = GetSpellInfo(18265);
local SPELL_REFLECTIVE_SHIELD = GetSpellInfo(33201);
local SPELL_VAMPIRIC_EMBRACE = GetSpellInfo(15286);
local SPELL_VAMPIRIC_TOUCH = GetSpellInfo(34914);
local SPELL_VIPER_STING = GetSpellInfo(3034);
 
 
-------------------------------------------------------------------------------
-- Private variables.
-------------------------------------------------------------------------------
 
-- Meta table for the differential profile tables.
local differentialMap = {};
local differential_mt = { __index = function(t,k) return differentialMap[t][k] end };
local differentialCache = {};
 
-- Holds variables to be saved between sessions.
local savedVariables;
local savedVariablesPerChar;
 
-- Currently selected profile.
local currentProfile;
 
-- Path information for setting differential options.
local pathTable = {};
 
 
-------------------------------------------------------------------------------
-- Imports.
-------------------------------------------------------------------------------
 
-- Local references to certain MSBT modules for faster access.
local MSBTLocale = MikSBT.Locale;
 
-- Local references to certain functions for faster access.
local string_find = string.find;
local string_gsub = string.gsub;
local CopyTable = MikSBT.CopyTable;
local EraseTable = MikSBT.EraseTable;
local SplitString = MikSBT.SplitString;
local Print = MikSBT.Print;
 
 
-------------------------------------------------------------------------------
-- Master profile.
-------------------------------------------------------------------------------
 
local masterProfile = {
scrollAreas = {
Incoming = {
name = MSBTLocale.MSG_INCOMING,
offsetX = -140,
offsetY = -160,
animationStyle = "Parabola",
direction = "Down",
behavior = "CurvedLeft",
stickyBehavior = "Jiggle",
textAlignIndex = 3,
stickyTextAlignIndex = 3,
},
Outgoing = {
name = MSBTLocale.MSG_OUTGOING,
offsetX = 100,
offsetY = -160,
animationStyle = "Parabola",
direction = "Down",
behavior = "CurvedRight",
stickyBehavior = "Jiggle",
textAlignIndex = 1,
stickyTextAlignIndex = 1,
},
Notification = {
name = MSBTLocale.MSG_NOTIFICATION,
offsetX = -175,
offsetY = 120,
scrollHeight = 200,
scrollWidth = 350,
},
Static = {
name = MSBTLocale.MSG_STATIC,
offsetX = -20,
offsetY = -300,
scrollHeight = 125,
animationStyle = "Static",
direction = "Down",
normalFontName = "Yellowjacket",
normalFontSize = 20,
},
},
 
 
events = {
INCOMING_DAMAGE = {
colorG = 0,
colorB = 0,
message = "(%n) -%a",
scrollArea = "Incoming",
},
INCOMING_DAMAGE_CRIT = {
colorG = 0,
colorB = 0,
message = "(%n) -%a",
scrollArea = "Incoming",
isCrit = true,
},
INCOMING_MISS = {
colorR = 0,
colorG = 0,
message = MISS .. "!",
scrollArea = "Incoming",
},
INCOMING_DODGE = {
colorR = 0,
colorG = 0,
message = DODGE .. "!",
scrollArea = "Incoming",
},
INCOMING_PARRY = {
colorR = 0,
colorG = 0,
message = PARRY .. "!",
scrollArea = "Incoming",
},
INCOMING_BLOCK = {
colorR = 0,
colorG = 0,
message = BLOCK .. "!",
scrollArea = "Incoming",
},
INCOMING_ABSORB = {
colorB = 0,
message = ABSORB .. "!",
scrollArea = "Incoming",
},
INCOMING_IMMUNE = {
colorB = 0,
message = IMMUNE .. "!",
scrollArea = "Incoming",
},
INCOMING_SPELL_DAMAGE = {
colorG = 0,
colorB = 0,
message = "(%s) -%a",
scrollArea = "Incoming",
},
INCOMING_SPELL_DAMAGE_CRIT = {
colorG = 0,
colorB = 0,
message = "(%s) -%a",
scrollArea = "Incoming",
isCrit = true,
},
INCOMING_SPELL_DOT = {
colorG = 0,
colorB = 0,
message = "(%s) -%a",
scrollArea = "Incoming",
},
INCOMING_SPELL_MISS = {
colorR = 0,
colorG = 0,
message = "(%s) " .. MISS .. "!",
scrollArea = "Incoming",
},
INCOMING_SPELL_DODGE = {
colorR = 0,
colorG = 0,
message = "(%s) " .. DODGE .. "!",
scrollArea = "Incoming",
},
INCOMING_SPELL_PARRY = {
colorR = 0,
colorG = 0,
message = "(%s) " .. PARRY .. "!",
scrollArea = "Incoming",
},
INCOMING_SPELL_BLOCK = {
colorR = 0,
colorG = 0,
message = "(%s) " .. BLOCK .. "!",
scrollArea = "Incoming",
},
INCOMING_SPELL_RESIST = {
colorR = 0.5,
colorG = 0,
colorB = 0.5,
message = "(%s) " .. RESIST .. "!",
scrollArea = "Incoming",
},
INCOMING_SPELL_ABSORB = {
colorB = 0,
message = "(%s) " .. ABSORB .. "!",
scrollArea = "Incoming",
},
INCOMING_SPELL_IMMUNE = {
colorB = 0,
message = "(%s) " .. IMMUNE .. "!",
scrollArea = "Incoming",
},
INCOMING_SPELL_REFLECT = {
colorR = 0.5,
colorG = 0,
colorB = 0.5,
message = "(%s - %a) " .. REFLECT .. "!",
scrollArea = "Incoming",
},
INCOMING_SPELL_INTERRUPT = {
colorB = 0,
message = "(%s) " .. INTERRUPT .. "!",
scrollArea = "Incoming",
},
INCOMING_HEAL = {
colorR = 0,
colorB = 0,
message = "(%s - %n) +%a",
scrollArea = "Incoming",
},
INCOMING_HEAL_CRIT = {
colorR = 0,
colorB = 0,
message = "(%s - %n) +%a",
fontSize = 22,
scrollArea = "Incoming",
isCrit = true,
},
INCOMING_HOT = {
colorR = 0,
colorB = 0,
message = "(%s - %n) +%a",
scrollArea = "Incoming",
},
INCOMING_ENVIRONMENTAL = {
colorG = 0,
colorB = 0,
message = "-%a %e",
scrollArea = "Incoming",
},
 
 
OUTGOING_DAMAGE = {
message = "%a",
scrollArea = "Outgoing",
},
OUTGOING_DAMAGE_CRIT = {
message = "%a",
scrollArea = "Outgoing",
isCrit = true,
},
OUTGOING_MISS = {
message = MISS .. "!",
scrollArea = "Outgoing",
},
OUTGOING_DODGE = {
message = DODGE .. "!",
scrollArea = "Outgoing",
},
OUTGOING_PARRY = {
message = PARRY .. "!",
scrollArea = "Outgoing",
},
OUTGOING_BLOCK = {
message = BLOCK .. "!",
scrollArea = "Outgoing",
},
OUTGOING_ABSORB = {
colorB = 0,
message = ABSORB .. "!",
scrollArea = "Outgoing",
},
OUTGOING_IMMUNE = {
colorB = 0,
message = IMMUNE .. "!",
scrollArea = "Outgoing",
},
OUTGOING_EVADE = {
colorG = 0.5,
colorB = 0,
message = EVADE .. "!",
fontSize = 22,
scrollArea = "Outgoing",
},
OUTGOING_SPELL_DAMAGE = {
colorB = 0,
message = "%a (%s)",
scrollArea = "Outgoing",
},
OUTGOING_SPELL_DAMAGE_CRIT = {
colorB = 0,
message = "%a (%s)",
scrollArea = "Outgoing",
isCrit = true,
},
OUTGOING_SPELL_DOT = {
colorB = 0,
message = "%a (%s)",
scrollArea = "Outgoing",
},
OUTGOING_SPELL_MISS = {
message = MISS .. "! (%s)",
scrollArea = "Outgoing",
},
OUTGOING_SPELL_DODGE = {
message = DODGE .. "! (%s)",
scrollArea = "Outgoing",
},
OUTGOING_SPELL_PARRY = {
message = PARRY .. "! (%s)",
scrollArea = "Outgoing",
},
OUTGOING_SPELL_BLOCK = {
message = BLOCK .. "! (%s)",
scrollArea = "Outgoing",
},
OUTGOING_SPELL_RESIST = {
colorR = 0.5,
colorG = 0.5,
colorB = 0.698,
message = RESIST .. "! (%s)",
scrollArea = "Outgoing",
},
OUTGOING_SPELL_ABSORB = {
colorB = 0,
message = ABSORB .. "! (%s)",
scrollArea = "Outgoing",
},
OUTGOING_SPELL_IMMUNE = {
colorB = 0,
message = IMMUNE .. "! (%s)",
scrollArea = "Outgoing",
},
OUTGOING_SPELL_REFLECT = {
colorB = 0,
message = REFLECT .. "! (%s)",
scrollArea = "Outgoing",
},
OUTGOING_SPELL_INTERRUPT = {
colorB = 0,
message = INTERRUPT .. "! (%s)",
scrollArea = "Outgoing",
},
OUTGOING_SPELL_EVADE = {
colorG = 0.5,
colorB = 0,
message = EVADE .. "! (%s)",
fontSize = 22,
scrollArea = "Outgoing",
},
OUTGOING_HEAL = {
colorR = 0,
colorB = 0,
message = "+%a (%s - %n)",
scrollArea = "Outgoing",
},
OUTGOING_HEAL_CRIT = {
colorR = 0,
colorB = 0,
message = "+%a (%s - %n)",
fontSize = 22,
scrollArea = "Outgoing",
isCrit = true,
},
OUTGOING_HOT = {
colorR = 0,
colorB = 0,
message = "+%a (%s - %n)",
scrollArea = "Outgoing",
},
OUTGOING_DISPEL = {
colorB = 0.5,
message = MSBTLocale.MSG_DISPEL .. "! (%s)",
scrollArea = "Outgoing",
},
 
 
PET_INCOMING_DAMAGE = {
colorG = 0.41,
colorB = 0.41,
message = "(%n) " .. PET .. " -%a",
scrollArea = "Incoming",
},
PET_INCOMING_DAMAGE_CRIT = {
colorG = 0.41,
colorB = 0.41,
message = "(%n) " .. PET .. " -%a",
scrollArea = "Incoming",
isCrit = true,
},
PET_INCOMING_MISS = {
colorR = 0.57,
colorG = 0.58,
message = PET .. " " .. MISS .. "!",
scrollArea = "Incoming",
},
PET_INCOMING_DODGE = {
colorR = 0.57,
colorG = 0.58,
message = PET .. " " .. DODGE .. "!",
scrollArea = "Incoming",
},
PET_INCOMING_PARRY = {
colorR = 0.57,
colorG = 0.58,
message = PET .. " " .. PARRY .. "!",
scrollArea = "Incoming",
},
PET_INCOMING_BLOCK = {
colorR = 0.57,
colorG = 0.58,
message = PET .. " " .. BLOCK .. "!",
scrollArea = "Incoming",
},
PET_INCOMING_ABSORB = {
colorB = 0.57,
message = PET .. " " .. ABSORB .. "!",
scrollArea = "Incoming",
},
PET_INCOMING_IMMUNE = {
colorB = 0.57,
message = PET .. " " .. IMMUNE .. "!",
scrollArea = "Incoming",
},
PET_INCOMING_SPELL_DAMAGE = {
colorG = 0.41,
colorB = 0.41,
message = "(%s) " .. PET .. " -%a",
scrollArea = "Incoming",
},
PET_INCOMING_SPELL_DAMAGE_CRIT = {
colorG = 0.41,
colorB = 0.41,
message = "(%s) " .. PET .. " -%a",
scrollArea = "Incoming",
isCrit = true,
},
PET_INCOMING_SPELL_DOT = {
colorG = 0.41,
colorB = 0.41,
message = "(%s) " .. PET .. " -%a",
scrollArea = "Incoming",
},
PET_INCOMING_SPELL_MISS = {
colorR = 0.57,
colorG = 0.58,
message = "(%s) " .. PET .. " " .. MISS .. "!",
scrollArea = "Incoming",
},
PET_INCOMING_SPELL_DODGE = {
colorR = 0.57,
colorG = 0.58,
message = "(%s) " .. PET .. " " .. DODGE .. "!",
scrollArea = "Incoming",
},
PET_INCOMING_SPELL_PARRY = {
colorR = 0.57,
colorG = 0.58,
message = "(%s) " .. PET .. " " .. PARRY .. "!",
scrollArea = "Incoming",
},
PET_INCOMING_SPELL_BLOCK = {
colorR = 0.57,
colorG = 0.58,
message = "(%s) " .. PET .. " " .. BLOCK .. "!",
scrollArea = "Incoming",
},
PET_INCOMING_SPELL_RESIST = {
colorR = 0.94,
colorG = 0,
colorB = 0.94,
message = "(%s) " .. PET .. " " .. RESIST .. "!",
scrollArea = "Incoming",
},
PET_INCOMING_SPELL_ABSORB = {
colorB = 0.57,
message = "(%s) " .. PET .. " " .. ABSORB .. "!",
scrollArea = "Incoming",
},
PET_INCOMING_SPELL_IMMUNE = {
colorB = 0.57,
message = "(%s) " .. PET .. " " .. IMMUNE .. "!",
scrollArea = "Incoming",
},
PET_INCOMING_HEAL = {
colorR = 0.57,
colorB = 0.57,
message = "(%s - %n) " .. PET .. " +%a",
scrollArea = "Incoming",
},
PET_INCOMING_HEAL_CRIT = {
colorR = 0.57,
colorB = 0.57,
message = "(%s - %n) " .. PET .. " +%a",
scrollArea = "Incoming",
isCrit = true,
},
PET_INCOMING_HOT = {
colorR = 0.57,
colorB = 0.57,
message = "(%s - %n) " .. PET .. " +%a",
scrollArea = "Incoming",
},
 
 
PET_OUTGOING_DAMAGE = {
colorG = 0.5,
colorB = 0,
message = PET .. " %a",
scrollArea = "Outgoing",
},
PET_OUTGOING_DAMAGE_CRIT = {
colorG = 0.5,
colorB = 0,
message = PET .. " %a",
scrollArea = "Outgoing",
isCrit = true,
},
PET_OUTGOING_MISS = {
colorG = 0.5,
colorB = 0,
message = PET .. " " .. MISS,
scrollArea = "Outgoing",
},
PET_OUTGOING_DODGE = {
colorG = 0.5,
colorB = 0,
message = PET .. " " .. DODGE,
scrollArea = "Outgoing",
},
PET_OUTGOING_PARRY = {
colorG = 0.5,
colorB = 0,
message = PET .. " " .. PARRY,
scrollArea = "Outgoing",
},
PET_OUTGOING_BLOCK = {
colorG = 0.5,
colorB = 0,
message = PET .. " " .. BLOCK,
scrollArea = "Outgoing",
},
PET_OUTGOING_ABSORB = {
colorR = 0.5,
colorG = 0.5,
message = PET .. " " .. ABSORB,
scrollArea = "Outgoing",
},
PET_OUTGOING_IMMUNE = {
colorR = 0.5,
colorG = 0.5,
message = PET .. " " .. IMMUNE,
scrollArea = "Outgoing",
},
PET_OUTGOING_EVADE = {
colorG = 0.77,
colorB = 0.57,
message = PET .. " " .. EVADE,
fontSize = 22,
scrollArea = "Outgoing",
},
PET_OUTGOING_SPELL_DAMAGE = {
colorR = 0.33,
colorG = 0.33,
message = PET .. " %a (%s)",
scrollArea = "Outgoing",
},
PET_OUTGOING_SPELL_DAMAGE_CRIT = {
colorR = 0.33,
colorG = 0.33,
message = PET .. " %a (%s)",
scrollArea = "Outgoing",
isCrit = true,
},
PET_OUTGOING_SPELL_DOT = {
colorR = 0.33,
colorG = 0.33,
message = PET .. " %a (%s)",
scrollArea = "Outgoing",
},
PET_OUTGOING_SPELL_MISS = {
colorR = 0.33,
colorG = 0.33,
message = PET .. " " .. MISS .. "! (%s)",
scrollArea = "Outgoing",
},
PET_OUTGOING_SPELL_DODGE = {
colorR = 0.33,
colorG = 0.33,
message = PET .. " " .. DODGE .. "! (%s)",
scrollArea = "Outgoing",
},
PET_OUTGOING_SPELL_PARRY = {
colorR = 0.33,
colorG = 0.33,
message = PET .. " " .. PARRY .. "! (%s)",
scrollArea = "Outgoing",
},
PET_OUTGOING_SPELL_BLOCK = {
colorR = 0.33,
colorG = 0.33,
message = PET .. " " .. BLOCK .. "! (%s)",
scrollArea = "Outgoing",
},
PET_OUTGOING_SPELL_RESIST = {
colorR = 0.73,
colorG = 0.73,
colorB = 0.84,
message = PET .. " " .. RESIST .. "! (%s)",
scrollArea = "Outgoing",
},
PET_OUTGOING_SPELL_ABSORB = {
colorR = 0.5,
colorG = 0.5,
message = PET .. " " .. ABSORB .. "! (%s)",
scrollArea = "Outgoing",
},
PET_OUTGOING_SPELL_IMMUNE = {
colorR = 0.5,
colorG = 0.5,
message = PET .. " " .. IMMUNE .. "! (%s)",
scrollArea = "Outgoing",
},
PET_OUTGOING_SPELL_EVADE = {
colorG = 0.77,
colorB = 0.57,
message = PET .. " " .. EVADE .. "! (%s)",
scrollArea = "Outgoing",
},
PET_OUTGOING_DISPEL = {
colorB = 0.73,
message = PET .. " " .. MSBTLocale.MSG_DISPEL .. "! (%s)",
scrollArea = "Outgoing",
},
 
 
NOTIFICATION_DEBUFF = {
colorR = 0,
colorG = 0.5,
colorB = 0.5,
message = "[%sl]",
},
NOTIFICATION_BUFF = {
colorR = 0.698,
colorG = 0.698,
colorB = 0,
message = "[%sl]",
},
NOTIFICATION_ITEM_BUFF = {
colorR = 0.698,
colorG = 0.698,
colorB = 0.698,
message = "[%sl]",
},
NOTIFICATION_DEBUFF_FADE = {
colorR = 0,
colorG = 0.835,
colorB = 0.835,
message = "-[%sl]",
},
NOTIFICATION_BUFF_FADE = {
colorR = 0.918,
colorG = 0.918,
colorB = 0,
message = "-[%sl]",
},
NOTIFICATION_ITEM_BUFF_FADE = {
colorR = 0.831,
colorG = 0.831,
colorB = 0.831,
message = "-[%sl]",
},
NOTIFICATION_COMBAT_ENTER = {
message = "+" .. MSBTLocale.MSG_COMBAT,
},
NOTIFICATION_COMBAT_LEAVE = {
message = "-" .. MSBTLocale.MSG_COMBAT,
},
NOTIFICATION_POWER_GAIN = {
colorB = 0,
message = "+%a %p",
},
NOTIFICATION_POWER_LOSS = {
colorB = 0,
message = "-%a %p",
},
NOTIFICATION_CP_GAIN = {
colorG = 0.5,
colorB = 0,
message = "%a " .. MSBTLocale.MSG_CP,
},
NOTIFICATION_CP_FULL = {
colorG = 0.5,
colorB = 0,
message = MSBTLocale.MSG_CP_FULL .. "!",
alwaysSticky = true,
fontSize = 26,
},
NOTIFICATION_HONOR_GAIN = {
colorR = 0.5,
colorG = 0.5,
colorB = 0.698,
message = "+%a " .. HONOR,
},
NOTIFICATION_REP_GAIN = {
colorR = 0.5,
colorG = 0.5,
colorB = 0.698,
message = "+%a " .. REPUTATION .. " (%e)",
},
NOTIFICATION_REP_LOSS = {
colorR = 0.5,
colorG = 0.5,
colorB = 0.698,
message = "-%a " .. REPUTATION .. " (%e)",
},
NOTIFICATION_SKILL_GAIN = {
colorR = 0.333,
colorG = 0.333,
message = "%sl: %a",
},
NOTIFICATION_EXPERIENCE_GAIN = {
disabled = true,
colorR = 0.756,
colorG = 0.270,
colorB = 0.823,
message = "%a " .. XP,
alwaysSticky = true,
fontSize = 26,
},
NOTIFICATION_PC_KILLING_BLOW = {
colorR = 0.333,
colorG = 0.333,
message = MSBTLocale.MSG_KILLING_BLOW .. "! (%e)",
alwaysSticky = true,
fontSize = 26,
},
NOTIFICATION_NPC_KILLING_BLOW = {
disabled = true,
colorR = 0.333,
colorG = 0.333,
message = MSBTLocale.MSG_KILLING_BLOW .. "! (%e)",
alwaysSticky = true,
fontSize = 26,
},
NOTIFICATION_SOUL_SHARD_CREATED = {
colorR = 0.628,
colorG = 0,
colorB = 0.628,
message = "+%e",
alwaysSticky = true,
fontSize = 26,
},
NOTIFICATION_EXTRA_ATTACK = {
colorB = 0,
message = "%sl!",
alwaysSticky = true,
fontSize = 26,
},
NOTIFICATION_ENEMY_BUFF = {
colorB = 0.5,
message = "%n: [%sl]",
scrollArea = "Static",
},
NOTIFICATION_MONSTER_EMOTE = {
colorG = 0.5,
colorB = 0,
message = "%e",
scrollArea = "Static",
},
NOTIFICATION_MONEY = {
message = "+%e",
scrollArea = "Static",
},
NOTIFICATION_COOLDOWN = {
message = "%e " .. MSBTLocale.MSG_READY_NOW .. "!",
scrollArea = "Static",
fontSize = 22,
},
}, -- End events
 
 
triggers = {
MSBT_TRIGGER_BACKLASH = {
colorR = 0.709,
colorG = 0,
colorB = 0.709,
message = SPELL_BACKLASH .. "!",
alwaysSticky = true,
fontSize = 26,
classes = "WARLOCK",
mainEvents = "BuffApplication[amount=1;;effect=" .. SPELL_BACKLASH .. ";;unit=player]",
},
MSBT_TRIGGER_BLACKOUT = {
colorR = 0.709,
colorG = 0,
colorB = 0.709,
message = SPELL_BLACKOUT .. "!",
alwaysSticky = true,
fontSize = 26,
classes = "PRIEST",
mainEvents = "DebuffApplication[amount=1;;effect=" .. SPELL_BLACKOUT .. ";;unit=target]",
},
MSBT_TRIGGER_CLEARCASTING = {
colorB = 0,
message = SPELL_CLEARCASTING .. "!",
alwaysSticky = true,
fontSize = 26,
classes = "DRUID,MAGE,SHAMAN",
mainEvents = "BuffApplication[amount=1;;effect=" .. SPELL_CLEARCASTING .. ";;unit=player]",
},
MSBT_TRIGGER_COUNTER_ATTACK = {
colorB = 0,
message = SPELL_COUNTER_ATTACK .. "!",
alwaysSticky = true,
fontSize = 26,
classes = "HUNTER",
mainEvents = "Parry[direction=incoming]",
exceptions = "SkillUnavailable[effect=" .. SPELL_COUNTER_ATTACK .. "]",
iconSkill = SPELLID_COUNTER_ATTACK,
},
MSBT_TRIGGER_EXECUTE = {
colorB = 0,
message = SPELL_EXECUTE .. "!",
alwaysSticky = true,
fontSize = 26,
classes = "WARRIOR",
mainEvents = "Health[hostile=true;;threshold=20;;unit=target]",
exceptions = "SkillUnavailable[effect=" .. SPELL_EXECUTE .. "]",
iconSkill = SPELLID_EXECUTE,
},
MSBT_TRIGGER_FROSTBITE = {
colorR = 0,
colorG = 0.5,
message = SPELL_FROSTBITE .. "!",
alwaysSticky = true,
fontSize = 26,
classes = "MAGE",
mainEvents = "DebuffApplication[amount=1;;effect=" .. SPELL_FROSTBITE .. ";;unit=target]",
},
MSBT_TRIGGER_HAMMER_OF_WRATH = {
colorB = 0,
message = SPELL_HAMMER_OF_WRATH .. "!",
alwaysSticky = true,
fontSize = 26,
classes = "PALADIN",
mainEvents = "Health[hostile=true;;threshold=20;;unit=target]",
exceptions = "SkillUnavailable[effect=" .. SPELL_HAMMER_OF_WRATH .. "]",
iconSkill = SPELLID_HAMMER_OF_WRATH,
},
MSBT_TRIGGER_IMPACT = {
colorG = 0.25,
colorB = 0.25,
message = SPELL_IMPACT .. "!",
alwaysSticky = true,
fontSize = 26,
classes = "MAGE",
mainEvents = "DebuffApplication[amount=1;;effect=" .. SPELL_IMPACT .. ";;unit=target]",
},
MSBT_TRIGGER_KILL_COMMAND = {
colorB = 0,
message = SPELL_KILL_COMMAND .. "!",
alwaysSticky = true,
fontSize = 26,
classes = "HUNTER",
mainEvents = "Crit[direction=outgoing]",
exceptions = "SkillUnavailable[effect=" .. SPELL_KILL_COMMAND .. "]";
iconSkill = SPELLID_KILL_COMMAND,
},
MSBT_TRIGGER_LOW_HEALTH = {
colorG = 0.5,
colorB = 0.5,
message = MSBTLocale.MSG_TRIGGER_LOW_HEALTH .. "! (%1)",
alwaysSticky = true,
fontSize = 26,
soundFile = "LowHealth",
mainEvents = "Health[direction=declining;;threshold=40;;unit=player]",
exceptions = "RecentlyFired[duration=5]",
},
MSBT_TRIGGER_LOW_MANA = {
colorR = 0.5,
colorG = 0.5,
message = MSBTLocale.MSG_TRIGGER_LOW_MANA .. "! (%1)",
alwaysSticky = true,
fontSize = 26,
soundFile = "LowMana",
classes = "DRUID,HUNTER,MAGE,PALADIN,PRIEST,SHAMAN,WARLOCK",
mainEvents = "Mana[direction=declining;;threshold=35;;unit=player]",
exceptions = "RecentlyFired[duration=5]",
},
MSBT_TRIGGER_LOW_PET_HEALTH = {
colorG = 0.5,
colorB = 0.5,
message = MSBTLocale.MSG_TRIGGER_LOW_PET_HEALTH .. "! (%1)",
fontSize = 26,
classes = "HUNTER,MAGE,WARLOCK",
mainEvents = "Health[direction=declining;;threshold=40;;unit=pet]",
exceptions = "RecentlyFired[duration=5]",
},
MSBT_TRIGGER_MONGOOSE_BITE = {
colorB = 0,
message = SPELL_MONGOOSE_BITE .. "!",
alwaysSticky = true,
fontSize = 26,
classes = "HUNTER",
mainEvents = "Dodge[direction=incoming]",
exceptions = "SkillUnavailable[effect=" .. SPELL_MONGOOSE_BITE .. "]",
iconSkill = SPELLID_MONGOOSE_BITE,
},
MSBT_TRIGGER_NIGHTFALL = {
colorR = 0.709,
colorG = 0,
colorB = 0.709,
message = SPELL_NIGHTFALL .. "!",
alwaysSticky = true,
fontSize = 26,
classes = "WARLOCK",
mainEvents = "BuffApplication[amount=1;;effect=" .. SPELL_SHADOW_TRANCE .. ";;unit=player]",
},
MSBT_TRIGGER_RAMPAGE = {
colorG = 0.25,
colorB = 0.25,
message = SPELL_RAMPAGE .. "!",
alwaysSticky = true,
fontSize = 26,
classes = "WARRIOR",
mainEvents = "Crit[direction=outgoing]",
exceptions = "SkillUnavailable[effect=" .. SPELL_RAMPAGE .. "]&&BuffActive[effect=" .. SPELL_RAMPAGE .. "]&&InsufficientPower[amount=20]",
iconSkill = SPELLID_RAMPAGE,
},
MSBT_TRIGGER_REVENGE = {
colorB = 0,
message = SPELL_REVENGE .. "!",
alwaysSticky = true,
fontSize = 26,
classes = "WARRIOR",
mainEvents = "Block[direction=incoming]&&Dodge[direction=incoming]&&Parry[direction=incoming]",
exceptions = "WarriorStance[reversed=true;;stance=2]&&SkillUnavailable[effect=" .. SPELL_REVENGE .. "]&&RecentlyFired[duration=2]",
iconSkill = SPELLID_REVENGE,
},
MSBT_TRIGGER_RIPOSTE = {
colorB = 0,
message = SPELL_RIPOSTE .. "!",
alwaysSticky = true,
fontSize = 26,
classes = "ROGUE",
mainEvents = "Parry[direction=incoming]",
exceptions = "SkillUnavailable[effect=" .. SPELL_RIPOSTE .. "]",
iconSkill = SPELLID_RIPOSTE,
},
MSBT_TRIGGER_OVERPOWER = {
colorB = 0,
message = SPELL_OVERPOWER .. "!",
alwaysSticky = true,
fontSize = 26,
classes = "WARRIOR",
mainEvents = "Dodge[direction=outgoing]",
exceptions = "SkillUnavailable[effect=" .. SPELL_OVERPOWER .. "]",
iconSkill = SPELLID_OVERPOWER,
},
MSBT_TRIGGER_VICTORY_RUSH = {
colorG = 0.25,
colorB = 0.25,
message = SPELL_VICTORY_RUSH .. "!",
alwaysSticky = true,
fontSize = 26,
classes = "WARRIOR",
mainEvents = "KillingBlow[]",
exceptions = "SkillUnavailable[effect=" .. SPELL_VICTORY_RUSH .. "]&&TrivialTarget[]",
iconSkill = SPELLID_VICTORY_RUSH,
},
MSBT_TRIGGER_VIPER_STING = {
colorR = 0,
colorG = 0,
message = SPELL_VIPER_STING .. "!",
alwaysSticky = true,
fontSize = 26,
classes = "DRUID,HUNTER,MAGE,PALADIN,PRIEST,SHAMAN,WARLOCK",
mainEvents = "DebuffApplication[amount=1;;effect=" .. SPELL_VIPER_STING .. ";;unit=player]",
},
}, -- End triggers
 
 
-- Master font settings.
normalFontName = "Default",
normalOutlineIndex = 2,
normalFontSize = 18,
normalFontAlpha = 85,
critFontName = "Default",
critOutlineIndex = 2,
critFontSize = 26,
critFontAlpha = 85,
 
 
-- Animation speed.
animationSpeed = 100,
 
 
-- Partial effect settings.
crushing = { colorR = 0.5, colorG = 0, colorB = 0, trailer = CRUSHING_TRAILER },
glancing = { colorR = 1, colorG = 0, colorB = 0, trailer = GLANCING_TRAILER },
absorb = { colorR = 1, colorG = 1, colorB = 0, trailer = ABSORB_TRAILER },
block = { colorR = 0.5, colorG = 0, colorB = 1, trailer = BLOCK_TRAILER },
resist = { colorR = 0.5, colorG = 0, colorB = 0.5, trailer = RESIST_TRAILER },
overheal = { colorR = 0, colorG = 0.705, colorB = 0.5, trailer = " <%d>" },
 
 
-- Damage color settings.
physical = { colorR = 1, colorG = 1, colorB = 1 },
holy = { colorR = 1, colorG = 1, colorB = 0.627 },
fire = { colorR = 1, colorG = 0.5, colorB = 0.5 },
nature = { colorR = 0.5, colorG = 1, colorB = 0.5 },
frost = { colorR = 0.5, colorG = 0.5, colorB = 1 },
shadow = { colorR = 0.628, colorG = 0, colorB = 0.628 },
arcane = { colorR = 1, colorG = 0.725, colorB = 1 },
 
 
-- Throttle settings.
dotThrottleDuration = 3,
hotThrottleDuration = 3,
powerThrottleDuration = 0,
throttleList = {
[SPELL_DRAIN_LIFE] = 3,
[SPELL_MANA_SPRING] = 5,
[SPELL_SHADOWMEND] = 5,
[SPELL_SIPHON_LIFE] = 3,
[SPELL_REFLECTIVE_SHIELD] = 5,
[SPELL_VAMPIRIC_EMBRACE] = 5,
[SPELL_VAMPIRIC_TOUCH] = 5,
},
 
 
-- Spam control settings.
mergeExclusions = {},
abilitySubstitutions = {},
abilitySuppressions = {},
damageThreshold = 0,
healThreshold = 0,
powerThreshold = 0,
 
-- Cooldown settings.
cooldownExclusions = {},
cooldownThreshold = 5,
};
 
 
-------------------------------------------------------------------------------
-- Utility functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Recursively removes empty tables and their differential map entries.
-- ****************************************************************************
local function RemoveEmptyDifferentials(currentTable)
-- Find nested tables in the current table.
for fieldName, fieldValue in pairs(currentTable) do
if (type(fieldValue) == "table") then
-- Recursively clear empty tables in the nested table.
RemoveEmptyDifferentials(fieldValue);
 
-- Remove the table from the differential map and current table if it's
-- empty.
if (not next(fieldValue)) then
differentialMap[fieldValue] = nil;
differentialCache[#differentialCache+1] = fieldValue;
currentTable[fieldName] = nil;
end
end
end
end
 
 
-- ****************************************************************************
-- Recursively associates the tables in the passed saved table to corresponding
-- entries in the passed master table.
-- ****************************************************************************
local function AssociateDifferentialTables(savedTable, masterTable)
-- Associate the saved table with the corresponding master entry.
differentialMap[savedTable] = masterTable;
setmetatable(savedTable, differential_mt);
 
-- Look for nested tables that have a corresponding master entry.
for fieldName, fieldValue in pairs(savedTable) do
if (type(fieldValue) == "table" and type(masterTable[fieldName]) == "table") then
-- Recursively call the function to associate nested tables.
AssociateDifferentialTables(fieldValue, masterTable[fieldName]);
end
end
end
 
 
-- ****************************************************************************
-- Set the passed option to the current profile while handling differential
-- profile mechanics.
-- ****************************************************************************
local function SetOption(optionPath, optionName, optionValue, optionDefault)
-- Clear the path table.
EraseTable(pathTable);
 
-- Split the passed option path into the path table.
if (optionPath) then SplitString(optionPath, "%.", pathTable); end
 
-- Attempt to go to the option path in the master profile.
local masterOption = masterProfile;
for _, fieldName in ipairs(pathTable) do
masterOption = masterOption[fieldName];
if (not masterOption) then break; end
end
 
-- Get the option name from the master profile.
masterOption = masterOption and masterOption[optionName];
 
-- Check if the option being set needs to be overridden.
local needsOverride = false;
if (optionValue ~= masterOption) then needsOverride = true; end
 
-- Treat a nil master option the same as false.
if ((optionValue == false or optionValue == optionDefault) and not masterOption) then
needsOverride = false;
end
 
-- Make the option value false if the option being set is nil and the master option set.
if (optionValue == nil and masterOption) then optionValue = false; end
 
-- Start at the root of the current profile and master profile.
local currentTable = currentProfile;
local masterTable = masterProfile;
 
-- Override needed.
if (needsOverride and optionValue ~= nil) then
-- Loop through all of the fields in path table.
for _, fieldName in ipairs(pathTable) do
-- Check if the field doesn't exist in the current profile.
if (not rawget(currentTable, fieldName)) then
-- Create a table for the field and setup the associated inheritance table.
currentTable[fieldName] = table.remove(differentialCache) or {};
if (masterTable and masterTable[fieldName]) then
differentialMap[currentTable[fieldName]] = masterTable[fieldName];
setmetatable(currentTable[fieldName], differential_mt);
end
end
 
-- Move to the next field in the option path.
currentTable = currentTable[fieldName];
masterTable = masterTable and masterTable[fieldName];
end
 
-- Set the option's value.
currentTable[optionName] = optionValue;
 
-- Override NOT needed.
else
-- Attempt to go to the option path in the current profile.
for _, fieldName in ipairs(pathTable) do
currentTable = rawget(currentTable, fieldName);
if (not currentTable) then return; end
end
 
-- Clear the option from the path and remove any empty differential tables.
if (currentTable) then
currentTable[optionName] = nil;
RemoveEmptyDifferentials(currentProfile);
end
end
end
 
 
-- ****************************************************************************
-- Sets the game damage and healing options according to the current profile.
-- ****************************************************************************
local function UpdateGameOptions()
-- Turn the game damage and healing display on or off.
SetCVar("CombatDamage", currentProfile.gameDamageEnabled and 1 or 0)
SetCVar("CombatHealing", currentProfile.gameHealingEnabled and 1 or 0)
end
 
 
-- ****************************************************************************
-- Disable or enable blizzard's combat text.
-- ****************************************************************************
local function DisableBlizzardCombatText(isDisabled)
-- Check if the text should be disabled.
if (isDisabled) then
-- Turn off Blizzard's default combat text.
SetCVar("enableCombatText", 0);
SHOW_COMBAT_TEXT = "0";
if (CombatText_UpdateDisplayedMessages) then
CombatText_UpdateDisplayedMessages();
end
else
-- Turn on Blizzard's default combat text.
SetCVar("enableCombatText", 1);
SHOW_COMBAT_TEXT = "1";
if (not IsAddOnLoaded("Blizzard_CombatText")) then
UIParentLoadAddOn("Blizzard_CombatText");
end
if (CombatText_UpdateDisplayedMessages) then
CombatText_UpdateDisplayedMessages();
end
end
end
 
 
-- ****************************************************************************
-- Set the user disabled option
-- ****************************************************************************
local function SetOptionUserDisabled(isDisabled)
savedVariables.userDisabled = isDisabled or nil;
 
-- Check if the mod is being set to disabled.
if (isDisabled) then
-- Disable the cooldowns, triggers, event parser, and main modules.
MikSBT.Cooldowns.Disable();
MikSBT.Triggers.Disable();
MikSBT.Parser.Disable();
MikSBT.Main.Disable();
 
-- Turn on the game's display of outgoing damage.
SetCVar("CombatDamage", 1);
 
-- Turn on the game's display of outgoing heals.
SetCVar("CombatHealing", 1);
 
else
-- Enable the main, event parser, triggers, and cooldowns modules.
MikSBT.Main.Enable();
MikSBT.Parser.Enable();
MikSBT.Triggers.Enable();
if (not currentProfile.events.NOTIFICATION_COOLDOWN.disabled) then
MikSBT.Cooldowns.Enable();
end
 
-- Disable or enable game damage and healing based on the settings.
UpdateGameOptions();
end
 
-- Toggle the game's floating combat text depending on mod's disable state.
DisableBlizzardCombatText(not isDisabled);
end
 
 
-- ****************************************************************************
-- Returns whether or not the mod is disabled.
-- ****************************************************************************
local function IsModDisabled()
return savedVariables.userDisabled;
end
 
 
-------------------------------------------------------------------------------
-- Profile functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Updates profiles created with older versions.
-- ****************************************************************************
local function UpdateProfiles()
-- Loop through all the profiles.
for profileName, profile in pairs(savedVariables.profiles) do
-- Delete triggers if upgrading from a version prior to 5.1.
if (profile.creationVersion < 5.1) then
profile.triggers = nil;
profile.creationVersion = MikSBT.VERSION_NUMBER;
end
end
end
 
 
-- ****************************************************************************
-- Selects the passed profile.
-- ****************************************************************************
local function SelectProfile(profileName)
-- Make sure the profile exists.
if (savedVariables.profiles[profileName]) then
-- Set the current profile name for the character to the one being selected.
savedVariablesPerChar.currentProfileName = profileName;
 
-- Set the current profile pointer.
currentProfile = savedVariables.profiles[profileName];
module.currentProfile = currentProfile;
 
-- Clear the differential table map.
EraseTable(differentialMap);
 
-- Associate the current profile tables with the corresponding master profile entries.
AssociateDifferentialTables(currentProfile, masterProfile);
 
-- Disable or enable game damage and healing based on the settings.
UpdateGameOptions();
 
-- Update the scroll areas and triggers with the current profile settings.
MikSBT.Animations.UpdateScrollAreas();
MikSBT.Triggers.UpdateTriggers();
end
end
 
 
-- ****************************************************************************
-- Copies the passed profile to a new profile with the passed name.
-- ****************************************************************************
local function CopyProfile(srcProfileName, destProfileName)
-- Leave the function if the the destination profile name is invalid.
if (not destProfileName or destProfileName == "") then return; end
 
-- Make sure the source profile exists and the destination profile doesn't.
if (savedVariables.profiles[srcProfileName] and not savedVariables.profiles[destProfileName]) then
-- Copy the profile.
savedVariables.profiles[destProfileName] = CopyTable(savedVariables.profiles[srcProfileName]);
end
end
 
 
-- ****************************************************************************
-- Deletes the passed profile.
-- ****************************************************************************
local function DeleteProfile(profileName)
-- Ignore the delete if the passed profile is the default one.
if (profileName == DEFAULT_PROFILE_NAME) then return; end
 
-- Make sure the profile exists.
if (savedVariables.profiles[profileName]) then
-- Check if the profile being deleted is the current one.
if (profileName == savedVariablesPerChar.currentProfileName) then
-- Select the default profile.
SelectProfile(DEFAULT_PROFILE_NAME);
end
 
-- Delete the profile.
savedVariables.profiles[profileName] = nil;
end
end
 
 
-- ****************************************************************************
-- Resets the passed profile to its defaults.
-- ****************************************************************************
local function ResetProfile(profileName, showOutput)
-- Set the profile name to the current profile is one wasn't passed.
if (not profileName) then profileName = savedVariablesPerChar.currentProfileName; end
 
-- Make sure the profile exists.
if (savedVariables.profiles[profileName]) then
-- Reset the profile.
EraseTable(savedVariables.profiles[profileName]);
 
-- Reset the profile's creation version.
savedVariables.profiles[profileName].creationVersion = MikSBT.VERSION_NUMBER;
 
 
-- Check if it's the current profile being reset.
if (profileName == savedVariablesPerChar.currentProfileName) then
-- Reselect the profile to update everything.
SelectProfile(profileName);
end
 
-- Check if the output text is to be shown.
if (showOutput) then
-- Print the profile reset string.
Print(profileName .. " " .. MSBTLocale.MSG_PROFILE_RESET, 0, 1, 0);
end
end
end
 
 
-- ****************************************************************************
-- This function initializes the saved variables.
-- ****************************************************************************
local function InitSavedVariables()
-- Set the saved variables per character to the value specified in the .toc file.
savedVariablesPerChar = _G[SAVED_VARS_PER_CHAR_NAME];
 
-- Check if there are no saved variables per character.
if (not savedVariablesPerChar) then
-- Create a new table to hold the saved variables per character, and set the .toc entry to it.
savedVariablesPerChar = {};
_G[SAVED_VARS_PER_CHAR_NAME] = savedVariablesPerChar;
 
-- Set the current profile for the character to the default profile.
savedVariablesPerChar.currentProfileName = DEFAULT_PROFILE_NAME;
end
 
 
-- Set the saved variables to the value specified in the .toc file.
savedVariables = _G[SAVED_VARS_NAME];
 
-- Check if there are no saved variables.
if (not savedVariables) then
-- Create a new table to hold the saved variables, and set the .toc entry to it.
savedVariables = {};
_G[SAVED_VARS_NAME] = savedVariables;
 
-- Create the profiles table and default profile.
savedVariablesPerChar.currentProfileName = DEFAULT_PROFILE_NAME;
savedVariables.profiles = {};
savedVariables.profiles[DEFAULT_PROFILE_NAME] = {};
 
savedVariables.profiles[DEFAULT_PROFILE_NAME].creationVersion = MikSBT.VERSION_NUMBER;
 
-- There are saved variables.
else
-- Updates profiles created by older versions.
UpdateProfiles();
end
 
-- Select the current profile for the character if it exists, otherwise select the default profile.
if (savedVariables.profiles[savedVariablesPerChar.currentProfileName]) then
SelectProfile(savedVariablesPerChar.currentProfileName);
else
SelectProfile(DEFAULT_PROFILE_NAME);
end
 
-- Allow public access to saved variables.
module.savedVariables = savedVariables;
end
 
 
 
 
-------------------------------------------------------------------------------
-- Module interface.
-------------------------------------------------------------------------------
 
-- Protected Variables.
module.masterProfile = masterProfile;
 
-- Protected Functions.
module.InitSavedVariables = InitSavedVariables;
module.CopyProfile = CopyProfile;
module.DeleteProfile = DeleteProfile;
module.ResetProfile = ResetProfile;
module.SelectProfile = SelectProfile;
module.UpdateGameOptions = UpdateGameOptions;
module.SetOption = SetOption;
module.SetOptionUserDisabled = SetOptionUserDisabled;
module.IsModDisabled = IsModDisabled;
\ No newline at end of file
MSBT5_13/MikScrollingBattleText/MSBTMain.lua New file
0,0 → 1,1390
-------------------------------------------------------------------------------
-- Title: Mik's Scrolling Battle Text Main
-- Author: Mik
-------------------------------------------------------------------------------
 
-- Create module and set its name.
local module = {};
local moduleName = "Main";
MikSBT[moduleName] = module;
 
 
-------------------------------------------------------------------------------
-- Constants.
-------------------------------------------------------------------------------
 
-- How long to wait before showing events so that merges may happen.
local MERGE_DELAY_TIME = 0.3;
 
-- How long to wait between throttle window checking.
local THROTTLE_UPDATE_TIME = 0.5;
 
-- Amount of time to hold recent monster emotes in cache.
local EMOTE_HOLD_TIME = 1;
 
-- Damage types.
local DAMAGETYPE_PHYSICAL = 0x1;
local DAMAGETYPE_HOLY = 0x2;
local DAMAGETYPE_FIRE = 0x4;
local DAMAGETYPE_NATURE = 0x8;
local DAMAGETYPE_FROST = 0x10;
local DAMAGETYPE_SHADOW = 0x20;
local DAMAGETYPE_ARCANE = 0x40;
 
-- Spell names.
local SPELL_INNERVATE = GetSpellInfo(29166);
local SPELL_SPIRIT_TAP = GetSpellInfo(15270);
 
-- Money strings.
local GOLD = string.gsub(GOLD_AMOUNT, "%%d ", "");
local SILVER = string.gsub(SILVER_AMOUNT, "%%d ", "");
local COPPER = string.gsub(COPPER_AMOUNT, "%%d ", "");
 
 
-------------------------------------------------------------------------------
-- Private variables.
-------------------------------------------------------------------------------
 
-- Dynamically created frames for receiving events.
local eventFrame;
local throttleFrame;
 
-- Pool of dynamically created combat events that are reused.
local combatEventCache = {};
 
-- Lookup tables.
local eventHandlers = {};
local damageTypeMap = {};
local damageColorProfileEntries = {};
local powerTypes = {};
 
-- Throttled ability info.
local throttledAbilities = {};
 
-- Holds unmerged and merged combat events.
local unmergedEvents = {};
local mergedEvents = {};
 
-- Used for timing between updates.
local lastMergeUpdate = 0;
local lastThrottleUpdate = 0;
 
-- Spam control info.
local isEnglish;
local lastPowerAmount = 65535;
local finisherShown;
local emoteCleanupTime = 0;
local recentEmotes = {};
 
-- Regen ability info.
local regenAbilities = {};
local activeRegenAbility;
local currentBuffs = MikSBT.Parser.currentAuras.buffs;
 
 
 
-------------------------------------------------------------------------------
-- Imports.
-------------------------------------------------------------------------------
 
-- Local references to certain MSBT modules for faster access.
local MSBTLocale = MikSBT.Locale;
local MSBTAnimations = MikSBT.Animations;
local MSBTParser = MikSBT.Parser;
local MSBTTriggers = MikSBT.Triggers;
local MSBTProfiles = MikSBT.Profiles;
 
-- Local references to certain functions and variables for faster access.
local table_remove = table.remove;
local math_ceil = math.ceil;
local string_find = string.find;
local string_gsub = string.gsub;
local string_format = string.format;
local bit_bor = bit.bor;
local GetTime = GetTime;
local EraseTable = MikSBT.EraseTable;
local Print = MikSBT.Print;
local DisplayEvent = MSBTAnimations.DisplayEvent;
local IsScrollAreaActive = MSBTAnimations.IsScrollAreaActive;
local TestFlagsAll = MSBTParser.TestFlagsAll;
 
local triggerSuppressions = MSBTTriggers.triggerSuppressions;
 
 
-------------------------------------------------------------------------------
-- Utility functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Sets up a button to access MSBT's options from the Blizzard interface
-- options AddOns tab.
-- ****************************************************************************
local function SetupBlizzardOptions()
-- Create a container frame for the Blizzard options area.
local frame = CreateFrame("Frame");
frame.name = "MikScrollingBattleText";
 
-- Create an option button in the center of the frame to launch MSBT's options.
local button = CreateFrame("Button", nil, frame, "OptionsButtonTemplate");
button:SetPoint("CENTER");
button:SetText(MikSBT.COMMAND);
button:SetScript("OnClick",
function (this)
InterfaceOptionsFrameCancel_OnClick();
HideUIPanel(GameMenuFrame);
if (not IsAddOnLoaded("MSBTOptions")) then UIParentLoadAddOn("MSBTOptions"); end
if (IsAddOnLoaded("MSBTOptions")) then MSBTOptions.Main.ShowMainFrame(); end
end
);
 
-- Add the frame as a new category to Blizzard's interface options.
InterfaceOptions_AddCategory(frame);
end
 
 
-- ****************************************************************************
-- Returns an abbreviated form of the passed skill name.
-- ****************************************************************************
local function AbbreviateSkillName(skillName)
if (string_find(skillName, "[%s%-]")) then
skillName = string_gsub(skillName, "(%a)[%l%p]*[%s%-]*", "%1");
end
 
return skillName;
end
 
 
-- ****************************************************************************
-- Returns a formatted partial effects trailer using the passed parameters.
-- ****************************************************************************
local function FormatPartialEffects(absorbAmount, blockAmount, resistAmount, isGlancing, isCrushing)
-- Get a local reference to the current profile.
local currentProfile = MSBTProfiles.currentProfile;
 
local effectSettings, amount;
local partialEffectText = "";
 
-- Partial Absorb
if (absorbAmount) then
effectSettings = currentProfile.absorb;
amount = absorbAmount;
 
-- Partial Block
elseif (blockAmount) then
effectSettings = currentProfile.block;
amount = blockAmount;
 
-- Partial Resist
elseif (resistAmount) then
effectSettings = currentProfile.resist;
amount = resistAmount;
end
 
-- Set the partial effect text if there are settings for it, it's enabled, and it's valid.
local trailer = effectSettings and effectSettings.trailer;
if (trailer and not effectSettings.disabled) then
-- Substitute the amount into the trailer.
trailer = string_gsub(trailer, "%%d", amount);
 
-- Color the text if coloring isn't disabled.
if (not currentProfile.partialColoringDisabled) then
partialEffectText = string_format("|cFF%02x%02x%02x%s|r", math_ceil(effectSettings.colorR * 255), math_ceil(effectSettings.colorG * 255), math_ceil(effectSettings.colorB * 255), trailer);
else
partialEffectText = trailer;
end
end
 
 
-- Clear the effect settings and trailer.
effectSettings = nil;
trailer = nil;
 
-- Glancing hit
if (isGlancing) then
effectSettings = currentProfile.glancing;
 
-- Crushing blow
elseif (isCrushing) then
effectSettings = currentProfile.crushing;
end
 
-- Append the crushing/glancing text if there are settings for it, it's enabled, and it's valid.
trailer = effectSettings and effectSettings.trailer;
if (trailer and not effectSettings.disabled) then
-- Color the text if coloring isn't disabled.
if (not currentProfile.partialColoringDisabled) then
partialEffectText = partialEffectText .. string_format("|cFF%02x%02x%02x%s|r", math_ceil(effectSettings.colorR * 255), math_ceil(effectSettings.colorG * 255), math_ceil(effectSettings.colorB * 255), trailer);
else
partialEffectText = partialEffectText .. trailer;
end
end
 
return partialEffectText;
end
 
 
-- ****************************************************************************
-- Formats an event with the parameters.
-- ****************************************************************************
local function FormatEvent(message, amount, damageType, overhealAmount, powerType, name, effectName, partialEffects, mergeTrailer, hasTexture, ignorePhysical, filterCodes)
-- Get a local reference to the current profile.
local currentProfile = MSBTProfiles.currentProfile;
local checkParens;
 
-- Substitute amount.
if (amount and string_find(message, "%%a")) then
-- Get the hex color for the damage type if there is one and coloring is enabled.
local damageColorCode;
if (damageType and not currentProfile.damageColoringDisabled) then
-- Set the damage color code if the color data is present for the damage type.
local damageColor = currentProfile[damageColorProfileEntries[damageType]];
if (damageColor and not damageColor.disabled) then
damageColorCode = string_format("|cFF%02x%02x%02x", math_ceil(damageColor.colorR * 255), math_ceil(damageColor.colorG * 255), math_ceil(damageColor.colorB * 255));
end
 
-- Ignore physical damage coloring on outgoing events.
if (ignorePhysical and damageType == DAMAGETYPE_PHYSICAL) then damageColorCode = nil; end
end -- Damage type and damage coloring is enabled.
 
-- Check if there is overheal information and displaying it is enabled.
if (overhealAmount and not currentProfile.overheal.disabled) then
-- Deduct the overheal amount from the total amount healed.
amount = amount - overhealAmount;
 
-- Get the overheal amount and color it with the correct color if coloring is enabled.
local overhealColorCode;
if (not currentProfile.partialColoringDisabled) then
local overhealColor = currentProfile.overheal;
overhealColorCode = string_format("|cFF%02x%02x%02x", math_ceil(overhealColor.colorR * 255), math_ceil(overhealColor.colorG * 255), math_ceil(overhealColor.colorB * 255));
end
 
-- Color the overheal amount if there is a color code.
if (overhealColorCode) then
overhealAmount = overhealColorCode .. overhealAmount .. "|r";
end
 
-- Append the overheal amount to the actual amount healed.
amount = amount .. string_gsub(currentProfile.overheal.trailer, "%%d", overhealAmount);
end -- Overheal amount and overhealing display enabled.
 
-- Color the amount according to the damage type, if any.
if (damageColorCode) then amount = damageColorCode .. amount .. "|r"; end
 
-- Substitute all %a event codes with the amount.
message = string_gsub(message, "%%a", amount);
end -- Substitute amount.
 
 
-- Substitute power type.
if (powerType and string_find(message, "%%p")) then message = string_gsub(message, "%%p", powerTypes[powerType] or UNKNOWN); end
 
 
-- Substitute names.
if (name and string_find(message, "%%n")) then
if (filterCodes and currentProfile.hideNames) then
message = string_gsub(message, "%s?%-?%s?%%n", "");
checkParens = true;
else
message = string_gsub(message, "%%n", name);
end
end
 
 
-- Substitute effect names.
if (effectName and string_find(message, "%%e")) then message = string_gsub(message, "%%e", effectName); end
 
 
-- Substitute skill names.
if (effectName) then
if (string_find(message, "%%s")) then
-- Hide skill names if there is an icon for it and the option is set.
if (filterCodes and (hasTexture and not currentProfile.exclusiveSkillsDisabled or currentProfile.hideSkills)) then
message = string_gsub(message, "%s?%-?%s?%%sl?%s?%-?%s?", "");
checkParens = true;
else
-- Use the user defined substitution for the ability if there is one.
local isChanged;
if (currentProfile.abilitySubstitutions[effectName]) then
effectName = currentProfile.abilitySubstitutions[effectName];
isChanged = true;
end
 
-- Do long substitutions.
if (string_find(message, "%%sl")) then message = string_gsub(message, "%%sl", effectName); end
 
-- Abbreviate skill for English if it wasn't user substituted and abbreviation is enabled.
if (isEnglish and not isChanged and currentProfile.abbreviateAbilities) then
effectName = AbbreviateSkillName(effectName);
end
 
-- Do remaining substitutions.
message = string_gsub(message, "%%s", effectName);
end
end
end
 
 
-- Remove empty parenthesis left frame ignoring event codes.
if (checkParens) then message = string_gsub(message, "%(%)", ""); end
 
 
-- Substitute damage types.
if (damageType and string_find(message, "%%t")) then message = string_gsub(message, "%%t", damageTypeMap[damageType] or STRING_SCHOOL_UNKNOWN); end
 
 
-- Append partial effects if there are any.
if (partialEffects) then message = message .. partialEffects; end
 
 
-- Append the merge trailer if there is one.
if (mergeTrailer) then message = message .. mergeTrailer; end
 
-- Return the formatted message.
return message;
end
 
 
-- ****************************************************************************
-- Returns the event type prefix and affected unit name for events that
-- can be incoming or outgoing.
-- ****************************************************************************
local function GetInOutEventData(parserEvent)
local eventTypeString, affectedUnitName, ignorePhysical;
 
-- Get the information for whether the event is incoming or outgoing.
if (parserEvent.recipientUnit == "player") then
affectedUnitName = parserEvent.sourceName;
eventTypeString = "INCOMING";
elseif (parserEvent.sourceUnit == "player") then
affectedUnitName = parserEvent.recipientName;
eventTypeString = "OUTGOING";
ignorePhysical = true;
elseif (parserEvent.recipientUnit == "pet") then
affectedUnitName = parserEvent.sourceName;
eventTypeString = "PET_INCOMING";
elseif (parserEvent.sourceUnit == "pet") then
affectedUnitName = parserEvent.recipientName;
eventTypeString = "PET_OUTGOING";
end
 
return eventTypeString, affectedUnitName, ignorePhysical;
end
 
 
-- ****************************************************************************
-- Detect all power gains.
-- ****************************************************************************
local function DetectPowerGain(powerAmount)
-- Get the event settings.
local eventSettings = MSBTProfiles.currentProfile.events.NOTIFICATION_POWER_GAIN;
 
-- Don't do anything if the event is disabled.
if (eventSettings.disabled) then return; end
 
-- Display the power change if it is a gain.
if (powerAmount > lastPowerAmount) then
DisplayEvent(eventSettings, FormatEvent(eventSettings.message, powerAmount - lastPowerAmount, nil, nil, UnitPowerType("player")));
end
end
 
 
-- ****************************************************************************
-- Handle combo point changes.
-- ****************************************************************************
local function HandleComboPoints(numCP)
-- Get the correct event settings.
local eventSettings = MSBTProfiles.currentProfile.events.NOTIFICATION_CP_GAIN;
if (numCP == MAX_COMBO_POINTS) then
-- Prevent the full combo point event from showing more than once.
if (finisherShown) then return; end
eventSettings = MSBTProfiles.currentProfile.events.NOTIFICATION_CP_FULL;
finisherShown = true;
else
finisherShown = false;
end
 
-- Don't do anything if the event is disabled.
if (eventSettings.disabled) then return; end
 
-- Display the event.
DisplayEvent(eventSettings, FormatEvent(eventSettings.message, numCP));
end
 
 
-- ****************************************************************************
-- Handle monster emotes.
-- ****************************************************************************
local function HandleMonsterEmotes(emoteString)
-- Get the event settings.
local eventSettings = MSBTProfiles.currentProfile.events.NOTIFICATION_MONSTER_EMOTE;
 
-- Don't do anything if the event is disabled.
if (eventSettings.disabled) then return; end
 
-- Loop through all of the recent emotes and remove the old ones.
local now = GetTime();
for emote, cleanupTime in pairs(recentEmotes) do
if (now >= cleanupTime) then recentEmotes[emote] = nil; end
end
 
-- Don't do anything if the emote has already been shown within the specified time frame.
if (recentEmotes[emoteString]) then return; end
 
-- Display the event and add it to the recent emotes list.
DisplayEvent(eventSettings, FormatEvent(eventSettings.message, nil, nil, nil, nil, nil, emoteString));
recentEmotes[emoteString] = now + EMOTE_HOLD_TIME;
end
 
 
-- ****************************************************************************
-- Merges like combat events.
-- ****************************************************************************
local function MergeEvents(numEvents)
-- Holds an unmerged event and whether or not to merge it.
local unmergedEvent;
local doMerge = false;
 
-- Don't attempt to merge any more events than were available when the function was called since
-- more events may get added while the merge is taking place.
for i = 1, numEvents do
-- Get the unmerged event.
unmergedEvent = unmergedEvents[i];
 
-- Loop through all of the events in the merged events array.
for _, mergedEvent in ipairs(mergedEvents) do
-- Check if the event types match.
if (unmergedEvent.eventType == mergedEvent.eventType) then
-- Check if there is no skill name.
if (not unmergedEvent.effectName) then
-- Set the merge flag if the affected unit name is the same.
if ((unmergedEvent.name == mergedEvent.name) and unmergedEvent.name) then doMerge = true; end
 
-- The skill names match.
elseif (unmergedEvent.effectName == mergedEvent.effectName) then
-- Change the name to the multiple targets string if the names don't match.
if (unmergedEvent.name ~= mergedEvent.name) then mergedEvent.name = MSBTLocale.MSG_MULTIPLE_TARGETS; end
 
-- Set the merge flag.
doMerge = true;
end
end -- Event types match.
 
-- Check if the event should be merged.
if (doMerge) then
-- Clear partial effects.
mergedEvent.partialEffects = nil;
 
-- Set the event merged flag for the event being merged.
unmergedEvent.eventMerged = true;
 
-- Total the amount if there is one.
if (unmergedEvent.amount) then mergedEvent.amount = (mergedEvent.amount or 0) + unmergedEvent.amount; end
 
-- Total the overheal amount if there is one.
if (unmergedEvent.overhealAmount) then mergedEvent.overhealAmount = (mergedEvent.overhealAmount or 0) + unmergedEvent.overhealAmount; end
 
-- Increment the number of merged events.
mergedEvent.numMerged = mergedEvent.numMerged + 1;
 
-- Increment the number of crits is the event being merged is a crit. Clear the crit flag for the merged event if it isn't.
if (unmergedEvent.isCrit) then mergedEvent.numCrits = mergedEvent.numCrits + 1; else mergedEvent.isCrit = false; end
 
-- Break out of the merged events loop since the event has been merged.
break;
end -- Do Merge.
end -- Loop through merged events.
 
-- Add the event to the end of the merged events array if it wasn't merged.
if (not doMerge) then
unmergedEvent.numMerged = 0;
 
-- Set the number of crits depending on if the event is a crit or not.
if (unmergedEvent.isCrit) then unmergedEvent.numCrits = 1; else unmergedEvent.numCrits = 0; end
 
-- Add the event to the end of the merged events array.
mergedEvents[#mergedEvents+1] = unmergedEvent;
end
 
-- Reset the event merge flag.
doMerge = false;
end -- Loop through unmerged events.
 
 
-- Append merge trailer information to the merged events.
for _, mergedEvent in ipairs(mergedEvents) do
-- Check if there were any events merged.
if (mergedEvent.numMerged > 0) then
-- Create the crit trailer text if there were any crits.
local critTrailer = "";
if (mergedEvent.numCrits > 0) then
critTrailer = string_format(", %d %s", mergedEvent.numCrits, mergedEvent.numCrits == 1 and MSBTLocale.MSG_CRIT or MSBTLocale.MSG_CRITS);
end
 
-- Set the event's merge trailer field.
mergedEvent.mergeTrailer = string_format(" [%d %s%s]", mergedEvent.numMerged + 1, MSBTLocale.MSG_HITS, critTrailer);
end -- Events were merged.
end
 
 
-- Remove the processed events from unmerged events queue.
for i = 1, numEvents do
-- Recycle the unmerged event if it was merged.
if (unmergedEvents[1].eventMerged) then
EraseTable(unmergedEvents[1]);
combatEventCache[#combatEventCache+1] = unmergedEvents[1];
end
 
-- Remove the event from the unmerged events array.
table_remove(unmergedEvents, 1);
end
end
 
 
-------------------------------------------------------------------------------
-- Command handler functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Returns the current and remaining parameters from the passed string.
-- ****************************************************************************
local function GetNextParameter(paramString)
local remainingParams;
local currentParam = paramString;
 
-- Look for a space.
local index = string_find(paramString, " ");
if (index) then
-- Get the current and remaing parameters.
currentParam = string.sub(paramString, 1, index-1);
remainingParams = string.sub(paramString, index+1);
end
 
-- Return the current parameter and the remaining ones.
return currentParam, remainingParams;
end
 
 
-- ****************************************************************************
-- Called to handle commands.
-- ****************************************************************************
local function CommandHandler(params)
-- Get the parameter.
local currentParam, remainingParams;
currentParam, remainingParams = GetNextParameter(params);
 
-- Flag for whether or not to show usage info.
local showUsage = true;
 
-- Make sure there is a current parameter and lower case it.
if (currentParam) then currentParam = string.lower(currentParam); end
 
-- Look for the recognized parameters.
if (currentParam == "") then
-- Load the on demand options if they are not loaded.
if (not IsAddOnLoaded("MSBTOptions")) then UIParentLoadAddOn("MSBTOptions"); end
 
-- Show the options interface after verifying the on demand options actually loaded.
if (IsAddOnLoaded("MSBTOptions")) then MSBTOptions.Main.ShowMainFrame(); end
 
-- Don't show the usage info.
showUsage = false;
 
-- Reset.
elseif (currentParam == MSBTLocale.COMMAND_RESET) then
-- Reset the current profile.
MSBTProfiles.ResetProfile(nil, true);
 
-- Don't show the usage info.
showUsage = false;
 
-- Disable.
elseif (currentParam == MSBTLocale.COMMAND_DISABLE) then
-- Set the user disabled option.
MSBTProfiles.SetOptionUserDisabled(true);
 
-- Output an informative message.
Print(MSBTLocale.MSG_DISABLE, 1,1,1);
 
-- Don't show the usage info.
showUsage = false;
 
-- Enable.
elseif (currentParam == MSBTLocale.COMMAND_ENABLE) then
-- Unset the user disabled option.
MSBTProfiles.SetOptionUserDisabled(false);
 
-- Output an informative message.
Print(MSBTLocale.MSG_ENABLE, 1,1,1);
 
-- Don't show the usage info.
showUsage = false;
 
-- Version.
elseif (currentParam == MSBTLocale.COMMAND_SHOWVER) then
-- Output the current version number.
Print(MikSBT.VERSION_STRING, 1,1,1);
 
-- Don't show the usage info.
showUsage = false;
 
end
 
-- Check if the usage information should be shown.
if (showUsage) then
-- Loop through all of the entries in the command usage list.
for _, msg in ipairs(MSBTLocale.COMMAND_USAGE) do
Print(msg, 1, 1, 1);
end
end -- Show usage.
end
 
 
-------------------------------------------------------------------------------
-- Event handlers.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Handles damage parser events.
-- ****************************************************************************
local function DamageHandler(parserEvent, currentProfile)
-- Setup info for whether the event is incoming or outgoing.
local eventTypeString, affectedUnitName, ignorePhysical = GetInOutEventData(parserEvent);
 
-- Ignore the event if it doesn't pertain to the player or their pet.
if (not eventTypeString) then return; end
 
-- Ignore the event if the damage amount is under the damage threshold to be shown.
if (parserEvent.amount and parserEvent.amount < currentProfile.damageThreshold) then return; end
 
-- Append the spell prefix if there is a skill.
if (parserEvent.skillID) then eventTypeString = eventTypeString .. "_SPELL"; end
 
-- Append dot suffix if it's a dot.
eventTypeString = eventTypeString .. (parserEvent.isDoT and "_DOT" or "_DAMAGE");
 
return eventTypeString, true, parserEvent.skillName, affectedUnitName, ignorePhysical;
end
 
 
-- ****************************************************************************
-- Handles miss parser events.
-- ****************************************************************************
local function MissHandler(parserEvent, currentProfile)
-- Setup info for whether the event is incoming or outgoing.
local eventTypeString, affectedUnitName = GetInOutEventData(parserEvent);
 
-- Ignore the event if it doesn't pertain to the player or their pet.
if (not eventTypeString) then return; end
 
-- Append the spell prefix if there is a skill.
if (parserEvent.skillID) then eventTypeString = eventTypeString .. "_SPELL"; end
 
-- Append the miss type.
eventTypeString = eventTypeString .. "_" .. parserEvent.missType;
 
return eventTypeString, true, parserEvent.skillName, affectedUnitName;
end
 
 
-- ****************************************************************************
-- Handles heal parser events.
-- ****************************************************************************
local function HealHandler(parserEvent, currentProfile)
-- Setup info for whether the event is incoming or outgoing.
local eventTypeString, affectedUnitName = GetInOutEventData(parserEvent);
 
-- Ignore the event if it doesn't pertain to the player or their pet.
if (not eventTypeString) then return; end
 
-- Ignore the event if the heal amount is under the healing threshold to be shown.
if (parserEvent.amount and parserEvent.amount < currentProfile.healThreshold) then return; end
 
-- Append hot suffix if it's a hot.
eventTypeString = eventTypeString .. (parserEvent.isHoT and "_HOT" or "_HEAL");
 
return eventTypeString, true, parserEvent.skillName, affectedUnitName;
end
 
 
-- ****************************************************************************
-- Handles interrupt parser events.
-- ****************************************************************************
local function InterruptHandler(parserEvent, currentProfile)
-- Setup info for whether the event is incoming or outgoing.
local eventTypeString, affectedUnitName = GetInOutEventData(parserEvent);
 
-- Ignore the event if it doesn't pertain to the player or their pet.
if (not eventTypeString) then return; end
 
-- Append interrupt suffix.
eventTypeString = eventTypeString .. "_SPELL_INTERRUPT";
 
return eventTypeString, true, parserEvent.extraSkillName, affectedUnitName;
end
 
 
-- ****************************************************************************
-- Handles environmental parser events.
-- ****************************************************************************
local function EnvironmentalHandler(parserEvent, currentProfile)
-- Ignore the event if it isn't the player.
if (parserEvent.recipientUnit ~= "player") then return; end
 
return "INCOMING_ENVIRONMENTAL", nil, _G["STRING_ENVIRONMENTAL_DAMAGE_" .. parserEvent.hazardType];
end
 
 
-- ****************************************************************************
-- Handles aura parser events.
-- ****************************************************************************
local function AuraHandler(parserEvent, currentProfile)
local eventTypeString, affectedUnitName;
local effectName = parserEvent.skillName;
 
-- Aura is pertaining to the player.
if (parserEvent.recipientUnit == "player") then
-- Buff gain/fade.
if (parserEvent.auraType == "BUFF") then
-- Buff gain.
if (not parserEvent.isFade) then
-- Set the active regen ability if the buff being gained is on the regen abilities list.
if (regenAbilities[effectName] and not currentProfile.regenAbilitiesDisabled) then activeRegenAbility = effectName; end
 
-- Buff fade.
else
-- Clear the active regen ability if the fading buff is the active one.
if (effectName == activeRegenAbility) then activeRegenAbility = nil; end
end
end
 
-- Ignore the event if it's suppressed due to a trigger.
if (triggerSuppressions[effectName]) then return; end
 
-- Set notificaiton buff/debuff and append fade prefix if the aura is fading.
eventTypeString = "NOTIFICATION_" .. parserEvent.auraType;
if (parserEvent.isFade) then eventTypeString = eventTypeString .. "_FADE"; end
 
-- Aura is pertaining to another unit.
else
-- Ignore the event if it's suppressed due to a trigger.
if (triggerSuppressions[effectName]) then return; end
 
-- Ignore the event if it isn't for the current target.
if (not TestFlagsAll(parserEvent.recipientFlags, MSBTParser.TARGET_TARGET)) then return; end
 
-- Ignore the event if it's a friendly unit.
if (not UnitIsEnemy("player", "target")) then return; end
 
-- Ignore the event it isn't not a buff gain.
if (parserEvent.auraType ~= "BUFF" or parserEvent.isFade == true) then return; end
 
eventTypeString = "NOTIFICATION_ENEMY_BUFF";
affectedUnitName = parserEvent.recipientName;
end -- Player or enemy check.
 
return eventTypeString, nil, effectName, affectedUnitName;
end
 
 
-- ****************************************************************************
-- Handles enchant parser events.
-- ****************************************************************************
local function EnchantHandler(parserEvent, currentProfile)
-- Ignore the event if it isn't the player.
if (parserEvent.recipientUnit ~= "player") then return; end
 
-- Set the item buff event type and append fade suffix if the enchant is fading.
local eventTypeString = "NOTIFICATION_ITEM_BUFF";
if (parserEvent.isFade) then eventTypeString = eventTypeString .. "_FADE"; end
 
return eventTypeString, nil, parserEvent.skillName;
end
 
 
-- ****************************************************************************
-- Handles dispel parser events.
-- ****************************************************************************
local function DispelHandler(parserEvent, currentProfile)
-- Ignore the event if it isn't a buff.
if (parserEvent.auraType ~= "BUFF") then return; end
 
-- Get the correct dispel event.
local eventTypeString;
if (parserEvent.sourceUnit == "player") then
eventTypeString = "OUTGOING_DISPEL";
elseif (parserEvent.sourceUnit == "pet") then
eventTypeString = "PET_OUTGOING_DISPEL";
else
-- Ignore the event if it isn't from the player or their pet.
return;
end
 
return eventTypeString, nil, parserEvent.extraSkillName;
end
 
 
-- ****************************************************************************
-- Handles power parser events.
-- ****************************************************************************
local function PowerHandler(parserEvent, currentProfile)
-- Ignore the event if it isn't the player.
if (parserEvent.recipientUnit ~= "player") then return; end
 
-- Ignore the event if all power gains are being shown.
if (currentProfile.showAllPowerGains or currentBuffs[activeRegenAbility]) then return; end
 
-- Ignore the event if the power change is under the threshold to be shown.
if (parserEvent.amount and parserEvent.amount < currentProfile.powerThreshold) then return; end
 
-- Append gain or loss suffix.
local eventTypeString = "NOTIFICATION_POWER_" .. (parserEvent.isGain and "GAIN" or "LOSS");
 
return eventTypeString, true, parserEvent.skillName;
end
 
 
-- ****************************************************************************
-- Handles kill parser events.
-- ****************************************************************************
local function KillHandler(parserEvent, currentProfile)
-- Ignore the event if it isn't a kill from the player.
if (parserEvent.sourceUnit ~= "player") then return; end
 
-- Ignore the event if it is a player guardian (Hunter snakes, etc).
if (TestFlagsAll(parserEvent.recipientFlags, bit_bor(MSBTParser.UNITTYPE_GUARDIAN, MSBTParser.CONTROL_HUMAN))) then return; end
 
-- Figure out the event type depending on whether a player or the server
-- controlled the unit that was killed.
local eventTypeString = "NOTIFICATION_";
eventTypeString = eventTypeString .. (TestFlagsAll(parserEvent.recipientFlags, MSBTParser.CONTROL_SERVER) and "NPC" or "PC");
eventTypeString = eventTypeString .. "_KILLING_BLOW";
 
return eventTypeString, nil, parserEvent.recipientName;
end
 
 
-- ****************************************************************************
-- Handles honor parser events.
-- ****************************************************************************
local function HonorHandler(parserEvent, currentProfile)
-- Ignore the event if it isn't for the player.
if (parserEvent.recipientUnit ~= "player") then return; end
 
return "NOTIFICATION_HONOR_GAIN";
end
 
 
-- ****************************************************************************
-- Handles reputation parser events.
-- ****************************************************************************
local function ReputationHandler(parserEvent, currentProfile)
-- Ignore the event if it isn't for the player.
if (parserEvent.recipientUnit ~= "player") then return; end
 
-- Append loss or gain suffix.
local eventTypeString = "NOTIFICATION_REP_" .. (parserEvent.isLoss and "LOSS" or "GAIN");
return eventTypeString, nil, parserEvent.factionName;
end
 
 
-- ****************************************************************************
-- Handles proficiency parser events.
-- ****************************************************************************
local function ProficiencyHandler(parserEvent, currentProfile)
-- Ignore the event if it isn't for the player.
if (parserEvent.recipientUnit ~= "player") then return; end
 
return "NOTIFICATION_SKILL_GAIN", nil, parserEvent.skillName;
end
 
 
-- ****************************************************************************
-- Handles experience parser events.
-- ****************************************************************************
local function ExperienceHandler(parserEvent, currentProfile)
-- Ignore the event if it isn't for the player.
if (parserEvent.recipientUnit ~= "player") then return; end
 
return "NOTIFICATION_EXPERIENCE_GAIN";
end
 
 
-- ****************************************************************************
-- Handles extra attacks parser events.
-- ****************************************************************************
local function ExtraAttacksHandler(parserEvent, currentProfile)
-- Ignore the event if it isn't for the player.
if (parserEvent.sourceUnit ~= "player") then return; end
 
return "NOTIFICATION_EXTRA_ATTACK", nil, parserEvent.skillName;
end
 
 
-- ****************************************************************************
-- Handles loot parser events.
-- ****************************************************************************
local function LootHandler(parserEvent, currentProfile)
-- Ignore the event if it isn't for the player.
if (parserEvent.recipientUnit ~= "player") then return; end
 
-- Money gain.
if (parserEvent.isMoney) then
local moneyString = parserEvent.moneyString;
moneyString = string_gsub(moneyString, GOLD, "|cffffd700%1|r");
moneyString = string_gsub(moneyString, SILVER, "|cff808080%1|r");
moneyString = string_gsub(moneyString, COPPER, "|cffeda55f%1|r");
 
return "NOTIFICATION_MONEY", nil, moneyString;
end
 
-- Ignore the event if there is no item link.
local itemLink = parserEvent.itemLink
if (not itemLink) then return; end
-- Ignore the event if the item is not a soul shard.
local matchStart, _, itemID, itemName = string_find(itemLink, "item:(%d+):[%-%d:]+|h%[(.+)%]");
if (itemID ~= "6265") then return; end
 
return "NOTIFICATION_SOUL_SHARD_CREATED", nil, itemName;
end
 
 
-- ****************************************************************************
-- Parser events handler.
-- ****************************************************************************
local function ParserEventsHandler(parserEvent)
-- Get a local reference to the current profile.
local currentProfile = MSBTProfiles.currentProfile;
 
-- Information regarding how to display the event.
local eventTypeString, mergeEligible, effectName, affectedUnitName, ignorePhysical;
 
-- Local copy of the eventType for faster access.
local eventType = parserEvent.eventType;
 
-- Call the correct handler for the event type if there is one.
local handler = eventHandlers[eventType];
if (handler) then
eventTypeString, mergeEligible, effectName, affectedUnitName, ignorePhysical = handler(parserEvent, currentProfile);
end
 
-- Ignore the event if it is unrecognized.
if (not eventTypeString) then return; end
 
-- Ignore the event if there is a skill name and it's suppressed.
if (effectName and currentProfile.abilitySuppressions[effectName]) then return; end
 
-- Ignore the event if there is no profile data for it, it's disabled, or the scroll area it's using is not active.
local isCrit = parserEvent.isCrit;
local eventSettings = currentProfile.events[isCrit and eventTypeString .. "_CRIT" or eventTypeString];
if (not eventSettings or eventSettings.disabled or not IsScrollAreaActive(eventSettings.scrollArea)) then return; end
 
-- Get the formatted partial effects if it's a damage or environmental event.
local partialEffects;
if (eventType == "damage" or eventType == "environmental") then
partialEffects = FormatPartialEffects(parserEvent.absorbAmount, parserEvent.blockAmount, parserEvent.resistAmount, parserEvent.isGlancing, parserEvent.isCrushing);
end
 
 
-- Attempt to get the texture for the event if icons are not disabled.
local effectTexture;
if (not currentProfile.skillIconsDisabled) then
effectTexture = parserEvent.skillTexture;
if (not effectTexture and parserEvent.skillID) then _, _, effectTexture = GetSpellInfo(parserEvent.skillID); end
 
-- Override texture for dispels and interrupts.
if ((eventType == "dispel" or eventType == "interrupt") and parserEvent.extraSkillID) then
_, _, effectTexture = GetSpellInfo(parserEvent.extraSkillID);
end
end
 
-- Check if the event is eligible for merging.
if (mergeEligible and not currentProfile.mergeExclusions[effectName]) then
-- Acquire a recycled table from cache or create a new one if there aren't any available in cache.
local combatEvent = table_remove(combatEventCache) or {};
 
 
-- Setup the combat event.
combatEvent.eventType = eventTypeString;
combatEvent.isCrit = isCrit;
combatEvent.amount = parserEvent.amount;
combatEvent.effectName = effectName;
combatEvent.effectTexture = effectTexture;
combatEvent.name = affectedUnitName;
combatEvent.damageType = parserEvent.damageType;
combatEvent.ignorePhysical = ignorePhysical;
combatEvent.partialEffects = partialEffects;
combatEvent.overhealAmount = parserEvent.overhealAmount;
combatEvent.powerType = parserEvent.powerType;
 
 
-- Throttle events according to user settings.
if (effectName) then
-- Get the duration the ability should be throttled for, if any.
local throttleDuration = currentProfile.throttleList[effectName];
 
-- Set throttle duration for power changes or dots/hots if there isn't a specific one set for the ability.
if (not throttleDuration) then
-- Use the dot throttle duration.
if (parserEvent.isDoT and currentProfile.dotThrottleDuration > 0) then
throttleDuration = currentProfile.dotThrottleDuration;
 
-- Use the hot throttle duration.
elseif (parserEvent.isHoT and currentProfile.hotThrottleDuration > 0) then
throttleDuration = currentProfile.hotThrottleDuration;
 
-- Use the power change throttle duration.
elseif (parserEvent.powerType and currentProfile.powerThrottleDuration > 0) then
throttleDuration = currentProfile.powerThrottleDuration;
end
end
 
-- Check if there is a throttle duration for the ability.
if (throttleDuration and throttleDuration > 0) then
-- Get throttle info for the ability. Create it if it hasn't already been.
local throttledAbility = throttledAbilities[effectName];
if (not throttledAbility) then
throttledAbility = {};
throttledAbility.throttleWindow = 0;
throttledAbility.lastEventTime = 0;
throttledAbilities[effectName] = throttledAbility;
end
 
-- Throttle the event and exit if the throttle window for the ability hasn't elapsed.
local now = GetTime();
if (throttledAbility.throttleWindow > 0) then
throttledAbility.lastEventTime = now;
throttledAbility[#throttledAbility+1] = combatEvent;
return;
 
-- The throttle window for the ability has elapsed.
else
-- Set the throttle window for the ability to its throttle duration.
throttledAbility.throttleWindow = throttleDuration;
 
-- Check if the throttle frame is not visible and make it visible so the OnUpdate events start firing.
-- This is done to keep the number of OnUpdate events down to a minimum for better performance.
if (not throttleFrame:IsVisible()) then throttleFrame:Show(); end
 
-- Throttle the event and exit if it has been seen within the throttle duration.
if (now - throttledAbility.lastEventTime < throttleDuration) then
throttledAbility.lastEventTime = now;
throttledAbility[#throttledAbility+1] = combatEvent;
return;
end
end
end -- Has throttle duration.
end -- Has effectName.
 
-- Add event to the unmerged events for potential merging.
unmergedEvents[#unmergedEvents+1] = combatEvent;
 
-- Check if the merge event frame is not visible and make it visible so the OnUpdate events start firing.
-- This is done to keep the number of OnUpdate events down to a minimum for better performance.
if (not eventFrame:IsVisible()) then eventFrame:Show(); end
 
-- Event is not to be merged so just display it now.
else
-- Display the event.
local outputMessage = FormatEvent(eventSettings.message, parserEvent.amount, parserEvent.damageType, parserEvent.overhealAmount, parserEvent.powerType, affectedUnitName, effectName, partialEffects, nil, effectTexture, ignorePhysical);
DisplayEvent(eventSettings, outputMessage, effectTexture);
end
end
 
 
-- ****************************************************************************
-- Called when the event frame is updated.
-- ****************************************************************************
local function OnUpdateEventFrame(this, elapsed)
-- Increment the amount of time passed since the last update.
lastMergeUpdate = lastMergeUpdate + elapsed;
 
-- If it's time for an update.
if (lastMergeUpdate >= MERGE_DELAY_TIME) then
-- Merge like events.
MergeEvents(#unmergedEvents);
 
-- Display and recycle the merged events.
local eventSettings, outputMessage;
for i, combatEvent in ipairs(mergedEvents) do
eventSettings = MSBTProfiles.currentProfile.events[combatEvent.isCrit and combatEvent.eventType .. "_CRIT" or combatEvent.eventType];
outputMessage = FormatEvent(eventSettings.message, combatEvent.amount, combatEvent.damageType, combatEvent.overhealAmount, combatEvent.powerType, combatEvent.name, combatEvent.effectName, combatEvent.partialEffects, combatEvent.mergeTrailer, combatEvent.effectTexture, combatEvent.ignorePhysical, true)
DisplayEvent(eventSettings, outputMessage, combatEvent.effectTexture);
mergedEvents[i] = nil;
EraseTable(combatEvent);
combatEventCache[#combatEventCache+1] = combatEvent;
end
 
-- Hide the frame if there are no remaining unmerged events so the OnUpdate events stop firing.
-- This is done to keep the number of OnUpdate events down to a minimum for better performance.
if (#unmergedEvents == 0) then this:Hide(); end
 
-- Reset the time since last update.
lastMergeUpdate = 0;
end
end
 
 
-- ****************************************************************************
-- Called when the throttle frame is updated.
-- ****************************************************************************
local function OnUpdateThrottleFrame(this, elapsed)
-- Increment the amount of time passed since the last update.
lastThrottleUpdate = lastThrottleUpdate + elapsed;
 
-- If it's time for an update.
if (lastThrottleUpdate >= THROTTLE_UPDATE_TIME) then
-- Flag for whether there are any events currently throttled.
local eventsThrottled;
 
-- Loop through all the throttled abilities.
for _, throttledAbility in pairs(throttledAbilities) do
-- Check if the ability is currently being throttled.
if (throttledAbility.throttleWindow > 0) then
-- Decrement the throttle window.
throttledAbility.throttleWindow = throttledAbility.throttleWindow - lastThrottleUpdate;
 
-- Check if the throttle window has elapsed.
if (throttledAbility.throttleWindow <= 0) then
-- Add throttled events to the merging system if there are any.
if (#throttledAbility > 0) then
for i = 1, #throttledAbility do
unmergedEvents[#unmergedEvents+1] = throttledAbility[i];
throttledAbility[i] = nil;
end
 
-- Check if the merge event frame is not visible and make it visible so the OnUpdate events start firing.
-- This is done to keep the number of OnUpdate events down to a minimum for better performance.
if (not eventFrame:IsVisible()) then eventFrame:Show(); end
end
-- Ability is still throttled so set the flag.
else
eventsThrottled = true;
end
end -- Ability is within its throttle window.
end -- Loop through throttled abilities.
 
 
-- Hide the frame if there are no remaining throttled events so the OnUpdate events stop firing.
-- This is done to keep the number of OnUpdate events down to a minimum for better performance.
if (not eventsThrottled) then this:Hide(); end
 
-- Reset the time since last update.
lastThrottleUpdate = 0;
end
end
 
 
-- ****************************************************************************
-- Called when the registered events occur.
-- ****************************************************************************
local function OnEvent(this, event, arg1, arg2)
-- When an addon is loaded.
if (event == "ADDON_LOADED") then
-- Make sure it's this addon.
if (arg1 == "MikScrollingBattleText") then
-- Don't get notification for other addons being loaded.
this:UnregisterEvent("ADDON_LOADED");
 
-- Register slash commands
SLASH_MSBT1 = MikSBT.COMMAND;
SlashCmdList["MSBT"] = CommandHandler;
 
-- Initialize the saved variables to make sure there is a profile to work with.
MSBTProfiles.InitSavedVariables();
 
-- Add a button to launch MSBT's options from the Blizzard interface options.
SetupBlizzardOptions();
end
 
-- Variables for all addons loaded.
elseif (event == "VARIABLES_LOADED") then
-- Disable or enable the mod depending on the saved setting.
-- Must do it once the variables are loaded because blizzard's code overrides the FCT
-- settings after the ADDON_LOADED code runs.
MSBTProfiles.SetOptionUserDisabled(MSBTProfiles.IsModDisabled());
 
-- Display warning if the old icon module is loaded.
if (MSBTIconSupport) then message(MSBTLocale.MSG_ICON_MODULE_WARNING); end
collectgarbage("collect");
 
 
-- Power changes.
elseif (event == "UNIT_MANA" or event == "UNIT_RAGE" or event == "UNIT_ENERGY") then
-- Check if the power change is for the player.
if (arg1 == "player") then
-- Update the power amount.
-- Detect power gains if there is a regen ability active or show all power gains is enabled.
local powerAmount = UnitMana("player");
if (currentBuffs[activeRegenAbility] or MSBTProfiles.currentProfile.showAllPowerGains) then DetectPowerGain(powerAmount); end
lastPowerAmount = powerAmount;
end
 
-- Leave Combat.
elseif (event == "PLAYER_REGEN_ENABLED") then
-- Get the event settings for leaving combat.
local eventSettings = MSBTProfiles.currentProfile.events.NOTIFICATION_COMBAT_LEAVE;
 
-- Display the event if it isn't disabled.
if (not eventSettings.disabled) then DisplayEvent(eventSettings, eventSettings.message); end
 
-- Enter Combat.
elseif (event == "PLAYER_REGEN_DISABLED") then
-- Get the event settings for leaving combat.
local eventSettings = MSBTProfiles.currentProfile.events.NOTIFICATION_COMBAT_ENTER;
 
-- Display the event if it isn't disabled.
if (not eventSettings.disabled) then DisplayEvent(eventSettings, eventSettings.message); end
 
-- Leave Combat.
elseif (event == "PLAYER_COMBO_POINTS") then
-- Make sure there are combo points and show the normal or full cp event.
local numCP = GetComboPoints();
if (numCP ~= 0) then HandleComboPoints(numCP); end
 
-- Monster emotes.
elseif (event == "CHAT_MSG_MONSTER_EMOTE") then
-- Ignore the event if it's not the current target.
if (arg2 ~= UnitName("target")) then return; end
HandleMonsterEmotes(string_gsub(arg1, "%%s", arg2));
end
end
 
 
-- ****************************************************************************
-- Enables the module.
-- ****************************************************************************
local function Enable()
-- Register events to handle extra notifications.
eventFrame:RegisterEvent("UNIT_MANA");
eventFrame:RegisterEvent("UNIT_RAGE");
eventFrame:RegisterEvent("UNIT_ENERGY");
eventFrame:RegisterEvent("PLAYER_COMBO_POINTS");
eventFrame:RegisterEvent("PLAYER_REGEN_ENABLED");
eventFrame:RegisterEvent("PLAYER_REGEN_DISABLED");
eventFrame:RegisterEvent("CHAT_MSG_MONSTER_EMOTE");
 
-- Register the parser events handler.
MSBTParser.RegisterHandler(ParserEventsHandler);
end
 
 
-- ****************************************************************************
-- Disables the module.
-- ****************************************************************************
local function Disable()
-- Stop receiving updates.
eventFrame:Hide();
eventFrame:UnregisterAllEvents();
 
-- Unregister the parser events handler.
MSBTParser.UnregisterHandler(ParserEventsHandler);
end
 
 
-- ****************************************************************************
-- Called when the module is loaded.
-- ****************************************************************************
local function OnLoad()
-- Create a frame to receive events.
eventFrame = CreateFrame("Frame");
eventFrame:Hide();
eventFrame:SetScript("OnEvent", OnEvent);
eventFrame:SetScript("OnUpdate", OnUpdateEventFrame);
 
-- Create a frame to receive throttle update events.
throttleFrame = CreateFrame("Frame");
throttleFrame:Hide();
throttleFrame:SetScript("OnUpdate", OnUpdateThrottleFrame);
 
-- Create the map of handlers to call for each event.
eventHandlers["damage"] = DamageHandler;
eventHandlers["miss"] = MissHandler;
eventHandlers["heal"] = HealHandler;
eventHandlers["interrupt"] = InterruptHandler;
eventHandlers["environmental"] = EnvironmentalHandler;
eventHandlers["aura"] = AuraHandler;
eventHandlers["enchant"] = EnchantHandler;
eventHandlers["dispel"] = DispelHandler;
eventHandlers["power"] = PowerHandler;
eventHandlers["kill"] = KillHandler;
eventHandlers["honor"] = HonorHandler;
eventHandlers["reputation"] = ReputationHandler;
eventHandlers["proficiency"] = ProficiencyHandler;
eventHandlers["experience"] = ExperienceHandler;
eventHandlers["extraattacks"] = ExtraAttacksHandler;
eventHandlers["loot"] = LootHandler;
 
-- Create the damage type lookup map.
damageTypeMap[DAMAGETYPE_PHYSICAL] = STRING_SCHOOL_PHYSICAL;
damageTypeMap[DAMAGETYPE_HOLY] = STRING_SCHOOL_HOLY;
damageTypeMap[DAMAGETYPE_FIRE] = STRING_SCHOOL_FIRE;
damageTypeMap[DAMAGETYPE_NATURE] = STRING_SCHOOL_NATURE;
damageTypeMap[DAMAGETYPE_FROST] = STRING_SCHOOL_FROST;
damageTypeMap[DAMAGETYPE_SHADOW] = STRING_SCHOOL_SHADOW;
damageTypeMap[DAMAGETYPE_ARCANE] = STRING_SCHOOL_ARCANE;
 
-- Create the damage color profile entries lookup map.
damageColorProfileEntries[DAMAGETYPE_PHYSICAL] = "physical";
damageColorProfileEntries[DAMAGETYPE_HOLY] = "holy";
damageColorProfileEntries[DAMAGETYPE_FIRE] = "fire";
damageColorProfileEntries[DAMAGETYPE_NATURE] = "nature";
damageColorProfileEntries[DAMAGETYPE_FROST] = "frost";
damageColorProfileEntries[DAMAGETYPE_SHADOW] = "shadow";
damageColorProfileEntries[DAMAGETYPE_ARCANE] = "arcane";
 
-- Create the power types lookup map.
powerTypes[0] = MANA;
powerTypes[1] = RAGE;
powerTypes[3] = ENERGY;
 
-- Set the isEnglish flag correctly.
if (string_find(GetLocale(), "en..")) then isEnglish = true; end
 
-- Add the regen abilities.
regenAbilities[SPELL_SPIRIT_TAP] = true;
regenAbilities[SPELL_INNERVATE] = true;
 
-- Register events for when the mod is loaded and variables are loaded.
eventFrame:RegisterEvent("ADDON_LOADED");
eventFrame:RegisterEvent("VARIABLES_LOADED");
end
 
 
 
 
-------------------------------------------------------------------------------
-- Module interface.
-------------------------------------------------------------------------------
 
-- Protected Functions.
module.Enable = Enable;
module.Disable = Disable;
 
 
------------------------------------------------------------------------------------
-- API.
-------------------------------------------------------------------------------
 
-- Public Constants.
MikSBT.DISPLAYTYPE_INCOMING = "Incoming";
MikSBT.DISPLAYTYPE_OUTGOING = "Outgoing";
MikSBT.DISPLAYTYPE_NOTIFICATION = "Notification";
MikSBT.DISPLAYTYPE_STATIC = "Static";
 
-- Public Functions.
MikSBT.RegisterFont = MSBTAnimations.RegisterFont;
MikSBT.RegisterAnimationStyle = MSBTAnimations.RegisterAnimationStyle;
MikSBT.RegisterStickyAnimationStyle = MSBTAnimations.RegisterStickyAnimationStyle;
MikSBT.RegisterSound = MSBTAnimations.RegisterSound;
MikSBT.IterateFonts = MSBTAnimations.IterateFonts;
MikSBT.IterateScrollAreas = MSBTAnimations.IterateScrollAreas;
MikSBT.IterateSounds = MSBTAnimations.IterateSounds;
MikSBT.DisplayMessage = MSBTAnimations.DisplayMessage;
MikSBT.IsModDisabled = MSBTProfiles.IsModDisabled;
 
 
-------------------------------------------------------------------------------
-- Load.
-------------------------------------------------------------------------------
 
OnLoad();
\ No newline at end of file
MSBT5_13/MikScrollingBattleText/MSBTTriggers.lua New file
0,0 → 1,716
-------------------------------------------------------------------------------
-- Title: Mik's Scrolling Battle Text Triggers
-- Author: Mik
-------------------------------------------------------------------------------
 
-- Create module and set its name.
local module = {};
local moduleName = "Triggers";
MikSBT[moduleName] = module;
 
 
-------------------------------------------------------------------------------
-- Constants.
-------------------------------------------------------------------------------
 
-- Main Trigger Events.
local MAINEVENT_HEALTH = "Health";
local MAINEVENT_MANA = "Mana";
local MAINEVENT_ENERGY = "Energy";
local MAINEVENT_RAGE = "Rage";
local MAINEVENT_CRIT = "Crit";
local MAINEVENT_BLOCK = "Block";
local MAINEVENT_DODGE = "Dodge";
local MAINEVENT_PARRY = "Parry";
local MAINEVENT_BUFF_APP = "BuffApplication";
local MAINEVENT_BUFF_FADE = "BuffFade";
local MAINEVENT_DEBUFF_APP = "DebuffApplication";
local MAINEVENT_DEBUFF_FADE = "DebuffFade";
local MAINEVENT_CAST_START = "CastStart";
local MAINEVENT_KILLING_BLOW = "KillingBlow";
 
-- Trigger Exceptions.
local EXCEPTION_BUFF_ACTIVE = "BuffActive";
local EXCEPTION_INSUFFICIENT_POWER = "InsufficientPower";
local EXCEPTION_INSUFFICIENT_CP = "InsufficientComboPoints";
local EXCEPTION_NOT_IN_ARENA = "NotInArena";
local EXCEPTION_NOT_IN_PVP_ZONE = "NotInPvPZone";
local EXCEPTION_RECENTLY_FIRED = "RecentlyFired";
local EXCEPTION_SKILL_UNAVAILABLE = "SkillUnavailable";
local EXCEPTION_TRIVIAL_TARGET = "TrivialTarget";
local EXCEPTION_WARRIOR_STANCE = "WarriorStance";
 
-- Power types.
local POWERTYPE_MANA = 0;
local POWERTYPE_RAGE = 1;
local POWERTYPE_ENERGY = 3;
 
 
-------------------------------------------------------------------------------
-- Private variables.
-------------------------------------------------------------------------------
 
-- Holds dynamically created frame for receiving events.
local eventFrame;
 
-- Holds the player's name, GUID, and class.
local playerName, playerGUID, playerClass;
local targetGUID, focusGUID;
 
-- Hold the events the triggers use.
local listenEvents = {};
 
-- Holds triggers in a format optimized for searching.
local categorizedTriggers = {};
local triggerExceptions = {};
 
-- Information about triggers used for condition checking.
local lastPercentages = {};
local lastPowerTypes = {};
local firedTimes = {};
local fireTriggers = {};
 
-- Hold buffs and debuffs that should be suppressed since there is a trigger for them.
local triggerSuppressions = {};
 
 
-------------------------------------------------------------------------------
-- Imports.
-------------------------------------------------------------------------------
 
-- Local references to certain MSBT modules for faster access.
local MSBTProfiles = MikSBT.Profiles;
local MSBTParser = MikSBT.Parser;
 
-- Local references to certain constants and variables for faster access.
local TARGET_TARGET = MSBTParser.TARGET_TARGET;
local TARGET_FOCUS = MSBTParser.TARGET_FOCUS;
local REACTION_HOSTILE = bit.bor(MSBTParser.REACTION_HOSTILE, MSBTParser.REACTION_NEUTRAL);
 
local currentBuffs = MSBTParser.currentAuras.buffs;
local unitMap = MSBTParser.unitMap;
 
-- Get local references to certain functions for faster access.
local string_find = string.find;
local string_gsub = string.gsub;
local string_gmatch = string.gmatch;
local Print = MikSBT.Print;
local EraseTable = MikSBT.EraseTable;
local DisplayEvent = MikSBT.Animations.DisplayEvent;
local TestFlagsAny = MSBTParser.TestFlagsAny;
local TestFlagsAll = MSBTParser.TestFlagsAll;
 
 
-------------------------------------------------------------------------------
-- Trigger utility functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Converts a string representation of a number, boolean, or nil to its
-- corresponding type.
-- ****************************************************************************
local function ConvertType(value)
if (type(value) == "string") then
if (value == "true") then return true; end
if (value == "false") then return false; end
if (tonumber(value)) then return tonumber(value); end
if (value == "nil") then return nil; end
end
 
return value;
end
 
 
-- ****************************************************************************
-- Categorizes the passed trigger if it is not disabled and it applies to the
-- current player's class. Also tracks the events the trigger uses so the
-- only events that are received are those needed by the active triggers.
-- ****************************************************************************
local function CategorizeTrigger(triggerSettings)
-- Don't register the trigger if it is disabled, not for the current class,
-- or there aren't any main events.
if (triggerSettings.disabled) then return; end
if (triggerSettings.classes and not string_find(triggerSettings.classes, playerClass, nil, 1)) then return; end
if (not triggerSettings.mainEvents) then return; end
 
-- Loop through the main events for the trigger.
local eventConditions, conditions;
for mainEvent, conditionsString in string.gmatch(triggerSettings.mainEvents .. "&&", "(.-)%[(.-)%]&&") do
-- Loop through the conditions for the event and populate the settings into a conditions table.
conditions = {triggerSettings = triggerSettings};
for conditionName, conditionValue in string.gmatch(conditionsString .. ";;", "(.-)=(.-);;") do
conditions[conditionName] = ConvertType(conditionValue);
end
 
-- Create a table to hold an array of the triggers for the main event if there isn't already one for it.
if (not categorizedTriggers[mainEvent]) then categorizedTriggers[mainEvent] = {}; end
eventConditions = categorizedTriggers[mainEvent];
 
-- Add the conditions table categorized by main event.
eventConditions[#eventConditions+1] = conditions;
 
-- Health.
if (mainEvent == MAINEVENT_HEALTH) then
listenEvents["UNIT_HEALTH"] = true;
 
-- Mana.
elseif (mainEvent == MAINEVENT_MANA) then
listenEvents["UNIT_MANA"] = true;
 
-- Energy.
elseif (mainEvent == MAINEVENT_ENERGY) then
listenEvents["UNIT_ENERGY"] = true;
 
-- Rage.
elseif (mainEvent == MAINEVENT_RAGE) then
listenEvents["UNIT_RAGE"] = true;
 
-- Buff and debuff gains.
elseif (mainEvent == MAINEVENT_BUFF_APP or
mainEvent == MAINEVENT_DEBUFF_APP) then
 
-- Add player buff/debuff names to the trigger suppressions list.
if (conditions.unit == "player" and conditions.effect and conditions.amount == 1) then triggerSuppressions[conditions.effect] = true; end
end
end -- Loop through conditions.
 
-- Leave the function if there are no exceptions for the trigger.
if (not triggerSettings.exceptions) then return; end
 
-- Create a table to hold an array of the exceptions if there isn't already one for it.
if (not triggerExceptions[triggerSettings]) then triggerExceptions[triggerSettings] = {}; end
local exceptions = triggerExceptions[triggerSettings];
 
-- Loop through the exceptions for the trigger.
for exceptionType, exceptionConditions in string_gmatch(triggerSettings.exceptions .. "&&", "(.-)%[(.-)%]&&") do
-- Loop through the conditions for the exception and populate the settings into a conditions table.
conditions = {exceptionType = exceptionType};
for conditionName, conditionValue in string.gmatch(exceptionConditions .. ";;", "(.-)=(.-);;") do
conditions[conditionName] = ConvertType(conditionValue);
end
 
-- Add the conditions to the list of exceptions for the trigger.
exceptions[#exceptions+1] = conditions;
end
end
 
 
-- ****************************************************************************
-- Update the categorized triggers table that is used for optimized searching.
-- ****************************************************************************
local function UpdateTriggers()
-- Unregister all of the events from the event frame.
eventFrame:UnregisterAllEvents();
 
-- Erase the listen events table.
EraseTable(listenEvents);
 
-- Loop through all of the categorized trigger arrays and erase them.
for mainEvent in pairs(categorizedTriggers) do
EraseTable(categorizedTriggers[mainEvent]);
end
 
-- Erase the trigger exceptions array.
EraseTable(triggerExceptions);
 
-- Categorize triggers from the current profile.
local currentProfileTriggers = rawget(MSBTProfiles.currentProfile, "triggers");
if (currentProfileTriggers) then
for triggerKey, triggerSettings in pairs(currentProfileTriggers) do
if (triggerSettings) then CategorizeTrigger(triggerSettings); end
end
end
 
-- Categorize triggers available in the master profile that aren't in the current profile.
for triggerKey, triggerSettings in pairs(MSBTProfiles.masterProfile.triggers) do
if (not currentProfileTriggers or rawget(currentProfileTriggers, triggerKey) == nil) then
CategorizeTrigger(triggerSettings);
end
end
 
-- Register all of the events the triggers use.
for event in pairs(listenEvents) do
eventFrame:RegisterEvent(event);
end
end
 
 
-- ****************************************************************************
-- Displays the passed trigger settings.
-- ****************************************************************************
local function DisplayTrigger(triggerSettings, sourceName, recipientName, effectTexture, ...)
-- Get the trigger message and icon skill.
local message = triggerSettings.message;
local iconSkill = triggerSettings.iconSkill;
 
-- Substitute the source and recipient names if there are any.
if (sourceName) then message = string_gsub(message, "%%n", sourceName); end
if (recipientName) then message = string_gsub(message, "%%r", recipientName); end
 
-- Loop through all of the arguments replacing any %i codes with the corresponding
-- arguments.
for i = 1, select("#", ...) do
local value = select(i, ...);
if (value) then message = string_gsub(message, "%%" .. i, tostring(value)); end
if (type(iconSkill) == "string") then iconSkill = string_gsub(iconSkill, "%%" .. i, tostring(value)); end
end
 
-- Override the texture if there is an icon skill for the trigger.
if (iconSkill) then _, _, effectTexture = GetSpellInfo(iconSkill); end
 
-- Display the trigger event.
DisplayEvent(triggerSettings, message, effectTexture);
end
 
 
-- ****************************************************************************
-- Tests if the passed unit based conditions are satisfied.
-- ****************************************************************************
local function TestUnitConditions(eventConditions, testUnit, testFlags)
-- Hostile check.
if (eventConditions.hostile and not TestFlagsAny(testFlags, REACTION_HOSTILE)) then return false; end
 
-- Any.
local conditionUnit = eventConditions.unit;
if (conditionUnit == "any") then return true; end
 
-- Player.
if (conditionUnit == "player" and testUnit == "player") then return true; end
 
-- Target.
if (conditionUnit == "target" and TestFlagsAny(testFlags, TARGET_TARGET)) then return true; end
 
-- Focus.
if (conditionUnit == "focus" and TestFlagsAny(testFlags, TARGET_FOCUS)) then return true; end
end
 
 
-------------------------------------------------------------------------------
-- Trigger condition functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Returns whether or not the passed spell name is unavailable.
-- ****************************************************************************
local function IsSpellUnavailable(spellName)
-- Pass if there is no skill to check.
if (not spellName or spellName == "") then return true; end
 
-- Pass if the spell isn't known.
if (not GetSpellInfo(spellName)) then return true; end
 
-- Pass check if the spell is cooling down (but ignore the global cooldown).
local start, duration = GetSpellCooldown(spellName);
if (start > 0 and duration > 1.5) then return true; end
end
 
 
-- ****************************************************************************
-- Returns true if any of the exceptions for the passed trigger settings are
-- true.
-- ****************************************************************************
local function IsTriggerExcluded(triggerSettings)
-- Trigger is not excluded if there are no exceptions.
if (not triggerExceptions[triggerSettings]) then return; end
 
-- Holds whether or not the trigger is excluded.
local isExcluded;
 
-- Holds whether or not the trigger has a recently fired exception.
local hasRecentlyFired;
 
local exceptionType;
for _, exceptionConditions in pairs(triggerExceptions[triggerSettings]) do
exceptionType = exceptionConditions.exceptionType;
 
-- Buff Active.
if (exceptionType == EXCEPTION_BUFF_ACTIVE) then
if (currentBuffs[exceptionConditions.effect]) then isExcluded = true; end
 
-- Insufficient Power.
elseif (exceptionType == EXCEPTION_INSUFFICIENT_POWER) then
if (UnitMana("player") < exceptionConditions.amount) then isExcluded = true; end
 
-- Insufficient Combo Points.
elseif (exceptionType == EXCEPTION_INSUFFICIENT_CP) then
if (GetComboPoints() < exceptionConditions.amount) then isExcluded = true; end
 
-- Not In Arena.
elseif (exceptionType == EXCEPTION_NOT_IN_ARENA) then
local _, zoneType = IsInInstance();
if (zoneType ~= "arena") then isExcluded = true; end
 
-- Not In PvP Zone.
elseif (exceptionType == EXCEPTION_NOT_IN_PVP_ZONE) then
local _, zoneType = IsInInstance();
if (zoneType ~= "arena" and zoneType ~= "pvp") then isExcluded = true; end
 
-- Recently Fired.
elseif (exceptionType == EXCEPTION_RECENTLY_FIRED) then
hasRecentlyFired = true;
local lastFired = firedTimes[triggerSettings] or 0;
if ((GetTime() - lastFired) <= exceptionConditions.duration) then isExcluded = true; end
 
-- Skill Unavailable.
elseif (exceptionType == EXCEPTION_SKILL_UNAVAILABLE) then
if (IsSpellUnavailable(exceptionConditions.effect)) then isExcluded = true; end
 
-- Trivial Target.
elseif (exceptionType == EXCEPTION_TRIVIAL_TARGET) then
if (UnitIsTrivial("target")) then isExcluded = true; end
 
-- Warrior Stance.
elseif (exceptionType == EXCEPTION_WARRIOR_STANCE) then
if (playerClass == "WARRIOR" and (GetShapeshiftForm(true) == exceptionConditions.stance)) then
isExcluded = true;
end
end
 
-- Reverse the result if the reverse logic flag is set.
if (exceptionConditions.reversed) then isExcluded = not isExcluded; end
if (isExcluded) then return true; end
end
 
-- Set the current time as the last time the trigger was fired if the the trigger
-- has a recently fired exception.
if (hasRecentlyFired) then firedTimes[triggerSettings] = GetTime(); end
end
 
 
-- ****************************************************************************
-- Fires triggers that have threshold conditions which are satisfied.
-- ****************************************************************************
local function FireThresholdTriggers(unit, mainEvent, currentAmount, maxAmount, powerType)
-- Ignore the event if it isn't one of the supported units.
if (unit ~= "player" and unit ~= "target" and unit ~= "pet" and unit ~= "focus") then return; end
 
-- Calculate current last percentages.
local currentPercentage = currentAmount / maxAmount;
local percentageKey = unit .. mainEvent;
local lastPercentage = lastPercentages[percentageKey];
 
-- Ignore thresholds on death and power type changes.
if (not lastPercentage) then lastPercentages[percentageKey] = currentPercentage; return; end
if (powerType and powerType ~= UnitPowerType(unit) or UnitIsDeadOrGhost(unit)) then lastPercentages[percentageKey] = nil; return; end
 
-- Clear the list of triggers to fire.
EraseTable(fireTriggers);
 
-- Loop through conditions and test the ones that apply to the affected unit.
local threshold;
for _, eventConditions in pairs(categorizedTriggers[mainEvent]) do
if (eventConditions.unit == unit and (not eventConditions.hostile or UnitIsEnemy("player", unit))) then
threshold = eventConditions.threshold / 100;
 
-- Rising threshold.
if (eventConditions.direction == "rising") then
if (currentPercentage > threshold and lastPercentage <= threshold) then
fireTriggers[eventConditions.triggerSettings] = true;
end
 
-- Declining threshold.
else
if (currentPercentage < threshold and lastPercentage >= threshold) then
fireTriggers[eventConditions.triggerSettings] = true;
end
end -- Rising check.
end -- Applies to unit.
end -- Conditions loop.
 
-- Display the fired triggers if none of the exceptions are true.
local recipientName = UnitName(unit);
for triggerSettings in pairs(fireTriggers) do
if (not IsTriggerExcluded(triggerSettings)) then
DisplayTrigger(triggerSettings, nil, recipientName, nil, currentAmount);
end
end
 
-- Update the last percentage for the unit.
lastPercentages[percentageKey] = currentPercentage;
end
 
 
-- ****************************************************************************
-- Fires triggers that have incoming/outgoing conditions which are satisfied.
-- ****************************************************************************
local function FireInOutTriggers(mainEvent, parserEvent)
-- Ignore the event if there are no triggers to search for it.
if (not categorizedTriggers[mainEvent]) then return; end
 
-- Get local copies for faster access.
local recipientUnit = parserEvent.recipientUnit;
local sourceUnit = parserEvent.sourceUnit;
 
-- Clear the list of triggers to fire.
EraseTable(fireTriggers);
 
-- Loop through conditions and fire the ones that apply to the affected unit.
for _, eventConditions in pairs(categorizedTriggers[mainEvent]) do
if (recipientUnit == "player" and eventConditions.direction == "incoming" or
sourceUnit == "player" and eventConditions.direction == "outgoing") then
fireTriggers[eventConditions.triggerSettings] = true;
end
end
 
-- Get the texture for the event any display triggers that meet all conditions if there are any.
if (next(fireTriggers)) then
local effectTexture;
if (parserEvent.skillID) then _, _, effectTexture = GetSpellInfo(parserEvent.skillID); end
 
-- Display the fired triggers if none of the exceptions are true.
local sourceName = parserEvent.sourceName;
local recipientName = parserEvent.recipientName;
local skillName = parserEvent.skillName or "";
for triggerSettings in pairs(fireTriggers) do
if (not IsTriggerExcluded(triggerSettings)) then
DisplayTrigger(triggerSettings, sourceName, recipientName, effectTexture, skillName);
end
end
end
end
 
 
-- ****************************************************************************
-- Fires triggers that have aura conditions which are satisfied.
-- ****************************************************************************
local function FireAuraTriggers(mainEvent, parserEvent)
-- Ignore the event if there are no triggers to search for it.
if (not categorizedTriggers[mainEvent]) then return; end
 
-- Get local copies for faster access.
local skillName = parserEvent.skillName;
local recipientUnit = parserEvent.recipientUnit;
local recipientFlags = parserEvent.recipientFlags;
local amount = parserEvent.amount or 1;
 
-- Clear the list of triggers to fire.
EraseTable(fireTriggers);
 
-- Loop through conditions and test the conditions.
local conditionAmount;
for _, eventConditions in pairs(categorizedTriggers[mainEvent]) do
conditionAmount = eventConditions.amount;
if (eventConditions.effect == skillName and
TestUnitConditions(eventConditions, recipientUnit, recipientFlags) and
(not conditionAmount or conditionAmount == amount)) then
fireTriggers[eventConditions.triggerSettings] = true;
end
end
 
-- Get the texture for the event any display triggers that meet all conditions if there are any.
if (next(fireTriggers)) then
local effectTexture = parserEvent.skillTexture;
if (not effectTexture and parserEvent.skillID) then _, _, effectTexture = GetSpellInfo(parserEvent.skillID); end
 
-- Display the fired triggers if none of the exceptions are true.
local recipientName = parserEvent.recipientName;
for triggerSettings in pairs(fireTriggers) do
if (not IsTriggerExcluded(triggerSettings)) then
DisplayTrigger(triggerSettings, nil, recipientName, effectTexture, skillName, amount);
end
end
end
end
 
 
-- ****************************************************************************
-- Fires triggers that have cast conditions which are satisfied.
-- ****************************************************************************
local function FireCastTriggers(mainEvent, parserEvent)
-- Ignore the event if there are no triggers to search for it.
if (not categorizedTriggers[mainEvent]) then return; end
 
-- Get local copies for faster access.
local skillName = parserEvent.skillName;
local sourceUnit = parserEvent.sourceUnit;
local sourceFlags = parserEvent.sourceFlags;
 
-- Clear the list of triggers to fire.
EraseTable(fireTriggers);
 
-- Loop through conditions and test the conditions.
for _, eventConditions in pairs(categorizedTriggers[mainEvent]) do
if (eventConditions.effect == skillName and
TestUnitConditions(eventConditions, sourceUnit, sourceFlags)) then
fireTriggers[eventConditions.triggerSettings] = true;
end
end
 
-- Get the texture for the event any display triggers that meet all conditions if there are any.
if (next(fireTriggers)) then
local effectTexture = parserEvent.skillTexture;
if (not effectTexture and parserEvent.skillID) then _, _, effectTexture = GetSpellInfo(parserEvent.skillID); end
 
-- Display the fired triggers if none of the exceptions are true.
local sourceName = parserEvent.sourceName;
for triggerSettings in pairs(fireTriggers) do
if (not IsTriggerExcluded(triggerSettings)) then
DisplayTrigger(triggerSettings, sourceName, nil, effectTexture, skillName);
end
end
end
end
 
 
-- ****************************************************************************
-- Fires triggers for the passed condition type.
-- ****************************************************************************
local function FireBasicTriggers(mainEvent, parserEvent)
-- Ignore the event if there are no triggers for it.
if (not categorizedTriggers[mainEvent]) then return; end
 
-- Clear the list of triggers to fire.
EraseTable(fireTriggers);
 
-- Loop through conditions and test the ones that apply to the affected unit.
for _, eventConditions in pairs(categorizedTriggers[mainEvent]) do
fireTriggers[eventConditions.triggerSettings] = true;
end
 
-- Display the fired triggers if none of the exceptions are true.
local sourceName = parserEvent.sourceName;
local recipientName = parserEvent.recipientName;
for triggerSettings in pairs(fireTriggers) do
if (not IsTriggerExcluded(triggerSettings)) then
DisplayTrigger(triggerSettings, sourceName, recipientName);
end
end
end
 
 
-------------------------------------------------------------------------------
-- Initialization and event handlers.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Handle parser events.
-- ****************************************************************************
local function ParserEventsHandler(parserEvent)
local eventType = parserEvent.eventType;
-- Crit.
if (eventType == "damage") then
if (parserEvent.isCrit) then FireInOutTriggers(MAINEVENT_CRIT, parserEvent); end
 
-- Miss.
elseif (eventType == "miss") then
-- Block.
if (parserEvent.missType == "BLOCK") then
FireInOutTriggers(MAINEVENT_BLOCK, parserEvent);
 
-- Dodge.
elseif (parserEvent.missType == "DODGE") then
FireInOutTriggers(MAINEVENT_DODGE, parserEvent);
 
-- Miss.
elseif (parserEvent.missType == "PARRY") then
FireInOutTriggers(MAINEVENT_PARRY, parserEvent);
end
 
-- Aura.
elseif (eventType == "aura") then
local mainEvent = (parserEvent.auraType == "BUFF") and "Buff" or "Debuff";
if (parserEvent.isFade) then
mainEvent = mainEvent .. "Fade";
else
mainEvent = mainEvent .. "Application";
end
FireAuraTriggers(mainEvent, parserEvent);
 
-- Cast.
elseif (eventType == "cast") then
FireCastTriggers(MAINEVENT_CAST_START, parserEvent);
 
-- Kill.
elseif (eventType == "kill") then
if (parserEvent.sourceUnit == "player") then FireBasicTriggers(MAINEVENT_KILLING_BLOW, parserEvent); end
end -- Check eventType.
end
 
 
-- ****************************************************************************
-- Called when the registered events occur.
-- ****************************************************************************
local function OnEvent(this, event, arg1, ...)
-- Health.
if (event == "UNIT_HEALTH") then
FireThresholdTriggers(arg1, MAINEVENT_HEALTH, UnitHealth(arg1), UnitHealthMax(arg1));
 
-- Mana.
elseif (event == "UNIT_MANA") then
FireThresholdTriggers(arg1, MAINEVENT_MANA, UnitMana(arg1), UnitManaMax(arg1), POWERTYPE_MANA);
 
-- Energy.
elseif (event == "UNIT_ENERGY") then
FireThresholdTriggers(arg1, MAINEVENT_ENERGY, UnitMana(arg1), UnitManaMax(arg1), POWERTYPE_ENERGY);
 
-- Rage.
elseif (event == "UNIT_RAGE") then
FireThresholdTriggers(arg1, MAINEVENT_RAGE, UnitMana(arg1), UnitManaMax(arg1), POWERTYPE_RAGE);
 
end -- Event types.
end
 
 
-- ****************************************************************************
-- Enables the trigger parsing.
-- ****************************************************************************
local function Enable()
-- Register events the triggers use that aren't covered by the parser.
for event in pairs(listenEvents) do
eventFrame:RegisterEvent(event);
end
 
-- Register the parser events handler.
MSBTParser.RegisterHandler(ParserEventsHandler);
end
 
 
-- ****************************************************************************
-- Disables the trigger parsing.
-- ****************************************************************************
local function Disable()
-- Unregister all of the events from the event frame.
eventFrame:UnregisterAllEvents();
 
-- Unregister the parser events handler.
MSBTParser.UnregisterHandler(ParserEventsHandler);
end
 
 
-- ****************************************************************************
-- Called when the module is loaded.
-- ****************************************************************************
local function OnLoad()
-- Get the player's name and class.
playerName = UnitName("player");
playerGUID = UnitGUID("player");
_, playerClass = UnitClass("player");
 
-- Create a frame to receive events.
eventFrame = CreateFrame("Frame");
eventFrame:Hide();
eventFrame:SetScript("OnEvent", OnEvent);
end
 
 
 
 
-------------------------------------------------------------------------------
-- Module interface.
-------------------------------------------------------------------------------
 
-- Protected Variables.
module.triggerSuppressions = triggerSuppressions;
 
-- Protected Functions.
module.ConvertType = ConvertType;
module.UpdateTriggers = UpdateTriggers;
module.Enable = Enable;
module.Disable = Disable;
 
 
-------------------------------------------------------------------------------
-- Load.
-------------------------------------------------------------------------------
 
OnLoad();
\ No newline at end of file
MSBT5_13/MikScrollingBattleText/localization.de.lua New file
0,0 → 1,66
-------------------------------------------------------------------------------
-- Title: Mik's Scrolling Battle Text German Localization
-- Author: Mik
-- German Translation by: Farook
-------------------------------------------------------------------------------
 
-- Don't do anything if the locale isn't German.
if (GetLocale() ~= "deDE") then return; end
 
-------------------------------------------------------------------------------
-- German localization
-------------------------------------------------------------------------------
 
-- Local reference for faster access.
local MSBTLocale = MikSBT.Locale;
 
 
MSBTLocale.COMMAND_USAGE = {
"Usage: " .. MikSBT.COMMAND .. " <befehle> [params]",
" Befehle:",
" " .. MSBTLocale.COMMAND_RESET .. " - Das aktuelle Profil auf Standardwerte zur\195\188cksetzen.",
" " .. MSBTLocale.COMMAND_DISABLE .. " - Das Addon deaktivieren.",
" " .. MSBTLocale.COMMAND_ENABLE .. " - Das Addon aktivieren.",
" " .. MSBTLocale.COMMAND_SHOWVER .. " - Zeigt die aktuelle Version an.",
" " .. MSBTLocale.COMMAND_HELP .. " - Hilfe anzeigen.",
};
 
 
------------------------------
-- Output messages
------------------------------
 
MSBTLocale.MSG_SEARCH_ENABLE = "Event-Suchmodus aktiviert. Suche nach: ";
MSBTLocale.MSG_SEARCH_DISABLE = "Event-Suchmodus deaktiviert.";
MSBTLocale.MSG_DISABLE = "Addon deaktiviert.";
MSBTLocale.MSG_ENABLE = "Addon aktiviert.";
MSBTLocale.MSG_PROFILE_RESET = "Profil zur\195\188cksetzen";
MSBTLocale.MSG_HITS = "Treffer";
--MSBTLocale.MSG_CRIT = "Crit";
--MSBTLocale.MSG_CRITS = "Crits";
MSBTLocale.MSG_MULTIPLE_TARGETS = "Mehrere";
MSBTLocale.MSG_READY_NOW = "Vorhanden";
 
 
------------------------------
-- Scroll area messages
------------------------------
 
MSBTLocale.MSG_INCOMING = "Eingehend";
MSBTLocale.MSG_OUTGOING = "Ausgehend";
MSBTLocale.MSG_NOTIFICATION = "Benachrichtigung";
MSBTLocale.MSG_STATIC = "Statisch";
 
 
---------------------------------------
-- Master profile event output messages
---------------------------------------
 
MSBTLocale.MSG_COMBAT = "Kampf";
MSBTLocale.MSG_DISPEL = "Zerstreuen";
--MSBTLocale.MSG_CP = "CP";
MSBTLocale.MSG_CP_FULL = "Alle Combo-Punkte";
MSBTLocale.MSG_KILLING_BLOW = "Todessto\195\159";
MSBTLocale.MSG_TRIGGER_LOW_HEALTH = "Gesundheit Niedrig";
MSBTLocale.MSG_TRIGGER_LOW_MANA = "Mana Niedrig";
MSBTLocale.MSG_TRIGGER_LOW_PET_HEALTH = "Begleiter Gesundheit Niedrig";
\ No newline at end of file
MSBT5_13/MikScrollingBattleText/MSBTFonts.lua New file
0,0 → 1,34
-------------------------------------------------------------------------------
-- Title: Mik's Scrolling Battle Text Fonts
-- Author: Mik
-------------------------------------------------------------------------------
 
-------------------------------------------------------------------------------
-- Private constants.
-------------------------------------------------------------------------------
 
-- The font files to use.
local FONT_FILES = {
Adventure = "Interface\\Addons\\MikScrollingBattleText\\Fonts\\adventure.ttf",
Bazooka = "Interface\\Addons\\MikScrollingBattleText\\Fonts\\bazooka.ttf",
Cooline = "Interface\\Addons\\MikScrollingBattleText\\Fonts\\cooline.ttf",
Default = "Interface\\Addons\\MikScrollingBattleText\\Fonts\\porky.ttf",
Diogenes = "Interface\\Addons\\MikScrollingBattleText\\Fonts\\diogenes.ttf",
Friz = "Fonts\\FRIZQT__.TTF",
Ginko = "Interface\\Addons\\MikScrollingBattleText\\Fonts\\ginko.ttf",
Heroic = "Interface\\Addons\\MikScrollingBattleText\\Fonts\\heroic.ttf",
Talisman = "Interface\\Addons\\MikScrollingBattleText\\Fonts\\talisman.ttf",
Transformers = "Interface\\Addons\\MikScrollingBattleText\\Fonts\\transformers.ttf",
Yellowjacket = "Interface\\Addons\\MikScrollingBattleText\\Fonts\\yellowjacket.ttf",
Zephyr = "Interface\\Addons\\MikScrollingBattleText\\Fonts\\zephyr.ttf",
}
 
 
-------------------------------------------------------------------------------
-- Load.
-------------------------------------------------------------------------------
 
-- Loop through all of the fonts and register them.
for fontName, fontPath in pairs(FONT_FILES) do
MikSBT.RegisterFont(fontName, fontPath);
end
\ No newline at end of file
MSBT5_13/MikScrollingBattleText/readme.html New file
0,0 → 1,1434
<html>
<head>
<title>Mik's Scrolling Battle Text Readme</title>
<style type="text/css">
body { font-size : 10pt; font-family : verdana,arial,helvetica,sans-serif; }
hr { color : #e0e0e0; }
 
a:link { color : #000060; text-decoration : none; }
a:visited { color : #000060; text-decoration : none; }
a:hover { text-decoration : underline; }
 
div#HeaderBlock {background-color : ivory; border : solid #000050 1px; padding : 1ex; margin-top : 2em; margin-bottom : 2em; }
div#NotificationBlock {font-size : 120%; font-weight : bold; color : red; margin-top : 1em; margin-bottom : 2em; }
 
div.TOCTitle { font-weight : bold; font-size : 12pt; }
div.TOC { margin : 2ex 1ex 4em 2ex; }
div.TOCSection { margin : 1ex 1ex 2ex 2ex; }
 
div.SectionTitle { margin-top : 6ex; font-weight : bold; font-size : 14pt; }
div.SectionBody { margin-top : 2ex; margin-left : 2ex; margin-bottom : 2em; }
 
div.SectionBody a:link { color : #002080; }
div.SectionBody a:visited { color : #002080; }
div.SectionBody a:hover { text-decoration : underline; }
 
td.ParameterName { font-size : 10pt; background-color : #e0e0e0; vertical-align : top; }
td.ParameterDesc { font-size : 10pt; background-color : #e0e0e0; text-align : left; }
</style>
</head>
<body>
<center><b>Mik's Scrolling Battle Text Readme</b></center>
<div id="HeaderBlock">
Version: 5.13<br />
Author: Mik<br />
Released: May 14, 2008<br />
Official Site: <a href="http://mikord.wowinterface.com">http://mikord.wowinterface.com</a><br /><br />
<a href="#Credits">See Credits</a>
</div>
 
<a name="TOC"><div class="TOCTitle">Table of Contents:</div></a>
<div class="TOC">
<a href="#WhatsNew">What's new?</a><br />
<a href="#Install">Installation Instructions</a><br />
<a href="#Description">Description</a><br />
<a href="#Commands">Commands</a><br />
<a href="#TriggerSystem">Trigger System Documentation</a><br />
<div id="TOCSection">
<ul style="margin-top : 1ex;">
<li><a href="#MainEvents">Trigger Main Events</a></li>
<li><a href="#TriggerExceptions">Trigger Exceptions</a></li>
</ul>
</div>
 
<a href="#SearchPatternReference">Search Pattern Reference</a><br />
<a href="#FAQ">Frequently Asked Questions</a><br />
<div id="TOCSection">
<ul style="margin-top : 1ex;">
<li><a href="#FAQ1">I don't like any of the fonts supplied with MSBT. How do I use my own fonts?</a></li>
<li><a href="#FAQ2">How do I create a new trigger?</a></li>
<li><a href="#FAQ3">How do I add my own custom sounds?</a></li>
<li><a href="#FAQ4">Is it possible to prevent Mutilate from being merged?</a></li>
<li><a href="#FAQ5">How do I suppress Vampiric Embrace?</a></li>
<li><a href="#FAQ6">I want to see skill names even when there is an icon. Is that possible?</a></li>
<li><a href="#FAQ7">Does MSBT support fonts and sounds from Shared Media?</a></li>
<li><a href="#FAQ8">Is there a way to show the damage above the target's heads like the default damage text?</a></li>
<li><a href="#FAQ9">Is MSBT efficient?</a></li>
</ul>
</div>
<a href="#VersionHistory">Version History</a><br />
<div id="TOCSection">
<ul style="margin-top : 1ex;">
<li><a href="#Verions5.12">5.12</a></li>
<li><a href="#Version5.11">5.11</a></li>
<li><a href="#Version5.1">5.1</a></li>
<li><a href="#Version5.03">5.03</a></li>
<li><a href="#Version5.02">5.02</a></li>
<li><a href="#Version5.01">5.01</a></li>
<li><a href="#Version5.0">5.0</a></li>
<li><a href="#Version4.13">4.13</a></li>
<li><a href="#Version4.12">4.12</a></li>
<li><a href="#Version4.11">4.11</a></li>
<li><a href="#Version4.1">4.1</a></li>
<li><a href="#Version4.03">4.03</a></li>
<li><a href="#Version4.02">4.02</a></li>
<li><a href="#Version4.01">4.01</a></li>
<li><a href="#Version4.0">4.0</a></li>
<li><a href="#Version3.11">3.11</a></li>
<li><a href="#Version3.1">3.1</a></li>
<li><a href="#Version3.01">3.01</a></li>
<li><a href="#Version3.0">3.0</a></li>
<li><a href="#Version2.11">2.11</a></li>
<li><a href="#Version2.1">2.1</a></li>
<li><a href="#Version2.0">2.0</a></li>
<li><a href="#Version1.03">1.03</a></li>
<li><a href="#Version1.02">1.02</a></li>
<li><a href="#Version1.01">1.01</a></li>
<li><a href="#Version1.0">1.0</a></li>
</ul>
</div>
<a href="#Credits">Credits</a><br />
 
</div>
 
<div class="SectionTitle"><a name="WhatsNew">What's New?</a></div>
<hr size="1" />
<a href="#TOC">Return to TOC</a><br /><br />
<div class="SectionBody">
<ul>
<li>The threshold based triggers such as "Low Mana" and "Low Health" will once again display the current amount.</li>
</ul>
</div>
 
<div class="SectionTitle"><a name="Install">Installation Instructions</a></div>
<hr size="1" />
<a href="#TOC">Return to TOC</a><br /><br />
<div class="SectionBody">
Unzip the contents into the AddOns directory of your WoW game directory.<br /><br />
This is typically C:\Program Files\World of Warcraft\Interface\AddOns.<br /><br />
<b>If you are upgrading the mod from a previous version, make sure to delete the old version prior to installing
the new version.</b>
</div>
 
<div class="SectionTitle"><a name="Description">Description</a></div>
<hr size="1" />
<a href="#TOC">Return to TOC</a><br /><br />
<div class="SectionBody">
MSBT is designed to be an extremely lightweight, efficient, and highly configurable mod that makes it easier to see combat
information by scrolling the information on the screen in separate, dynamically creatable scroll areas. It is a replacement
for Blizzard's Floating Combat Text and Damage output.<br /><br />
 
<b>Features:</b>
<ul>
<li>Lightweight and efficient design.</li>
<li>Scroll incoming damage/heals, outgoing damage/heals, and notifications in separate configurable scroll areas on the playing field.</li>
<li>Add triggers that will allow you to show notifications based on a variety of conditions.</li>
<li>Assign a sound file to play for events/triggers.</li>
<li>Dynamically create new scroll areas and assign any event/trigger to them.</li>
<li>Customize the position, size, animation style, enabled state, font style, font size, font outline, and opacity for each of the scroll areas.</li>
<li>Customize each individual event's color, font style, font size, font outline, opacity, output message, enabled state, and scroll area.</li>
<li>Set "Master Font" settings that will be inherited by all of the scroll areas and the events in them unless they are overridden at the scroll area or event level.</li>
<li>Merge AoE data into one event with cumulative damage/healing done with number of normal and crits specified.</li>
<li>Show overhealing amounts against yourself or party/raid members.</li>
<li>Color damage amounts according to damage type.</li>
<li>Show partial effects (resists, absorbs, vulnerabilities, etc) colored according to type.</li>
<li>Filter output information with a full suite of spam controls.</li>
<li>Load on demand options.</li>
 
<li>For mod developers:
<ul>
<li>
Output your own scrolling messages with the MikSBT.DisplayMessage function instead of having
to create your own frame and animation code. You can also use your own font by first registering
it with MSBT via the MikSBT.RegisterFont function.
</li>
<li>Create custom animation styles.</li>
<li>See the included API.html file for reference information.</li>
</ul>
</li>
</ul>
 
<br />
<b>Supported Events:</b>
<ul>
<li>Incoming:</li>
<ul>
<li>Melee Damage, Misses, Dodges, Parries, Blocks, Absorbs, and Immunes</li>
<li>Skill Damage, Damage Over Time (DoTs), Misses, Dodges, Parries, Blocks, Absorbs, Immunes, Reflects, and Interrupts</li>
<li>Spell Resists</li>
<li>Pet Melee Damage, Misses, Dodges, Parries, Blocks, Absorbs, and Immunes</li>
<li>Pet Skill Damage, Damage Over Time (DoTs), Misses, Dodges, Parries, Blocks, Absorbs, and Immunes</li>
<li>Pet Spell Resists</li>
<li>Heals and Heals Over Time (HoTs)</li>
<li>Environmental Damage</li>
</ul>
<br />
<li>Outgoing:</li>
<ul>
<li>Melee Damage, Misses, Dodges, Parries, Blocks, Absorbs, Immunes, Evades</li>
<li>Skill Damage, Damage Over Time (DoTs), Misses, Dodges, Parries, Blocks, Absorbs, Immunes, Reflects, Interrupts, and Evades</li>
<li>Spell Resists and Buff Dispels</li>
<li>Heals and Heals Over Time (HoTs)</li>
<li>Pet Melee Damage, Misses, Dodges, Parries, Blocks, Absorbs, Immunes, and Evades</li>
<li>Pet Skill Damage, Damage Over Time (DoTs), Misses, Dodges, Parries, Blocks, Absorbs, Immunes, and Evades</li>
<li>Pet Spell Resists and Buff Dispels</li>
</ul>
 
<br />
<li>Notification:</li>
<ul>
<li>Buffs / Buff Fades</li>
<li>Debuffs / Debuff Fades</li>
<li>Item Buffs / Item Buff Fades</li>
<li>Enter/Leave Combat</li>
<li>Power Gains and Losses</li>
<li>Combo Point Gains</li>
<li>Combo Points Full</li>
<li>Honor Gains</li>
<li>Reputation Gains and Losses</li>
<li>Skill Gains</li>
<li>Experience Gains</li>
<li>Killing Blows (Player and NPC)</li>
<li>Extra Attacks</li>
<li>Soul Shard Creation</li>
<li>Enemy Buff Gains</li>
<li>Monster Emotes</li>
<li>Money Gains</li>
<li>Cooldown Completions</li>
</ul>
 
<br />
<li>Default Triggers:</li>
<ul>
<li>Backlash</li>
<li>Blackout</li>
<li>Clearcasting</li>
<li>Counter Attack</li>
<li>Execute / Hammer of Wrath</li>
<li>Frostbite</li>
<li>Impact</li>
<li>Kill Command</li>
<li>Low Health</li>
<li>Low Mana</li>
<li>Low Pet Health</li>
<li>Mongoose Bite</li>
<li>Nightfall</li>
<li>Overpower</li>
<li>Rampage</li>
<li>Revenge</li>
<li>Riposte</li>
<li>Victory Rush</li>
<li>Viper Sting</li>
</ul>
</ul>
</div>
 
<div class="SectionTitle"><a name="Commands">Commands</a></div>
<hr size="1" />
<a href="#TOC">Return to TOC</a><br /><br />
<div class="SectionBody">
<table cellspacing="3">
<tr>
<td class="ParameterName">/msbt</td>
<td class="ParameterDesc">Shows the options interface.</td>
</tr>
<tr>
<td class="ParameterName">/msbt reset</td>
<td class="ParameterDesc">Resets the current profile to the default settings.</td>
</tr>
<tr>
<td class="ParameterName">/msbt disable</td>
<td class="ParameterDesc">Disables the mod.</td>
</tr>
<tr>
<td class="ParameterName">/msbt enable</td>
<td class="ParameterDesc">Enables the mod.</td>
</tr>
<tr>
<td class="ParameterName">/msbt version</td>
<td class="ParameterDesc">Shows the current version.</td>
</tr>
<tr>
<td class="ParameterName">/msbt help</td>
<td class="ParameterDesc">Shows the command usage.</td>
</tr>
</table>
</div>
 
<div class="SectionTitle"><a name="TriggerSystem">Trigger System Documentation</a></div>
<hr size="1" />
<a href="#TOC">Return to TOC</a><br /><br />
<div class="SectionBody">
The trigger system is a powerful, flexible, and efficient system that allows you to specify custom events to be displayed based on
specific game events that are not already handled by default. There are several mechanisms in place to ensure triggers are efficient as
possible so they are not needlessly wasting CPU cycles checking conditions that aren't relevant. Due to this optimization, several common
triggers are included by default.
<br /><br />
The system is based around <a href="#MainEvents">main events</a> and <a href="#TriggerExceptions">exceptions</a>. Each trigger can have
one or more <a href="#MainEvents">main events</a> each with unique conditions. After ANY (or relationship) one of the <a href="#MainEvents">main events</a>
occurs and its conditions are true, the trigger will then check the <a href="#TriggerExceptions">exceptions</a> before firing.
The trigger will NOT fire if ANY (or relationship) of the <a href="#TriggerExceptions">exceptions</a> are true.
<br /><br />
Triggers will try to choose an appropriate icon based on the <a href="#MainEvents">main event</a> that fired it.
<br /><br />
The <a href="#FAQ">Frequently Asked Questions</a> section has step-by-step instructions on the process of <a href="#FAQ2">creating a trigger</a>.
<br /><br />
The following is a description of the fields unique to the trigger system interface:
<br /><br />
<table cellspacing="3">
<tr>
<td class="ParameterName" nowrap="nowrap">Output Message:</td>
<td class="ParameterDesc">
This is the message that will be displayed when the trigger fires. As detailed in the <a href="#MainEvents">main events</a> table,
some of the <a href="#MainEvents">main events</a> return captured information that can be accessed with substitution codes of %1 or %2.
<br /><br />
In addition, most <a href="#MainEvents">main events</a> allow %n to be substituted with the name of the source of the event and %r to be
substituted with the name of the recipient of the event.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap">Trigger Classes:</td>
<td class="ParameterDesc">
This allows you to set the classes that you want the trigger to apply to. <b>NOTE: THIS IS YOUR
CLASS NOT THE TARGET CLASS.</b> You may look at the Execute trigger for an example. Since Warrior is
selected, the trigger will only apply when you are playing on a warrior.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><a href="#MainEvents">Main Events</a>:</td>
<td class="ParameterDesc">
This allows you to define which <a href="#MainEvents">main events</a> should begin the process of testing the trigger. When <b>ANY</b>
(or relationship) of these main events apply and their conditions are true, the trigger will then make sure none of the
<a href="#TriggerExceptions">exceptions</a> are true before firing.
<br /><br />
The <a href="#MainEvents">main events</a> table below details the purpose of each event along with its available conditions.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><a href="#TriggerExceptions">Trigger Exceptions</a>:</td>
<td class="ParameterDesc">
This allows you define <a href="#TriggerExceptions">exceptions</a> to prevent the trigger from firing.
<br /><br />
They are only checked if one of the <a href="#MainEvents">main events</a> and its conditions has already occurred.
<br /><br />
The <a href="#TriggerExceptions">trigger exceptions</a> table below details the purpose of each exception along with its
available conditions.
</td>
</tr>
</table>
<br /><br /><br />
<a name="MainEvents"><span style="font-weight : bold; font-size : 110%">Trigger Main Events:</span></a>
<br /><br />
<table cellspacing="3">
<tr>
<td class="ParameterName" nowrap="nowrap">Health Threshold:</td>
<td class="ParameterDesc">
Fires when a health percentage falls below or rises above the chosen threshold depending on which direction is selected.
<br /><br />
Conditions:
<ul>
<li>Affected Unit - The trigger will only fire if the threshold has been crossed for this unit.</li>
<li>Hostile Only - The affected unit must be hostile. <b>NOTE:</b> "You" can never be hostile, so don't check it in conjunction with yourself!</li>
<li>Direction - Specifies whether the trigger should fire when the health percentage falls below or rises above the threshold.</li>
<li>Threshold - The percentage that must be crossed for the trigger to fire.</li>
</ul>
Available Substitution Codes:
<ul>
<li>%1 - The actual amount of health.</li>
<li>%r - The name of the unit whose health changed.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap">Mana Threshold:</td>
<td class="ParameterDesc">
Fires when a mana percentage falls below or rises above the chosen threshold depending on which direction is selected.
<br /><br />
The conditions and available substitution codes are identical to a health threshold. See above for further details.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap">Energy Threshold:</td>
<td class="ParameterDesc">
Fires when an energy percentage falls below or rises above the chosen threshold depending on which direction is selected.
<br /><br />
The conditions and available substitution codes are identical to a health threshold. See above for further details.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap">Rage Threshold:</td>
<td class="ParameterDesc">
Fires when a rage percentage falls below or rises above the chosen threshold depending on which direction is selected.
<br /><br />
The conditions and available substitution codes are identical to a health threshold. See above for further details.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap">Crit:</td>
<td class="ParameterDesc">
Fires when an incoming or outgoing critical hit is landed.
<br /><br />
Conditions:
<ul>
<li>Direction - Specifies whether the trigger should fire on an incoming (to you) or outgoing (from you) critical hit.</li>
</ul>
Available Substitution Codes:
<ul>
<li>%1 - The name of the skill the caused the crit. <b>NOTE:</b> This will be blank when the crit was from a skill such as a regular swing.</li>
<li>%n - The name of the unit who did the crit.</li>
<li>%r - The name of the unit who was crit.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap">Block:</td>
<td class="ParameterDesc">
Fires when an incoming or outgoing attack is blocked.
<br /><br />
The conditions and available substitution codes are identical to a Crit. See above for further details.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap">Dodge:</td>
<td class="ParameterDesc">
Fires when an incoming or outgoing attack is dodged.
<br /><br />
The conditions and available substitution codes are identical to a Crit. See above for further details.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap">Parry:</td>
<td class="ParameterDesc">
Fires when an incoming or outgoing attack is parried.
<br /><br />
The conditions and available substitution codes are identical to a Crit. See above for further details.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap">Buff Application:</td>
<td class="ParameterDesc">
Fires when a buff is applied to a unit.
<br /><br />
Conditions:
<ul>
<li>Affected Unit - The trigger will only fire if the buff was applied to this unit.</li>
<li>Hostile Only - The affected unit must be hostile. <b>NOTE:</b> "You" can never be hostile, so don't check it in conjunction with yourself!</li>
<li>Skill Name - The <b>case-sensitive</b> name of the buff that trigger will fire on.</li>
<li>Amount - The application number of the buff. This is typically 1 for most buffs.</li>
</ul>
Available Substitution Codes:
<ul>
<li>%1 - The name of the buff.</li>
<li>%2 - The number of applications of the buff.</li>
<li>%r - The name of the unit who received the buff.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap">Buff Fade:</td>
<td class="ParameterDesc">
Fires when a buff fades from a unit.
<br /><br />
Conditions:
<ul>
<li>Affected Unit - The trigger will only fire if the buff faded from this unit.</li>
<li>Hostile Only - The affected unit must be hostile. <b>NOTE:</b> "You" can never be hostile, so don't check it in conjunction with yourself!</li>
<li>Skill Name - The <b>case-sensitive</b> name of the buff that trigger will fire on.</li>
</ul>
Available Substitution Codes:
<ul>
<li>%1 - The name of the buff.</li>
<li>%r - The name of the unit who the buff faded from.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap">Debuff Application:</td>
<td class="ParameterDesc">
Fires when a debuff is applied to a unit.
<br /><br />
The conditions and available substitution codes are identical to a Buff Application. See above for further details.
 
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap">Debuff Fade:</td>
<td class="ParameterDesc">
Fires when a debuff fades from a unit.
<br /><br />
The conditions and available substitution codes are identical to a Buff Fade. See above for further details.
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap">Cast Start:</td>
<td class="ParameterDesc">
Fires when a skill with a cast time has started.
<br /><br />
Conditions:
<ul>
<li>Affected Unit - The trigger will only fire if this unit started the cast.</li>
<li>Hostile Only - The affected unit must be hostile. <b>NOTE:</b> "You" can never be hostile, so don't check it in conjunction with yourself!</li>
<li>Skill Name - The <b>case-sensitive</b> name of the skill for which the cast is starting.</li>
</ul>
Available Substitution Codes:
<ul>
<li>%1 - The name of the skill for which the cast is starting.</li>
<li>%n - The name of the unit that started the cast.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap">Killing Blow:</td>
<td class="ParameterDesc">
Fires when you perform a killing blow.
<br /><br />
There are no conditions for this event.
<br /><br />
Available Substitution Codes:
<ul>
<li>%n - Your name since you are the source of the killing blow.</li>
<li>%r - The name of the unit that was killed.</li>
</ul>
</td>
</tr>
</table>
<br /><br /><br />
<a name="TriggerExceptions"><span style="font-weight : bold; font-size : 110%">Trigger Exceptions:</span></a>
<br /><br />
<table cellpacing="3">
<tr>
<td class="ParameterName" nowrap="nowrap">Buff Active:</td>
<td class="ParameterDesc">
This exception will be true if the specified buff is currently active on you.
<br /><br />
Conditions:
<ul>
<li>Skill name - The <b>case-sensitive</b> name of the buff to check.</li>
<li>Reverse Logic - Makes this exception check if a buff is currently INACTIVE on you.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap">Insufficient Power:</td>
<td class="ParameterDesc">
This exception will be true if you currently have less rage or energy than the specified amount.
<br /><br />
Conditions:
<ul>
<li>Amount - The amount of rage or energy to check.</li>
<li>Reverse Logic - Makes this exception true if you currently have MORE rage or energy than the specified amount.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap">Insufficient Combo Points:</td>
<td class="ParameterDesc">
This exception will be true if you currently have less combo points than the specified amount.
<br /><br />
Conditions:
<ul>
<li>Amount - The amount of combo points to check.</li>
<li>Reverse Logic - Makes this exception true if you currently have MORE combo points than the specified amount.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap">Not In Arena:</td>
<td class="ParameterDesc">
This exception will be true if you currently not in the arena.
<br /><br />
Conditions:
<ul>
<li>Amount - The amount of rage or energy to check.</li>
<li>Reverse Logic - Makes this exception true if you ARE currently in the arena.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap">Not In PvP Zone:</td>
<td class="ParameterDesc">
This exception will be true if you currently not in a PvP Zone which includes all battlegrounds and the arena.
<br /><br />
Conditions:
<ul>
<li>Amount - The amount of rage or energy to check.</li>
<li>Reverse Logic - Makes this exception true if you ARE currently in a PvP Zone.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap">Trigger Recently Fired:</td>
<td class="ParameterDesc">
This exception will be true if the trigger has been fired within the last number of seconds specified.
<br /><br />
Conditions:
<ul>
<li>Amount - The number of seconds to test.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap">Skill Unavailable:</td>
<td class="ParameterDesc">
This exception will be true if the specified skill is not known or is on cooldown. It does not cover other
facets such as necessary reagents, appropriate range, etc.
<br /><br />
Conditions:
<ul>
<li>Skill Name - The <b>case-sensitive</b> name of the skill to check.</li>
<li>Reverse Logic - Makes this exception true if the specified skill IS known or on cooldown.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap">Trivial Target:</td>
<td class="ParameterDesc">
This exception will be true if the current target is trivial. A trivial unit is a unit that a grey to you and does
not yield experience.
<br /><br />
Conditions:
<ul>
<li>Reverse Logic - Makes this exception true if the current target is NOT trivial.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap">Warrior Stance:</td>
<td class="ParameterDesc">
This exception will be true if you are playing a warrior and the current stance is the specified stance.
<br /><br />
Conditions:
<ul>
<li>Warrior Stance - The stance to check.</li>
<li>Reverse Logic - Makes this exception true if the current stance is NOT the selected stance.</li>
</ul>
</td>
</tr>
</table>
</div>
 
<div class="SectionTitle"><a name="SearchPatternReference">Search Pattern Reference</a></div>
<hr size="1" />
<a href="#TOC">Return to TOC</a><br /><br />
<div class="SectionBody">
Here is the official lua reference for patterns:
<blockquote>
<span style="font-weight : bold; font-size : 110%">Character Class:</span>
<br /><br />
 
A <i>character class</i> is used to represent a set of characters. The following combinations are allowed in describing a character class:
<ul>
 
<li>x: (where x is not one of the magic characters ^$()%.[]*+-?) represents the character x itself.</li>
<li>.: (a dot) represents all characters.</li>
<li>%a: represents all letters.</li>
<li>%c: represents all control characters.</li>
<li>%d: represents all digits.</li>
<li>%l: represents all lowercase letters.</li>
 
<li>%p: represents all punctuation characters.</li>
<li>%s: represents all space characters.</li>
<li>%u: represents all uppercase letters.</li>
<li>%w: represents all alphanumeric characters.</li>
<li>%x: represents all hexadecimal digits.</li>
<li>%z: represents the character with representation 0.</li>
 
<li>
%x: (where x is any non-alphanumeric character) represents the character x. This is the standard way to escape the magic characters. Any punctuation character (even the non magic)
can be preceded by a '%' when used to represent itself in a pattern.
</li>
<li>
[set]: represents the class which is the union of all characters in set. A range of characters may be specified by separating the end characters of the range with a '-'. All classes
%x described above may also be used as components in set. All other characters in set represent themselves. For example, [%w_] (or [_%w]) represents all alphanumeric characters plus
the underscore, [0-7] represents the octal digits, and [0-7%l%-] represents the octal digits plus the lowercase letters plus the '-' character.
<br /><br />
The interaction between ranges and classes is not defined. Therefore, patterns like [%a-z] or [a-%%] have no meaning.
</li>
<br />
<li>[^set]: represents the complement of set, where set is interpreted as above.</li>
 
</ul>
For all classes represented by single letters (%a, %c, etc.), the corresponding uppercase letter represents the complement of the class. For instance, %S represents all non-space characters.
<br /><br />
The definitions of letter, space, and other character groups depend on the current locale. In particular, the class [a-z] may not be equivalent to %l.
<br /><br />
 
<span style="font-weight : bold; font-size : 110%">Pattern Item:</span>
<br /><br />
 
A pattern item may be:
<ul>
<li>a single character class, which matches any single character in the class;</li>
 
<li>a single character class followed by '*', which matches 0 or more repetitions of characters in the class. These repetition items will always match the longest possible sequence;</li>
<li>a single character class followed by '+', which matches 1 or more repetitions of characters in the class. These repetition items will always match the longest possible sequence;</li>
<li>a single character class followed by '-', which also matches 0 or more repetitions of characters in the class. Unlike '*', these repetition items will always match the shortest possible sequence;</li>
<li>a single character class followed by '?', which matches 0 or 1 occurrence of a character in the class;</li>
<li>%n, for n between 1 and 9; such item matches a substring equal to the n-th captured string (see below);</li>
<li>
 
%bxy, where x and y are two distinct characters; such item matches strings that start with x, end with y, and where the x and y are balanced. This means that, if one reads the string from left to right,
counting +1 for an x and -1 for a y, the ending y is the first y where the count reaches 0. For instance, the item %b() matches expressions with balanced parentheses.
</li>
</ul>
 
<span style="font-weight : bold; font-size : 110%">Pattern:</span>
<br /><br />
A <i>pattern</i> is a sequence of pattern items. A '^' at the beginning of a pattern anchors the match at the beginning of the subject string. A '$' at the end of a pattern anchors the match at the end of the subject string.
At other positions, '^' and '$' have no special meaning and represent themselves.
<br /><br />
 
<span style="font-weight : bold; font-size : 110%">Captures:</span>
<br /><br />
A pattern may contain sub-patterns enclosed in parentheses; they describe captures. When a match succeeds, the substrings of the subject string that match captures are stored (captured) for future use. Captures are numbered
according to their left parentheses. For instance, in the pattern "(a*(.)%w(%s*))", the part of the string matching "a*(.)%w(%s*)" is stored as the first capture (and therefore has number 1); the character matching "." is
captured with number 2, and the part matching "%s*" has number 3.
<br /><br />
 
As a special case, the empty capture () captures the current string position (a number). For instance, if we apply the pattern "()aa()" on the string "flaaap", there will be two captures: 3 and 5.
</blockquote>
</div>
 
<div class="SectionTitle"><a name="FAQ">Frequently Asked Questions</a></div>
<hr size="1" />
<a href="#TOC">Return to TOC</a><br /><br />
<div class="SectionBody">
<ol>
<li>
<a name="FAQ1"><b>I don't like any of the fonts supplied with MSBT. How do I use my own fonts?</b></a>
<br /><br />
 
<span style="color : red;">WARNING: ALL FONT MODIFICATION WILL REQUIRE THAT YOU COMPLETELY QUIT THE GAME AND RESTART IT.
RELOADING THE CONSOLE ALONE WILL NOT WORK.</span>
<br /><br />
 
NOTE: Keep in mind that if you use your own font files that you need to make sure the font
supports the characters that will be displayed. For example the typical way to display buff
gains is [BuffName]. If the font you use does not have a character glyph for the [ or ]
characters you will likely see a big ugly block (or nothing at all) instead of the intended characters. This is
especially important with non-English clients since a lot of characters aren't supported by
English fonts.
<br /><br />
 
There are a few ways to use custom fonts:
<ul>
<li>
The first, and easiest, method is to simply replace one of the font files in the
MikScrollingBattleText\Fonts directory with the truetype font (.ttf) that you want. The drawback
to this approach is that the mod's option screen will still reference the font with the old font's name.
<br /><br />
 
For example, if you had a truetype font file "MyUberFont.ttf" you wanted to use. Rename MyUberFont.ttf to Adventure.ttf
and replace the Adventure.ttf font file in the MikScrollingBattleText\Fonts directory. In the MSBT options interface
it would still be called "Adventure," but it would actually be using the new font.
</li>
<br /><br />
<li>
The second method is to open the file MSBTFonts.lua in the MikScrollingBattleText directory and find the
FONT_FILES entry. Add your font with the appropriate name and path following the same pattern as the other
entries. One thing to keep in mind with this approach is that due to the way WoW loads its data, I would
suggest you put the new fonts you want to add in the same place as the current fonts for the mod (MikScrollingBattleText\Fonts)
to avoid problems with loading.
</li>
<br /><br />
<li>
The third method is aimed more at mod developers that want to display information using MSBT. You can call the MikSBT.RegisterFont
function to register a custom font that you may then specify in your call to MikSBT.DisplayMessage. See the included API.html file
for reference information.
</li>
</ul>
</li>
<br /><br /><br />
 
 
<li>
<a name="FAQ2"><b>How do I create a new trigger?</b></a>
<br /><br />
The first step is to <b>read</b> the <a href="#TriggerSystem">Trigger System Documentation</a> section above.
Every event and exception is explained along with the conditions and available substitution codes.
<br /><br />
Once you've read that section, we can continue on to the process for creating triggers.
<br /><br />
We will be creating a trigger that notifies us when Polymorph breaks from a hostile unit when we are playing on a mage in the arena.
<br /><br />
<ol type="a">
<li>Since a new trigger is being created, click the Add New Trigger button, enter "Poly Broke - %r!" for the output message, and click Okay.</li>
 
<li>Click the trigger conditions icon button (the gear) next to the newly added trigger at the bottom of the list.</li>
<li>
Click the edit Trigger Classes icon button and uncheck "All" classes. Check Mage for the class the trigger will apply to.
It is better to select the specific classes the trigger applies to instead of selecting all classes since by specifying
classes, the mod can completely ignore the trigger and save resources for the classes to which it does not apply.
</li>
<li>Click the Add Event button next to the Main Events label to add a new main event.</li>
<li>Select Debuff Fade for the Main Event.</li>
<li>Select Any for the Affected Unit.</li>
<li>Check the Hostile Only checkbox because we don't want to see when poly fades from our teammates.</li>
<li>Enter Polymorph for the Skill Name. It is case-sensitive, so make sure you use a capital P.</li>
<li>Click the Save button to save the new main event and its conditions.</li>
<li>Click the Add Exception button next to the Trigger Exceptions label to add a new exception.</li>
<li>Select Not In Arena for the Exception. This makes it so the trigger will not fire when we aren't in the arena.</li>
<li>Click the Save button to save the new exception.</li>
<li>Click the Save button on the trigger frame to save the trigger's new conditions.</li>
</ol>
<br /><br />
The %r used in step a is a substitution code for the name of the unit that the debuff (polymorph in this case) faded from.
You already knew that though because you read the <a href="#TriggerSystem">Trigger System Documentation</a>!
<br /><br />
The color, font settings, sticky state, sound, and output scroll area for the trigger can be set like any other event.
</li>
<br /><br />
 
<li>
<a name="FAQ3"><b>How do I add my own custom sounds?</b></a>
<br /><br />
<span style="color : red;">WARNING: NEW SOUND FILES WILL REQUIRE THAT YOU COMPLETELY QUIT THE GAME AND RESTART IT BEFORE
THEY WILL BE PLAYED. RELOADING THE CONSOLE ALONE WILL NOT WORK.</span>
<br /><br />
 
There are a few methods that can be used to add custom sounds.
<ul>
<li>
The first, and easiest, method is to simply place a .wav file or .mp3 file in the MikScrollingBattleText\Sounds folder
<b>before</b> you start World of Warcraft. You may now click the event settings icon for any event/trigger and then click
the icon next to the sound dropdown. Enter the name of the file you placed in the folder.
</li>
<br /><br />
<li>
The second method is to open the file MSBTSounds.lua in the MikScrollingBattleText directory and find the SOUND_FILES entry.
Add your sound with the appropriate name and path following the same pattern as the other entries. One thing to keep in
mind with this approach is that due to the way WoW loads its data, I would suggest you put the new sounds you want to add in
the same place as the current sounds for the mod (MikScrollingBattleText\Sounds) to avoid problems with loading.
</li>
<br /><br />
<li>
The third method is aimed more at mod developers. You can call the MikSBT.RegisterSound function to register a custom
sound. See the included API.html file for reference information.
</li>
</ul>
</li>
<br /><br />
 
<li>
<a name="FAQ4"><b>Is it possible to prevent Mutilate from being merged?</b></a>
<br /><br />
Yes. Add it to the merge exclusions list under the Spam Controls tab in the options interface.
</li>
<br /><br />
 
<li>
<a name="FAQ5"><b>How do I suppress Vampiric Embrace?</b></a>
<br /><br />
This can be accomplished a couple of different ways.
<br /><br />
 
<ul>
<li>The preferred method is to add it to the skill suppressions list under the Spam Controls tab.</li>
<br /><br />
<li>
Another way is to use the heal threshold slider under the Spam Controls tab.<br />
The drawback to this approach is that all heals under the specified value will be suppressed and not
specifically Vampiric Embrace, which may or may not be your desired behavior.
</li>
</ul>
</li>
<br /><br />
 
<li>
<a name="FAQ6"><b>I want to see skill names even when there is an icon. Is that possible?</b></a>
<br /><br />
Yes. Uncheck "Exclusive Skill Names" under the Skill Icons tab.
</li>
<br /><br />
 
<li>
<a name="FAQ7"><b>Does MSBT support fonts and sounds from Shared Media?</b></a>
<br /><br />
Not directly, but you can download MSBTSharedMedia to add support for it.
</li>
<br /><br />
 
<li>
<a name="FAQ8"><b>Is there a way to show the damage above the target's heads like the default damage text?</b></a>
<br /><br />
The only way this is possible is using the built-in game damage. The "Game Damage" option on the General tab will reenable
it, but keep in mind you will lose all customization capabilities for outgoing damage if you choose to use the game's built-in damage.
WoW's API does not provide a method to get the position of 3D game objects such as players and mobs. This is intentional on their
part and will likely never change.
<br /><br />
I do not recommend using the built-in game damage option. If you take the time to get used to having the damage in a consolidated area,
you will likely find it superior in many ways. Aside from the obvious visual customization capabilities of using MSBT's damage display,
there are many other benefits such as being able to see the damage and healing being done to targets that are not in your viewport, merging
of AoE with cumulative amounts, throttling of DoT spam, damage thresholds, per skill suppressions for things you don't care about, icons
annotating which skill caused the damage or healing, and more.
</li>
<br /><br />
 
<li>
<a name="FAQ9"><b>Is MSBT efficient?</b></a>
<br /><br />
Absolutely. MSBT 5.0 was completely re-designed from the ground up using Blizzard's new mod statistics
API tools with the #1 priority of optimization for reduced memory usage and CPU efficiency. As a result,
it is both lightweight (low memory usage) and efficient (low CPU usage), which, sadly, is frequently ignored
in performance discussions. Performance entails both memory usage and CPU usage. Unless you don't have enough
RAM available, CPU usage is almost always more of a factor on your FPS than raw memory usage is.
<br /><br />
Please don't just take my word for it though. Test it out for yourself. Blizzard has made it simple to see
statistics about mod usage with the GetAddOnMemoryUsage and GetAddOnCPUUsage API calls. Testing a mod will
give you a true picture of its performance.
<br /><br />
 
One thing to keep in mind during your testing is that MSBT is written to be completely dynamic. It will only create exactly what
objects it needs when it needs them and then reuse them from that point forward. This means during the first few combat cycles
you will see a slightly higher increasing rate than you might expect as the first set of objects is created. The rate will quickly
stabilize to typically less than 1 KiB/s as the objects begin to be reused. The main benefits to this approach are less overall memory
usage and very little memory churn.
<br /><br />
 
Also, don't forget to look at CPU utilization. As I said above, it is frequently ignored, but it is also important. Would you
rather have your CPU spending extra time on the game engine, or wasting cycles on an inefficient mod?
</li>
</ol>
</div>
 
<div class="SectionTitle"><a name="VersionHistory">Version History</a></div>
<hr size="1" />
<a href="#TOC">Return to TOC</a><br /><br />
<div class="SectionBody">
<table cellspacing="3">
<tr>
<td class="ParameterName" nowrap="nowrap"><a name="Version5.12">5.12</a></td>
<td class="ParameterDesc">
<ul>
<li>Fixed the error when looting money induced in patch 2.4.2.</li>
<li>Fixed the erroneous "Low Mana" warnings when in druid forms.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><a name="Version5.11">5.11</a></td>
<td class="ParameterDesc">
<ul>
<li>Redesigned the trigger system to work with the new combat log mechanics and improve flexibility:
<ul>
<li>
The old main conditions have been replaced with main events that can have several conditions for greater control
over things such as affected units (target, focus, etc), applications, etc.
</li>
<li>
The old secondary conditions has been replaced with exceptions. Exceptions will cause the trigger not to fire when
they are true. In addition, most exceptions has a "reverse logic" option that causes them to behave as their opposite for
high flexibility.
</li>
<li>
Triggers now try to choose an appropriate icon based on the main event that fired it. It is still possible
to specify an icon that will override the default.
</li>
<li>All of the default triggers will now work on non-English clients without the need for localization.</li>
<li>Any additional triggers you may have created in previous versions will have to be recreated under the new system.</li>
<li>Added a default trigger for Viper Sting.</li>
<li>Added the default clearcasting trigger to druids.</li>
</ul>
</li>
<br />
<li>Skills like "Mangle (Bear)()" will now be displayed as "Mangle" in the cooldown area.</li>
<li>Animations may now be as slow as 20% of normal instead of the previous 50%.</li>
<li>Scroll areas can now have a minimum height of 50 down from 100.</li>
<li>Increased the allowed font size range to 4-38.</li>
<li>Threshold triggers will no longer misfire when shapeshifting.</li>
<li>Soul Shard gains will now be displayed again.</li>
<li>The %t event type will no longer throw an error.</li>
<li>Added a button to the AddOns tab of Blizzard's Interface Options to launch MSBT's options.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><a name="Version5.1">5.1</a></td>
<td class="ParameterDesc">
<ul>
<li>The optional icons module is no longer required. This is a significant memory savings for those previously using the module.</li>
<li>Unfortunately, the ability to add and customize triggers is disabled for this release while the system is rewritten.</li>
<li>
Rewrote the parser to work with the new combat log mechanics implemented in Patch 2.4. Since
manually parsing text strings is no longer required, things like pets with the same name as
party/raid members will no longer cause confusion. There also should no longer be problems with
non-English clients that had strange parsing issues due to ambiguous strings.
</li>
<li>Load up memory usage is now around 221 KiB.</li>
<li>Damage from spell reflects will now be shown to the player who reflected it as if they did the damage.</li>
<li>The horizontal animation style now has an alternating direction option.</li>
<li>Added new events for outgoing (offensive) player and pet dispels.</li>
<li>Internal filtering for identical monster emotes has been added to reduce potential spam.</li>
<li>Only one five combo point notification will now be shown per combo point cycle.</li>
<li>Overhealing will now show on heals that have been excluded from merging.</li>
<li>Fixed an issue regarding cooldowns not being displayed for certain skills like Mangle (Bear).</li>
<li>Added Simplified Chinese localization. Thanks to elafor and hscui for their work.</li>
<li>Updated TOC for Patch 2.4.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><a name="Version5.03">5.03</a></td>
<td class="ParameterDesc">
<ul>
<li>
Updated LibStub in MSBTIcons to resolve incompatibilities with a newer library version.
This should clear up some issues with other mod compatibility.
</li>
<li>Made icons for triggers obey the enable/disable skill icons option.</li>
<li>Updated for Patch 2.3.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><a name="Version5.02">5.02</a></td>
<td class="ParameterDesc">
<ul>
<li>Modified the sound system to allow custom registrations for easier sound selection.</li>
<li>Triggers may now specify a skill name to use for displaying an icon.</li>
<li>Added suitable icons to most of the default triggers.</li>
<li>Added parsing for mana gains from sources like Mana Spring totems now that they can be suppressed, if desired.</li>
<li>Mana gains during Innervate are now shown if the "Hyper Regen" option is set.</li>
<li>Damage from totems and other miscellaneous "pets" will now be displayed.</li>
<li>Changed the minimum scroll area width to 10.</li>
<li>Fixed a problem that was causing all periodic enemy heals and power gains to be shown instead of only buff gains.</li>
<li>Fixed an issue where delayed cooldowns such as combustion were completing before they should.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><a name="Version5.01">5.01</a></td>
<td class="ParameterDesc">
<ul>
<li>DoTs and HoTs may now have independent throttle times.</li>
<li>Power gains can now be throttled and there is a default Vampiric Touch throttle entry.</li>
<li>Power gains now have icons when possible.</li>
<li>Added a "Move All" button to the Events tab to allow the whole category to be moved to a new scroll area quickly.</li>
<li>Added some logic to counteract ill behaved mods such as Recount and SW_Stats modifying global strings.</li>
<li>Fixed some issues with the options interface not saving certain fields properly.</li>
<li>Made search pattern triggers also check secondary conditions to match the behavior of the other condition types.</li>
<li>Updated the MSBTIcons module .toc file to prevent certain cases where it wasn't being loaded in the correct order (Thanks dylanm).</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><a name="Version5.0">5.0</a></td>
<td class="ParameterDesc">
<ul>
<li>
Complete code rewrite to further reduce memory usage and CPU utilization. Blizzard's addition
of memory and CPU tracking tools to the API were used to help achieve this. The CPU utilization
is about 55% less, and the load up memory usage is now around 258 KiB.
</li>
<li>
Redesigned the profile system to use a full master/diff approach. This leads to a substantial
memory savings when using multiple profiles. It also adds the benefit of allowing future changes
to defaults to take place without having to completely reset user profiles.
</li>
<li>
The options interface was streamlined and rewritten using pure lua. All the tabs and popup
frames are now dynamically created only when needed. The options are still load on demand
and use no resources when not loaded.
</li>
<li>Created a new set of spam controls:
<ul>
<li>Show ALL power gains <span style="color:red;">WARNING: This can and will spam you!</span></li>
<li>Show hyper regen (mana gains during Evocation and Spirit Tap)</li>
<li>Thresholds for Healing, Damage, and Power Gains</li>
<li>Skill name substitution</li>
<li>Skill suppression (e.g. Vampiric Embrace)</li>
<li>Skill abbreviation option with new %sl event code to override at the event level</li>
<li>Independent throttle times per skill</li>
<li>Merge exclusion list (e.g. avoid merging mutilate)</li>
</ul>
</li>
<li>
New font opacity setting that follows the same inheritance mechanics as the other font
settings, so each individual scroll area and event can have a custom opacity.
</li>
<li>
Added some "high level" controls to the options interface such as a "Toggle All" button to quickly toggle
the enable state of all events in the selected category. This allows you to disable all incoming pet events
with one click for example. Another example is a "Disable Skill Names" checkbox which quickly allows you
to stop all skill names from being displayed without having to modify every single event and remove the %s.
</li>
<li>Added built-in customizable cooldown notifications.</li>
<li>Crits are now separate events so they can be individually controlled.</li>
<li>Each scroll area may now have its own independent animation speed.</li>
<li>Scroll areas now have a customizable width that the animation styles obey when it makes sense.</li>
<li>New horizontal and static animation styles.</li>
<li>Created a new default scroll area using the new static animation style.</li>
<li>Implemented behaviors in the animation system which allow more customization of animation styles.</li>
<li>Added a new selectable behavior (Normal) to the Pow sticky animation style that will not perform the jiggle effect.</li>
<li>Added enemy buff gain and monster emote events (spell alert).</li>
<li>New money gains notification event.</li>
<li>There is now a full set of incoming pet events.</li>
<li>Added outgoing pet DoTs.</li>
<li>Every event can now be assigned a custom sound. (e.g. full combo points)</li>
<li>Several trigger conditions such as Self Buff Gains can now have multiple entries per trigger.</li>
<li>Added a debuff application number secondary trigger condition.</li>
<li>Added a spell usable secondary trigger condition.</li>
<li>Added several new fonts.</li>
<li>Added an optional skill icons module.</li>
<li>Made some minor tweaks to the default display and throttle settings to improve readability.</li>
<li>Fixed a few parsing issues.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><a name="Version4.13">4.13</a></td>
<td class="ParameterDesc">
<ul>
<li>Added temporary fix for PlaySoundFile() bug in Patch 2.2.2.</li>
<li>Updated for Patch 2.2.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><a name="Version4.12">4.12</a></td>
<td class="ParameterDesc">
<ul>
<li>Added the option to disable/enable Blizzard's new built-in healing display above the target's head.</li>
<li>Updated for Patch 2.1.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><a name="Version4.11">4.11</a></td>
<td class="ParameterDesc">
<ul>
<li>Fixed the issue where crits were being improperly displayed on some non-English clients.</li>
<li>Modified the outgoing crit/block/dodge/parry trigger conditions to only apply to the player and not any pets.</li>
<li>Added a "Trigger Cooldown" secondary condition.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><a name="Version4.1">4.1</a></td>
<td class="ParameterDesc">
<ul>
<li>Rewrote the trigger system to allow for multiple conditions while maintaining efficiency. In addition several commonly requested triggers were added.</li>
<li>Triggers may now have a custom sound assigned to them.</li>
<li>Added parsing for some new TBC patterns that will fix a few issues where certain events were not showing up.</li>
<li>Made several parsing optimizations.</li>
<li>Created an event for incoming and outgoing Spell Interrupts.</li>
<li>Added Shadowmend to the list of throttled HoTs.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><a name="Version4.03">4.03</a></td>
<td class="ParameterDesc">
<ul>
<li>Recharacterized some damage based spells into DoTs so they will now follow the throttling mechanics.</li>
<li>Added damage types to environmental damage so it will now have the damage type colors applied.</li>
<li>Updated for Patch 2.0.3 / Burning Crusade.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><a name="Version4.02">4.02</a></td>
<td class="ParameterDesc">
<ul>
<li>
Fixed parsing order error with Foreign languages which resolves a lot of issues on foreign clients with substitution codes
showing up instead of the actual data.
</li>
<li>The soul shard notification event should now work again.</li>
<li>The mana gained form the warlock Dark Pact talent will now be displayed.</li>
<li>
Recharacterized healing from some damage based spells (most notably Vampiric Embrace) into HoTs so they
will now follow the throttling mechanics. Basically this means those spells should no longer spam you with healing
if you have HoT and DoT throttling enabled (it's on by default).
</li>
<li>Added parsing for damage taken from the tornado in the arenas.</li>
<li>Added French localization.</li>
<li>Added more German localization.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><a name="Version4.01">4.01</a></td>
<td class="ParameterDesc">
<ul>
<li>Fixed the problem induced by the 2.0 patch where wand damage was not showing up.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><a name="Version4.0">4.0</a></td>
<td class="ParameterDesc">
<ul>
<li>Complete code rewrite for even better performance and features.</li>
<li>
Major Optimizations:
<ul>
<li>
Rewrote the combat parsing engine to significantly increase performance and lower the memory footprint.
</li>
<li>
Redesigned the suppression system to use a hash table searching algorithm so that any number of suppressions may be added without any appreciable slowdown.
</li>
<li>
Optimized the default profile handling. Due to the large number of options, the default
profile table takes up a decent chunk of memory (around 90 KiB). In the previous versions, the
table was always memory resident - even when it wasn't needed. It is now created dynamically
only when it's needed, which is the first time you load a new version of the mod or reset a profile
to its defaults.
</li>
<li>
Redesigned the underlying options tables such that shared information amongst the events is
only stored once instead of separately for each event. This saves quite a bit of memory,
especially when there are multiple profiles.
</li>
<li>
Created a single pool of dynamically created font strings to be shared by the various scroll areas.
Previously a set number of font strings were created for every scroll area.
</li>
<li>Load up memory usage is now around 450 KiB.</li>
</ul>
</li>
<br />
 
<li>
Minor Optimizations:
<ul>
<li>
Trigger system will no longer listen for events that there are no triggers for. Previously it received the same events the mod was already
parsing and ignored the ones with no triggers.
</li>
<li>Reduced the amount of information that needs to be passed around to lower memory usage during operation.</li>
</ul>
</li>
<br />
 
<li>
Rewrote the animation code to work using scaled timing. Previously the animation was created by moving the text a set
amount of pixels each update. This had the effect of causing the animation speed to vary greatly depending on system performance.
The animations should now keep the same speed regardless of large performance hits, such as those incurred while recording a
video or during extreme lag.
</li>
<li>Each character will now load the last selected profile for that character by default.</li>
<li>
Changed the default font to Porky, which has glyphs for most common German, French, and Spanish special characters. In addition, most of the fonts were
replaced with new versions that support them as well. However, the old Adventure font is still available for those who want to use it.
</li>
<li>
Added an option (enabled by default) to throttle DoTs and HoTs so that only one event for each ability will be displayed within the time period
specified (2.5 seconds by default). Any additional DoT/HoT abilities that occur while being throttled are merged into one event to be shown once the throttle
period has passed. This will reduce the spam when you have HoTs and/or DoTs on multiple targets.
</li>
<li>Made scroll areas dynamically creatable and made events/triggers assignable to them.</li>
<li>
Ability/Spell damage amounts now use a custom color according to their damage type by default. The rest of the message will still show up with the event's selected color.
This behavior can be disabled.
</li>
<li>Partial effects (absorbs, resists, glancing, crushing, overheals, etc) can now be individually enabled, disabled, and color coded.</li>
<li>Separated Debuff and Item Buff Fades from Buff Fades into new notification events. Totem buffs are now also handled as buff gains and fades.</li>
<li>Added an Extra Attacks notification event which will give notifications for Windfury, Thrash, Sword Spec, etc.</li>
<li>Added a Soul Shard Created notification event.</li>
<li>Overhauled the interface to include the new features.</li>
<li>Added a font registration function so other mod developers can choose to display their custom messages in their own font.</li>
<li>Added an animation style registration function so other mod developers can easily provide custom animation styles for MSBT.</li>
<li>
Provided an additional file named API.html that is a reference for the publicly accessible functions that
other mod developers can use to display messages through MSBT and register custom animation styles.
</li>
</ul>
 
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><a name="Version3.11">3.11</a></td>
<td class="ParameterDesc">
<ul>
<li>
Fixed the bug where in certain circumstances the trigger interface would give an error
when trying to setup a new search pattern trigger.
</li>
<li>Made newly created triggers inherit all font settings instead of specifying a font size by default.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><a name="Version3.1">3.1</a></td>
<td class="ParameterDesc">
<ul>
<li>Added support for power gains to yourself from other people.</li>
<li>
Increased the number of available event types for the trigger system to allow for greater
flexibility. Due to the way the trigger system is designed this will not add much overhead since
triggers are only parsed against the selected event types.
</li>
<li>Alphabetized the list of available trigger events to make finding the one you want easier.</li>
<li>
Removed the default Blessing/Judgement of Wisdom suppression. The user can choose to add one in for it
if they prefer.
</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><a name="Version3.01">3.01</a></td>
<td class="ParameterDesc">
<ul>
<li>Fixed the bug where you could only add one suppression and adding a new one was overwriting it.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><a name="Version3.0">3.0</a></td>
<td class="ParameterDesc">
<ul>
<li>Implemented a low overhead trigger system. <a href="#TriggerSystem">See documentation above</a>.</li>
<li>Implemented a suppression system that allows you to suppress particular messages you don't want to see.</li>
<li>
Made significant changes to the scroll area settings interface. The new interface shows all three
scroll areas at the same time. Each scroll area is now titled with its coordinates and there are
editboxes to enter specific coordinates in addition to being able to drag the scroll areas around.
</li>
<li>
Changed the core animation routines to use function pointers in order to eliminate the need for a
ton of conditional testing. Previously, every time the animation routine was called (typically
60-70 times per second for every scrolling item), the animation style and scroll direction were
checked to calculate how to move the text. Now those items are only checked during the initial
animation object setup phase. This should help performance on slower PCs.
</li>
<li>Added the command "/msbt search pattern" to enable an event searching mode which helps identify event types used in the trigger system. See documentation above for more info.</li>
<li>
Moved the Low Health, Low Mana, and Execute events into the trigger system. Due to this change
the Low Mana and Execute triggers will no longer waste resources checking on classes that don't
use mana or have an execute ability. Also moving them into the trigger system made the thresholds
at which to show the Low Health, and Low Mana warnings selectable.
</li>
<li>Made a few minor code performance tweaks to the animation setup "pipeline."</li>
<li>Added Killing Blow notification events for both players and NPCs.</li>
<li>Added crushing and glancing hit partial effects.</li>
<li>The font settings frame can now be moved.</li>
<li>Fixed a bug where messages added via the MikSBT.DisplayMessage function were being shown even if the scroll area was set to not show messages.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><a name="Version2.11">2.11</a></td>
<td class="ParameterDesc">
<ul>
<li>Disabled Blizzard's new floating text in Patch 1.12 when MSBT is enabled.</li>
<li>Updated for Patch 1.12.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><a name="Version2.1">2.1</a></td>
<td class="ParameterDesc">
<ul>
<li>Reduced memory usage a little by removing the underlying tables used to store crit information for events that can never be crits. (Down to around 477 KiB)</li>
<li>To go along with the above change, the font settings interface for events was reworked so that you can no longer set crit information for events that don't support them.</li>
<li>Added a title at the top of the font settings frame to help distinguish what is being modified.</li>
<li>Added an Experience Gains notification event.</li>
<li>Added the capability for notifications to be displayed "sticky" style.</li>
<li>Fixed the bug induced by patch 1.11 where reputation gains and losses weren't being displayed.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><a name="Version2.0">2.0</a></td>
<td class="ParameterDesc">
<ul>
<li>
MAJOR optimization code rewrite:
<ul>
<li>Made options load on demand to significantly reduce memory usage and start up time.</li>
<li>
Implemented a table recycling system to reuse tables created during combat instead
of creating new ones and allowing them to be garbage collected. The net effect is that a
ton of garbage collection churn has been eliminated. Thanks go to kergoth and Wobin for
tips on how to achieve this.
</li>
<li>The combat event parser has been changed to reuse one single table for storing the results of the parsed data.</li>
<li>Streamlined the combat event to screen animation "pipeline."</li>
<li>Namespaced all code to reduce global namespace pollution.</li>
<li>
Load up KiB Usage in v1.03 was approximately 1050 KiB. This has been reduced to around
488 KiB. In addition, due to the table recycling system, memory usage during operation is
much more consistent instead of continuously increasing until the next garbage collection
cycle.
</li>
</ul>
</li>
<br />
<li>
Added a function to allow messages to be easily displayed through MSBT from external sources.<br />
This function is MikSBT.DisplayMessage and is detailed in the included API.html file.
</li>
<li>Added the command "/msbt stats" to report statistics about the table recycling system.</li>
<li>Changed the functionality of AoE merges so that the name reported is "Multiple" instead of the last affected unit.</li>
<li>Added the option to disable "game damage" instead of just always doing it.</li>
<li>Added the option to disable "sticky crits."</li>
<li>Added Execute/Hammer of Wrath notification event.</li>
<li>Separated Heals over time (HoTs) and Damage over time (DoTs) into their own events.</li>
<li>Added the option to display overhealing.</li>
<li>Fixed a bug where crits were not being recognized in non-English clients.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><a name="Version1.03">1.03</a></td>
<td class="ParameterDesc">
<ul>
<li>Fixed a bug where options set with a checkbox were not being properly saved on logout.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><a name="Version1.02">1.02</a></td>
<td class="ParameterDesc">
<ul>
<li>Fixed a bug where the global string parser wasn't appropriately accounting for the argument order of non-English clients.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><a name="Version1.01">1.01</a></td>
<td class="ParameterDesc">
<ul>
<li>Updated for Patch 1.11.</li>
</ul>
</td>
</tr>
<tr>
<td class="ParameterName" nowrap="nowrap"><a name="Version1.0">1.0</a></td>
<td class="ParameterDesc">
<ul>
<li>Initial version.</li>
</ul>
</td>
</tr>
</table>
</div>
 
<div class="SectionTitle"><a name="Credits">Credits</a></div>
<hr size="1" />
<a href="#TOC">Return to TOC</a><br /><br />
<div class="SectionBody">
Thanks to:
<ul>
<li>Grayhoof, the author of SCT, for the original mod which inspired this mod.</li>
<li>Kergoth and Wobin for their suggestions on optimizations via reduced GC churn and namespacing tips.</li>
<li>Farook for the German localizations.</li>
<li>Calthas for the French localizations.</li>
<li>Hscui and Netcookies for the Simplified Chinese localizations.</li>
</ul>
</div>
</body>
</html>
\ No newline at end of file
MSBT5_13/MikScrollingBattleText/MSBTParser.lua New file
0,0 → 1,1031
-------------------------------------------------------------------------------
-- Title: Mik's Scrolling Battle Text Parser
-- Author: Mik
-------------------------------------------------------------------------------
 
-- Create module and set its name.
local module = {};
local moduleName = "Parser";
MikSBT[moduleName] = module;
 
 
-------------------------------------------------------------------------------
-- Constants.
-------------------------------------------------------------------------------
 
-- Bit flags.
local AFFILIATION_MINE = 0x00000001;
local AFFILIATION_PARTY = 0X00000002;
local AFFILIATION_RAID = 0X00000004;
local AFFILIATION_OUTSIDER = 0X00000008;
local REACTION_FRIENDLY = 0x00000010;
local REACTION_NEUTRAL = 0x00000020;
local REACTION_HOSTILE = 0x00000040;
local CONTROL_HUMAN = 0x00000100;
local CONTROL_SERVER = 0x00000200;
local UNITTYPE_PLAYER = 0x00000400;
local UNITTYPE_NPC = 0x00000800;
local UNITTYPE_PET = 0x00001000;
local UNITTYPE_GUARDIAN = 0x00002000;
local UNITTYPE_OBJECT = 0x00004000;
local TARGET_TARGET = 0x00010000;
local TARGET_FOCUS = 0x00020000;
local OBJECT_NONE = 0x80000000;
 
-- Value when there is no GUID.
local GUID_NONE = "0x0000000000000000";
 
-- The maximum number of buffs and debuffs that can be on a unit.
local MAX_BUFFS = 16;
local MAX_DEBUFFS = 40;
 
-- Aura types.
local AURA_TYPE_BUFF = "BUFF";
local AURA_TYPE_DEBUFF = "DEBUFF";
 
-- Update timings.
local UNIT_MAP_UPDATE_DELAY = 0.2;
local PET_UPDATE_DELAY = 1;
local REFLECT_HOLD_TIME = 3;
 
-- Commonly used flag combinations.
local FLAGS_ME = bit.bor(AFFILIATION_MINE, REACTION_FRIENDLY, CONTROL_HUMAN, UNITTYPE_PLAYER);
local FLAGS_MY_GUARDIAN = bit.bor(AFFILIATION_MINE, REACTION_FRIENDLY, CONTROL_HUMAN, UNITTYPE_GUARDIAN);
 
 
-------------------------------------------------------------------------------
-- Private variables.
-------------------------------------------------------------------------------
 
-- Dynamically created frames for receiving events and tooltip info.
local eventFrame;
 
-- Name and GUID of the player.
local playerName;
local playerGUID;
 
-- Used for timing between updates.
local lastUnitMapUpdate = 0;
local lastPetMapUpdate = 0;
 
-- Whether or not values that need to be updated after a delay are stale.
local isUnitMapStale;
local isPetMapStale;
 
-- Map of names to unit ids.
local unitMap = {};
local petMap = {};
 
-- Information about buffs and debuffs.
local recentAuras = {};
local currentAuras = {buffs = {}, debuffs = {}};
local savedAuras = {buffs = {}, debuffs = {}};
local aurasInitialized;
 
-- Map of data to capture and set for combat log events.
local captureMaps;
 
-- Events to parse even if the source or recipient is not the player or pet.
local fullParseEvents;
 
-- Information about global strings for CHAT_MSG_X events.
local searchMap;
local searchCaptureMaps;
local rareWords = {};
local searchPatterns = {};
local captureOrders = {};
 
-- Captured and parsed event data.
local captureTable = {};
local parserEvent = {};
 
-- List of functions to call when an event occurs.
local handlers = {};
 
-- Holds information about reflected skills to track how much was reflected.
local reflectedSkills = {};
local reflectedTimes = {};
 
 
-------------------------------------------------------------------------------
-- Imports.
-------------------------------------------------------------------------------
 
-- Local references to certain functions for faster access.
local string_find = string.find;
local string_gmatch = string.gmatch;
local string_gsub = string.gsub;
local string_len = string.len;
local bit_band = bit.band;
local Print = MikSBT.Print;
local EraseTable = MikSBT.EraseTable;
 
 
-------------------------------------------------------------------------------
-- Utility functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Registers a function to be called when an event occurs.
-- ****************************************************************************
local function RegisterHandler(handler)
handlers[handler] = true;
end
 
-- ****************************************************************************
-- Unregisters a previously registered function.
-- ****************************************************************************
local function UnregisterHandler(handler)
handlers[handler] = nil;
end
 
 
-- ****************************************************************************
-- Tests if any of the bits in the passed testFlags are set in the unit flags.
-- ****************************************************************************
local function TestFlagsAny(unitFlags, testFlags)
if (bit_band(unitFlags, testFlags) > 0) then return true; end
end
 
 
-- ****************************************************************************
-- Tests if all of the passed testFlags are set in the unit flags.
-- ****************************************************************************
local function TestFlagsAll(unitFlags, testFlags)
if (bit_band(unitFlags, testFlags) == testFlags) then return true; end
end
 
 
-- ****************************************************************************
-- Sends the parser event to the registered handlers.
-- ****************************************************************************
local function SendParserEvent()
for handler in pairs(handlers) do
local success, ret = pcall(handler, parserEvent);
if (not success) then geterrorhandler()(ret); end
end
end
 
 
-- ****************************************************************************
-- Compares two global strings so the most specific one comes first. This
-- prevents incorrectly capturing information for certain events.
-- ****************************************************************************
local function GlobalStringCompareFunc(globalStringNameOne, globalStringNameTwo)
-- Get the global string for the passed names.
local globalStringOne = _G[globalStringNameOne];
local globalStringTwo = _G[globalStringNameTwo];
 
local gsOneStripped = string_gsub(globalStringOne, "%%%d?%$?[sd]", "");
local gsTwoStripped = string_gsub(globalStringTwo, "%%%d?%$?[sd]", "");
 
-- Check if the stripped global strings are the same length.
if (string_len(gsOneStripped) == string_len(gsTwoStripped)) then
-- Count the number of captures in each string.
local numCapturesOne = 0;
for _ in string_gmatch(globalStringOne, "%%%d?%$?[sd]") do
numCapturesOne = numCapturesOne + 1;
end
 
local numCapturesTwo = 0;
for _ in string_gmatch(globalStringTwo, "%%%d?%$?[sd]") do
numCapturesTwo = numCapturesTwo + 1;
end
 
-- Return the global string with the least captures.
return numCapturesOne < numCapturesTwo;
 
else
-- Return the longest global string.
return string_len(gsOneStripped) > string_len(gsTwoStripped);
end
end
 
 
-- ****************************************************************************
-- Converts the passed global string into a lua search pattern with a capture
-- order table and stores the results so any requests to convert the same
-- global string will just return the cached one.
-- ****************************************************************************
local function ConvertGlobalString(globalStringName)
-- Don't do anything if the passed global string does not exist.
local globalString = _G[globalStringName];
if (globalString == nil) then return; end
 
-- Return the cached conversion if it has already been converted.
if (searchPatterns[globalStringName]) then
return searchPatterns[globalStringName], captureOrders[globalStringName];
end
 
-- Hold the capture order.
local captureOrder;
local numCaptures = 0;
 
-- Escape lua magic chars.
local searchPattern = string.gsub(globalString, "([%^%(%)%.%[%]%*%+%-%?])", "%%%1");
 
-- Loop through each capture and setup the capture order.
for captureIndex in string_gmatch(searchPattern, "%%(%d)%$[sd]") do
if (not captureOrder) then captureOrder = {}; end
numCaptures = numCaptures + 1;
captureOrder[tonumber(captureIndex)] = numCaptures;
end
 
-- Convert %1$s / %s to (.+) and %1$d / %d to (%d+).
searchPattern = string.gsub(searchPattern, "%%%d?%$?s", "(.+)");
searchPattern = string.gsub(searchPattern, "%%%d?%$?d", "(%%d+)");
 
-- Escape any remaining $ chars.
searchPattern = string.gsub(searchPattern, "%$", "%%$");
 
-- Cache the converted pattern and capture order.
searchPatterns[globalStringName] = searchPattern;
captureOrders[globalStringName] = captureOrder;
 
-- Return the converted global string.
return searchPattern, captureOrder;
end
 
 
-- ****************************************************************************
-- Fills in the capture table with the captured data if a match is found.
-- ****************************************************************************
local function CaptureData(matchStart, matchEnd, c1, c2, c3, c4, c5, c6, c7, c8, c9)
-- Check if a match was found.
if (matchStart) then
captureTable[1] = c1;
captureTable[2] = c2;
captureTable[3] = c3;
captureTable[4] = c4;
captureTable[5] = c5;
captureTable[6] = c6;
captureTable[7] = c7;
captureTable[8] = c8;
captureTable[9] = c9;
 
-- Return the last position of the match.
return matchEnd;
end
 
-- Don't return anything since no match was found.
return nil;
end
 
 
-- ****************************************************************************
-- Reorders the capture table according to the passed capture order.
-- ****************************************************************************
local function ReorderCaptures(capOrder)
local t = captureTable;
 
t[1], t[2], t[3], t[4], t[5], t[6], t[7], t[8], t[9] =
t[capOrder[1]], t[capOrder[2]], t[capOrder[3]], t[capOrder[4]], t[capOrder[5]], t[capOrder[6]],
t[capOrder[7]], t[capOrder[8]], t[capOrder[9]];
end
 
 
-- ****************************************************************************
-- Parses the CHAT_MSG_X search style events.
-- ****************************************************************************
local function ParseSearchMessage(event, combatMessage)
-- Leave if there is no map of global strings to search for the event.
if (not searchMap[event]) then return; end
 
-- Loop through all of the global strings to search for the event.
for _, globalStringName in pairs(searchMap[event]) do
-- Make sure the capture map for the global string exists.
local captureMap = searchCaptureMaps[globalStringName];
if (captureMap) then
-- First, check if there is a rare word for the global string and it is in the combat
-- message since a plain text search is faster than doing a full regular expression search.
if (not rareWords[globalStringName] or string_find(combatMessage, rareWords[globalStringName], 1, true)) then
-- Get capture data.
local matchEnd = CaptureData(string_find(combatMessage, searchPatterns[globalStringName]));
 
 
-- Check if a match was found.
if (matchEnd) then
-- Check if there is a capture order for the global string and reorder the data accordingly.
if (captureOrders[globalStringName]) then ReorderCaptures(captureOrders[globalStringName]); end
 
-- Erase the parser event table..
for key in pairs(parserEvent) do parserEvent[key] = nil; end
 
-- Populate fields that exist for all events.
parserEvent.sourceGUID = GUID_NONE;
parserEvent.sourceFlags = OBJECT_NONE;
parserEvent.recipientGUID = playerGUID;
parserEvent.recipientName = playerName;
parserEvent.recipientFlags = FLAGS_ME;
parserEvent.recipientUnit = "player";
 
-- Map the captured arguments into the parser event table.
for argumentNum, fieldName in ipairs(captureMap) do
parserEvent[fieldName] = captureTable[argumentNum];
end
 
-- Copy any additional fields from the capture map into the parser event table.
for fieldName, fieldValue in pairs(captureMap) do
if(type(fieldName) == "string") then parserEvent[fieldName] = fieldValue; end
end
 
-- Send the event.
SendParserEvent();
return;
end -- Match found.
end -- Fast plain search.
end -- Capture map is valid.
end -- Loop through global strings to search.
end
 
 
-- ****************************************************************************
-- Parses the parameter style events going to the combat log.
-- ****************************************************************************
local function ParseLogMessage(timestamp, event, sourceGUID, sourceName, sourceFlags, recipientGUID, recipientName, recipientFlags, ...)
-- Make sure the capture map for the event exists.
local captureMap = captureMaps[event];
if (not captureMap) then return; end
 
-- Look for spells the player reflected and make the damage belong to the player.
if (sourceGUID == recipientGUID and reflectedTimes[recipientGUID] and event == "SPELL_DAMAGE") then
local skillID = ...;
if (skillID == reflectedSkills[recipientGUID]) then
-- Clear the reflected skill entries.
reflectedTimes[recipientGUID] = nil;
reflectedSkills[recipientGUID] = nil;
 
-- Change the source to the player.
sourceGUID = playerGUID;
sourceName = playerName;
sourceFlags = FLAGS_ME;
end
end
 
-- Attempt to figure out the source and recipient unitIDs.
local sourceUnit = unitMap[sourceGUID] or petMap[sourceGUID];
local recipientUnit = unitMap[recipientGUID] or petMap[recipientGUID];
 
-- Treat player guardians like pets.
if (not sourceUnit and TestFlagsAll(sourceFlags, FLAGS_MY_GUARDIAN)) then sourceUnit = "pet"; end
if (not recipientUnit and TestFlagsAll(recipientFlags, FLAGS_MY_GUARDIAN)) then recipientUnit = "pet"; end
 
-- Ignore the event if it is not one that should be fully parsed and it doesn't pertain to the player
-- or pet. This is done to avoid wasting time parsing events that won't be used like damage that other
-- players are doing.
if (not fullParseEvents[event] and sourceUnit ~= "player" and sourceUnit ~= "pet" and
recipientUnit ~= "player" and recipientUnit ~= "pet") then
return;
end
 
-- Erase the parser event table.
for k in pairs(parserEvent) do parserEvent[k] = nil; end
 
-- Populate fields that exist for all events.
parserEvent.sourceGUID = sourceGUID;
parserEvent.sourceName = sourceName;
parserEvent.sourceFlags = sourceFlags;
parserEvent.recipientGUID = recipientGUID;
parserEvent.recipientName = recipientName;
parserEvent.recipientFlags = recipientFlags;
parserEvent.sourceUnit = sourceUnit;
parserEvent.recipientUnit = recipientUnit;
 
 
-- Map the local arguments into the parser event table.
for argumentNum, fieldName in ipairs(captureMap) do
parserEvent[fieldName] = select(argumentNum, ...);
end
 
-- Copy any additional fields from the capture map into the parser event table.
for fieldName, fieldValue in pairs(captureMap) do
if(type(fieldName) == "string") then parserEvent[fieldName] = fieldValue; end
end
 
-- Add new auras parsed from the combat log to a list of recent auras so they are not
-- duplicated by the aura change event.
local eventType = parserEvent.eventType;
if (eventType == "aura" and recipientUnit == "player") then
local skillName = parserEvent.skillName;
if (skillName) then recentAuras[skillName] = true; end
 
-- Calculate the overhealing on the healed unit if unit is in the party/raid.
elseif (eventType == "heal" and recipientUnit) then
-- Get the unit ID of the recipient.
local healthMissing = UnitHealthMax(recipientUnit) - UnitHealth(recipientUnit);
local overhealAmount = parserEvent.amount - healthMissing;
 
-- Populate the overheal amount if any occurred.
if (overhealAmount > 0) then parserEvent.overhealAmount = overhealAmount; end
 
-- Track reflected skills.
elseif (eventType == "miss" and parserEvent.missType == "REFLECT" and recipientUnit == "player") then
-- Clean up old entries.
for guid, reflectTime in pairs(reflectedTimes) do
if (timestamp - reflectTime > REFLECT_HOLD_TIME) then
reflectedTimes[guid] = nil;
reflectedSkills[guid] = nil;
end
end
 
-- Save the time of the reflect and the reflected skillID.
reflectedTimes[sourceGUID] = timestamp;
reflectedSkills[sourceGUID] = parserEvent.skillID;
 
-- Ignore the reflect until the amount can be obtained.
return;
end
 
-- Send the event.
SendParserEvent();
end
 
 
-------------------------------------------------------------------------------
-- Startup utility functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Creates a list of events that will be fully parsed even if they event
-- doesn't pertain to the player or player's pet.
-- ****************************************************************************
local function CreateFullParseList()
fullParseEvents = {
SPELL_AURA_APPLIED = true,
SPELL_AURA_REMOVED = true,
SPELL_AURA_APPLIED_DOSE = true,
SPELL_AURA_REMOVED_DOSE = true,
SPELL_CAST_START = true,
};
end
 
 
-- ****************************************************************************
-- Creates a map of global strings to search for CHAT_MSG_X events.
-- ****************************************************************************
local function CreateSearchMap()
searchMap = {
-- Honor Gains.
CHAT_MSG_COMBAT_HONOR_GAIN = {"COMBATLOG_HONORGAIN", "COMBATLOG_HONORAWARD"},
 
-- Reputation Gains/Losses.
CHAT_MSG_COMBAT_FACTION_CHANGE = {"FACTION_STANDING_INCREASED", "FACTION_STANDING_DECREASED"},
 
-- Skill Gains.
CHAT_MSG_SKILL = {"SKILL_RANK_UP"},
 
-- Experience Gains.
CHAT_MSG_COMBAT_XP_GAIN = {"COMBATLOG_XPGAIN_FIRSTPERSON", "COMBATLOG_XPGAIN_FIRSTPERSON_UNNAMED"},
 
-- Looted Items.
CHAT_MSG_LOOT = {
"LOOT_ITEM_CREATED_SELF_MULTIPLE", "LOOT_ITEM_CREATED_SELF", "LOOT_ITEM_PUSHED_SELF_MULTIPLE",
"LOOT_ITEM_PUSHED_SELF", "LOOT_ITEM_SELF_MULTIPLE", "LOOT_ITEM_SELF"
},
 
-- Money.
CHAT_MSG_MONEY = {"YOU_LOOT_MONEY", "LOOT_MONEY_SPLIT"},
};
 
 
-- Loop through each of the events.
for event, map in pairs(searchMap) do
-- Remove invalid global strings.
for i = #map, 1, -1 do
if (not _G[map[i]]) then table.remove(map, i); end
end
 
-- Sort the global strings from most to least specific.
table.sort(map, GlobalStringCompareFunc);
end
end
 
 
-- ****************************************************************************
-- Creates a map of data to capture for supported global strings.
-- ****************************************************************************
local function CreateSearchCaptureMaps()
searchCaptureMaps = {
-- Honor events.
COMBATLOG_HONORAWARD = {eventType = "honor", "amount"},
COMBATLOG_HONORGAIN = {eventType = "honor", "sourceName", "sourceRank", "amount"},
 
-- Experience events.
COMBATLOG_XPGAIN_FIRSTPERSON = {eventType = "experience", "sourceName", "amount"},
COMBATLOG_XPGAIN_FIRSTPERSON_UNNAMED = {eventType = "experience", "amount"},
 
-- Reputation events.
FACTION_STANDING_DECREASED = {eventType = "reputation", isLoss = true, "factionName", "amount"},
FACTION_STANDING_INCREASED = {eventType = "reputation", "factionName", "amount"},
 
-- Proficiency events.
SKILL_RANK_UP = {eventType = "proficiency", "skillName", "amount"},
 
-- Loot events.
LOOT_ITEM_CREATED_SELF = {eventType = "loot", "itemLink", "amount"},
LOOT_MONEY_SPLIT = {eventType = "loot", isMoney = true, "moneyString"},
};
 
searchCaptureMaps["LOOT_ITEM_CREATED_SELF_MULTIPLE"] = searchCaptureMaps["LOOT_ITEM_CREATED_SELF"];
searchCaptureMaps["LOOT_ITEM_PUSHED_SELF"] = searchCaptureMaps["LOOT_ITEM_CREATED_SELF"];
searchCaptureMaps["LOOT_ITEM_PUSHED_SELF_MULTIPLE"] = searchCaptureMaps["LOOT_ITEM_CREATED_SELF"];
searchCaptureMaps["LOOT_ITEM_SELF"] = searchCaptureMaps["LOOT_ITEM_CREATED_SELF"];
searchCaptureMaps["LOOT_ITEM_SELF_MULTIPLE"] = searchCaptureMaps["LOOT_ITEM_CREATED_SELF"];
searchCaptureMaps["YOU_LOOT_MONEY"] = searchCaptureMaps["LOOT_MONEY_SPLIT"];
 
-- Print an error message for each global string that isn't found and remove it from the map.
for globalStringName in pairs(searchCaptureMaps) do
if (not _G[globalStringName]) then
Print("Unable to find global string: " .. globalStringName, 1, 0, 0);
searchCaptureMaps[globalStringName] = nil;
end
end
end
 
 
-- ****************************************************************************
-- Finds the rarest word for each global string.
-- ****************************************************************************
local function FindRareWords()
-- Hold the number of times each word appears in all the global strings.
local wordCounts = {};
 
-- Loop through all of the supported global strings.
for globalStringName in pairs(searchCaptureMaps) do
-- Strip out all of the formatting codes.
local strippedGS = string.gsub(_G[globalStringName], "%%%d?%$?[sd]", "");
 
-- Count how many times each word appears in the global string.
for word in string_gmatch(strippedGS, "%w+") do
wordCounts[word] = (wordCounts[word] or 0) + 1;
end
end
 
 
-- Loop through all of the supported global strings.
for globalStringName in pairs(searchCaptureMaps) do
local leastSeen, rarestWord;
 
-- Strip out all of the formatting codes.
local strippedGS = string.gsub(_G[globalStringName], "%%%d?%$?[sd]", "");
 
-- Find the rarest word in the global string.
for word in string_gmatch(strippedGS, "%w+") do
if (not leastSeen or wordCounts[word] < leastSeen) then
leastSeen = wordCounts[word];
rarestWord = word;
end
end
 
-- Set the rarest word.
rareWords[globalStringName] = rarestWord;
end
end
 
 
-- ****************************************************************************
-- Validates rare words to make sure there are no oddities caused by various
-- languages.
-- ****************************************************************************
local function ValidateRareWords()
-- Loop through all of the global strings there is a rare word entry for.
for globalStringName, rareWord in pairs(rareWords) do
-- Remove the entry if the rare word isn't found in the associated global string.
if (not string_find(_G[globalStringName], rareWord, 1, true)) then
rareWords[globalStringName] = nil;
end
end
end
 
 
-- ****************************************************************************
-- Converts all of the supported global strings.
-- ****************************************************************************
local function ConvertGlobalStrings()
-- Loop through all of the global string capture maps.
for globalStringName in pairs(searchCaptureMaps) do
-- Get the global string converted to a lua search pattern and prepend an anchor to
-- speed up searching.
searchPatterns[globalStringName] = "^" .. ConvertGlobalString(globalStringName);
end
end
 
 
-- ****************************************************************************
-- Creates a map of fields to capture for each combat log event.
-- ****************************************************************************
local function CreateCaptureMaps()
captureMaps = {
-- Damage events.
SWING_DAMAGE = {eventType = "damage", "amount", "damageType", "resistAmount", "blockAmount", "absorbAmount", "isCrit", "isGlancing", "isCrushing"},
RANGE_DAMAGE = {eventType = "damage", isRange = true, "skillID", "skillName", "skillSchool", "amount", "damageType", "resistAmount", "blockAmount", "absorbAmount", "isCrit", "isGlancing", "isCrushing"},
SPELL_DAMAGE = {eventType = "damage", "skillID", "skillName", "skillSchool", "amount", "damageType", "resistAmount", "blockAmount", "absorbAmount", "isCrit", "isGlancing", "isCrushing"},
SPELL_PERIODIC_DAMAGE = {eventType = "damage", isDoT = true, "skillID", "skillName", "skillSchool", "amount", "damageType", "resistAmount", "blockAmount", "absorbAmount", "isCrit", "isGlancing", "isCrushing"},
DAMAGE_SPLIT = {eventType = "damage", "skillID", "skillName", "skillSchool", "amount", "damageType", "resistAmount", "blockAmount", "absorbAmount", "isCrit", "isGlancing", "isCrushing"},
DAMAGE_SHIELD = {eventType = "damage", isDamageShield = true, "skillID", "skillName", "skillSchool", "amount", "damageType", "resistAmount", "blockAmount", "absorbAmount", "isCrit", "isGlancing", "isCrushing"},
 
-- Miss events.
SWING_MISSED = {eventType = "miss", "missType"},
RANGE_MISSED = {eventType = "miss", isRange = true, "skillID", "skillName", "skillSchool", "missType"},
SPELL_MISSED = {eventType = "miss", "skillID", "skillName", "skillSchool", "missType"},
SPELL_DISPEL_FAILED = {eventType = "miss", missType = "RESIST", "skillID", "skillName", "skillSchool", "extraSkillID", "extraSkillName", "extraSkillSchool"},
DAMAGE_SHIELD_MISS = {eventType = "miss", isDamageShield = true, "skillID", "skillName", "skillSchool", "missType"},
 
-- Heal events.
SPELL_HEAL = {eventType = "heal", "skillID", "skillName", "skillSchool", "amount", "isCrit"},
SPELL_PERIODIC_HEAL = {eventType = "heal", isHoT = true, "skillID", "skillName", "skillSchool", "amount", "isCrit"},
 
-- Environmental events.
ENVIRONMENTAL_DAMAGE = {eventType = "environmental", "hazardType", "amount", "damageType", "resistAmount", "blockAmount", "absorbAmount", "isCrit", "isGlancing", "isCrushing"},
 
-- Power events.
SPELL_ENERGIZE = {eventType = "power", isGain = true, "skillID", "skillName", "skillSchool", "amount", "powerType"},
SPELL_DRAIN = {eventType = "power", isDrain = true, "skillID", "skillName", "skillSchool", "amount", "powerType", "extraAmount"},
SPELL_LEECH = {eventType = "power", isLeech = true, "skillID", "skillName", "skillSchool", "amount", "powerType", "extraAmount"},
 
-- Interrupt events.
SPELL_INTERRUPT = {eventType = "interrupt", "skillID", "skillName", "skillSchool", "extraSkillID", "extraSkillName", "extraSkillSchool"},
 
-- Aura events.
SPELL_AURA_APPLIED = {eventType = "aura", "skillID", "skillName", "skillSchool", "auraType", "amount"},
SPELL_AURA_REMOVED = {eventType = "aura", isFade = true, "skillID", "skillName", "skillSchool", "auraType", "amount"},
 
-- Enchant events.
ENCHANT_APPLIED = {eventType = "enchant", "skillName", "itemID", "itemName"},
ENCHANT_REMOVED = {eventType = "enchant", isFade = true, "skillName", "itemID", "itemName"},
 
-- Dispel events.
SPELL_AURA_DISPELLED = {eventType = "dispel", "skillID", "skillName", "skillSchool", "extraSkillID", "extraSkillName", "extraSkillSchool", "auraType"},
 
-- Cast events.
SPELL_CAST_START = {eventType = "cast", "skillID", "skillName", "skillSchool"},
 
-- Kill events.
PARTY_KILL = {eventType = "kill"},
 
-- Extra Attack events.
SPELL_EXTRA_ATTACKS = {eventType = "extraattacks", "skillID", "skillName", "skillSchool", "amount"},
};
 
captureMaps["SPELL_PERIODIC_MISSED"] = captureMaps["SPELL_MISSED"];
captureMaps["SPELL_PERIODIC_ENERGIZE"] = captureMaps["SPELL_ENERGIZE"];
captureMaps["SPELL_PERIODIC_DRAIN"] = captureMaps["SPELL_DRAIN"];
captureMaps["SPELL_PERIODIC_LEECH"] = captureMaps["SPELL_LEECH"];
captureMaps["SPELL_AURA_STOLEN"] = captureMaps["SPELL_AURA_DISPELLED"];
captureMaps["SPELL_AURA_APPLIED_DOSE"] = captureMaps["SPELL_AURA_APPLIED"];
captureMaps["SPELL_AURA_REMOVED_DOSE"] = captureMaps["SPELL_AURA_REMOVED"];
end
 
 
-------------------------------------------------------------------------------
-- Aura functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Populates the current auras table with current buff and debuff information.
-- ****************************************************************************
local function PopulateCurrentBuffsAndDebuffs()
-- Erase the old current aura buffs and debuffs.
EraseTable(currentAuras.buffs);
EraseTable(currentAuras.debuffs);
 
-- Loop through all of the buffs and add the name to the buffs table.
local buffName, buffTexture;
for buffIndex = 1, MAX_BUFFS do
buffName, _, buffTexture = UnitBuff("player", buffIndex);
if (not buffName) then break; end
currentAuras.buffs[buffName] = buffTexture;
end
 
-- Loop through all of the debuffs and add the name to the debuffs table.
for buffIndex = 1, MAX_DEBUFFS do
buffName, _, buffTexture = UnitDebuff("player", buffIndex);
if (not buffName) then break; end
currentAuras.debuffs[buffName] = buffTexture;
end
end
 
 
-- ****************************************************************************
-- Populates the parser event data table for an aura change or the passed type.
-- ****************************************************************************
local function DoAuraChange(tableName, auraType)
-- Loop through all of the saved auras for the passed buff table to check for those that have faded.
for buffName, buffTexture in pairs(savedAuras[tableName]) do
if (not currentAuras[tableName][buffName]) then
savedAuras[tableName][buffName] = nil;
-- Ignore the fade if it was already seen via the combat log.
if (not recentAuras[buffName]) then
EraseTable(parserEvent);
parserEvent.sourceGUID = GUID_NONE;
parserEvent.sourceFlags = OBJECT_NONE;
parserEvent.recipientName = playerName;
parserEvent.recipientFlags = FLAGS_ME;
parserEvent.recipientUnit = "player";
parserEvent.eventType = "aura";
parserEvent.isFade = true;
parserEvent.auraType = auraType;
parserEvent.skillName = buffName;
parserEvent.skillTexture = buffTexture;
SendParserEvent();
end
recentAuras[buffName] = nil;
end
end
 
-- Loop through all of the current auras for the passed buff table to check for those that have been gained.
for buffName, buffTexture in pairs(currentAuras[tableName]) do
if (not savedAuras[tableName][buffName]) then
savedAuras[tableName][buffName] = buffTexture;
-- Ignore the gain if it was already seen via the combat log.
if (not recentAuras[buffName]) then
EraseTable(parserEvent);
parserEvent.sourceGUID = GUID_NONE;
parserEvent.sourceFlags = OBJECT_NONE;
parserEvent.recipientName = playerName;
parserEvent.recipientFlags = FLAGS_ME;
parserEvent.recipientUnit = "player";
parserEvent.eventType = "aura";
parserEvent.auraType = auraType;
parserEvent.skillName = buffName;
parserEvent.skillTexture = buffTexture;
SendParserEvent();
end
end
end
end
 
 
-- ****************************************************************************
-- Initializes the current auras.
-- ****************************************************************************
local function InitAuras()
-- Populate the current buffs and debuffs.
PopulateCurrentBuffsAndDebuffs();
 
-- Save the current auras as the initial state.
for tableName in pairs(currentAuras) do
for buffName, buffTexture in pairs(currentAuras[tableName]) do
savedAuras[tableName][buffName] = buffTexture;
end
end
 
-- Set the auras initialized flag.
aurasInitialized = true;
end
 
 
-------------------------------------------------------------------------------
-- Event handlers.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Called when there is information that needs to be obtained after a delay.
-- ****************************************************************************
local function OnUpdateDelayedInfo(this, elapsed)
-- Check if the unit map needs to be updated after a delay.
if (isUnitMapStale) then
-- Increment the amount of time passed since the last update.
lastUnitMapUpdate = lastUnitMapUpdate + elapsed;
 
-- Check if it's time for an update.
if (lastUnitMapUpdate >= UNIT_MAP_UPDATE_DELAY) then
-- Update the player GUID if it isn't known yet and verify it's now known.
if (not playerGUID) then playerGUID = UnitGUID("player"); end
if (playerGUID) then
-- Erase the unit map table.
for key in pairs(unitMap) do unitMap[key] = nil; end
 
-- Check if there are raid members.
local numRaidMembers = GetNumRaidMembers();
if (numRaidMembers > 0) then
-- Loop through all of the raid members and add them.
for i = 1, numRaidMembers do
local unitID = "raid" .. i;
unitMap[UnitGUID(unitID)] = unitID;
end
else
-- Loop through all of the party members and add them.
for i = 1, GetNumPartyMembers() do
local unitID = "party" .. i;
unitMap[UnitGUID(unitID)] = unitID;
end
end
 
-- Add the player.
unitMap[playerGUID] = "player";
 
-- Clear the unit map stale flag.
isUnitMapStale = false;
end
 
-- Reset the time since last update.
lastUnitMapUpdate = 0;
end
end -- Unit map is stale.
 
-- Check if the pet map needs to be updated after a delay.
if (isPetMapStale) then
-- Increment the amount of time passed since the last update.
lastPetMapUpdate = lastPetMapUpdate + elapsed;
 
-- Check if it's time for an update.
if (lastPetMapUpdate >= PET_UPDATE_DELAY) then
-- Verify the player's pet is not in an unknown state if there is one.
local petName = UnitName("pet");
if (not petName or petName ~= UNKNOWN) then
-- Erase the pet map table.
for key in pairs(petMap) do petMap[key] = nil; end
 
-- Check if there are raid members.
local numRaidMembers = GetNumRaidMembers();
if (numRaidMembers > 0) then
-- Loop through all of the raid members and add their pets.
for i = 1, numRaidMembers do
local unitID = "raidpet" .. i;
if (UnitExists(unitID)) then petMap[UnitGUID(unitID)] = unitID; end
end
else
-- Loop through all of the party members and add them.
for i = 1, GetNumPartyMembers() do
local unitID = "partypet" .. i;
if (UnitExists(unitID)) then petMap[UnitGUID(unitID)] = unitID; end
end
end
 
-- Add the player's pet if there is one.
if (petName) then petMap[UnitGUID("pet")] = "pet"; end
 
-- Clear the pet map stale flag.
isPetMapStale = false;
end -- Pet in known state.
 
-- Reset the time since last update.
lastPetMapUpdate = 0;
end
end -- Pet map is stale.
 
-- Stop receiving updates if no more data needs to be updated.
if (not isUnitMapStale and not isPetMapStale) then this:Hide(); end
end
 
 
-- ****************************************************************************
-- Called when the events the parser registered for occur.
-- ****************************************************************************
local function OnEvent(this, event, arg1, arg2, ...)
if (event == "COMBAT_LOG_EVENT_UNFILTERED") then
ParseLogMessage(arg1, arg2, ...);
elseif (event == "PLAYER_AURAS_CHANGED") then
-- Initialize the auras if they haven't already been.
if (not aurasInitialized) then
InitAuras();
return;
end
 
-- Populate the current buffs and debuffs.
PopulateCurrentBuffsAndDebuffs();
 
-- Send events for buff and debuff changes.
DoAuraChange("buffs", AURA_TYPE_BUFF);
DoAuraChange("debuffs", AURA_TYPE_DEBUFF);
 
-- Party/Raid changes
elseif (event == "PARTY_MEMBERS_CHANGED" or event == "RAID_ROSTER_UPDATE") then
-- Set the unit map stale flag and schedule the unit map to be updated after a short delay.
isUnitMapStale = true;
eventFrame:Show();
 
-- Pet changes
elseif (event == "UNIT_PET") then
isPetMapStale = true;
eventFrame:Show();
 
-- Chat message combat events.
else
ParseSearchMessage(event, arg1);
end
end
 
 
-- ****************************************************************************
-- Enables parsing.
-- ****************************************************************************
local function Enable()
-- Register for parameter style events going to the combat log.
eventFrame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED");
 
-- Register CHAT_MSG_X search style events.
for event in pairs(searchMap) do
eventFrame:RegisterEvent(event);
end
 
-- Register additional events for aura and overheal processing.
eventFrame:RegisterEvent("PLAYER_AURAS_CHANGED");
eventFrame:RegisterEvent("PARTY_MEMBERS_CHANGED");
eventFrame:RegisterEvent("RAID_ROSTER_UPDATE");
eventFrame:RegisterEvent("UNIT_PET");
 
-- Update the unit map and current pet information.
isUnitMapStale = true;
isPetNameStale = true;
 
-- Start receiving updates.
eventFrame:Show();
end
 
 
-- ****************************************************************************
-- Disables the parsing.
-- ****************************************************************************
local function Disable()
-- Stop receiving updates.
eventFrame:Hide();
eventFrame:UnregisterAllEvents();
 
-- Erase the saved and recent aura tables.
EraseTable(recentAuras);
EraseTable(savedAuras.buffs);
EraseTable(savedAuras.debuffs)
aurasInitialized = nil;
 
-- Erase the reflected skill tables.
EraseTable(reflectedTimes);
EraseTable(reflectedSkills);
end
 
 
-- ****************************************************************************
-- Called when the parser is loaded.
-- ****************************************************************************
local function OnLoad()
-- Create a frame to receive events.
eventFrame = CreateFrame("Frame");
eventFrame:Hide();
eventFrame:SetScript("OnEvent", OnEvent);
eventFrame:SetScript("OnUpdate", OnUpdateDelayedInfo);
 
-- Get the name and GUID of the player.
playerName = UnitName("player");
playerGUID = UnitGUID("player");
 
-- Create various maps.
CreateSearchMap();
CreateSearchCaptureMaps();
CreateCaptureMaps();
 
-- Create the list of events that should be fully parsed.
CreateFullParseList();
 
-- Find the rarest word for each supported global string.
FindRareWords();
ValidateRareWords();
 
-- Convert the supported global strings into lua search patterns.
ConvertGlobalStrings();
end
 
 
 
 
-------------------------------------------------------------------------------
-- Module interface.
-------------------------------------------------------------------------------
 
-- Protected Constants.
module.AFFILIATION_MINE = AFFILIATION_MINE;
module.AFFILIATION_PARTY = AFFILIATION_PARTY;
module.AFFILIATION_RAID = AFFILIATION_RAID;
module.AFFILIATION_OUTSIDER = AFFILIATION_OUTSIDER;
module.REACTION_FRIENDLY = REACTION_FRIENDLY;
module.REACTION_NEUTRAL = REACTION_NEUTRAL;
module.REACTION_HOSTILE = REACTION_HOSTILE;
module.CONTROL_HUMAN = CONTROL_HUMAN;
module.CONTROL_SERVER = CONTROL_SERVER;
module.UNITTYPE_PLAYER = UNITTYPE_PLAYER;
module.UNITTYPE_NPC = UNITTYPE_NPC;
module.UNITTYPE_PET = UNITTYPE_PET;
module.UNITTYPE_GUARDIAN = UNITTYPE_GUARDIAN;
module.UNITTYPE_OBJECT = UNITTYPE_OBJECT;
module.TARGET_TARGET = TARGET_TARGET;
module.TARGET_FOCUS = TARGET_FOCUS;
module.OBJECT_NONE = OBJECT_NONE;
 
-- Protected Variables.
module.currentAuras = currentAuras;
module.unitMap = unitMap;
 
-- Protected Functions.
module.RegisterHandler = RegisterHandler;
module.UnregisterHandler = UnregisterHandler;
module.TestFlagsAny = TestFlagsAny;
module.TestFlagsAll = TestFlagsAll;
module.Enable = Enable;
module.Disable = Disable;
 
 
-------------------------------------------------------------------------------
-- Load.
-------------------------------------------------------------------------------
 
OnLoad();
\ No newline at end of file
MSBT5_13/MikScrollingBattleText/localization.lua New file
0,0 → 1,77
-------------------------------------------------------------------------------
-- Title: Mik's Scrolling Battle Text Localization
-- Author: Mik
-------------------------------------------------------------------------------
 
-- Create module and set its name.
local module = {};
local moduleName = "Locale";
MikSBT[moduleName] = module;
 
-- Local reference for uniformity with localization files.
local MSBTLocale = module;
 
 
-------------------------------------------------------------------------------
-- English localization (Default)
-------------------------------------------------------------------------------
 
------------------------------
-- Commands
------------------------------
MSBTLocale.COMMAND_RESET = "reset";
MSBTLocale.COMMAND_DISABLE = "disable";
MSBTLocale.COMMAND_ENABLE = "enable";
MSBTLocale.COMMAND_SHOWVER = "version";
MSBTLocale.COMMAND_HELP = "help";
 
MSBTLocale.COMMAND_USAGE = {
"Usage: " .. MikSBT.COMMAND .. " <command> [params]",
" Commands:",
" " .. MSBTLocale.COMMAND_RESET .. " - Reset the current profile to the default settings.",
" " .. MSBTLocale.COMMAND_DISABLE .. " - Disables the mod.",
" " .. MSBTLocale.COMMAND_ENABLE .. " - Enables the mod.",
" " .. MSBTLocale.COMMAND_SHOWVER .. " - Shows the current version.",
" " .. MSBTLocale.COMMAND_HELP .. " - Show the command usage.",
};
 
 
------------------------------
-- Output messages
------------------------------
 
MSBTLocale.MSG_ICON_MODULE_WARNING = "WARNING: The MSBTIcons module is no longer required. Remove it from your AddOns folder to avoid wasting memory.";
--MSBTLocale.MSG_SEARCH_ENABLE = "Event search mode enabled. Searching for: ";
--MSBTLocale.MSG_SEARCH_DISABLE = "Event search mode disabled.";
MSBTLocale.MSG_DISABLE = "Mod disabled.";
MSBTLocale.MSG_ENABLE = "Mod enabled.";
MSBTLocale.MSG_PROFILE_RESET = "Profile Reset";
MSBTLocale.MSG_HITS = "Hits";
MSBTLocale.MSG_CRIT = "Crit";
MSBTLocale.MSG_CRITS = "Crits";
MSBTLocale.MSG_MULTIPLE_TARGETS = "Multiple";
MSBTLocale.MSG_READY_NOW = "Ready Now";
 
 
------------------------------
-- Scroll area names
------------------------------
 
MSBTLocale.MSG_INCOMING = "Incoming";
MSBTLocale.MSG_OUTGOING = "Outgoing";
MSBTLocale.MSG_NOTIFICATION = "Notification";
MSBTLocale.MSG_STATIC = "Static";
 
 
----------------------------------------
-- Master profile event output messages
----------------------------------------
 
MSBTLocale.MSG_COMBAT = "Combat";
MSBTLocale.MSG_DISPEL = "Dispel";
MSBTLocale.MSG_CP = "CP";
MSBTLocale.MSG_CP_FULL = "Finish It";
MSBTLocale.MSG_KILLING_BLOW = "Killing Blow";
MSBTLocale.MSG_TRIGGER_LOW_HEALTH = "Low Health";
MSBTLocale.MSG_TRIGGER_LOW_MANA = "Low Mana";
MSBTLocale.MSG_TRIGGER_LOW_PET_HEALTH = "Low Pet Health";
\ No newline at end of file
MSBT5_13/MikScrollingBattleText/MSBTAnimations.lua New file
0,0 → 1,549
-------------------------------------------------------------------------------
-- Title: Mik's Scrolling Battle Text Animations
-- Author: Mik
-------------------------------------------------------------------------------
 
-- Create module and set its name.
local module = {};
local moduleName = "Animations";
MikSBT[moduleName] = module;
 
 
-------------------------------------------------------------------------------
-- Constants.
-------------------------------------------------------------------------------
 
-- Max number of animations to show in a scroll area.
local MAX_ANIMATIONS_PER_AREA = 15;
 
-- The amount of time to delay between updating an animating object.
local ANIMATION_DELAY = 0.015;
 
-- Left, Center, Right Text Aligns.
local TEXT_ALIGN_MAP = {"BOTTOMLEFT", "BOTTOM", "BOTTOMRIGHT"};
 
-- None, Thin, Thick
local OUTLINE_MAP = {"", "OUTLINE", "THICKOUTLINE"};
 
-- Defaults for certain parameters.
local DEFAULT_FONT_NAME = "Default";
local DEFAULT_TEXT_ALIGN = TEXT_ALIGN_MAP[2];
local DEFAULT_OUTLINE = OUTLINE_MAP[1];
local DEFAULT_SCROLL_AREA = "Notification";
local DEFAULT_SCROLL_HEIGHT = 260;
local DEFAULT_SCROLL_WIDTH = 40;
local DEFAULT_ANIMATION_STYLE = "Straight";
local DEFAULT_STICKY_ANIMATION_STYLE = "Pow";
 
-- Path to look for sound files.
local DEFAULT_SOUND_PATH = "Interface\\AddOns\\MikScrollingBattleText\\Sounds\\";
 
 
-------------------------------------------------------------------------------
-- Private variables.
-------------------------------------------------------------------------------
 
-- Dynamically created frame for animation updates.
local animationFrame;
 
-- Pools of dynamically created display events and textures that are reused.
local displayEventCache = {};
local textureCache = {};
 
-- Animating display events.
local animationData = {normal = {}, sticky = {}};
 
-- Fonts, animation styles, scroll area, and sound information.
local fonts = {};
local animationStyles = {};
local stickyAnimationStyles = {};
local scrollAreas = {};
local sounds = {};
 
-- Scroll area table to be returned for external use.
local externalScrollAreas = {};
 
 
-------------------------------------------------------------------------------
-- Imports.
-------------------------------------------------------------------------------
 
-- Local references to certain MSBT modules for faster access.
local MSBTProfiles = MikSBT.Profiles;
 
-- Local references to certain functions for faster access.
local table_remove = table.remove;
local IsModDisabled = MSBTProfiles.IsModDisabled;
local EraseTable = MikSBT.EraseTable;
 
 
-------------------------------------------------------------------------------
-- Utility functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Return whether or not the passed scroll area is valid and enabled.
-- ****************************************************************************
local function IsScrollAreaActive(scrollArea)
local saSettings = scrollAreas[scrollArea] or scrollAreas[DEFAULT_SCROLL_AREA];
 
-- Return false if the scroll area is invalid or disabled.
if (not saSettings or saSettings.disabled) then return false; end
 
-- Return true to indicate the scroll area is active.
return true;
end
 
 
-- ****************************************************************************
-- Updates the available scroll areas.
-- ****************************************************************************
local function UpdateScrollAreas()
-- Erase the current scroll areas.
EraseTable(scrollAreas);
EraseTable(externalScrollAreas);
 
-- Add scroll areas from the current profile.
if (rawget(MSBTProfiles.currentProfile, "scrollAreas")) then
for saKey, saSettings in pairs(MSBTProfiles.currentProfile.scrollAreas) do
scrollAreas[saKey] = saSettings;
externalScrollAreas[saKey] = saSettings.name;
end
end
 
-- Add scroll areas available in the master profile that aren't in the current profile.
for saKey, saSettings in pairs(MSBTProfiles.masterProfile.scrollAreas) do
if (not scrollAreas[saKey]) then
scrollAreas[saKey] = saSettings;
externalScrollAreas[saKey] = saSettings.name;
end
end
end
 
 
-- ****************************************************************************
-- Registers a font.
-- See the included API.html file for usage info.
-- ****************************************************************************
local function RegisterFont(fontName, fontPath)
-- Add the font to the fonts array if it doesn't already exist.
if (not fonts[fontName] and fontPath) then
fonts[fontName] = fontPath;
end
end
 
 
-- ****************************************************************************
-- Registers an animation style for non sticky events.
-- See the included API.html file for usage info.
-- ****************************************************************************
local function RegisterAnimationStyle(styleID, initHandler, availableDirections, availableBehaviors, localizationTable)
-- Make sure there isn't already an animation style with the same name and the passed init function is valid.
if (not animationStyles[styleID] and initHandler) then
-- Create new animation style.
local animStyleSettings = {};
animStyleSettings.initHandler = initHandler;
animStyleSettings.availableDirections = availableDirections;
animStyleSettings.availableBehaviors = availableBehaviors;
animStyleSettings.localizationTable = localizationTable;
 
-- Add the new style to the animation styles table.
animationStyles[styleID] = animStyleSettings;
end
end
 
 
-- ****************************************************************************
-- Registers an animation style for sticky events.
-- See the included API.html file for usage info.
-- ****************************************************************************
local function RegisterStickyAnimationStyle(styleID, initHandler, availableDirections, availableBehaviors, localizationTable)
-- Make sure there isn't already an animation style with the same name and the passed init function is valid.
if (not stickyAnimationStyles[styleID] and initHandler) then
-- Create new animation style.
local animStyleSettings = {};
animStyleSettings.initHandler = initHandler;
animStyleSettings.availableDirections = availableDirections;
animStyleSettings.availableBehaviors = availableBehaviors;
animStyleSettings.localizationTable = localizationTable;
 
-- Add the new style to the sticky animation styles table.
stickyAnimationStyles[styleID] = animStyleSettings;
end
end
 
 
-- ****************************************************************************
-- Registers a sound.
-- See the included API.html file for usage info.
-- ****************************************************************************
local function RegisterSound(soundName, soundPath)
-- Add the sound to the sounds array if it doesn't already exist.
if (not sounds[soundName] and soundPath) then
sounds[soundName] = soundPath;
end
end
 
 
-- ****************************************************************************
-- Returns an iterator for the table containing the registered fonts.
-- See the included API.html file for usage info.
-- ****************************************************************************
local function IterateFonts()
return pairs(fonts);
end
 
 
-- ****************************************************************************
-- Returns an iterator for the table containing the available scroll areas.
-- See the included API.html file for usage info.
-- ****************************************************************************
local function IterateScrollAreas()
return pairs(externalScrollAreas);
end
 
 
-- ****************************************************************************
-- Returns an iterator for the table containing the registered sounds.
-- See the included API.html file for usage info.
-- ****************************************************************************
local function IterateSounds()
return pairs(sounds);
end
 
 
-------------------------------------------------------------------------------
-- Display functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Creates a display event using the passed settings. If the max number of
-- allowed animations for a scroll area are already active, the oldest one is
-- reused.
-- ****************************************************************************
local function Display(message, saSettings, isSticky, colorR, colorG, colorB, fontSize, fontPath, outlineIndex, fontAlpha, texturePath)
-- Get the correct animation style settings.
local animStyleSettings, direction, behavior, textAlignIndex;
if (isSticky) then
animStyleSettings = stickyAnimationStyles[saSettings.stickyAnimationStyle] or stickyAnimationStyles[DEFAULT_STICKY_ANIMATION_STYLE];
direction = saSettings.stickyDirection;
behavior = saSettings.stickyBehavior;
textAlignIndex = saSettings.stickyTextAlignIndex;
else
animStyleSettings = animationStyles[saSettings.animationStyle] or animationStyles[DEFAULT_ANIMATION_STYLE];
direction = saSettings.direction;
behavior = saSettings.behavior;
textAlignIndex = saSettings.textAlignIndex;
end
 
-- Leave the function if the animation style is invalid.
if (not animStyleSettings) then return; end
 
-- Create arrays to track the active display events for the scroll area if they haven't already been created.
if (not animationData.normal[saSettings]) then animationData.normal[saSettings] = {}; end
if (isSticky and not animationData.sticky[saSettings]) then animationData.sticky[saSettings] = {}; end
 
-- Get the correct animation array.
local animationArray = isSticky and animationData.sticky[saSettings] or animationData.normal[saSettings];
 
-- Reuse the oldest display event if the max number of allowed animations for the scroll
-- area has been reached. Otherwise acquire one from cache or create a new one if there
-- aren't any available in cache.
local displayEvent;
if (#animationArray >= MAX_ANIMATIONS_PER_AREA) then
displayEvent = table_remove(animationArray, 1)
else
displayEvent = table_remove(displayEventCache) or { fontString = animationFrame:CreateFontString(nil, "ARTWORK", MasterFont) };
end
 
-- Get a local reference to the current profile.
local currentProfile = MSBTProfiles.currentProfile;
 
-- Set scroll area related fields.
displayEvent.offsetX = saSettings.offsetX or 0;
displayEvent.offsetY = saSettings.offsetY or 0;
displayEvent.anchorPoint = TEXT_ALIGN_MAP[textAlignIndex] or DEFAULT_TEXT_ALIGN;
displayEvent.scrollHeight = saSettings.scrollHeight or DEFAULT_SCROLL_HEIGHT;
displayEvent.scrollWidth = saSettings.scrollWidth or DEFAULT_SCROLL_WIDTH;
displayEvent.animationSpeed = (saSettings.animationSpeed or currentProfile.animationSpeed) / 100;
displayEvent.masterAlpha = fontAlpha / 100;
 
-- Default starting alpha and x/y positions.
displayEvent.alpha = 0;
displayEvent.positionX = 0;
displayEvent.positionY = 0;
displayEvent.fontSize = fontSize;
 
-- Set font string properties.
local fontString = displayEvent.fontString;
fontString:ClearAllPoints();
fontString:SetFont(fontPath, fontSize, OUTLINE_MAP[outlineIndex] or DEFAULT_OUTLINE);
fontString:SetTextColor(colorR, colorG, colorB);
fontString:SetAlpha(0);
fontString:SetDrawLayer(isSticky and "OVERLAY" or "ARTWORK");
fontString:SetText(message);
 
-- Set texture properties if there is a texture path and icons are enabled.
if (texturePath and not currentProfile.skillIconsDisabled) then
-- Reuse the texture for the current display event if there is one.
local texture = displayEvent.texture;
 
-- No texture so acquire one from cache or create a new one if there aren't any available in cache.
if (not texture) then texture = table_remove(textureCache) or animationFrame:CreateTexture(nil, "ARTWORK"); end
 
-- Set texture properties.
texture:ClearAllPoints();
texture:SetTexture(nil);
texture:SetTexture(texturePath);
texture:SetWidth(fontSize);
texture:SetHeight(fontSize);
texture:SetTexCoord(0.125, 0.875, 0.125, 0.875)
texture:SetPoint("RIGHT", fontString, "LEFT", -4, 0);
texture:SetDrawLayer(isSticky and "OVERLAY" or "ARTWORK");
displayEvent.texture = texture;
end
 
-- Set timing properties.
displayEvent.elapsedTime = 0;
displayEvent.timeSinceLastUpdate = 0;
 
-- Call the initialize function and set the text position accordingly.
animStyleSettings.initHandler(displayEvent, animationArray, direction, behavior);
fontString:SetPoint(displayEvent.anchorPoint, displayEvent.offsetX + displayEvent.positionX, displayEvent.offsetY + displayEvent.positionY);
 
 
-- Add the display event to the appropriate scroll area array.
animationArray[#animationArray+1] = displayEvent;
 
-- Check if the animation frame is not visible and make it visible so the OnUpdate events start firing.
-- This is done to keep the number of OnUpdate events down to a minimum for better performance.
if (not animationFrame:IsVisible()) then animationFrame:Show(); end
end
 
 
-- ****************************************************************************
-- Displays the passed message using the passed event settings.
-- ****************************************************************************
local function DisplayEvent(eventSettings, message, texturePath)
-- Get a local reference to the current profile.
local currentProfile = MSBTProfiles.currentProfile;
 
-- Get the scroll area settings for the event.
local saSettings = scrollAreas[eventSettings.scrollArea] or scrollAreas[DEFAULT_SCROLL_AREA];
 
-- Leave the function if the scroll area is invalid.
if (not saSettings) then return; end
 
 
-- Get the inherited font values.
local fontSize, fontName, outlineIndex, fontAlpha, isSticky;
if (eventSettings.isCrit) then
fontSize = eventSettings.fontSize or saSettings.critFontSize or currentProfile.critFontSize;
fontName = eventSettings.fontName or saSettings.critFontName or currentProfile.critFontName;
outlineIndex = eventSettings.outlineIndex or saSettings.critOutlineIndex or currentProfile.critOutlineIndex;
fontAlpha = eventSettings.fontAlpha or saSettings.critFontAlpha or currentProfile.critFontAlpha;
 
if (not currentProfile.stickyCritsDisabled) then isSticky = true; end
 
else
fontSize = eventSettings.fontSize or saSettings.normalFontSize or currentProfile.normalFontSize;
fontName = eventSettings.fontName or saSettings.normalFontName or currentProfile.normalFontName;
outlineIndex = eventSettings.outlineIndex or saSettings.normalOutlineIndex or currentProfile.normalOutlineIndex;
fontAlpha = eventSettings.fontAlpha or saSettings.normalFontAlpha or currentProfile.normalFontAlpha;
end
 
local fontPath = fonts[fontName] or fonts[DEFAULT_FONT_NAME];
isSticky = isSticky or eventSettings.alwaysSticky;
 
-- Play the event's sound file if there is one and sounds are enabled.
local soundFile = eventSettings.soundFile;
if (soundFile and not currentProfile.soundsDisabled) then
soundFile = sounds[soundFile] or (DEFAULT_SOUND_PATH .. soundFile);
PlaySoundFile(soundFile);
end
 
Display(message, saSettings, isSticky, eventSettings.colorR or 1, eventSettings.colorG or 1, eventSettings.colorB or 1, fontSize, fontPath, outlineIndex, fontAlpha, texturePath);
end
 
 
-- ****************************************************************************
-- Displays the passed message using the passed parameters. This function is
-- for easy displaying of messages from external sources. See the included
-- API.html file for usage info.
-- ****************************************************************************
local function DisplayMessage(message, scrollArea, isSticky, colorR, colorG, colorB, fontSize, fontName, outlineIndex, texturePath)
-- Do nothing if no message was passed or the mod is disabled.
if (not message or IsModDisabled()) then return; end
 
-- Attempt to get the scroll area settings for the passed scroll area.
local saSettings = scrollAreas[scrollArea];
if (not saSettings) then
-- Loop through all of the scroll areas to see if the passed scroll area matches one of the names.
for _, settings in pairs(scrollAreas) do
if (scrollArea == settings.name) then saSettings = settings; end
end
end
 
-- Use the default scroll area settings if a valid one could not be found.
saSettings = saSettings or scrollAreas[DEFAULT_SCROLL_AREA];
 
-- Leave the function if the scroll area is invalid or disabled.
if (not saSettings or saSettings.disabled) then return; end
 
 
-- Set the red, green, and blue color values to default if they are invalid.
if (colorR == nil or colorR < 0 or colorR > 255) then colorR = 255; end
if (colorG == nil or colorG < 0 or colorG > 255) then colorG = 255; end
if (colorB == nil or colorB < 0 or colorB > 255) then colorB = 255; end
 
 
-- Get a local reference to the current profile.
local currentProfile = MSBTProfiles.currentProfile;
 
-- Inherit the font size if the passed value is invalid.
if (fontSize == nil or fontSize < 4 or fontSize > 38) then
fontSize = saSettings.normalFontSize or currentProfile.normalFontSize;
end
 
-- Inherit the font if the passed value is invalid.
local fontPath = fonts[fontName];
if (not fontPath) then
fontPath = fonts[saSettings.normalFontName or currentProfile.normalFontName] or fonts[DEFAULT_FONT_NAME];
end
 
-- Inherit the font outline if the passed value is invalid.
if (not OUTLINE_MAP[outlineIndex]) then
outlineIndex = saSettings.normalOutlineIndex or currentProfile.normalOutlineIndex;
end
 
-- Inherit the font alpha.
local fontAlpha = saSettings.normalFontAlpha or currentProfile.normalFontAlpha;
 
Display(message, saSettings, isSticky, colorR / 255, colorG / 255, colorB / 255, fontSize, fontPath, outlineIndex, fontAlpha, texturePath);
end
 
 
-- ****************************************************************************
-- Called when the animation frame is updated.
-- ****************************************************************************
local function OnUpdateAnimationFrame(this, elapsed)
-- Flag for whether or not all the animations are inactive.
local allInactive = true;
 
-- Local variables to hold display event info.
local numEvents, displayEvent, fontString, texture;
 
-- Loop through all of the animation arrays.
for _, animationArray in pairs(animationData) do
-- Loop through all of the display event arrays in the animation array.
for _, displayEvents in pairs(animationArray) do
numEvents = #displayEvents;
 
-- Loop through all the display events for the scroll area.
for i = 1, numEvents do
displayEvent = displayEvents[i];
displayEvent.elapsedTime = displayEvent.elapsedTime + elapsed;
displayEvent.timeSinceLastUpdate = displayEvent.timeSinceLastUpdate + elapsed;
fontString = displayEvent.fontString;
texture = displayEvent.texture;
 
-- Check if enough time has passed.
if (displayEvent.timeSinceLastUpdate >= ANIMATION_DELAY) then
-- Call the correct animation function for the display event and check if the animation is complete.
if (displayEvent.animationHandler(displayEvent)) then
-- Hide the font string and texture and set the animation complete flag.
fontString:SetAlpha(0);
if (texture) then texture:SetAlpha(0); end
displayEvent.animationComplete = true;
else
-- Move the font string and set its alpha.
fontString:SetPoint(displayEvent.anchorPoint, displayEvent.offsetX + displayEvent.positionX, displayEvent.offsetY + displayEvent.positionY);
fontString:SetAlpha(displayEvent.masterAlpha * displayEvent.alpha);
 
-- Set the texture's alpha if there is one.
if (texture) then texture:SetAlpha(displayEvent.masterAlpha * displayEvent.alpha); end
end
 
-- Reset the last updated time.
displayEvent.timeSinceLastUpdate = 0;
end
 
-- Clear the all inactive flag
allInactive = false;
end
 
-- Loop backwards through all the display events for the animation array and remove the ones
-- that are complete.
for i = numEvents, 1, -1 do
displayEvent = displayEvents[i];
if (displayEvent.animationComplete) then
table_remove(displayEvents, i);
 
-- Reclaim the texture to cache and clear it so it can be reused if there is one.
if (displayEvent.texture) then
textureCache[#textureCache+1] = displayEvent.texture;
displayEvent.texture = nil;
end
 
-- Reclaim the display event to cache so it can be reused.
displayEventCache[#displayEventCache+1] = displayEvent;
displayEvent.animationComplete = false;
end
end
end -- Loop through display event arrays.
end -- Loop through animation arrays.
 
 
-- Hide the animation frame if there are no active animations so the OnUpdate events stop firing.
-- This is done to keep the number of OnUpdate events down to a minimum for better performance.
if (allInactive) then this:Hide(); end
end
 
 
-- ****************************************************************************
-- Called when the module is loaded.
-- ****************************************************************************
local function OnLoad()
-- Create a frame for receiving animation updates.
animationFrame = CreateFrame("Frame", "MSBTAnimationFrame", UIParent);
animationFrame:SetFrameStrata("HIGH");
animationFrame:SetPoint("BOTTOM", UIParent, "CENTER");
animationFrame:SetWidth(1);
animationFrame:SetHeight(1);
animationFrame:Hide();
animationFrame:SetScript("OnUpdate", OnUpdateAnimationFrame);
end
 
 
 
 
-------------------------------------------------------------------------------
-- Module interface.
-------------------------------------------------------------------------------
 
-- Protected Variables.
module.fonts = fonts;
module.scrollAreas = scrollAreas;
module.animationStyles = animationStyles;
module.stickyAnimationStyles = stickyAnimationStyles;
module.sounds = sounds;
 
-- Protected Functions.
module.IsScrollAreaActive = IsScrollAreaActive;
module.UpdateScrollAreas = UpdateScrollAreas;
module.RegisterFont = RegisterFont;
module.RegisterAnimationStyle = RegisterAnimationStyle;
module.RegisterStickyAnimationStyle = RegisterStickyAnimationStyle;
module.RegisterSound = RegisterSound;
module.IterateFonts = IterateFonts;
module.IterateScrollAreas = IterateScrollAreas;
module.IterateSounds = IterateSounds;
module.DisplayMessage = DisplayMessage;
module.DisplayEvent = DisplayEvent;
 
 
-------------------------------------------------------------------------------
-- Load.
-------------------------------------------------------------------------------
 
OnLoad();
\ No newline at end of file
MSBT5_13/MikScrollingBattleText/localization.zhcn.lua New file
0,0 → 1,65
-------------------------------------------------------------------------------
-- Title: Mik's Scrolling Battle Text Simplified Chinese Localization
-- Author: Mik
-- Simplified Chinese Translation by: elafor,hscui
-------------------------------------------------------------------------------
 
-- Don't do anything if the locale isn't Simplified Chinese.
if (GetLocale() ~= "zhCN") then return; end
 
-------------------------------------------------------------------------------
-- Simplified Chinese localization
-------------------------------------------------------------------------------
 
-- Local reference for faster access.
local MSBTLocale = MikSBT.Locale;
 
MSBTLocale.COMMAND_USAGE = {
"使用方法: " .. MikSBT.COMMAND .. " <命令> [参数]",
" 命令:",
" " .. MSBTLocale.COMMAND_RESET .. " - 重置",
" " .. MSBTLocale.COMMAND_DISABLE .. " - 禁用",
" " .. MSBTLocale.COMMAND_ENABLE .. " - 启用",
" " .. MSBTLocale.COMMAND_SHOWVER .. " - 显示当前版本",
" " .. MSBTLocale.COMMAND_HELP .. " - 帮助",
};
 
 
------------------------------
-- Output messages
------------------------------
 
MSBTLocale.MSG_SEARCH_ENABLE = "事件搜索模式开启. 搜索: ";
MSBTLocale.MSG_SEARCH_DISABLE = "事件搜索模式关闭.";
MSBTLocale.MSG_DISABLE = "禁用插件.";
MSBTLocale.MSG_ENABLE = "启用插件.";
MSBTLocale.MSG_PROFILE_RESET = "重置配置";
MSBTLocale.MSG_HITS = "击中";
MSBTLocale.MSG_CRIT = "爆击";
MSBTLocale.MSG_CRITS = "爆击";
MSBTLocale.MSG_MULTIPLE_TARGETS = "多个目标";
MSBTLocale.MSG_READY_NOW = "准备完毕";
 
 
------------------------------
-- Scroll area messages
------------------------------
 
MSBTLocale.MSG_INCOMING = "承受伤害";
MSBTLocale.MSG_OUTGOING = "输出伤害";
MSBTLocale.MSG_NOTIFICATION = "通告信息";
MSBTLocale.MSG_STATIC = "静态信息";
 
 
---------------------------------------
-- Master profile event output messages
---------------------------------------
 
MSBTLocale.MSG_COMBAT = "战斗";
--MSBTLocale.MSG_DISPEL = "Dispel";
MSBTLocale.MSG_CP = "连击点";
MSBTLocale.MSG_FINISH_IT = "终结技";
MSBTLocale.MSG_KILLING_BLOW = "击杀";
MSBTLocale.MSG_TRIGGER_LOW_HEALTH = "生命值低";
MSBTLocale.MSG_TRIGGER_LOW_MANA = "魔法值低";
MSBTLocale.MSG_TRIGGER_LOW_PET_HEALTH = "宠物生命值低";
\ No newline at end of file
MSBT5_13/MikScrollingBattleText/MikSBT.lua New file
0,0 → 1,92
-------------------------------------------------------------------------------
-- Title: Mik's Scrolling Battle Text
-- Author: Mik
-------------------------------------------------------------------------------
 
-- Create mod namespace and set its name.
local mod = {};
local modName = "MikSBT";
_G[modName] = mod;
 
 
-------------------------------------------------------------------------------
-- Mod constants
-------------------------------------------------------------------------------
 
mod.VERSION_NUMBER = 5.13;
mod.VERSION_STRING = "v5.13";
 
mod.COMMAND = "/msbt";
 
 
-------------------------------------------------------------------------------
-- Utility functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Copies the passed table and all its subtables.
-- ****************************************************************************
local function CopyTable(srcTable)
-- Create a new table.
local newTable = {};
 
-- Loop through all of the entries in the table.
for key, value in pairs(srcTable) do
-- Recursively call the function to copy nested tables.
if (type(value) == "table") then value = CopyTable(value); end
 
-- Make a copy of the value into the new table.
newTable[key] = value;
end
 
-- Return the new table.
return newTable;
end
 
 
-- ****************************************************************************
-- Erases the passed table. Subtables are NOT erased.
-- ****************************************************************************
local function EraseTable(t)
-- Loop through all the keys in the table and clear it.
for key in next, t do
t[key] = nil;
end
end
 
 
-- ****************************************************************************
-- Splits a string into the passed table using the delimeter.
-- ****************************************************************************
local function SplitString(text, delimeter, splitTable)
local start = 1;
local splitStart, splitEnd = string.find(text, delimeter, start);
while splitStart do
splitTable[#splitTable+1] = string.sub(text, start, splitStart - 1);
start = splitEnd + 1;
splitStart, splitEnd = string.find(text, delimeter, start);
end
splitTable[#splitTable+1] = string.sub(text, start);
end
 
 
-- ****************************************************************************
-- Prints out the passed message to the default chat frame.
-- ****************************************************************************
local function Print(msg, r, g, b)
-- Add the message to the default chat frame.
DEFAULT_CHAT_FRAME:AddMessage("MSBT: " .. tostring(msg), r, g, b);
end
 
 
 
 
-------------------------------------------------------------------------------
-- Mod utility interface.
-------------------------------------------------------------------------------
 
-- Protected Functions.
mod.CopyTable = CopyTable;
mod.EraseTable = EraseTable;
mod.SplitString = SplitString;
mod.Print = Print;
\ No newline at end of file
MSBT5_13/MikScrollingBattleText/MSBTLegacy.lua New file
0,0 → 1,39
-------------------------------------------------------------------------------
-- Title: Mik's Scrolling Battle Text Legacy
-- Author: Mik
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- DEPRECATED. DO NOT USE.
-- USE MikSBT.IterateScrollAreas INSTEAD.
-- See the included API.html file for usage info.
-- ****************************************************************************
function MikSBT.GetScrollAreaList()
-- Create a new table to hold the list.
local scrollAreas = {};
 
-- Loop through all of the scroll areas and add them to the list.
for _, scrollAreaName in MikSBT.IterateScrollAreas() do
scrollAreas[#scrollAreas+1] = scrollAreaName;
end
 
return scrollAreas;
end
 
 
-- ****************************************************************************
-- DEPRECATED. DO NOT USE.
-- USE MikSBT.IterateFonts INSTEAD.
-- See the included API.html file for usage info.
-- ****************************************************************************
function MikSBT.GetRegisteredFontList()
-- Create a new table to hold the list.
local fonts = {};
 
-- Loop through all of the registered fonts and add them to the list.
for fontName in MikSBT.IterateFonts() do
fonts[#fonts+1] = fontName;
end
 
return fonts;
end
\ No newline at end of file
MSBT5_13/MSBTOptions/Artwork/FontSettingsIconDisable.blp Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes : Added: svn:mime-type + application/octet-stream
MSBT5_13/MSBTOptions/Artwork/TriggerSettingsIconHighlight.blp Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes : Added: svn:mime-type + application/octet-stream
MSBT5_13/MSBTOptions/Artwork/FontSettingsIconHighlight.blp Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes : Added: svn:mime-type + application/octet-stream
MSBT5_13/MSBTOptions/Artwork/PlainBackdrop.blp Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes : Added: svn:mime-type + application/octet-stream
MSBT5_13/MSBTOptions/Artwork/ConfigureIcon.blp Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes : Added: svn:mime-type + application/octet-stream
MSBT5_13/MSBTOptions/Artwork/DeleteIcon.blp Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes : Added: svn:mime-type + application/octet-stream
MSBT5_13/MSBTOptions/Artwork/TriggerSettingsIcon.blp Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes : Added: svn:mime-type + application/octet-stream
MSBT5_13/MSBTOptions/Artwork/ConfigureIconDisable.blp Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes : Added: svn:mime-type + application/octet-stream
MSBT5_13/MSBTOptions/Artwork/DeleteIconDisable.blp Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes : Added: svn:mime-type + application/octet-stream
MSBT5_13/MSBTOptions/Artwork/FontSettingsIcon.blp Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes : Added: svn:mime-type + application/octet-stream
MSBT5_13/MSBTOptions/Artwork/TriggerSettingsIconDisable.blp Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes : Added: svn:mime-type + application/octet-stream
MSBT5_13/MSBTOptions/Artwork/ConfigureIconHighlight.blp Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes : Added: svn:mime-type + application/octet-stream
MSBT5_13/MSBTOptions/Artwork/DeleteIconHighlight.blp Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes : Added: svn:mime-type + application/octet-stream
MSBT5_13/MSBTOptions/localization.zhcn.lua New file
0,0 → 1,503
----------------------------------------------------------------------------
-- Title: MSBT Options Simplified Chinese Localization
-- Author: Mik
-- Simplified Chinese Translation by: elafor, hscui
-------------------------------------------------------------------------------
 
-- Don't do anything if the locale isn't Simplified Chinese.
if (GetLocale() ~= "zhCN") then return; end
 
-- Local reference for faster access.
local MSBTLocale = MikSBT.Locale;
 
 
-------------------------------------------------------------------------------
-- Simplified Chinese localization
-------------------------------------------------------------------------------
 
 
------------------------------
-- Interface messages
------------------------------
 
MSBTLocale.MSG_NEW_PROFILE = "新建配置";
MSBTLocale.MSG_PROFILE_ALREADY_EXISTS = "此配置文件已存在";
MSBTLocale.MSG_INVALID_PROFILE_NAME = "无效的配置名字";
MSBTLocale.MSG_NEW_SCROLL_AREA = "新建滚动区域";
MSBTLocale.MSG_SCROLL_AREA_ALREADY_EXISTS = "此滚动区域已存在";
MSBTLocale.MSG_INVALID_SCROLL_AREA_NAME = "无效的滚动区名字";
MSBTLocale.MSG_ACKNOWLEDGE_TEXT = "你确定想这样做吗?";
MSBTLocale.MSG_NORMAL_PREVIEW_TEXT = "普通文字";
MSBTLocale.MSG_INVALID_SOUND_FILE = "声音必须为MP3或WAV文件。";
MSBTLocale.MSG_NEW_TRIGGER = "新建触发器";
MSBTLocale.MSG_TRIGGER_CLASSES = "触发种类";
--MSBTLocale.MSG_MAIN_EVENTS = "Main Events";
--MSBTLocale.MSG_TRIGGER_EXCEPTIONS = "Trigger Exceptions";
MSBTLocale.MSG_SKILLS = "技能";
MSBTLocale.MSG_SKILL_ALREADY_EXISTS = "技能名字已存在";
MSBTLocale.MSG_INVALID_SKILL_NAME = "无效的技能名字";
--MSBTLocale.MSG_HOSTILE = "Hostile";
--MSBTLocale.MSG_ANY = "Any";
--MSBTLocale.MSG_RISES_ABOVE = "Rises Above";
--MSBTLocale.MSG_FALLS_BELOW = "Falls Below";
 
 
------------------------------
-- Class Names.
------------------------------
 
local obj = MSBTLocale.CLASS_NAMES;
obj["DRUID"] = "德鲁伊";
obj["HUNTER"] = "猎人";
obj["MAGE"] = "法师";
obj["PALADIN"] = "圣骑士";
obj["PRIEST"] = "牧师";
obj["ROGUE"] = "潜行者";
obj["SHAMAN"] = "萨满祭司";
obj["WARLOCK"] = "术士";
obj["WARRIOR"] = "战士";
 
 
------------------------------
-- Interface tabs
------------------------------
 
obj = MSBTLocale.TABS;
obj[1] = { label="总体", tooltip="总体设置"};
obj[2] = { label="滚动区域", tooltip="创建、删除和配置滚动区域;鼠标指向按钮可得到更多提示"};
obj[3] = { label="事件", tooltip="设置承受伤害、输出伤害和通告的事件;鼠标指向按钮可得到更多提示"};
obj[4] = { label="触发器", tooltip="设置触发器;鼠标指向按钮可得到更多提示"};
obj[5] = { label="预防刷屏", tooltip="设置对可能造成刷屏的信息进行控制"};
obj[6] = { label="冷却通告", tooltip="设置冷却通告"};
obj[7] = { label="技能图标", tooltip="设置技能图标"};
 
 
------------------------------
-- Interface checkboxes
------------------------------
 
obj = MSBTLocale.CHECKBOXES;
obj["enableMSBT"] = { label="启用MSBT", tooltip="启用MSBT"};
obj["stickyCrits"] = { label="爆击粘滞显示", tooltip="使用粘滞样式显示爆击"};
obj["gameDamage"] = { label="游戏内置伤害", tooltip="在敌人头上显示游戏内置伤害信息"};
obj["gameHealing"] = { label="游戏内置治疗", tooltip="在目标头上显示游戏内置治疗信息"};
obj["enableSounds"] = { label="启用声音", tooltip="当指定事件和触发器发生时播放声音"};
obj["colorPartialEffects"] = { label="特效着色", tooltip="给某些特殊战斗效果的信息着色"};
obj["crushing"] = { label="碾压", tooltip="显示碾压提示"};
obj["glancing"] = { label="偏斜", tooltip="显示偏斜提示"};
obj["absorb"] = { label="部分吸收", tooltip="显示部分吸收数值"};
obj["block"] = { label="部分格挡", tooltip="显示部分格挡数值"};
obj["resist"] = { label="部分抵抗", tooltip="显示部分抵抗数值"};
obj["vulnerability"] = { label="易伤加成", tooltip="显示易伤加成数值"};
obj["overheal"] = { label="过量治疗", tooltip="显示过量治疗数值"};
obj["colorDamageAmounts"] = { label="伤害数值着色", tooltip="为伤害值着色"};
obj["colorDamageEntry"] = { tooltip="为此类伤害着色"};
obj["enableScrollArea"] = { tooltip="启用滚动区域"};
obj["inheritField"] = { label="继承", tooltip="继承此区域的值,不勾选则无效"};
obj["stickyEvent"] = { label="始终粘滞", tooltip="总是使用粘滞样式显示事件"};
obj["enableTrigger"] = { tooltip="启用触发器"};
obj["allPowerGains"] = { label="所有能量获取", tooltip="显示所有获取的能量包括那些战斗日志中不显示的。警告:这个选项将会大量刷屏同时无视能量阈值和抑制显示设置\n不推荐"};
obj["hyperRegen"] = { label="超级回复", tooltip="显示从快速回复技能(比如唤醒和精神分流)中获取的能量数值;注意:此显示无法抑制显示"};
obj["abbreviateSkills"] = { label="技能简称", tooltip="简缩技能名字(仅适用于英文版)。若事件描述中加入“%sl”代码,此选项即失效"};
obj["hideSkills"] = { label="隐藏技能", tooltip="在承受伤害和输出伤害中不显示技能名字。开启此选项将使你失去某些事件自定义功能,因为它会忽略“%s”代码"};
obj["hideNames"] = { label="隐藏名字", tooltip="在承受伤害和输出伤害中不显示单位名字。开启此选项将使你失去某些事件自定义功能,因为它会忽略“%n”代码"};
obj["allClasses"] = { label="所有职业"};
obj["enableCooldowns"] = { label="启用冷却", tooltip="当冷却结束时显示通告"};
obj["enableIcons"] = { label="启用技能图标", tooltip="如果可能,在技能旁显示图标"};
obj["exclusiveSkills"] = { label="否则仅显示技能名字", tooltip="如果没有图标,就只显示技能名字"};
--obj["hostileOnly"] = { label="Hostile Only", tooltip="Only fire the trigger if the selected unit is hostile."};
--obj["reverseLogic"] = { label="Reverse Logic", tooltip="Reverses the meaning of the selected exception. For example, Buff Active would mean Buff Inactive."};
 
 
------------------------------
-- Interface dropdowns
------------------------------
 
obj = MSBTLocale.DROPDOWNS;
obj["profile"] = { label="当前配置文件:", tooltip="设置当前配置文件"};
obj["normalFont"] = { label="普通字体:", tooltip="选择非爆击伤害的字体"};
obj["critFont"] = { label="爆击字体:", tooltip="选择爆击伤害的字体"};
obj["normalOutline"] = { label="普通字体描边:", tooltip="选择非爆击伤害字体的描边样式"};
obj["critOutline"] = { label="爆击字体描边:", tooltip="选择爆击伤害字体的描边样式"};
obj["scrollArea"] = { label="滚动区域:", tooltip="选择滚动区域进行配置"};
obj["sound"] = { label="声音:", tooltip="选择事件发生时播放的声音"};
obj["animationStyle"] = { label="动画样式:", tooltip="滚动区域内非粘滞的动画样式"};
obj["stickyAnimationStyle"] = { label="粘滞样式:", tooltip="滚动区域内粘滞的动画样式"};
obj["direction"] = { label="方向:", tooltip="动画的方向"};
obj["behavior"] = { label="特效:", tooltip="动画的特效"};
obj["textAlign"] = { label="文本排列:", tooltip="动画中文本的排列方式"};
obj["eventCategory"] = { label="事件种类:", tooltip="设置事件种类"};
obj["outputScrollArea"] = { label="输出滚动区域:", tooltip="选择输出伤害滚动区域"};
--obj["mainEvent"] = { label="Main Event:"};
--obj["affectedUnit"] = { label="Affected Unit:", tooltip="The unit the event must be associated with."};
--obj["eventDirection"] = { label="Direction:", tooltip="The direction associated with the event."};
--obj["triggerException"] = { label="Exception:"};
--obj["warriorStance"] = { label="Warrior Stance:", tooltip="The stance the warrior is currently in."};
 
 
------------------------------
-- Interface buttons
------------------------------
 
obj = MSBTLocale.BUTTONS;
obj["copyProfile"] = { label="复制配置", tooltip="复制配置文件到新建的配置中"};
obj["resetProfile"] = { label="重置配置", tooltip="重置配置至默认设置"};
obj["deleteProfile"] = { label="删除配置", tooltip="删除配置文件"};
obj["masterFont"] = { label="主要字体", tooltip="设置主要字体样式;除非另有指定,否则所有的滚动区域和事件均将使用这种字体样式"};
obj["partialEffects"] = { label="特效着色", tooltip="设置显示哪些特殊战斗效果以及着什么颜色"};
obj["damageColors"] = { label="伤害着色", tooltip="设置是否为某种伤害数值着色以及着什么颜色"};
obj["inputOkay"] = { label=OKAY, tooltip="接受输入"};
obj["inputCancel"] = { label=CANCEL, tooltip="取消输入"};
obj["genericSave"] = { label=SAVE, tooltip="保存改变"};
obj["genericCancel"] = { label=CANCEL, tooltip="取消改变"};
obj["addScrollArea"] = { label="增加滚动区域", tooltip="增加一个新的滚动区域以包含事件和触发器"};
obj["configScrollAreas"] = { label="设置滚动区域", tooltip="设置普通和粘滞动画效果,文本排列,滚动区域的宽度/高度,以及区域位置"};
obj["editScrollAreaName"] = { tooltip="点击编辑滚动区域名字"};
obj["scrollAreaFontSettings"] = { tooltip="点击设置字体;除非另有指定,否则此区域中所有事件均将使用这种字体样式显示"};
obj["deleteScrollArea"] = { tooltip="点击删除此滚动区域"};
obj["scrollAreasPreview"] = { label="预览", tooltip="预览效果"};
obj["toggleAll"] = { label="开启/关闭所有事件", tooltip="开启/关闭所选事件分类中所有事件显示"};
obj["moveAll"] = { label="移动所有事件", tooltip="移动所选事件分类中所有事件至指定滚动区域"};
obj["eventFontSettings"] = { tooltip="点击设置此事件字体"};
obj["eventSettings"] = { tooltip="点击设置事件效果比如输出区域,输出信息,播放声音等"};
obj["customSound"] = { tooltip="点击选择自定义声音文件" };
obj["addTrigger"] = { label="增加新触发器", tooltip="增加新触发器"};
obj["triggerSettings"] = { tooltip="点击设置触发条件"};
obj["deleteTrigger"] = { tooltip="点击删除触发器"};
obj["editTriggerClasses"] = { tooltip="点击编辑触发器使用职业"};
--obj["addMainEvent"] = { label="Add Event", tooltip="When ANY of these events occur and their defined conditions are true, the trigger will fire unless one of the exceptions specified below is true."};
--obj["addTriggerException"] = { label="Add Exception", tooltip="When ANY of these exceptions are true, the trigger will not fire."};
--obj["editEventConditions"] = { tooltip="Click to edit the conditions for the event."};
--obj["deleteMainEvent"] = { tooltip="Click to delete the event."};
--obj["editExceptionConditions"] = { tooltip="Click to edit the conditions for the exception."};
--obj["deleteException"] = { tooltip="Click to delete the exception."};
obj["triggerEventTypes"] = { label="触发事件条件", tooltip="设置哪种事件种类可以用搜索模式搜索"};
obj["throttleList"] = { label="抑制列表", tooltip="设置指定技能的自定义抑制时间"};
obj["mergeExclusions"] = { label="防止合并", tooltip="防止指定技能的伤害数值合并"};
obj["skillSuppressions"] = { label="技能缩写", tooltip="缩写技能名字"};
obj["skillSubstitutions"] = { label="技能替换", tooltip="用自定义名称替换技能名字"};
obj["addSkill"] = { label="增加技能", tooltip="增加新技能到列表中"};
obj["deleteSkill"] = { tooltip="点击删除技能"};
obj["cooldownExclusions"] = { label="冷却排除列表", tooltip="不追踪指定技能的冷却"};
 
 
------------------------------
-- Interface editboxes
------------------------------
 
obj = MSBTLocale.EDITBOXES;
obj["copyProfile"] = { label="新建配置:", tooltip="输入新建配置的名称"};
obj["scrollAreaName"] = { label="新建滚动区域:", tooltip="新建滚动区域的名称"};
obj["xOffset"] = { label="X值:", tooltip="所选择滚动区域的X值"};
obj["yOffset"] = { label="Y值:", tooltip="所选择滚动区域的Y值"};
obj["eventMessage"] = { label="输出信息:", tooltip="事件发生时显示的信息"};
obj["soundFile"] = { label="声音文件:", tooltip="事件发生时播放的声音"};
obj["iconSkill"] = { label="技能图标:", tooltip="The name or spell ID of a skill whose icon will be displayed when the event occurs.\n\nMSBT will automatically try to figure out an appropriate icon if one is not specified.\n\nNOTE: A spell ID must be used in place of a name if the skill is not in the spellbook for the class that is playing when the event occurs. Most online databases such as wowhead can be used to discover it."};
obj["skillName"] = { label="技能名称:", tooltip="所增加的技能的名字"};
obj["substitutionText"] = { label="替代文本:", tooltip="用来代替技能名字的文本"};
 
 
------------------------------
-- Interface sliders
------------------------------
 
obj = MSBTLocale.SLIDERS;
obj["animationSpeed"] = { label="动画速度", tooltip="设置主动画速度\n每个滚动区域也可以设置自身独有的速度"};
obj["normalFontSize"] = { label="普通字体大小", tooltip="设置非爆击字体的大小"};
obj["normalFontOpacity"] = { label="普通字体不透明度", tooltip="设置非爆击字体的不透明度"};
obj["critFontSize"] = { label="爆击字体大小", tooltip="设置爆击字体大小"};
obj["critFontOpacity"] = { label="爆击字体不透明度", tooltip="设置爆击字体不透明度"};
obj["scrollHeight"] = { label="滚动高度", tooltip="滚动区域高度"};
obj["scrollWidth"] = { label="滚动宽度", tooltip="滚动区域宽度"};
obj["scrollAnimationSpeed"] = { label="动画速度", tooltip="设置滚动区域内动画速度"};
obj["powerThreshold"] = { label="能量阈值", tooltip="能量获得只有超过此值才会被显示"};
obj["healThreshold"] = { label="治疗阈值", tooltip="治疗量只有超过此值才会被显示"};
obj["damageThreshold"] = { label="伤害阈值", tooltip="伤害量只有超过此值才会被显示"};
obj["dotThrottleTime"] = { label="持续伤害抑制显示", tooltip="在设定的秒数中造成的持续伤害将合并为一次显示"};
obj["hotThrottleTime"] = { label="持续治疗抑制显示", tooltip="在设定的秒数中造成的持续治疗将合并为一次显示"};
obj["powerThrottleTime"] = { label="能量抑制显示", tooltip="在设定的秒数中持续获得的能量将合并为一次显示"};
obj["skillThrottleTime"] = { label="技能抑制显示", tooltip="在设定的秒数中持续使用的技能将只显示一次"};
obj["cooldownThreshold"] = { label="冷却阈值", tooltip="冷却时间低于设定秒数的技能不会被显示"};
--obj["genericAmount"] = { label="Amount", tooltip="Select the amount."};
 
 
------------------------------
-- Event categories
------------------------------
obj = MSBTLocale.EVENT_CATEGORIES;
obj[1] = "玩家受到伤害";
obj[2] = "宠物受到伤害";
obj[3] = "玩家输出伤害";
obj[4] = "宠物输出伤害";
obj[5] = "通告";
 
 
------------------------------
-- Event codes
------------------------------
 
obj = MSBTLocale.EVENT_CODES;
obj["DAMAGE_TAKEN"] = "%a - Amount of damage taken.\n";
obj["HEALING_TAKEN"] = "%a - Amount of healing taken.\n";
obj["DAMAGE_DONE"] = "%a - Amount of damage done.\n";
obj["HEALING_DONE"] = "%a - Amount of healing done.\n";
obj["ENERGY_AMOUNT"] = "%a - Amount of energy.\n";
obj["CP_AMOUNT"] = "%a - Amount of combo points you have.\n";
obj["HONOR_AMOUNT"] = "%a - Amount of honor.\n";
obj["REP_AMOUNT"] = "%a - Amount of reputation.\n";
obj["SKILL_AMOUNT"] = "%a - Amount of points you have in the skill.\n";
obj["EXPERIENCE_AMOUNT"] = "%a - Amount of experience you gained.\n";
obj["ATTACKER_NAME"] = "%n - Name of the attacker.\n";
obj["HEALER_NAME"] = "%n - Name of the healer.\n";
obj["ATTACKED_NAME"] = "%n - Name of the attacked unit.\n";
obj["HEALED_NAME"] = "%n - Name of the healed unit.\n";
obj["BUFFED_NAME"] = "%n - Name of the buffed unit.\n";
obj["SKILL_NAME"] = "%s - Name of the skill.\n";
obj["SPELL_NAME"] = "%s - Name of the spell.\n";
obj["DEBUFF_NAME"] = "%s - Name of the debuff.\n";
obj["BUFF_NAME"] = "%s - Name of the buff.\n";
obj["ITEM_BUFF_NAME"] = "%s - Name of the item buff.\n";
obj["EXTRA_ATTACKS"] = "%s - Name of skill granting the extra attacks.\n";
obj["SKILL_LONG"] = "%sl - Long form of %s. Used to override abbreviation for the event.\n";
obj["DAMAGE_TYPE_TAKEN"] = "%t - Type of damage taken.\n";
obj["DAMAGE_TYPE_DONE"] = "%t - Type of damage done.\n";
obj["ENVIRONMENTAL_DAMAGE"] = "%e - Name of the source of the damage (falling, drowning, lava, etc...)\n";
obj["FACTION_NAME"] = "%e - Name of the faction.\n";
obj["UNIT_KILLED"] = "%e - Name of the unit killed.\n";
obj["SHARD_NAME"] = "%e - Localized name of the soul shard.\n";
obj["EMOTE_TEXT"] = "%e - The text of the emote.\n";
obj["MONEY_TEXT"] = "%e - The money gained text.\n";
obj["COOLDOWN_NAME"] = "%e - The name of skill that is ready.\n"
obj["POWER_TYPE"] = "%p - Type of power (energy, rage, mana).\n";
 
 
------------------------------
-- Incoming events
------------------------------
 
obj = MSBTLocale.INCOMING_PLAYER_EVENTS;
obj[1] = { label="近战伤害", tooltip="显示被近战伤害"};
obj[2] = { label="近战爆击", tooltip="显示被近战爆击"};
obj[3] = { label="近战未命中", tooltip="显示未被近战命中"};
obj[4] = { label="近战闪躲", tooltip="显示闪躲近战攻击"};
obj[5] = { label="近战招架", tooltip="显示招架近战攻击"};
obj[6] = { label="近战格挡", tooltip="显示格挡近战攻击"};
obj[7] = { label="近战吸收", tooltip="显示吸收近战伤害"};
obj[8] = { label="近战免疫", tooltip="显示免疫近战伤害"};
obj[9] = { label="技能伤害", tooltip="显示被技能伤害"};
obj[10] = { label="技能爆击", tooltip="显示被技能爆击"};
obj[11] = { label="技能持续伤害", tooltip="显示被技能持续伤害"};
obj[12] = { label="技能未命中", tooltip="显示未被技能命中"};
obj[13] = { label="技能闪躲", tooltip="显示闪躲技能攻击"};
obj[14] = { label="技能招架", tooltip="显示招架技能攻击"};
obj[15] = { label="技能格挡", tooltip="显示格挡技能攻击"};
obj[16] = { label="法术抵抗", tooltip="显示抵抗法术攻击"};
obj[17] = { label="技能吸收", tooltip="显示吸收技能伤害"};
obj[18] = { label="技能免疫", tooltip="显示免疫技能伤害"};
obj[19] = { label="技能反射", tooltip="显示反射技能伤害"};
obj[20] = { label="法术打断", tooltip="显示打断法术"};
obj[21] = { label="治疗", tooltip="显示被治疗"};
obj[22] = { label="爆击治疗", tooltip="显示被治疗爆击"};
obj[23] = { label="持续治疗", tooltip="显示被持续治疗"};
obj[24] = { label="环境伤害", tooltip="显示环境伤害(如跌落,窒息,熔岩等)"};
 
obj = MSBTLocale.INCOMING_PET_EVENTS;
obj[1] = { label="近战伤害", tooltip="显示宠物被近战伤害"};
obj[2] = { label="近战爆击", tooltip="显示宠物被近战爆击"};
obj[3] = { label="近战未命中", tooltip="显示宠物未被近战命中"};
obj[4] = { label="近战闪躲", tooltip="显示宠物闪躲近战攻击"};
obj[5] = { label="近战招架", tooltip="显示宠物招架近战攻击"};
obj[6] = { label="近战格挡", tooltip="显示宠物格挡近战攻击"};
obj[7] = { label="近战吸收", tooltip="显示宠物吸收近战伤害"};
obj[8] = { label="近战免疫", tooltip="显示宠物免疫近战伤害"};
obj[9] = { label="技能伤害", tooltip="显示宠物被技能伤害"};
obj[10] = { label="技能爆击", tooltip="显示宠物被技能爆击"};
obj[11] = { label="技能持续伤害", tooltip="显示宠物被技能持续伤害"};
obj[12] = { label="技能未命中", tooltip="显示宠物未被技能命中"};
obj[13] = { label="技能闪躲", tooltip="显示宠物闪躲技能攻击"};
obj[14] = { label="技能招架", tooltip="显示宠物招架技能攻击"};
obj[15] = { label="技能格挡", tooltip="显示宠物格挡技能攻击"};
obj[16] = { label="法术抵抗", tooltip="显示宠物抵抗法术攻击"};
obj[17] = { label="技能吸收", tooltip="显示宠物吸收技能伤害"};
obj[18] = { label="技能免疫", tooltip="显示宠物免疫技能伤害"};
obj[19] = { label="治疗", tooltip="显示宠物被治疗"};
obj[20] = { label="治疗爆击", tooltip="显示宠物被治疗爆击"};
obj[21] = { label="持续治疗", tooltip="显示宠物被持续治疗"};
 
 
------------------------------
-- Outgoing events
------------------------------
 
obj = MSBTLocale.OUTGOING_PLAYER_EVENTS;
obj[1] = { label="近战伤害", tooltip="显示对敌近战伤害"};
obj[2] = { label="近战爆击", tooltip="显示对敌近战爆击"};
obj[3] = { label="近战未命中", tooltip="显示近战未命中敌人"};
obj[4] = { label="近战闪躲", tooltip="显示敌人闪躲近战攻击"};
obj[5] = { label="近战招架", tooltip="显示敌人招架近战攻击"};
obj[6] = { label="近战格挡", tooltip="显示敌人格挡近战攻击"};
obj[7] = { label="近战吸收", tooltip="显示敌人吸收近战伤害"};
obj[8] = { label="近战免疫", tooltip="显示敌人免疫近战伤害"};
obj[9] = { label="近战闪避", tooltip="显示敌人闪避近战攻击"};
obj[10] = { label="技能伤害", tooltip="显示技能伤害敌人"};
obj[11] = { label="技能爆击", tooltip="显示技能爆击敌人"};
obj[12] = { label="技能持续伤害", tooltip="显示技能持续伤害敌人"};
obj[13] = { label="技能未命中", tooltip="显示技能未命中敌人"};
obj[14] = { label="技能闪躲", tooltip="显示敌人闪躲技能攻击"};
obj[15] = { label="技能招架", tooltip="显示敌人招架技能攻击"};
obj[16] = { label="技能格挡", tooltip="显示敌人格挡技能攻击"};
obj[17] = { label="法术抵抗", tooltip="显示敌人抵抗法术攻击"};
obj[18] = { label="技能吸收", tooltip="显示敌人吸收法术伤害"};
obj[19] = { label="技能免疫", tooltip="显示敌人免疫技能伤害"};
obj[20] = { label="技能反射", tooltip="显示敌人反射技能伤害"};
obj[21] = { label="法术打断", tooltip="显示法术攻击被打断"};
obj[22] = { label="技能闪避", tooltip="显示技能攻击被闪避"};
obj[23] = { label="治疗", tooltip="显示治疗目标"};
obj[24] = { label="治疗爆击", tooltip="显示爆击治疗目标"};
obj[25] = { label="持续治疗", tooltip="显示持续治疗目标"};
--obj[26] = { label="Dispels", tooltip="Enable outgoing dispels."};
 
obj = MSBTLocale.OUTGOING_PET_EVENTS;
obj[1] = { label="近战伤害", tooltip="显示宠物近战伤害"};
obj[2] = { label="近战爆击", tooltip="显示宠物近战爆击"};
obj[3] = { label="近战未命中", tooltip="显示宠物的近战攻击未命中敌人"};
obj[4] = { label="近战闪躲", tooltip="显示宠物的近战攻击被闪躲"};
obj[5] = { label="近战招架", tooltip="显示宠物的近战攻击被招架"};
obj[6] = { label="近战格挡", tooltip="显示宠物的近战攻击被格挡"};
obj[7] = { label="近战吸收", tooltip="显示宠物的近战伤害被吸收"};
obj[8] = { label="近战免疫", tooltip="显示宠物的近战伤害被免疫"};
obj[9] = { label="近战闪避", tooltip="显示宠物的近战攻击被闪避"};
obj[10] = { label="技能伤害", tooltip="显示宠物的技能伤害"};
obj[11] = { label="技能爆击", tooltip="显示宠物的技能爆击"};
obj[12] = { label="技能持续伤害", tooltip="显示宠物技能的持续伤害"};
obj[13] = { label="技能未命中", tooltip="显示宠物技能攻击未命中敌人"};
obj[14] = { label="技能闪躲", tooltip="显示宠物的技能攻击被闪躲"};
obj[15] = { label="技能招架", tooltip="显示宠物的技能攻击被招架"};
obj[16] = { label="技能格挡", tooltip="显示宠物的技能攻击被格挡"};
obj[17] = { label="法术抵抗", tooltip="显示宠物的法术攻击被抵抗"};
obj[18] = { label="技能吸收", tooltip="显示宠物的技能伤害被吸收"};
obj[19] = { label="技能免疫", tooltip="显示宠物的技能伤害被免疫"};
obj[20] = { label="技能闪避", tooltip="显示宠物的技能攻击被闪避"};
--obj[21] = { label="Dispels", tooltip="Enable your pet's outgoing dispels."};
 
 
------------------------------
-- Notification events
------------------------------
 
obj = MSBTLocale.NOTIFICATION_EVENTS;
obj[1] = { label="Debuff", tooltip="显示你遭受的Debuff"};
obj[2] = { label="Buff", tooltip="显示你得到的Buff"};
obj[3] = { label="物品Buff", tooltip="显示使用物品得到的Buff"};
obj[4] = { label="Debuff消失", tooltip="显示从你身上消失的Debuff"};
obj[5] = { label="Buff消失", tooltip="显示从你身上消失的Buff"};
obj[6] = { label="物品Buff消失", tooltip="显示从你身上消失的物品Buff"};
obj[7] = { label="战斗开始", tooltip="显示你已经开始战斗"};
obj[8] = { label="战斗结束", tooltip="显示你已经结束了战斗"};
obj[9] = { label="能量获得", tooltip="显示你额外获得的法力,怒气或者能量"};
obj[10] = { label="能量行动", tooltip="显示你失去的法力,怒气或者能量"};
obj[11] = { label="连击点获得", tooltip="显示你获得的连击点"};
obj[12] = { label="连击点已满", tooltip="显示你的连击点已满"};
obj[13] = { label="获得荣誉", tooltip="显示你获得荣誉"};
obj[14] = { label="声望提高", tooltip="显示你的声望提高"};
obj[15] = { label="声望下降", tooltip="显示你的声望下降"};
obj[16] = { label="获得技能点", tooltip="显示你获得了技能点"};
obj[17] = { label="获得经验", tooltip="显示你获得了经验值"};
obj[18] = { label="击杀玩家", tooltip="显示你击杀了一个敌对玩家"};
obj[19] = { label="击杀NPC", tooltip="显示你击杀了一个敌对NPC"};
obj[20] = { label="获得灵魂碎片", tooltip="显示你获得了一个灵魂碎片"};
obj[21] = { label="额外攻击", tooltip="显示你从风怒,痛击之刃,剑系掌握等方面获得了一次额外攻击"};
obj[22] = { label="敌人获得Buff", tooltip="显示当前敌对目标获得的Buff"};
obj[23] = { label="怪物表情", tooltip="显示当前目标怪物表情"};
obj[24] = { label="获得金钱", tooltip="显示获得的金钱"};
 
 
------------------------------
-- Trigger info
------------------------------
 
-- Holds the available trigger main events.
obj = MSBTLocale.TRIGGER_MAIN_EVENTS;
--obj["Health"] = "Health Threshold";
--obj["Mana"] = "Mana Threshold";
--obj["Energy"] = "Energy Threshold";
--obj["Rage"] = "Rage Threshold";
--obj["Crit"] = "Crit";
--obj["Block"] = "Block";
--obj["Dodge"] = "Dodge";
--obj["Parry"] = "Parry";
--obj["BuffGain"] = "Buff Gain";
--obj["BuffFade"] = "Buff Fade";
--obj["BuffApplication"] = "Buff Application";
--obj["DebuffGain"] = "Debuff Gain";
--obj["DebuffFade"] = "Debuff Fade";
--obj["DebuffApplication"] = "Debuff Application";
--obj["CastStart"] = "Cast Start";
--obj["KillingBlow"] = "Killing Blow";
 
 
-- Holds the available trigger exceptions.
obj = MSBTLocale.TRIGGER_EXCEPTIONS;
--obj["BuffActive"] = "Buff Active";
--obj["InsufficientPower"] = "Insufficient Power";
--obj["InsufficientComboPoints"] = "Insufficient Combo Points";
--obj["NotInArena"] = "Not In Arena";
--obj["NotInPvPZone"] = "Not In PvP Zone";
--obj["RecentlyFired"] = "Trigger Recently Fired";
--obj["SkillUnavailable"] = "Skill Unavailable";
--obj["TrivialTarget"] = "Trivial Target";
obj["WarriorStance"] = "战士姿态";
 
 
------------------------------
-- Font info
------------------------------
 
-- Font outlines.
obj = MSBTLocale.OUTLINES;
obj[1] = "无";
obj[2] = "细";
obj[3] = "粗";
 
-- Text aligns.
obj = MSBTLocale.TEXT_ALIGNS;
obj[1] = "左边";
obj[2] = "中间";
obj[3] = "右边";
 
 
------------------------------
-- Sound info
------------------------------
 
obj = MSBTLocale.SOUNDS;
obj["LowMana"] = "能量不足";
obj["LowHealth"] = "血量不足";
 
 
------------------------------
-- Animation style info
------------------------------
 
-- Animation styles
obj = MSBTLocale.ANIMATION_STYLE_DATA;
obj["Horizontal"] = "æ°´å¹³";
obj["Parabola"] = "抛物线";
obj["Straight"] = "直线";
obj["Static"] = "静止";
obj["Pow"] = "抖动";
 
-- Animation style directions.
--obj["Alternate"] = "Alternate";
obj["Left"] = "å·¦";
obj["Right"] = "右";
obj["Up"] = "上";
obj["Down"] = "下";
 
-- Animation style behaviors.
obj["GrowUp"] = "向上增长";
obj["GrowDown"] = "向下增长";
obj["CurvedLeft"] = "向左抛出";
obj["CurvedRight"] = "向右抛出";
obj["Jiggle"] = "摇动";
obj["Normal"] = "普通";
\ No newline at end of file
MSBT5_13/MSBTOptions/MSBTOptionsTabs.lua New file
0,0 → 1,2372
-------------------------------------------------------------------------------
-- Title: MSBT Options Tab Frames
-- Author: Mik
-------------------------------------------------------------------------------
 
-- Create module and set its name.
local module = {};
local moduleName = "Tabs";
MSBTOptions[moduleName] = module;
 
 
-------------------------------------------------------------------------------
-- Private constants.
-------------------------------------------------------------------------------
 
local DEFAULT_PROFILE_NAME = "Default";
local DEFAULT_FONT_NAME = "Default";
local DEFAULT_SCROLL_AREA = "Notification";
 
local EVENT_CATEGORY_MAP = {
"INCOMING_PLAYER_EVENTS", "INCOMING_PET_EVENTS",
"OUTGOING_PLAYER_EVENTS", "OUTGOING_PET_EVENTS",
"NOTIFICATION_EVENTS"
};
 
 
-------------------------------------------------------------------------------
-- Private variables.
-------------------------------------------------------------------------------
 
-- Various tab frames.
local tabFrames = {};
 
-- Reusable table to configure popup frames.
local configTable = {};
 
-- Reusable table for skill lists.
local skillsTable = {};
 
-------------------------------------------------------------------------------
-- Imports.
-------------------------------------------------------------------------------
 
-- Local references to certain modules for faster access.
local MSBTOptMain = MSBTOptions.Main;
local MSBTControls = MSBTOptions.Controls;
local MSBTPopups = MSBTOptions.Popups;
local MSBTLocale = MikSBT.Locale;
local MSBTProfiles = MikSBT.Profiles;
local MSBTAnimations = MikSBT.Animations;
local MSBTTriggers = MikSBT.Triggers;
local MSBTCooldowns = MikSBT.Cooldowns;
 
-- Local references to certain functions for faster access.
local EraseTable = MikSBT.EraseTable;
local DisableControls = MSBTPopups.DisableControls;
 
 
-------------------------------------------------------------------------------
-- Utility functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Returns a list of keys for the passed table sorted according to their
-- associated value.
-- ****************************************************************************
local function SortKeysByValue(t)
local sortedKeys = {};
local sortedValues = {};
 
for k, v in pairs(t) do
sortedKeys[#sortedKeys+1] = k;
sortedValues[#sortedValues+1] = v;
end
 
local tempKey, tempValue, j;
for i = 2, #sortedValues do
tempValue = sortedValues[i];
tempKey = sortedKeys[i];
j = i - 1;
while (j > 0 and sortedValues[j] > tempValue) do
sortedValues[j + 1] = sortedValues[j];
sortedKeys[j + 1] = sortedKeys[j];
j = j - 1;
end
sortedValues[j + 1] = tempValue;
sortedKeys[j + 1] = tempKey;
end
 
return sortedKeys;
end
 
 
 
-- ****************************************************************************
-- Populates the skills table with the skills from the current/master profile.
-- ****************************************************************************
local function PopulateSkillList(listName)
EraseTable(skillsTable);
local currentProfileList = rawget(MSBTProfiles.currentProfile, listName);
if (currentProfileList) then
for skillName, value in pairs(currentProfileList) do
skillsTable[skillName] = value;
end
end
 
-- Get skills available in the master profile that aren't in the current profile.
for skillName, value in pairs(MSBTProfiles.masterProfile[listName]) do
if (skillsTable[skillName] == nil) then skillsTable[skillName] = value; end
end
end
 
 
-- ****************************************************************************
-- Saves the modified skill list to the current profile.
-- ****************************************************************************
local function SaveSkillList(listName)
for skillName, value in pairs(skillsTable) do
MSBTProfiles.SetOption(listName, skillName, value);
end
end
 
 
-------------------------------------------------------------------------------
-- General tab functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Toggle the enable state of the profile buttons appropriately.
-- ****************************************************************************
local function GeneralTab_ToggleDeleteButton()
local controls = tabFrames.general.controls;
 
if (controls.profileDropdown:GetSelectedID() == DEFAULT_PROFILE_NAME) then
controls.deleteProfileButton:Disable();
else
controls.deleteProfileButton:Enable();
end
end
 
 
-- ****************************************************************************
-- Enables the controls on the general tab.
-- ****************************************************************************
local function GeneralTab_EnableControls()
for name, frame in pairs(tabFrames.general.controls) do
if (frame.Enable) then frame:Enable(); end
end
 
GeneralTab_ToggleDeleteButton();
end
 
 
-- ****************************************************************************
-- Populate the controls with the profile settings.
-- ****************************************************************************
local function GeneralTab_Populate()
local currentProfile = MSBTProfiles.currentProfile;
local controls = tabFrames.general.controls;
 
controls.enableCheckbox:SetChecked(not MSBTProfiles.IsModDisabled());
controls.stickyCritsCheckbox:SetChecked(not currentProfile.stickyCritsDisabled);
controls.gameDamageCheckbox:SetChecked(currentProfile.gameDamageEnabled);
controls.gameHealingCheckbox:SetChecked(currentProfile.gameHealingEnabled);
controls.enableSoundsCheckbox:SetChecked(not currentProfile.soundsDisabled);
controls.animationSpeedSlider:SetValue(currentProfile.animationSpeed);
end
 
 
-- ****************************************************************************
-- Validates if the passed profile name does not already exist and is valid.
-- ****************************************************************************
local function GenerelTab_ValidateProfileName(profileName)
if (not profileName or profileName == "") then
return MSBTLocale.MSG_INVALID_PROFILE_NAME;
end
 
if (MSBTProfiles.savedVariables.profiles[profileName]) then
return MSBTLocale.MSG_PROFILE_ALREADY_EXISTS;
end
end
 
 
-- ****************************************************************************
-- Copies the selected profile to the name entered.
-- ****************************************************************************
local function GeneralTab_CopyProfile(settings)
local profileName = settings.inputText;
local controls = tabFrames.general.controls;
 
local dropdown = controls.profileDropdown;
MSBTProfiles.CopyProfile(dropdown:GetSelectedID(), profileName);
dropdown:AddItem(profileName, profileName);
dropdown:Sort();
 
dropdown:SetSelectedID(profileName);
MSBTProfiles.SelectProfile(profileName);
GeneralTab_Populate();
GeneralTab_ToggleDeleteButton();
end
 
 
-- ****************************************************************************
-- Resets the selected profile.
-- ****************************************************************************
local function GeneralTab_ResetProfile()
local controls = tabFrames.general.controls;
 
MSBTProfiles.ResetProfile(controls.profileDropdown:GetSelectedID());
GeneralTab_Populate();
end
 
 
-- ****************************************************************************
-- Deletes the selected profile.
-- ****************************************************************************
local function GeneralTab_DeleteProfile()
local controls = tabFrames.general.controls;
 
local dropdown = controls.profileDropdown;
local profileName = dropdown:GetSelectedID();
MSBTProfiles.DeleteProfile(profileName);
dropdown:RemoveItem(profileName);
 
dropdown:SetSelectedID(DEFAULT_PROFILE_NAME);
GeneralTab_Populate();
GeneralTab_ToggleDeleteButton();
end
 
 
-- ****************************************************************************
-- Saves the font settings selected by the user.
-- ****************************************************************************
local function GeneralTab_SaveFontSettings(fontSettings)
-- Normal font settings.
MSBTProfiles.SetOption(nil, "normalFontName", fontSettings.normalFontName);
MSBTProfiles.SetOption(nil, "normalOutlineIndex", fontSettings.normalOutlineIndex);
MSBTProfiles.SetOption(nil, "normalFontSize", fontSettings.normalFontSize);
MSBTProfiles.SetOption(nil, "normalFontAlpha", fontSettings.normalFontAlpha);
 
-- Crit font settings.
MSBTProfiles.SetOption(nil, "critFontName", fontSettings.critFontName);
MSBTProfiles.SetOption(nil, "critOutlineIndex", fontSettings.critOutlineIndex);
MSBTProfiles.SetOption(nil, "critFontSize", fontSettings.critFontSize);
MSBTProfiles.SetOption(nil, "critFontAlpha", fontSettings.critFontAlpha);
end
 
 
-- ****************************************************************************
-- Creates the general tab frame contents.
-- ****************************************************************************
local function GeneralTab_Create()
local tabFrame = tabFrames.general;
tabFrame.controls = {};
local controls = tabFrame.controls;
 
-- Enable checkbox.
local checkbox = MSBTControls.CreateCheckbox(tabFrame);
local objLocale = MSBTLocale.CHECKBOXES["enableMSBT"];
checkbox:Configure(28, objLocale.label, objLocale.tooltip);
checkbox:SetPoint("TOPLEFT", tabFrame, "TOPLEFT", 5, -5);
checkbox:SetClickHandler(
function (this, isChecked)
MSBTProfiles.SetOptionUserDisabled(not isChecked);
end
);
controls.enableCheckbox = checkbox;
 
 
-- Profile dropdown.
local dropdown = MSBTControls.CreateDropdown(tabFrame);
objLocale = MSBTLocale.DROPDOWNS["profile"];
dropdown:Configure(180, objLocale.label, objLocale.tooltip);
dropdown:SetPoint("TOPLEFT", checkbox, "BOTTOMLEFT", 0, -30);
dropdown:SetChangeHandler(
function (this, id)
MSBTProfiles.SelectProfile(id);
GeneralTab_Populate();
GeneralTab_ToggleDeleteButton();
end
);
controls.profileDropdown = dropdown;
 
 
-- Copy profile button.
local button = MSBTControls.CreateOptionButton(tabFrame);
objLocale = MSBTLocale.BUTTONS["copyProfile"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("TOPLEFT", dropdown, "BOTTOMLEFT", 0, -20);
button:SetClickHandler(
function (this)
local objLocale = MSBTLocale.EDITBOXES["copyProfile"];
EraseTable(configTable);
configTable.defaultText = MSBTLocale.MSG_NEW_PROFILE;
configTable.editboxLabel = objLocale.label;
configTable.editboxTooltip = objLocale.tooltip
configTable.parentFrame = tabFrame;
configTable.anchorFrame = this;
configTable.validateHandler = GeneralTab_ValidateProfileName;
configTable.saveHandler = GeneralTab_CopyProfile;
configTable.hideHandler = GeneralTab_EnableControls;
DisableControls(controls);
MSBTPopups.ShowInput(configTable);
end
);
controls.copyProfileButton = button;
 
-- Reset profile button.
button = MSBTControls.CreateOptionButton(tabFrame);
objLocale = MSBTLocale.BUTTONS["resetProfile"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("LEFT", controls.copyProfileButton, "RIGHT", 10, 0);
button:SetClickHandler(
function (this)
EraseTable(configTable);
configTable.parentFrame = tabFrame;
configTable.anchorFrame = this;
configTable.acknowledgeHandler = GeneralTab_ResetProfile;
configTable.hideHandler = GeneralTab_EnableControls;
DisableControls(controls);
MSBTPopups.ShowAcknowledge(configTable);
end
);
controls.resetProfileButton = button;
 
-- Delete profile button.
button = MSBTControls.CreateOptionButton(tabFrame);
objLocale = MSBTLocale.BUTTONS["deleteProfile"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("LEFT", controls.resetProfileButton, "RIGHT", 10, 0);
button:SetClickHandler(
function (this)
EraseTable(configTable);
configTable.parentFrame = tabFrame;
configTable.anchorFrame = this;
configTable.anchorPoint = "TOPRIGHT";
configTable.relativePoint = "BOTTOMRIGHT";
configTable.acknowledgeHandler = GeneralTab_DeleteProfile;
configTable.hideHandler = GeneralTab_EnableControls;
DisableControls(controls);
MSBTPopups.ShowAcknowledge(configTable);
end
);
controls.deleteProfileButton = button;
 
 
-- Animation speed slider.
local slider = MSBTControls.CreateSlider(tabFrame);
objLocale = MSBTLocale.SLIDERS["animationSpeed"];
slider:Configure(180, objLocale.label, objLocale.tooltip);
slider:SetPoint("TOPLEFT", controls.copyProfileButton, "BOTTOMLEFT", 0, -45);
slider:SetMinMaxValues(20, 250);
slider:SetValueStep(10);
slider:SetValueChangedHandler(
function(this, value)
MSBTProfiles.SetOption(nil, "animationSpeed", value);
end
);
controls.animationSpeedSlider = slider;
 
 
-- Enable sounds checkbox.
checkbox = MSBTControls.CreateCheckbox(tabFrame);
objLocale = MSBTLocale.CHECKBOXES["enableSounds"];
checkbox:Configure(28, objLocale.label, objLocale.tooltip);
checkbox:SetPoint("BOTTOMRIGHT", tabFrame, "BOTTOMRIGHT", -10, 15);
checkbox:SetClickHandler(
function (this, isChecked)
MSBTProfiles.SetOption(nil, "soundsDisabled", not isChecked);
end
);
controls.enableSoundsCheckbox = checkbox;
 
-- Game healing checkbox.
checkbox = MSBTControls.CreateCheckbox(tabFrame);
objLocale = MSBTLocale.CHECKBOXES["gameHealing"];
checkbox:Configure(28, objLocale.label, objLocale.tooltip);
checkbox:SetPoint("BOTTOMRIGHT", controls.enableSoundsCheckbox, "TOPRIGHT", 0, 0);
checkbox:SetClickHandler(
function (this, isChecked)
MSBTProfiles.SetOption(nil, "gameHealingEnabled", isChecked);
MSBTProfiles.UpdateGameOptions();
end
);
controls.gameHealingCheckbox = checkbox;
 
-- Game damage checkbox.
checkbox = MSBTControls.CreateCheckbox(tabFrame);
objLocale = MSBTLocale.CHECKBOXES["gameDamage"];
checkbox:Configure(28, objLocale.label, objLocale.tooltip);
checkbox:SetPoint("BOTTOMRIGHT", controls.gameHealingCheckbox, "TOPRIGHT", 0, 0);
checkbox:SetClickHandler(
function (this, isChecked)
MSBTProfiles.SetOption(nil, "gameDamageEnabled", isChecked);
MSBTProfiles.UpdateGameOptions();
end
);
controls.gameDamageCheckbox = checkbox;
 
-- Sticky crits checkbox.
checkbox = MSBTControls.CreateCheckbox(tabFrame);
objLocale = MSBTLocale.CHECKBOXES["stickyCrits"];
checkbox:Configure(28, objLocale.label, objLocale.tooltip);
checkbox:SetPoint("BOTTOMRIGHT", controls.gameDamageCheckbox, "TOPRIGHT", 0, 0);
checkbox:SetClickHandler(
function (this, isChecked)
MSBTProfiles.SetOption(nil, "stickyCritsDisabled", not isChecked);
end
);
controls.stickyCritsCheckbox = checkbox;
 
 
 
-- Damage colors button.
button = MSBTControls.CreateOptionButton(tabFrame);
objLocale = MSBTLocale.BUTTONS["damageColors"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("BOTTOMLEFT", tabFrame, "BOTTOMLEFT", 5, 15);
button:SetClickHandler(
function (this)
EraseTable(configTable);
configTable.parentFrame = tabFrame;
configTable.anchorFrame = this;
configTable.anchorPoint = "BOTTOMLEFT";
configTable.relativePoint = "TOPLEFT";
configTable.hideHandler = GeneralTab_EnableControls;
DisableControls(controls);
MSBTPopups.ShowDamageColors(configTable);
end
);
controls.damageColorsButton = button;
 
-- Partial effects button.
button = MSBTControls.CreateOptionButton(tabFrame);
objLocale = MSBTLocale.BUTTONS["partialEffects"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("BOTTOMLEFT", controls.damageColorsButton, "TOPLEFT", 0, 10);
button:SetClickHandler(
function (this)
EraseTable(configTable);
configTable.parentFrame = tabFrame;
configTable.anchorFrame = this;
configTable.anchorPoint = "BOTTOMLEFT";
configTable.relativePoint = "TOPLEFT";
configTable.hideHandler = GeneralTab_EnableControls;
DisableControls(controls);
MSBTPopups.ShowPartialEffects(configTable);
end
);
controls.partialEffectsButton = button;
 
-- Master font settings button.
button = MSBTControls.CreateOptionButton(tabFrame);
objLocale = MSBTLocale.BUTTONS["masterFont"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("BOTTOMLEFT", controls.partialEffectsButton, "TOPLEFT", 0, 10);
button:SetClickHandler(
function (this)
EraseTable(configTable);
configTable.title = objLocale.label;
 
local fontName = MSBTProfiles.currentProfile.normalFontName;
if (not MSBTAnimations.fonts[fontName]) then fontName = DEFAULT_FONT_NAME; end
configTable.normalFontName = fontName;
configTable.normalOutlineIndex = MSBTProfiles.currentProfile.normalOutlineIndex;
configTable.normalFontSize = MSBTProfiles.currentProfile.normalFontSize;
configTable.normalFontAlpha = MSBTProfiles.currentProfile.normalFontAlpha;
 
fontName = MSBTProfiles.currentProfile.critFontName;
if (not MSBTAnimations.fonts[fontName]) then fontName = DEFAULT_FONT_NAME; end
configTable.critFontName = fontName;
configTable.critOutlineIndex = MSBTProfiles.currentProfile.critOutlineIndex;
configTable.critFontSize = MSBTProfiles.currentProfile.critFontSize;
configTable.critFontAlpha = MSBTProfiles.currentProfile.critFontAlpha;
configTable.hideInherit = true;
configTable.parentFrame = tabFrame;
configTable.anchorFrame = tabFrame;
configTable.anchorPoint = "BOTTOM";
configTable.relativePoint = "BOTTOM";
configTable.saveHandler = GeneralTab_SaveFontSettings;
configTable.hideHandler = GeneralTab_EnableControls;
DisableControls(controls);
MSBTPopups.ShowFont(configTable);
end
);
controls.masterFontButton = button;
 
 
-- Populate the available profiles and select the current profile by default.
local currentProfileName;
for profileName, profile in pairs(MSBTProfiles.savedVariables.profiles) do
dropdown:AddItem(profileName, profileName);
if (profile == MSBTProfiles.currentProfile) then currentProfileName = profileName; end
end
dropdown:SetSelectedID(currentProfileName);
dropdown:Sort();
GeneralTab_ToggleDeleteButton();
 
tabFrame.created = true;
end
 
 
-- ****************************************************************************
-- Called when the tab frame is shown.
-- ****************************************************************************
local function GeneralTab_OnShow()
if (not tabFrames.general.created) then GeneralTab_Create(); end
 
-- Set the frame up to populate the profile options when it is shown.
GeneralTab_Populate();
end
 
 
-------------------------------------------------------------------------------
-- Scroll areas tab functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Enables the controls on the scroll areas tab.
-- ****************************************************************************
local function ScrollAreasTab_EnableControls()
for name, frame in pairs(tabFrames.scrollAreas.controls) do
if (frame.Enable) then frame:Enable(); end
end
 
-- Refresh listbox so the default scroll area delete buttons are disabled.
tabFrames.scrollAreas.controls.scrollAreasListbox:Refresh();
end
 
 
-- ****************************************************************************
-- Validates if the passed scroll area does not already exist and is valid.
-- ****************************************************************************
local function ScrollAreasTab_ValidateScrollAreaName(scrollAreaName)
if (not scrollAreaName or scrollAreaName == "") then
return MSBTLocale.MSG_INVALID_SCROLL_AREA_NAME;
end
 
for saKey, saSettings in pairs(MSBTAnimations.scrollAreas) do
if (saSettings.name == scrollAreaName) then return MSBTLocale.MSG_SCROLL_AREA_ALREADY_EXISTS; end
end
end
 
 
-- ****************************************************************************
-- Adds a new scroll area with the passed scroll area name.
-- ****************************************************************************
local function ScrollAreasTab_AddScrollArea(settings)
local nextAvailable = 1;
while (MSBTProfiles.currentProfile.scrollAreas["Custom" .. nextAvailable]) do
nextAvailable = nextAvailable + 1;
end
 
local newKey = "Custom" .. nextAvailable;
local saSettings = {};
saSettings.name = settings.inputText;
MSBTProfiles.SetOption("scrollAreas", newKey, saSettings);
MSBTAnimations.UpdateScrollAreas();
tabFrames.scrollAreas.controls.scrollAreasListbox:AddItem(newKey, true);
end
 
 
-- ****************************************************************************
-- Called when one of the enable scroll area checkboxes is clicked.
-- ****************************************************************************
local function ScrollAreasTab_EnableOnClick(this, isChecked)
local line = this:GetParent();
MSBTProfiles.SetOption("scrollAreas." .. line.scrollAreaKey, "disabled", not isChecked);
MSBTAnimations.UpdateScrollAreas();
end
 
 
-- ****************************************************************************
-- Changes the passed scroll area to the passed name.
-- ****************************************************************************
local function ScrollAreasTab_ChangeScrollAreaName(settings)
MSBTProfiles.SetOption("scrollAreas." .. settings.saveArg1, "name", settings.inputText);
MSBTAnimations.UpdateScrollAreas();
tabFrames.scrollAreas.controls.scrollAreasListbox:Refresh();
end
 
 
-- ****************************************************************************
-- Called when one of the edit scroll area name buttons is clicked.
-- ****************************************************************************
local function ScrollAreasTab_EditNameButtonOnClick(this)
local saKey = this:GetParent().scrollAreaKey;
local objLocale = MSBTLocale.EDITBOXES["scrollAreaName"];
EraseTable(configTable);
configTable.defaultText = MSBTProfiles.currentProfile.scrollAreas[saKey].name;
configTable.editboxLabel = objLocale.label;
configTable.editboxTooltip = objLocale.tooltip
configTable.parentFrame = tabFrames.scrollAreas;
configTable.anchorFrame = this;
configTable.anchorPoint = this:GetParent().lineNumber > 5 and "BOTTOMRIGHT" or "TOPRIGHT";
configTable.relativePoint = this:GetParent().lineNumber > 5 and "TOPRIGHT" or "BOTTOMRIGHT";
configTable.validateHandler = ScrollAreasTab_ValidateScrollAreaName;
configTable.saveHandler = ScrollAreasTab_ChangeScrollAreaName;
configTable.saveArg1 = saKey;
configTable.hideHandler = ScrollAreasTab_EnableControls;
DisableControls(tabFrames.scrollAreas.controls);
MSBTPopups.ShowInput(configTable);
end
 
 
-- ****************************************************************************
-- Deletes the scroll area for the passed line and removes the line.
-- ****************************************************************************
local function ScrollAreasTab_DeleteScrollArea(line)
MSBTProfiles.SetOption("scrollAreas", line.scrollAreaKey, nil);
tabFrames.scrollAreas.controls.scrollAreasListbox:RemoveItem(line.itemNumber);
MSBTAnimations.UpdateScrollAreas();
end
 
 
-- ****************************************************************************
-- Called when one of the delete scroll area buttons is clicked.
-- ****************************************************************************
local function ScrollAreasTab_DeleteButtonOnClick(this)
EraseTable(configTable);
configTable.parentFrame = tabFrames.scrollAreas;
configTable.anchorFrame = this;
configTable.anchorPoint = this:GetParent().lineNumber > 5 and "BOTTOMRIGHT" or "TOPRIGHT";
configTable.relativePoint = this:GetParent().lineNumber > 5 and "TOPRIGHT" or "BOTTOMRIGHT";
configTable.acknowledgeHandler = ScrollAreasTab_DeleteScrollArea;
configTable.saveArg1 = this:GetParent();
configTable.hideHandler = ScrollAreasTab_EnableControls;
DisableControls(tabFrames.scrollAreas.controls);
MSBTPopups.ShowAcknowledge(configTable);
end
 
 
-- ****************************************************************************
-- Saves the font settings selected by the user.
-- ****************************************************************************
local function ScrollAreasTab_SaveFontSettings(fontSettings, scrollAreaKey)
-- Normal font settings.
MSBTProfiles.SetOption("scrollAreas." .. scrollAreaKey, "normalFontName", fontSettings.normalFontName);
MSBTProfiles.SetOption("scrollAreas." .. scrollAreaKey, "normalOutlineIndex", fontSettings.normalOutlineIndex);
MSBTProfiles.SetOption("scrollAreas." .. scrollAreaKey, "normalFontSize", fontSettings.normalFontSize);
MSBTProfiles.SetOption("scrollAreas." .. scrollAreaKey, "normalFontAlpha", fontSettings.normalFontAlpha);
 
-- Crit font settings.
MSBTProfiles.SetOption("scrollAreas." .. scrollAreaKey, "critFontName", fontSettings.critFontName);
MSBTProfiles.SetOption("scrollAreas." .. scrollAreaKey, "critOutlineIndex", fontSettings.critOutlineIndex);
MSBTProfiles.SetOption("scrollAreas." .. scrollAreaKey, "critFontSize", fontSettings.critFontSize);
MSBTProfiles.SetOption("scrollAreas." .. scrollAreaKey, "critFontAlpha", fontSettings.critFontAlpha);
 
MSBTAnimations.UpdateScrollAreas();
end
 
 
-- ****************************************************************************
-- Called when one of the font settings buttons is clicked.
-- ****************************************************************************
local function ScrollAreasTab_FontButtonOnClick(this)
local saKey = this:GetParent().scrollAreaKey;
local saSettings = MSBTProfiles.currentProfile.scrollAreas[saKey];
local fonts = MSBTAnimations.fonts;
 
EraseTable(configTable);
configTable.title = saSettings.name;
local fontName = MSBTProfiles.currentProfile.normalFontName;
if (not MSBTAnimations.fonts[fontName]) then fontName = DEFAULT_FONT_NAME; end
configTable.inheritedNormalFontName = fontName;
configTable.inheritedNormalOutlineIndex = MSBTProfiles.currentProfile.normalOutlineIndex;
configTable.inheritedNormalFontSize = MSBTProfiles.currentProfile.normalFontSize;
configTable.inheritedNormalFontAlpha = MSBTProfiles.currentProfile.normalFontAlpha;
 
fontName = MSBTProfiles.currentProfile.critFontName;
if (not MSBTAnimations.fonts[fontName]) then fontName = DEFAULT_FONT_NAME; end
configTable.inheritedCritFontName = fontName;
configTable.inheritedCritFontName = MSBTProfiles.currentProfile.critFontName;
configTable.inheritedCritOutlineIndex = MSBTProfiles.currentProfile.critOutlineIndex;
configTable.inheritedCritFontSize = MSBTProfiles.currentProfile.critFontSize;
configTable.inheritedCritFontAlpha = MSBTProfiles.currentProfile.critFontAlpha;
 
fontName = saSettings.normalFontName;
if (not MSBTAnimations.fonts[fontName]) then fontName = nil; end
configTable.normalFontName = fontName;
configTable.normalOutlineIndex = saSettings.normalOutlineIndex;
configTable.normalFontSize = saSettings.normalFontSize;
configTable.normalFontAlpha = saSettings.normalFontAlpha;
 
fontName = saSettings.critFontName;
if (not MSBTAnimations.fonts[fontName]) then fontName = nil; end
configTable.critFontName = fontName;
configTable.critOutlineIndex = saSettings.critOutlineIndex;
configTable.critFontSize = saSettings.critFontSize;
configTable.critFontAlpha = saSettings.critFontAlpha;
 
configTable.parentFrame = tabFrames.scrollAreas;
configTable.anchorFrame = tabFrames.scrollAreas;
configTable.anchorPoint = "BOTTOM";
configTable.relativePoint = "BOTTOM";
configTable.saveHandler = ScrollAreasTab_SaveFontSettings;
configTable.saveArg1 = saKey;
configTable.hideHandler = ScrollAreasTab_EnableControls;
DisableControls(tabFrames.scrollAreas.controls);
MSBTPopups.ShowFont(configTable);
end
 
 
-- ****************************************************************************
-- Called by listbox to create a line for scroll areas.
-- ****************************************************************************
local function ScrollAreasTab_CreateLine(this)
local controls = tabFrames.scrollAreas.controls;
 
local frame = CreateFrame("Button", nil, this);
frame:EnableMouse(false);
 
-- Enable checkbox.
local checkbox = MSBTControls.CreateCheckbox(frame);
local objLocale = MSBTLocale.CHECKBOXES["enableScrollArea"];
checkbox:Configure(24, nil, objLocale.tooltip);
checkbox:SetPoint("LEFT", frame, "LEFT", 5, 0);
checkbox:SetClickHandler(ScrollAreasTab_EnableOnClick);
frame.enableCheckbox = checkbox;
controls[#controls+1] = checkbox;
 
-- Delete scroll area button.
button = MSBTControls.CreateIconButton(frame, "Delete");
objLocale = MSBTLocale.BUTTONS["deleteScrollArea"];
button:SetTooltip(objLocale.tooltip);
button:SetPoint("RIGHT", frame, "RIGHT", -10, 0);
button:SetClickHandler(ScrollAreasTab_DeleteButtonOnClick);
frame.deleteButton = button;
controls[#controls+1] = button;
 
-- Edit scroll area name button.
local button = MSBTControls.CreateIconButton(frame, "Configure");
objLocale = MSBTLocale.BUTTONS["editScrollAreaName"];
button:SetTooltip(objLocale.tooltip);
button:SetPoint("RIGHT", controls[#controls], "LEFT", 0, 0);
button:SetClickHandler(ScrollAreasTab_EditNameButtonOnClick);
controls[#controls+1] = button;
 
 
-- Scroll area font settings button.
button = MSBTControls.CreateIconButton(frame, "FontSettings");
objLocale = MSBTLocale.BUTTONS["scrollAreaFontSettings"];
button:SetTooltip(objLocale.tooltip);
button:SetPoint("RIGHT", controls[#controls], "LEFT", 0, 0);
button:SetClickHandler(ScrollAreasTab_FontButtonOnClick);
controls[#controls+1] = button;
 
return frame;
end
 
 
-- ****************************************************************************
-- Called by listbox to display a line.
-- ****************************************************************************
local function ScrollAreasTab_DisplayLine(this, line, key, isSelected)
local saSettings = MSBTProfiles.currentProfile.scrollAreas[key];
line.scrollAreaKey = key;
line.enableCheckbox:SetLabel(saSettings.name);
line.enableCheckbox:SetChecked(not saSettings.disabled);
 
-- Disable the delete button for the default scroll areas.
if (MSBTProfiles.masterProfile.scrollAreas[key]) then
line.deleteButton:Disable();
else
line.deleteButton:Enable();
end
end
 
 
-- ****************************************************************************
-- Creates the scroll areas tab frame contents.
-- ****************************************************************************
local function ScrollAreasTab_Create()
local tabFrame = tabFrames.scrollAreas;
tabFrame.controls = {};
local controls = tabFrame.controls;
 
-- Horizontal bar.
local texture = tabFrame:CreateTexture(nil, "ARTWORK");
texture:SetTexture("Interface\\PaperDollInfoFrame\\SkillFrame-BotLeft");
texture:SetHeight(4);
texture:SetPoint("TOPLEFT", tabFrame, "TOPLEFT", 0, -45);
texture:SetPoint("TOPRIGHT", tabFrame, "TOPRIGHT", 0, -45);
texture:SetTexCoord(0.078125, 1, 0.59765625, 0.61328125);
 
-- Add scroll area button.
local button = MSBTControls.CreateOptionButton(tabFrame);
local objLocale = MSBTLocale.BUTTONS["addScrollArea"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("BOTTOMLEFT", texture, "TOPLEFT", 5, 15);
button:SetClickHandler(
function (this)
objLocale = MSBTLocale.EDITBOXES["scrollAreaName"];
EraseTable(configTable);
configTable.defaultText = MSBTLocale.MSG_NEW_SCROLL_AREA;
configTable.editboxLabel = objLocale.label;
configTable.editboxTooltip = objLocale.tooltip
configTable.parentFrame = tabFrames.scrollAreas;
configTable.anchorFrame = this;
configTable.validateHandler = ScrollAreasTab_ValidateScrollAreaName;
configTable.saveHandler = ScrollAreasTab_AddScrollArea;
configTable.hideHandler = ScrollAreasTab_EnableControls;
DisableControls(controls);
MSBTPopups.ShowInput(configTable);
end
);
controls.addScrollAreaButton = button;
 
-- Configure scroll areas button.
button = MSBTControls.CreateOptionButton(tabFrame);
objLocale = MSBTLocale.BUTTONS["configScrollAreas"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("BOTTOMRIGHT", texture, "TOPRIGHT", -5, 15);
button:SetClickHandler(
function (this)
MSBTOptMain.HideMainFrame();
MSBTPopups.ShowScrollAreaConfig();
end
);
controls.configScrollAreasButton = button;
 
-- Scroll areas listbox.
local listbox = MSBTControls.CreateListbox(tabFrame);
listbox:Configure(400, 300, 25);
listbox:SetPoint("TOPLEFT", tabFrame, "TOPLEFT", 0, -50);
listbox:SetCreateLineHandler(ScrollAreasTab_CreateLine);
listbox:SetDisplayHandler(ScrollAreasTab_DisplayLine);
controls.scrollAreasListbox = listbox;
 
-- Reusable table for scroll areas.
tabFrame.scrollAreasTable = {};
 
tabFrame.created = true;
end
 
 
-- ****************************************************************************
-- Called when the tab frame is shown.
-- ****************************************************************************
local function ScrollAreasTab_OnShow()
if (not tabFrames.scrollAreas.created) then ScrollAreasTab_Create(); end
 
-- Set the frame up to populate the profile options when it is shown.
local listbox = tabFrames.scrollAreas.controls.scrollAreasListbox;
 
local scrollAreasTable = tabFrames.scrollAreas.scrollAreasTable;
EraseTable(scrollAreasTable);
for saKey, saSettings in pairs(MSBTAnimations.scrollAreas) do
scrollAreasTable[saKey] = saSettings.name;
end
local sortedKeys = SortKeysByValue(scrollAreasTable);
 
local previousOffset = listbox:GetOffset();
listbox:Clear();
for _, key in ipairs(sortedKeys) do
listbox:AddItem(key);
end
listbox:SetOffset(previousOffset);
end
 
 
-------------------------------------------------------------------------------
-- Events tab functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Sets up an event with the passed event type and codes.
-- ****************************************************************************
local function EventsTab_SetupEvent(event, eventType, codes)
event.eventType = eventType;
event.codes = codes;
end
 
 
-- ****************************************************************************
-- Sets up the event category entries with their associated event types and
-- codes.
-- ****************************************************************************
local function EventsTab_SetupEvents()
local c = MSBTLocale.EVENT_CODES;
local obj = MSBTLocale.INCOMING_PLAYER_EVENTS;
EventsTab_SetupEvent(obj[1], "INCOMING_DAMAGE", c.DAMAGE_TAKEN .. c.ATTACKER_NAME);
EventsTab_SetupEvent(obj[2], "INCOMING_DAMAGE_CRIT", c.DAMAGE_TAKEN .. c.ATTACKER_NAME);
EventsTab_SetupEvent(obj[3], "INCOMING_MISS", c.ATTACKER_NAME);
EventsTab_SetupEvent(obj[4], "INCOMING_DODGE", c.ATTACKER_NAME);
EventsTab_SetupEvent(obj[5], "INCOMING_PARRY", c.ATTACKER_NAME);
EventsTab_SetupEvent(obj[6], "INCOMING_BLOCK", c.ATTACKER_NAME);
EventsTab_SetupEvent(obj[7], "INCOMING_ABSORB", c.ATTACKER_NAME);
EventsTab_SetupEvent(obj[8], "INCOMING_IMMUNE", c.ATTACKER_NAME);
EventsTab_SetupEvent(obj[9], "INCOMING_SPELL_DAMAGE", c.DAMAGE_TAKEN .. c.ATTACKER_NAME .. c.SKILL_NAME .. c.SKILL_LONG .. c.DAMAGE_TYPE_TAKEN);
EventsTab_SetupEvent(obj[10], "INCOMING_SPELL_DAMAGE_CRIT", c.DAMAGE_TAKEN .. c.ATTACKER_NAME .. c.SKILL_NAME .. c.SKILL_LONG .. c.DAMAGE_TYPE_TAKEN);
EventsTab_SetupEvent(obj[11], "INCOMING_SPELL_DOT", c.DAMAGE_TAKEN .. c.ATTACKER_NAME .. c.SKILL_NAME .. c.SKILL_LONG .. c.DAMAGE_TYPE_TAKEN);
EventsTab_SetupEvent(obj[12], "INCOMING_SPELL_MISS", c.ATTACKER_NAME .. c.SKILL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[13], "INCOMING_SPELL_DODGE", c.ATTACKER_NAME .. c.SKILL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[14], "INCOMING_SPELL_PARRY", c.ATTACKER_NAME .. c.SKILL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[15], "INCOMING_SPELL_BLOCK", c.ATTACKER_NAME .. c.SKILL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[16], "INCOMING_SPELL_RESIST", c.ATTACKER_NAME .. c.SPELL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[17], "INCOMING_SPELL_ABSORB", c.ATTACKER_NAME .. c.SKILL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[18], "INCOMING_SPELL_IMMUNE", c.ATTACKER_NAME .. c.SKILL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[19], "INCOMING_SPELL_REFLECT", c.ATTACKER_NAME .. c.SKILL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[20], "INCOMING_SPELL_INTERRUPT", c.ATTACKER_NAME .. c.SPELL_NAME);
EventsTab_SetupEvent(obj[21], "INCOMING_HEAL", c.HEALING_TAKEN .. c.HEALER_NAME .. c.SPELL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[22], "INCOMING_HEAL_CRIT", c.HEALING_TAKEN .. c.HEALER_NAME .. c.SPELL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[23], "INCOMING_HOT", c.HEALING_TAKEN .. c.HEALER_NAME .. c.SPELL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[24], "INCOMING_ENVIRONMENTAL", c.DAMAGE_TAKEN .. c.ENVIRONMENTAL_DAMAGE);
 
obj = MSBTLocale.INCOMING_PET_EVENTS;
EventsTab_SetupEvent(obj[1], "PET_INCOMING_DAMAGE", c.DAMAGE_TAKEN .. c.ATTACKER_NAME);
EventsTab_SetupEvent(obj[2], "PET_INCOMING_DAMAGE_CRIT", c.DAMAGE_TAKEN .. c.ATTACKER_NAME);
EventsTab_SetupEvent(obj[3], "PET_INCOMING_MISS", c.ATTACKER_NAME);
EventsTab_SetupEvent(obj[4], "PET_INCOMING_DODGE", c.ATTACKER_NAME);
EventsTab_SetupEvent(obj[5], "PET_INCOMING_PARRY", c.ATTACKER_NAME);
EventsTab_SetupEvent(obj[6], "PET_INCOMING_BLOCK", c.ATTACKER_NAME);
EventsTab_SetupEvent(obj[7], "PET_INCOMING_ABSORB", c.ATTACKER_NAME);
EventsTab_SetupEvent(obj[8], "PET_INCOMING_IMMUNE", c.ATTACKER_NAME);
EventsTab_SetupEvent(obj[9], "PET_INCOMING_SPELL_DAMAGE", c.DAMAGE_TAKEN .. c.ATTACKER_NAME .. c.SKILL_NAME .. c.SKILL_LONG .. c.DAMAGE_TYPE_TAKEN);
EventsTab_SetupEvent(obj[10], "PET_INCOMING_SPELL_DAMAGE_CRIT", c.DAMAGE_TAKEN .. c.ATTACKER_NAME .. c.SKILL_NAME .. c.SKILL_LONG .. c.DAMAGE_TYPE_TAKEN);
EventsTab_SetupEvent(obj[11], "PET_INCOMING_SPELL_DOT", c.DAMAGE_TAKEN .. c.ATTACKER_NAME .. c.SKILL_NAME .. c.SKILL_LONG .. c.DAMAGE_TYPE_TAKEN);
EventsTab_SetupEvent(obj[12], "PET_INCOMING_SPELL_MISS", c.ATTACKER_NAME .. c.SKILL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[13], "PET_INCOMING_SPELL_DODGE", c.ATTACKER_NAME .. c.SKILL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[14], "PET_INCOMING_SPELL_PARRY", c.ATTACKER_NAME .. c.SKILL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[15], "PET_INCOMING_SPELL_BLOCK", c.ATTACKER_NAME .. c.SKILL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[16], "PET_INCOMING_SPELL_RESIST", c.ATTACKER_NAME .. c.SPELL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[17], "PET_INCOMING_SPELL_ABSORB", c.ATTACKER_NAME .. c.SKILL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[18], "PET_INCOMING_SPELL_IMMUNE", c.ATTACKER_NAME .. c.SKILL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[19], "PET_INCOMING_HEAL", c.HEALING_TAKEN .. c.HEALER_NAME .. c.SPELL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[20], "PET_INCOMING_HEAL_CRIT", c.HEALING_TAKEN .. c.HEALER_NAME .. c.SPELL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[21], "PET_INCOMING_HOT", c.HEALING_TAKEN .. c.HEALER_NAME .. c.SPELL_NAME .. c.SKILL_LONG);
 
obj = MSBTLocale.OUTGOING_PLAYER_EVENTS;
EventsTab_SetupEvent(obj[1], "OUTGOING_DAMAGE", c.DAMAGE_DONE .. c.ATTACKED_NAME);
EventsTab_SetupEvent(obj[2], "OUTGOING_DAMAGE_CRIT", c.DAMAGE_DONE .. c.ATTACKED_NAME);
EventsTab_SetupEvent(obj[3], "OUTGOING_MISS", c.ATTACKED_NAME);
EventsTab_SetupEvent(obj[4], "OUTGOING_DODGE", c.ATTACKED_NAME);
EventsTab_SetupEvent(obj[5], "OUTGOING_PARRY", c.ATTACKED_NAME);
EventsTab_SetupEvent(obj[6], "OUTGOING_BLOCK", c.ATTACKED_NAME);
EventsTab_SetupEvent(obj[7], "OUTGOING_ABSORB", c.ATTACKED_NAME);
EventsTab_SetupEvent(obj[8], "OUTGOING_IMMUNE", c.ATTACKED_NAME);
EventsTab_SetupEvent(obj[9], "OUTGOING_EVADE", c.ATTACKED_NAME);
EventsTab_SetupEvent(obj[10], "OUTGOING_SPELL_DAMAGE", c.DAMAGE_DONE .. c.ATTACKED_NAME .. c.SKILL_NAME .. c.SKILL_LONG .. c.DAMAGE_TYPE_DONE);
EventsTab_SetupEvent(obj[11], "OUTGOING_SPELL_DAMAGE_CRIT", c.DAMAGE_DONE .. c.ATTACKED_NAME .. c.SKILL_NAME .. c.SKILL_LONG .. c.DAMAGE_TYPE_DONE);
EventsTab_SetupEvent(obj[12], "OUTGOING_SPELL_DOT", c.DAMAGE_DONE .. c.ATTACKED_NAME .. c.SKILL_NAME .. c.SKILL_LONG .. c.DAMAGE_TYPE_DONE);
EventsTab_SetupEvent(obj[13], "OUTGOING_SPELL_MISS", c.ATTACKED_NAME .. c.SKILL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[14], "OUTGOING_SPELL_DODGE", c.ATTACKED_NAME .. c.SKILL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[15], "OUTGOING_SPELL_PARRY", c.ATTACKED_NAME .. c.SKILL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[16], "OUTGOING_SPELL_BLOCK", c.ATTACKED_NAME .. c.SKILL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[17], "OUTGOING_SPELL_RESIST", c.ATTACKED_NAME .. c.SPELL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[18], "OUTGOING_SPELL_ABSORB", c.ATTACKED_NAME .. c.SKILL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[19], "OUTGOING_SPELL_IMMUNE", c.ATTACKED_NAME .. c.SKILL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[20], "OUTGOING_SPELL_REFLECT", c.ATTACKED_NAME .. c.SKILL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[21], "OUTGOING_SPELL_INTERRUPT", c.ATTACKED_NAME .. c.SKILL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[22], "OUTGOING_SPELL_EVADE", c.ATTACKED_NAME .. c.SKILL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[23], "OUTGOING_HEAL", c.HEALING_DONE .. c.HEALED_NAME .. c.SPELL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[24], "OUTGOING_HEAL_CRIT", c.HEALING_DONE .. c.HEALED_NAME .. c.SPELL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[25], "OUTGOING_HOT", c.HEALING_DONE .. c.HEALED_NAME .. c.SPELL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[26], "OUTGOING_DISPEL", c.BUFF_NAME .. c.SKILL_LONG);
 
obj = MSBTLocale.OUTGOING_PET_EVENTS;
EventsTab_SetupEvent(obj[1], "PET_OUTGOING_DAMAGE", c.DAMAGE_DONE .. c.ATTACKED_NAME);
EventsTab_SetupEvent(obj[2], "PET_OUTGOING_DAMAGE_CRIT", c.DAMAGE_DONE .. c.ATTACKED_NAME);
EventsTab_SetupEvent(obj[3], "PET_OUTGOING_MISS", c.ATTACKED_NAME);
EventsTab_SetupEvent(obj[4], "PET_OUTGOING_DODGE", c.ATTACKED_NAME);
EventsTab_SetupEvent(obj[5], "PET_OUTGOING_PARRY", c.ATTACKED_NAME);
EventsTab_SetupEvent(obj[6], "PET_OUTGOING_BLOCK", c.ATTACKED_NAME);
EventsTab_SetupEvent(obj[7], "PET_OUTGOING_ABSORB", c.ATTACKED_NAME);
EventsTab_SetupEvent(obj[8], "PET_OUTGOING_IMMUNE", c.ATTACKED_NAME);
EventsTab_SetupEvent(obj[9], "PET_OUTGOING_EVADE", c.ATTACKED_NAME);
EventsTab_SetupEvent(obj[10], "PET_OUTGOING_SPELL_DAMAGE", c.DAMAGE_DONE .. c.ATTACKED_NAME .. c.SKILL_NAME .. c.SKILL_LONG .. c.DAMAGE_TYPE_DONE);
EventsTab_SetupEvent(obj[11], "PET_OUTGOING_SPELL_DAMAGE_CRIT", c.DAMAGE_DONE .. c.ATTACKED_NAME .. c.SKILL_NAME .. c.SKILL_LONG .. c.DAMAGE_TYPE_DONE);
EventsTab_SetupEvent(obj[12], "PET_OUTGOING_SPELL_DOT", c.DAMAGE_DONE .. c.ATTACKED_NAME .. c.SKILL_NAME .. c.SKILL_LONG .. c.DAMAGE_TYPE_DONE);
EventsTab_SetupEvent(obj[13], "PET_OUTGOING_SPELL_MISS", c.ATTACKED_NAME .. c.SKILL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[14], "PET_OUTGOING_SPELL_DODGE", c.ATTACKED_NAME .. c.SKILL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[15], "PET_OUTGOING_SPELL_PARRY", c.ATTACKED_NAME .. c.SKILL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[16], "PET_OUTGOING_SPELL_BLOCK", c.ATTACKED_NAME .. c.SKILL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[17], "PET_OUTGOING_SPELL_RESIST", c.ATTACKED_NAME .. c.SPELL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[18], "PET_OUTGOING_SPELL_ABSORB", c.ATTACKED_NAME .. c.SKILL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[19], "PET_OUTGOING_SPELL_IMMUNE", c.ATTACKED_NAME .. c.SKILL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[20], "PET_OUTGOING_SPELL_EVADE", c.ATTACKED_NAME .. c.SKILL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[21], "PET_OUTGOING_DISPEL", c.BUFF_NAME .. c.SKILL_LONG);
 
obj = MSBTLocale.NOTIFICATION_EVENTS;
EventsTab_SetupEvent(obj[1], "NOTIFICATION_DEBUFF", c.DEBUFF_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[2], "NOTIFICATION_BUFF", c.BUFF_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[3], "NOTIFICATION_ITEM_BUFF", c.ITEM_BUFF_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[4], "NOTIFICATION_DEBUFF_FADE", c.DEBUFF_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[5], "NOTIFICATION_BUFF_FADE", c.BUFF_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[6], "NOTIFICATION_ITEM_BUFF_FADE", c.ITEM_BUFF_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[7], "NOTIFICATION_COMBAT_ENTER", "");
EventsTab_SetupEvent(obj[8], "NOTIFICATION_COMBAT_LEAVE", "");
EventsTab_SetupEvent(obj[9], "NOTIFICATION_POWER_GAIN", c.ENERGY_AMOUNT .. c.POWER_TYPE .. c.SKILL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[10], "NOTIFICATION_POWER_LOSS", c.ENERGY_AMOUNT .. c.POWER_TYPE .. c.SKILL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[11], "NOTIFICATION_CP_GAIN", c.CP_AMOUNT);
EventsTab_SetupEvent(obj[12], "NOTIFICATION_CP_FULL", c.CP_AMOUNT);
EventsTab_SetupEvent(obj[13], "NOTIFICATION_HONOR_GAIN", c.HONOR_AMOUNT);
EventsTab_SetupEvent(obj[14], "NOTIFICATION_REP_GAIN", c.REP_AMOUNT);
EventsTab_SetupEvent(obj[15], "NOTIFICATION_REP_LOSS", c.REP_AMOUNT);
EventsTab_SetupEvent(obj[16], "NOTIFICATION_SKILL_GAIN", c.SKILL_AMOUNT .. c.SKILL_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[17], "NOTIFICATION_EXPERIENCE_GAIN", c.EXPERIENCE_AMOUNT);
EventsTab_SetupEvent(obj[18], "NOTIFICATION_PC_KILLING_BLOW", c.UNIT_KILLED);
EventsTab_SetupEvent(obj[19], "NOTIFICATION_NPC_KILLING_BLOW", c.UNIT_KILLED);
EventsTab_SetupEvent(obj[20], "NOTIFICATION_SOUL_SHARD_CREATED", c.SHARD_NAME);
EventsTab_SetupEvent(obj[21], "NOTIFICATION_EXTRA_ATTACK", c.EXTRA_ATTACKS .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[22], "NOTIFICATION_ENEMY_BUFF", c.BUFFED_NAME .. c.BUFF_NAME .. c.SKILL_LONG);
EventsTab_SetupEvent(obj[23], "NOTIFICATION_MONSTER_EMOTE", c.EMOTE_TEXT);
EventsTab_SetupEvent(obj[24], "NOTIFICATION_MONEY", c.MONEY_TEXT);
end
 
 
-- ****************************************************************************
-- Changes the event category to the passed value.
-- ****************************************************************************
local function EventsTab_ChangeEventCategory(category)
local controls = tabFrames.events.controls;
 
controls.eventsListbox:Clear();
for index in ipairs(MSBTLocale[category]) do
controls.eventsListbox:AddItem(index);
end
end
 
 
-- ****************************************************************************
-- Enables the controls on the events tab.
-- ****************************************************************************
local function EventsTab_EnableControls()
for name, frame in pairs(tabFrames.events.controls) do
if (frame.Enable) then frame:Enable(); end
end
end
 
 
-- ****************************************************************************
-- Moves all the events in the selected category to the passed scroll area.
-- ****************************************************************************
local function EventsTab_MoveAll(scrollArea)
local events = MSBTLocale[tabFrames.events.controls.eventCategoryDropdown:GetSelectedID()];
for index, eventData in ipairs(events) do
MSBTProfiles.SetOption("events." .. eventData.eventType, "scrollArea", scrollArea);
end
end
 
 
-- ****************************************************************************
-- Called when one of the event color swatches is changed.
-- ****************************************************************************
local function EventsTab_ColorswatchOnChanged(this)
local eventType = this:GetParent().eventType;
MSBTProfiles.SetOption("events." .. eventType, "colorR", this.r, 1);
MSBTProfiles.SetOption("events." .. eventType, "colorG", this.g, 1);
MSBTProfiles.SetOption("events." .. eventType, "colorB", this.b, 1);
end
 
 
-- ****************************************************************************
-- Called when one of the event enable checkboxes is clicked.
-- ****************************************************************************
local function EventsTab_EnableOnClick(this, isChecked)
local eventType = this:GetParent().eventType;
MSBTProfiles.SetOption("events." .. eventType, "disabled", not isChecked);
end
 
 
-- ****************************************************************************
-- Saves the additional event settings selected by the user.
-- ****************************************************************************
local function EventsTab_SaveEventSettings(settings, eventType)
MSBTProfiles.SetOption("events." .. eventType, "scrollArea", settings.scrollArea, DEFAULT_SCROLL_AREA);
MSBTProfiles.SetOption("events." .. eventType, "message", settings.message);
MSBTProfiles.SetOption("events." .. eventType, "alwaysSticky", settings.alwaysSticky);
MSBTProfiles.SetOption("events." .. eventType, "soundFile", settings.soundFile, "");
 
tabFrames.events.controls.eventsListbox:Refresh();
end
 
 
-- ****************************************************************************
-- Called when one of the event settings buttons is clicked.
-- ****************************************************************************
local function EventsTab_SettingsButtonOnClick(this)
local eventType = this:GetParent().eventType;
local eventSettings = MSBTProfiles.currentProfile.events[eventType];
local categoryText = tabFrames.events.controls.eventCategoryDropdown:GetSelectedText();
 
EraseTable(configTable);
configTable.title = categoryText .. " - " .. this:GetParent().enableCheckbox.fontString:GetText();
configTable.message = eventSettings.message;
configTable.codes = this:GetParent().codes;
configTable.scrollArea = eventSettings.scrollArea or DEFAULT_SCROLL_AREA;
configTable.alwaysSticky = eventSettings.alwaysSticky;
configTable.soundFile = eventSettings.soundFile;
configTable.isCrit = eventSettings.isCrit;
configTable.parentFrame = tabFrames.events;
configTable.anchorFrame = tabFrames.events;
configTable.anchorPoint = "TOPRIGHT";
configTable.relativePoint = "TOPRIGHT";
configTable.saveHandler = EventsTab_SaveEventSettings;
configTable.saveArg1 = eventType;
configTable.hideHandler = EventsTab_EnableControls;
DisableControls(tabFrames.events.controls);
MSBTPopups.ShowEvent(configTable);
end
 
 
-- ****************************************************************************
-- Saves the font settings selected by the user.
-- ****************************************************************************
local function EventsTab_SaveFontSettings(settings, eventType)
local isCrit = MSBTProfiles.currentProfile.events[eventType].isCrit;
MSBTProfiles.SetOption("events." .. eventType, "fontName", isCrit and settings.critFontName or settings.normalFontName);
MSBTProfiles.SetOption("events." .. eventType, "outlineIndex", isCrit and settings.critOutlineIndex or settings.normalOutlineIndex);
MSBTProfiles.SetOption("events." .. eventType, "fontSize", isCrit and settings.critFontSize or settings.normalFontSize);
MSBTProfiles.SetOption("events." .. eventType, "fontAlpha", isCrit and settings.critFontAlpha or settings.normalFontAlpha);
end
 
 
-- ****************************************************************************
-- Called when one of the font settings buttons is clicked.
-- ****************************************************************************
local function EventsTab_FontButtonOnClick(this)
local categoryText = tabFrames.events.controls.eventCategoryDropdown:GetSelectedText();
local eventType = this:GetParent().eventType;
local eventSettings = MSBTProfiles.currentProfile.events[eventType];
 
local saKey = eventSettings.scrollArea;
local saSettings = MSBTProfiles.currentProfile.scrollAreas[saKey];
if (not saSettings) then saSettings = MSBTProfiles.currentProfile.scrollAreas[DEFAULT_SCROLL_AREA]; end
local fonts = MSBTAnimations.fonts;
 
EraseTable(configTable);
configTable.title = categoryText .. " - " .. this:GetParent().enableCheckbox.fontString:GetText();
 
local fontName;
if (not eventSettings.isCrit) then
-- Inherit from the correct scroll area.
fontName = saSettings.normalFontName;
if (not MSBTAnimations.fonts[fontName]) then fontName = MSBTProfiles.currentProfile.normalFontName; end
if (not MSBTAnimations.fonts[fontName]) then fontName = DEFAULT_FONT_NAME; end
configTable.inheritedNormalFontName = fontName;
configTable.inheritedNormalOutlineIndex = saSettings.normalOutlineIndex or MSBTProfiles.currentProfile.normalOutlineIndex;
configTable.inheritedNormalFontSize = saSettings.normalFontSize or MSBTProfiles.currentProfile.normalFontSize;
configTable.inheritedNormalFontAlpha = saSettings.normalFontAlpha or MSBTProfiles.currentProfile.normalFontAlpha;
 
fontName = eventSettings.fontName;
if (not MSBTAnimations.fonts[fontName]) then fontName = nil; end
configTable.normalFontName = fontName;
configTable.normalOutlineIndex = eventSettings.outlineIndex;
configTable.normalFontSize = eventSettings.fontSize;
configTable.normalFontAlpha = eventSettings.fontAlpha;
 
configTable.hideCrit = true;
else
-- Inherit from the correct scroll area.
fontName = saSettings.critFontName;
if (not MSBTAnimations.fonts[fontName]) then fontName = MSBTProfiles.currentProfile.critFontName; end
if (not MSBTAnimations.fonts[fontName]) then fontName = DEFAULT_FONT_NAME; end
configTable.inheritedCritFontName = fontName;
configTable.inheritedCritOutlineIndex = saSettings.critOutlineIndex or MSBTProfiles.currentProfile.critOutlineIndex;
configTable.inheritedCritFontSize = saSettings.critFontSize or MSBTProfiles.currentProfile.critFontSize;
configTable.inheritedCritFontAlpha = saSettings.critFontAlpha or MSBTProfiles.currentProfile.critFontAlpha;
 
fontName = eventSettings.fontName;
if (not MSBTAnimations.fonts[fontName]) then fontName = nil; end
configTable.critFontName = fontName;
configTable.critOutlineIndex = eventSettings.outlineIndex;
configTable.critFontSize = eventSettings.fontSize;
configTable.critFontAlpha = eventSettings.fontAlpha;
 
configTable.hideNormal = true;
end
 
configTable.parentFrame = tabFrames.events;
configTable.anchorFrame = tabFrames.events;
configTable.anchorPoint = "BOTTOM";
configTable.relativePoint = "BOTTOM";
configTable.saveHandler = EventsTab_SaveFontSettings;
configTable.saveArg1 = eventType;
configTable.hideHandler = EventsTab_EnableControls;
DisableControls(tabFrames.events.controls);
MSBTPopups.ShowFont(configTable);
end
 
 
-- ****************************************************************************
-- Called by listbox to create a line for events.
-- ****************************************************************************
local function EventsTab_CreateLine(this)
local controls = tabFrames.events.controls;
 
local frame = CreateFrame("Button", nil, this);
frame:EnableMouse(false);
 
-- Event colorswatch.
local colorswatch = MSBTControls.CreateColorswatch(frame);
colorswatch:SetPoint("LEFT", frame, "LEFT", 5, 0);
colorswatch:SetColorChangedHandler(EventsTab_ColorswatchOnChanged);
frame.colorSwatch = colorswatch;
controls[#controls+1] = colorswatch;
 
-- Enable checkbox.
local checkbox = MSBTControls.CreateCheckbox(frame);
checkbox:Configure(24, nil, nil);
checkbox:SetPoint("LEFT", colorswatch, "RIGHT", 5, 0);
checkbox:SetPoint("RIGHT", frame, "LEFT", 190, 0);
checkbox:SetClickHandler(EventsTab_EnableOnClick);
frame.enableCheckbox = checkbox;
controls[#controls+1] = checkbox;
 
-- Event settings button.
button = MSBTControls.CreateIconButton(frame, "Configure");
objLocale = MSBTLocale.BUTTONS["eventSettings"];
button:SetTooltip(objLocale.tooltip);
button:SetPoint("RIGHT", frame, "RIGHT", -10, 0);
button:SetClickHandler(EventsTab_SettingsButtonOnClick);
controls[#controls+1] = button;
 
-- Event font settings button.
button = MSBTControls.CreateIconButton(frame, "FontSettings");
objLocale = MSBTLocale.BUTTONS["eventFontSettings"];
button:SetTooltip(objLocale.tooltip);
button:SetPoint("RIGHT", controls[#controls], "LEFT", 0, 0);
button:SetClickHandler(EventsTab_FontButtonOnClick);
controls[#controls+1] = button;
 
-- Message font string.
local fontString = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall");
fontString:SetPoint("LEFT", checkbox, "RIGHT", 10, 0);
fontString:SetPoint("RIGHT", button, "LEFT", -10, 0);
fontString:SetJustifyH("LEFT");
frame.messageFontString = fontString;
 
 
return frame;
end
 
 
-- ****************************************************************************
-- Called by listbox to display a line.
-- ****************************************************************************
local function EventsTab_DisplayLine(this, line, key, isSelected)
local events = MSBTLocale[tabFrames.events.controls.eventCategoryDropdown:GetSelectedID()];
local eventType = events[key].eventType;
local eventSettings = MSBTProfiles.currentProfile.events[eventType];
local objLocale = events[key];
line.eventType = eventType;
line.codes = events[key].codes;
 
line.colorSwatch:SetColor(eventSettings.colorR or 1, eventSettings.colorG or 1, eventSettings.colorB or 1);
line.enableCheckbox:SetLabel(objLocale.label);
line.enableCheckbox:SetTooltip(objLocale.tooltip);
line.enableCheckbox:SetChecked(not eventSettings.disabled);
line.messageFontString:SetText(eventSettings.message);
end
 
 
-- ****************************************************************************
-- Creates the scroll areas tab frame contents.
-- ****************************************************************************
local function EventsTab_Create()
local tabFrame = tabFrames.events;
tabFrame.controls = {};
local controls = tabFrame.controls;
 
-- Horizontal bar.
local texture = tabFrame:CreateTexture(nil, "ARTWORK");
texture:SetTexture("Interface\\PaperDollInfoFrame\\SkillFrame-BotLeft");
texture:SetHeight(4);
texture:SetPoint("TOPLEFT", tabFrame, "TOPLEFT", 0, -45);
texture:SetPoint("TOPRIGHT", tabFrame, "TOPRIGHT", 0, -45);
texture:SetTexCoord(0.078125, 1, 0.59765625, 0.61328125);
 
-- Move all button.
local button = MSBTControls.CreateOptionButton(tabFrame);
objLocale = MSBTLocale.BUTTONS["moveAll"];
button:Configure(15, objLocale.label, objLocale.tooltip);
button:SetPoint("BOTTOMLEFT", texture, "TOPLEFT", 5, 5);
button:SetClickHandler(
function (this)
EraseTable(configTable);
configTable.title = this:GetText() .. " - " .. controls.eventCategoryDropdown:GetSelectedText();
configTable.parentFrame = tabFrame;
configTable.anchorFrame = this;
configTable.saveHandler = EventsTab_MoveAll;
configTable.hideHandler = EventsTab_EnableControls;
DisableControls(controls);
MSBTPopups.ShowScrollAreaSelection(configTable);
end
);
controls.moveButton = button;
 
-- Toggle all button.
local button = MSBTControls.CreateOptionButton(tabFrame);
objLocale = MSBTLocale.BUTTONS["toggleAll"];
button:Configure(15, objLocale.label, objLocale.tooltip);
button:SetPoint("BOTTOMLEFT", controls.moveButton, "TOPLEFT", 0, 10);
button:SetClickHandler(
function (this)
local events = MSBTLocale[controls.eventCategoryDropdown:GetSelectedID()];
for index, eventData in ipairs(events) do
MSBTProfiles.SetOption("events." .. eventData.eventType, "disabled", not MSBTProfiles.currentProfile.events[eventData.eventType].disabled);
controls.eventsListbox:Refresh();
end
end
);
controls.toggleButton = button;
 
-- Event category dropdown.
local dropdown = MSBTControls.CreateDropdown(tabFrame);
objLocale = MSBTLocale.DROPDOWNS["eventCategory"];
dropdown:Configure(180, objLocale.label, objLocale.tooltip);
dropdown:SetPoint("BOTTOMRIGHT", texture, "TOPRIGHT", -5, 8);
dropdown:SetChangeHandler(
function (this, id)
EventsTab_ChangeEventCategory(id);
end
);
controls.eventCategoryDropdown = dropdown;
 
-- Events listbox.
local listbox = MSBTControls.CreateListbox(tabFrame);
listbox:Configure(400, 300, 25);
listbox:SetPoint("TOPLEFT", tabFrame, "TOPLEFT", 0, -50);
listbox:SetCreateLineHandler(EventsTab_CreateLine);
listbox:SetDisplayHandler(EventsTab_DisplayLine);
controls.eventsListbox = listbox;
 
 
-- Setup the events for all categories.
EventsTab_SetupEvents();
 
-- Populate the available event categories and select incoming player by default.
for index, category in ipairs(MSBTLocale.EVENT_CATEGORIES) do
dropdown:AddItem(category, EVENT_CATEGORY_MAP[index]);
end
dropdown:SetSelectedID(EVENT_CATEGORY_MAP[1]);
EventsTab_ChangeEventCategory(EVENT_CATEGORY_MAP[1]);
 
tabFrame.created = true;
end
 
 
-- ****************************************************************************
-- Called when the tab frame is shown.
-- ****************************************************************************
local function EventsTab_OnShow()
if (not tabFrames.events.created) then EventsTab_Create(); end
 
-- Set the frame up to populate the profile options when it is shown.
tabFrames.events.controls.eventsListbox:Refresh();
end
 
 
-------------------------------------------------------------------------------
-- Triggers tab functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Enables the controls on the triggers tab.
-- ****************************************************************************
local function TriggersTab_EnableControls()
for name, frame in pairs(tabFrames.triggers.controls) do
if (frame.Enable) then frame:Enable(); end
end
end
 
 
-- ****************************************************************************
-- Adds a new trigger with the passed output message.
-- ****************************************************************************
local function TriggersTab_AddTrigger(settings)
local nextAvailable = 1;
while (MSBTProfiles.currentProfile.triggers["Custom" .. nextAvailable]) do
nextAvailable = nextAvailable + 1;
end
 
local newKey = "Custom" .. nextAvailable;
local triggerSettings = {};
triggerSettings.message = settings.inputText;
triggerSettings.alwaysSticky = true;
triggerSettings.fontSize = 26;
MSBTProfiles.SetOption("triggers", newKey, triggerSettings);
MSBTTriggers.UpdateTriggers();
tabFrames.triggers.controls.triggersListbox:AddItem(newKey, true);
end
 
 
-- ****************************************************************************
-- Called when one of the trigger color swatches is changed.
-- ****************************************************************************
local function TriggersTab_ColorswatchOnChanged(this)
local triggerKey = this:GetParent().triggerKey;
MSBTProfiles.SetOption("triggers." .. triggerKey, "colorR", this.r, 1);
MSBTProfiles.SetOption("triggers." .. triggerKey, "colorG", this.g, 1);
MSBTProfiles.SetOption("triggers." .. triggerKey, "colorB", this.b, 1);
MSBTTriggers.UpdateTriggers();
end
 
 
-- ****************************************************************************
-- Called when one of the trigger enable checkboxes is clicked.
-- ****************************************************************************
local function TriggersTab_EnableOnClick(this, isChecked)
local triggerKey = this:GetParent().triggerKey;
MSBTProfiles.SetOption("triggers." .. triggerKey, "disabled", not isChecked);
MSBTTriggers.UpdateTriggers();
end
 
 
-- ****************************************************************************
-- Saves the trigger settings selected by the user.
-- ****************************************************************************
local function TriggersTab_SaveTriggerSettings(settings, triggerKey)
MSBTProfiles.SetOption("triggers." .. triggerKey, "classes", settings.classes);
MSBTProfiles.SetOption("triggers." .. triggerKey, "mainEvents", settings.mainEvents);
MSBTProfiles.SetOption("triggers." .. triggerKey, "exceptions", settings.exceptions);
MSBTTriggers.UpdateTriggers();
end
 
 
-- ****************************************************************************
-- Called when one of the trigger settings buttons is clicked.
-- ****************************************************************************
local function TriggersTab_TriggerSettingsButtonOnClick(this)
local triggerKey = this:GetParent().triggerKey;
local triggerSettings = MSBTProfiles.currentProfile.triggers[triggerKey];
 
EraseTable(configTable);
configTable.title = this:GetParent().enableCheckbox.fontString:GetText();
configTable.triggerKey = triggerKey;
configTable.parentFrame = tabFrames.triggers;
configTable.anchorFrame = tabFrames.triggers;
configTable.anchorPoint = "RIGHT";
configTable.relativePoint = "RIGHT";
configTable.saveHandler = TriggersTab_SaveTriggerSettings;
configTable.saveArg1 = triggerKey;
configTable.hideHandler = TriggersTab_EnableControls;
DisableControls(tabFrames.triggers.controls);
MSBTPopups.ShowTrigger(configTable);
end
 
 
-- ****************************************************************************
-- Saves the font settings selected by the user.
-- ****************************************************************************
local function TriggersTab_SaveFontSettings(settings, triggerKey)
MSBTProfiles.SetOption("triggers." .. triggerKey, "fontName", settings.normalFontName);
MSBTProfiles.SetOption("triggers." .. triggerKey, "outlineIndex", settings.normalOutlineIndex);
MSBTProfiles.SetOption("triggers." .. triggerKey, "fontSize", settings.normalFontSize);
MSBTProfiles.SetOption("triggers." .. triggerKey, "fontAlpha", settings.normalFontAlpha);
MSBTTriggers.UpdateTriggers();
end
 
 
-- ****************************************************************************
-- Called when one of the font settings buttons is clicked.
-- ****************************************************************************
local function TriggersTab_FontButtonOnClick(this)
local triggerKey = this:GetParent().triggerKey;
local triggerSettings = MSBTProfiles.currentProfile.triggers[triggerKey];
 
local saKey = triggerSettings.scrollArea;
local saSettings = MSBTProfiles.currentProfile.scrollAreas[saKey];
if (not saSettings) then saSettings = MSBTProfiles.currentProfile.scrollAreas[DEFAULT_SCROLL_AREA]; end
local fonts = MSBTAnimations.fonts;
 
EraseTable(configTable);
configTable.title = this:GetParent().enableCheckbox.fontString:GetText();
 
local fontName;
fontName = saSettings.normalFontName;
if (not MSBTAnimations.fonts[fontName]) then fontName = MSBTProfiles.currentProfile.normalFontName; end
if (not MSBTAnimations.fonts[fontName]) then fontName = DEFAULT_FONT_NAME; end
configTable.inheritedNormalFontName = fontName;
configTable.inheritedNormalOutlineIndex = saSettings.normalOutlineIndex or MSBTProfiles.currentProfile.normalOutlineIndex;
configTable.inheritedNormalFontSize = saSettings.normalFontSize or MSBTProfiles.currentProfile.normalFontSize;
configTable.inheritedNormalFontAlpha = saSettings.normalFontAlpha or MSBTProfiles.currentProfile.normalFontAlpha;
 
fontName = triggerSettings.fontName;
if (not MSBTAnimations.fonts[fontName]) then fontName = nil; end
configTable.normalFontName = fontName;
configTable.normalOutlineIndex = triggerSettings.outlineIndex;
configTable.normalFontSize = triggerSettings.fontSize;
configTable.normalFontAlpha = triggerSettings.fontAlpha;
 
configTable.hideCrit = true;
 
 
configTable.parentFrame = tabFrames.triggers;
configTable.anchorFrame = tabFrames.triggers;
configTable.anchorPoint = "BOTTOM";
configTable.relativePoint = "BOTTOM";
configTable.saveHandler = TriggersTab_SaveFontSettings;
configTable.saveArg1 = triggerKey;
configTable.hideHandler = TriggersTab_EnableControls;
DisableControls(tabFrames.triggers.controls);
MSBTPopups.ShowFont(configTable);
end
 
 
-- ****************************************************************************
-- Saves the additional event settings selected by the user.
-- ****************************************************************************
local function TriggersTab_SaveEventSettings(settings, triggerKey)
MSBTProfiles.SetOption("triggers." .. triggerKey, "scrollArea", settings.scrollArea, DEFAULT_SCROLL_AREA);
MSBTProfiles.SetOption("triggers." .. triggerKey, "message", settings.message);
MSBTProfiles.SetOption("triggers." .. triggerKey, "alwaysSticky", settings.alwaysSticky);
MSBTProfiles.SetOption("triggers." .. triggerKey, "soundFile", settings.soundFile, "");
MSBTProfiles.SetOption("triggers." .. triggerKey, "iconSkill", settings.iconSkill, "");
MSBTTriggers.UpdateTriggers();
 
tabFrames.triggers.controls.triggersListbox:Refresh();
end
 
 
-- ****************************************************************************
-- Called when one of the event settings buttons is clicked.
-- ****************************************************************************
local function TriggersTab_EventSettingsButtonOnClick(this)
local triggerKey = this:GetParent().triggerKey;
local triggerSettings = MSBTProfiles.currentProfile.triggers[triggerKey];
 
EraseTable(configTable);
configTable.title = this:GetParent().enableCheckbox.fontString:GetText();
configTable.message = triggerSettings.message;
configTable.scrollArea = triggerSettings.scrollArea or DEFAULT_SCROLL_AREA;
configTable.alwaysSticky = triggerSettings.alwaysSticky;
configTable.soundFile = triggerSettings.soundFile;
configTable.showIconSkillEditbox = true;
configTable.iconSkill = triggerSettings.iconSkill;
configTable.parentFrame = tabFrames.triggers;
configTable.anchorFrame = tabFrames.triggers;
configTable.anchorPoint = "TOPRIGHT";
configTable.relativePoint = "TOPRIGHT";
configTable.saveHandler = TriggersTab_SaveEventSettings;
configTable.saveArg1 = triggerKey;
configTable.hideHandler = TriggersTab_EnableControls;
DisableControls(tabFrames.triggers.controls);
MSBTPopups.ShowEvent(configTable);
end
 
 
-- ****************************************************************************
-- Deletes the trigger for the passed line and removes the line.
-- ****************************************************************************
local function TriggersTab_DeleteTrigger(line)
MSBTProfiles.SetOption("triggers", line.triggerKey, false);
tabFrames.triggers.controls.triggersListbox:RemoveItem(line.itemNumber);
MSBTTriggers.UpdateTriggers();
end
 
 
-- ****************************************************************************
-- Called when one of the delete buttons is clicked.
-- ****************************************************************************
local function TriggersTab_DeleteButtonOnClick(this)
EraseTable(configTable);
configTable.parentFrame = tabFrames.triggers;
configTable.anchorFrame = this;
configTable.anchorPoint = this:GetParent().lineNumber > 5 and "BOTTOMRIGHT" or "TOPRIGHT";
configTable.relativePoint = this:GetParent().lineNumber > 5 and "TOPRIGHT" or "BOTTOMRIGHT";
configTable.acknowledgeHandler = TriggersTab_DeleteTrigger;
configTable.saveArg1 = this:GetParent();
configTable.hideHandler = TriggersTab_EnableControls;
DisableControls(tabFrames.triggers.controls);
MSBTPopups.ShowAcknowledge(configTable);
end
 
 
-- ****************************************************************************
-- Called by listbox to create a line for triggers.
-- ****************************************************************************
local function TriggersTab_CreateLine(this)
local controls = tabFrames.triggers.controls;
 
local frame = CreateFrame("Button", nil, this);
frame:EnableMouse(false);
 
-- Event colorswatch.
local colorswatch = MSBTControls.CreateColorswatch(frame);
colorswatch:SetPoint("LEFT", frame, "LEFT", 5, 0);
colorswatch:SetColorChangedHandler(TriggersTab_ColorswatchOnChanged);
frame.colorSwatch = colorswatch;
controls[#controls+1] = colorswatch;
 
-- Enable checkbox.
local checkbox = MSBTControls.CreateCheckbox(frame);
local objLocale = MSBTLocale.CHECKBOXES["enableTrigger"];
checkbox:Configure(24, nil, objLocale.tooltip);
checkbox:SetPoint("LEFT", colorswatch, "RIGHT", 5, 0);
checkbox:SetPoint("RIGHT", frame, "LEFT", 190, 0);
checkbox:SetClickHandler(TriggersTab_EnableOnClick);
frame.enableCheckbox = checkbox;
controls[#controls+1] = checkbox;
 
-- Delete trigger button.
button = MSBTControls.CreateIconButton(frame, "Delete");
objLocale = MSBTLocale.BUTTONS["deleteTrigger"];
button:SetTooltip(objLocale.tooltip);
button:SetPoint("RIGHT", frame, "RIGHT", -10, 0);
button:SetClickHandler(TriggersTab_DeleteButtonOnClick);
controls[#controls+1] = button;
 
-- Event settings button.
button = MSBTControls.CreateIconButton(frame, "Configure");
objLocale = MSBTLocale.BUTTONS["eventSettings"];
button:SetTooltip(objLocale.tooltip);
button:SetPoint("RIGHT", controls[#controls], "LEFT", 0, 0);
button:SetClickHandler(TriggersTab_EventSettingsButtonOnClick);
controls[#controls+1] = button;
 
-- Event font settings button.
button = MSBTControls.CreateIconButton(frame, "FontSettings");
objLocale = MSBTLocale.BUTTONS["eventFontSettings"];
button:SetTooltip(objLocale.tooltip);
button:SetPoint("RIGHT", controls[#controls], "LEFT", 0, 0);
button:SetClickHandler(TriggersTab_FontButtonOnClick);
controls[#controls+1] = button;
 
-- Trigger settings button.
button = MSBTControls.CreateIconButton(frame, "TriggerSettings");
objLocale = MSBTLocale.BUTTONS["triggerSettings"];
button:SetTooltip(objLocale.tooltip);
button:SetPoint("RIGHT", controls[#controls], "LEFT", 0, 0);
button:SetClickHandler(TriggersTab_TriggerSettingsButtonOnClick);
controls[#controls+1] = button;
 
return frame;
end
 
 
-- ****************************************************************************
-- Called by listbox to display a line.
-- ****************************************************************************
local function TriggersTab_DisplayLine(this, line, key, isSelected)
local triggerSettings = MSBTProfiles.currentProfile.triggers[key];
line.triggerKey = key;
 
line.colorSwatch:SetColor(triggerSettings.colorR or 1, triggerSettings.colorG or 1, triggerSettings.colorB or 1);
line.enableCheckbox:SetLabel(triggerSettings.message);
line.enableCheckbox:SetChecked(not triggerSettings.disabled);
end
 
 
-- ****************************************************************************
-- Creates the triggers tab frame contents.
-- ****************************************************************************
local function TriggersTab_Create()
local tabFrame = tabFrames.triggers;
tabFrame.controls = {};
local controls = tabFrame.controls;
 
-- Horizontal bar.
local texture = tabFrame:CreateTexture(nil, "ARTWORK");
texture:SetTexture("Interface\\PaperDollInfoFrame\\SkillFrame-BotLeft");
texture:SetHeight(4);
texture:SetPoint("TOPLEFT", tabFrame, "TOPLEFT", 0, -45);
texture:SetPoint("TOPRIGHT", tabFrame, "TOPRIGHT", 0, -45);
texture:SetTexCoord(0.078125, 1, 0.59765625, 0.61328125);
 
-- Add trigger button.
local button = MSBTControls.CreateOptionButton(tabFrame);
local objLocale = MSBTLocale.BUTTONS["addTrigger"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("BOTTOMLEFT", texture, "TOPLEFT", 5, 15);
button:SetClickHandler(
function (this)
objLocale = MSBTLocale.EDITBOXES["eventMessage"];
EraseTable(configTable);
configTable.defaultText = MSBTLocale.MSG_NEW_TRIGGER;
configTable.editboxLabel = objLocale.label;
configTable.editboxTooltip = objLocale.tooltip
configTable.parentFrame = tabFrames.triggers;
configTable.anchorFrame = this;
configTable.saveHandler = TriggersTab_AddTrigger;
configTable.hideHandler = TriggersTab_EnableControls;
DisableControls(controls);
MSBTPopups.ShowInput(configTable);
end
);
controls.addTriggerButton = button;
 
 
-- Triggers listbox.
local listbox = MSBTControls.CreateListbox(tabFrame);
listbox:Configure(400, 300, 25);
listbox:SetPoint("TOPLEFT", tabFrame, "TOPLEFT", 0, -50);
listbox:SetCreateLineHandler(TriggersTab_CreateLine);
listbox:SetDisplayHandler(TriggersTab_DisplayLine);
controls.triggersListbox = listbox;
 
-- Reusable table for triggers.
tabFrame.triggerTable = {};
 
tabFrame.created = true;
end
 
 
-- ****************************************************************************
-- Called when the tab frame is shown.
-- ****************************************************************************
local function TriggersTab_OnShow()
if (not tabFrames.triggers.created) then TriggersTab_Create(); end
 
-- Set the frame up to populate the profile options when it is shown.
local triggersListbox = tabFrames.triggers.controls.triggersListbox;
 
-- Get triggers from the current profile.
local triggerTable = tabFrames.triggers.triggerTable;
EraseTable(triggerTable);
local currentProfileTriggers = rawget(MSBTProfiles.currentProfile, "triggers");
if (currentProfileTriggers) then
for triggerKey, triggerSettings in pairs(currentProfileTriggers) do
if (triggerSettings) then triggerTable[triggerKey] = triggerSettings.message; end
end
end
 
-- Get triggers available in the master profile that aren't in the current profile.
for triggerKey, triggerSettings in pairs(MSBTProfiles.masterProfile.triggers) do
if (not currentProfileTriggers or rawget(currentProfileTriggers, triggerKey) == nil) then
triggerTable[triggerKey] = triggerSettings.message;
end
end
 
-- Set the frame up to populate the profile options when it is shown.
local listbox = tabFrames.triggers.controls.triggersListbox;
local sortedKeys = SortKeysByValue(triggerTable);
 
local previousOffset = listbox:GetOffset();
listbox:Clear();
for _, key in ipairs(sortedKeys) do
listbox:AddItem(key);
end
listbox:SetOffset(previousOffset);
end
 
 
-------------------------------------------------------------------------------
-- Spam tab functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Enables the controls on the spam tab.
-- ****************************************************************************
local function SpamTab_EnableControls()
local controls = tabFrames.spam.controls;
for name, frame in pairs(controls) do
if (frame.Enable) then frame:Enable(); end
end
end
 
 
-- ****************************************************************************
-- Creates the spam tab frame contents.
-- ****************************************************************************
local function SpamTab_Create()
local tabFrame = tabFrames.spam;
tabFrame.controls = {};
local controls = tabFrame.controls;
 
-- Heal threshold slider.
local slider = MSBTControls.CreateSlider(tabFrame);
objLocale = MSBTLocale.SLIDERS["healThreshold"];
slider:Configure(150, objLocale.label, objLocale.tooltip);
slider:SetPoint("TOPLEFT", tabFrame, "TOPLEFT", 5, -10);
slider:SetMinMaxValues(0, 1000);
slider:SetValueStep(20);
slider:SetValueChangedHandler(
function(this, value)
MSBTProfiles.SetOption(nil, "healThreshold", value);
end
);
controls.healSlider = slider;
 
-- Damage threshold slider.
slider = MSBTControls.CreateSlider(tabFrame);
objLocale = MSBTLocale.SLIDERS["damageThreshold"];
slider:Configure(150, objLocale.label, objLocale.tooltip);
slider:SetPoint("TOPLEFT", controls.healSlider, "BOTTOMLEFT", 0, -10);
slider:SetMinMaxValues(0, 500);
slider:SetValueStep(10);
slider:SetValueChangedHandler(
function(this, value)
MSBTProfiles.SetOption(nil, "damageThreshold", value);
end
);
controls.damageSlider = slider;
 
-- Power threshold slider.
slider = MSBTControls.CreateSlider(tabFrame);
objLocale = MSBTLocale.SLIDERS["powerThreshold"];
slider:Configure(150, objLocale.label, objLocale.tooltip);
slider:SetPoint("TOPLEFT", controls.damageSlider, "BOTTOMLEFT", 0, -10);
slider:SetMinMaxValues(0, 250);
slider:SetValueStep(5);
slider:SetValueChangedHandler(
function(this, value)
MSBTProfiles.SetOption(nil, "powerThreshold", value);
end
);
controls.powerSlider = slider;
 
-- HoT throttling time slider.
slider = MSBTControls.CreateSlider(tabFrame);
objLocale = MSBTLocale.SLIDERS["hotThrottleTime"];
slider:Configure(150, objLocale.label, objLocale.tooltip);
slider:SetPoint("LEFT", controls.healSlider, "RIGHT", 40, 0);
slider:SetMinMaxValues(0, 5);
slider:SetValueStep(1);
slider:SetValueChangedHandler(
function(this, value)
MSBTProfiles.SetOption(nil, "hotThrottleDuration", value);
end
);
controls.hotThrottlingSlider = slider;
 
-- DoT throttling time slider.
slider = MSBTControls.CreateSlider(tabFrame);
objLocale = MSBTLocale.SLIDERS["dotThrottleTime"];
slider:Configure(150, objLocale.label, objLocale.tooltip);
slider:SetPoint("TOPLEFT", controls.hotThrottlingSlider, "BOTTOMLEFT", 0, -10);
slider:SetMinMaxValues(0, 5);
slider:SetValueStep(1);
slider:SetValueChangedHandler(
function(this, value)
MSBTProfiles.SetOption(nil, "dotThrottleDuration", value);
end
);
controls.dotThrottlingSlider = slider;
 
-- Power throttling time slider.
slider = MSBTControls.CreateSlider(tabFrame);
objLocale = MSBTLocale.SLIDERS["powerThrottleTime"];
slider:Configure(150, objLocale.label, objLocale.tooltip);
slider:SetPoint("TOPLEFT", controls.dotThrottlingSlider, "BOTTOMLEFT", 0, -10);
slider:SetMinMaxValues(0, 5);
slider:SetValueStep(1);
slider:SetValueChangedHandler(
function(this, value)
MSBTProfiles.SetOption(nil, "powerThrottleDuration", value);
end
);
controls.powerThrottlingSlider = slider;
 
-- All power gains checkbox.
local checkbox = MSBTControls.CreateCheckbox(tabFrame);
local objLocale = MSBTLocale.CHECKBOXES["allPowerGains"];
checkbox:Configure(28, objLocale.label, objLocale.tooltip);
checkbox:SetPoint("TOPLEFT", tabFrame, "TOPLEFT", 5, -150);
checkbox:SetClickHandler(
function (this, isChecked)
MSBTProfiles.SetOption(nil, "showAllPowerGains", isChecked);
end
);
controls.allPowerCheckbox = checkbox;
 
-- Hyper regen checkbox.
checkbox = MSBTControls.CreateCheckbox(tabFrame);
objLocale = MSBTLocale.CHECKBOXES["hyperRegen"];
checkbox:Configure(28, objLocale.label, objLocale.tooltip);
checkbox:SetPoint("TOPLEFT", controls.allPowerCheckbox, "BOTTOMLEFT", 0, 0);
checkbox:SetClickHandler(
function (this, isChecked)
MSBTProfiles.SetOption(nil, "regenAbilitiesDisabled", not isChecked);
end
);
controls.hyperRegenCheckbox = checkbox;
 
-- Abbreviate skills checkbox.
checkbox = MSBTControls.CreateCheckbox(tabFrame);
objLocale = MSBTLocale.CHECKBOXES["abbreviateSkills"];
checkbox:Configure(28, objLocale.label, objLocale.tooltip);
checkbox:SetPoint("TOPLEFT", controls.hyperRegenCheckbox, "BOTTOMLEFT", 0, 0);
checkbox:SetClickHandler(
function (this, isChecked)
MSBTProfiles.SetOption(nil, "abbreviateAbilities", isChecked);
end
);
controls.abbreviateCheckbox = checkbox;
 
-- Hide skills checkbox.
checkbox = MSBTControls.CreateCheckbox(tabFrame);
objLocale = MSBTLocale.CHECKBOXES["hideSkills"];
checkbox:Configure(28, objLocale.label, objLocale.tooltip);
checkbox:SetPoint("LEFT", controls.powerThrottlingSlider, "LEFT", 0, 0);
checkbox:SetPoint("TOP", controls.allPowerCheckbox, "TOP", 0, 0);
checkbox:SetClickHandler(
function (this, isChecked)
MSBTProfiles.SetOption(nil, "hideSkills", isChecked);
end
);
controls.hideSkillsCheckbox = checkbox;
 
-- Hide names checkbox.
checkbox = MSBTControls.CreateCheckbox(tabFrame);
objLocale = MSBTLocale.CHECKBOXES["hideNames"];
checkbox:Configure(28, objLocale.label, objLocale.tooltip);
checkbox:SetPoint("TOPLEFT", controls.hideSkillsCheckbox, "BOTTOMLEFT");
checkbox:SetClickHandler(
function (this, isChecked)
MSBTProfiles.SetOption(nil, "hideNames", isChecked);
end
);
controls.hideNamesCheckbox = checkbox;
 
-- Merge exclusions button.
button = MSBTControls.CreateOptionButton(tabFrame);
objLocale = MSBTLocale.BUTTONS["mergeExclusions"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("BOTTOMLEFT", tabFrame, "BOTTOMLEFT", 5, 15);
button:SetClickHandler(
function (this)
local listName = "mergeExclusions";
PopulateSkillList(listName);
EraseTable(configTable);
configTable.title = this:GetText();
configTable.skills = skillsTable;
configTable.parentFrame = tabFrame;
configTable.anchorFrame = this;
configTable.anchorPoint = "BOTTOMLEFT";
configTable.relativePoint = "TOPLEFT";
configTable.saveHandler = SaveSkillList;
configTable.saveArg1 = listName;
configTable.hideHandler = SpamTab_EnableControls;
DisableControls(controls);
MSBTPopups.ShowSkillList(configTable);
end
);
controls.mergeExclusionsButton = button;
 
-- Throttle list button.
local button = MSBTControls.CreateOptionButton(tabFrame);
objLocale = MSBTLocale.BUTTONS["throttleList"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("BOTTOMLEFT", controls.mergeExclusionsButton, "TOPLEFT", 0, 10);
button:SetClickHandler(
function (this)
local listName = "throttleList";
PopulateSkillList(listName);
EraseTable(configTable);
configTable.title = this:GetText();
configTable.skills = skillsTable;
configTable.listType = "throttle";
configTable.parentFrame = tabFrame;
configTable.anchorFrame = this;
configTable.anchorPoint = "BOTTOMLEFT";
configTable.relativePoint = "TOPLEFT";
configTable.saveHandler = SaveSkillList;
configTable.saveArg1 = listName;
configTable.hideHandler = SpamTab_EnableControls;
DisableControls(controls);
MSBTPopups.ShowSkillList(configTable);
end
);
controls.throttleListButton = button;
 
-- Skill substitutions button.
button = MSBTControls.CreateOptionButton(tabFrame);
objLocale = MSBTLocale.BUTTONS["skillSubstitutions"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("BOTTOMRIGHT", tabFrame, "BOTTOMRIGHT", -10, 15);
button:SetClickHandler(
function (this)
local listName = "abilitySubstitutions";
PopulateSkillList(listName);
EraseTable(configTable);
configTable.title = this:GetText();
configTable.skills = skillsTable;
configTable.listType = "substitution";
configTable.parentFrame = tabFrame;
configTable.anchorFrame = this;
configTable.anchorPoint = "BOTTOMRIGHT";
configTable.relativePoint = "TOPRIGHT";
configTable.saveHandler = SaveSkillList;
configTable.saveArg1 = listName;
configTable.hideHandler = SpamTab_EnableControls;
DisableControls(controls);
MSBTPopups.ShowSkillList(configTable);
end
);
controls.skillSubstitutionsButton = button;
 
-- Skill suppressions button.
button = MSBTControls.CreateOptionButton(tabFrame);
objLocale = MSBTLocale.BUTTONS["skillSuppressions"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("BOTTOMLEFT", controls.skillSubstitutionsButton, "TOPLEFT", 0, 10);
button:SetClickHandler(
function (this)
local listName = "abilitySuppressions";
PopulateSkillList(listName);
EraseTable(configTable);
configTable.title = this:GetText();
configTable.skills = skillsTable;
configTable.parentFrame = tabFrame;
configTable.anchorFrame = this;
configTable.anchorPoint = "BOTTOMRIGHT";
configTable.relativePoint = "TOPRIGHT";
configTable.saveHandler = SaveSkillList;
configTable.saveArg1 = listName;
configTable.hideHandler = SpamTab_EnableControls;
DisableControls(controls);
MSBTPopups.ShowSkillList(configTable);
end
);
controls.skillSuppressionsButton = button;
 
tabFrame.created = true;
end
 
 
-- ****************************************************************************
-- Called when the tab frame is shown.
-- ****************************************************************************
local function SpamTab_OnShow()
if (not tabFrames.spam.created) then SpamTab_Create(); end
 
local currentProfile = MSBTProfiles.currentProfile;
local controls = tabFrames.spam.controls;
 
controls.healSlider:SetValue(currentProfile.healThreshold);
controls.damageSlider:SetValue(currentProfile.damageThreshold);
controls.powerSlider:SetValue(currentProfile.powerThreshold);
controls.dotThrottlingSlider:SetValue(currentProfile.dotThrottleDuration);
controls.hotThrottlingSlider:SetValue(currentProfile.hotThrottleDuration);
controls.powerThrottlingSlider:SetValue(currentProfile.powerThrottleDuration);
controls.allPowerCheckbox:SetChecked(currentProfile.showAllPowerGains);
controls.hyperRegenCheckbox:SetChecked(not currentProfile.regenAbilitiesDisabled);
controls.abbreviateCheckbox:SetChecked(currentProfile.abbreviateAbilities);
controls.hideSkillsCheckbox:SetChecked(currentProfile.hideSkills);
controls.hideNamesCheckbox:SetChecked(currentProfile.hideNames);
end
 
 
-------------------------------------------------------------------------------
-- Cooldowns tab functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Enables the controls on the cooldowns tab.
-- ****************************************************************************
local function CooldownsTab_EnableControls()
for name, frame in pairs(tabFrames.cooldowns.controls) do
if (frame.Enable) then frame:Enable(); end
end
end
 
 
-- ****************************************************************************
-- Saves the event settings selected by the user.
-- ****************************************************************************
local function CooldownsTab_SaveEventSettings(settings)
local eventType = "NOTIFICATION_COOLDOWN";
MSBTProfiles.SetOption("events." .. eventType, "scrollArea", settings.scrollArea, DEFAULT_SCROLL_AREA);
MSBTProfiles.SetOption("events." .. eventType, "message", settings.message);
MSBTProfiles.SetOption("events." .. eventType, "alwaysSticky", settings.alwaysSticky);
MSBTProfiles.SetOption("events." .. eventType, "soundFile", settings.soundFile, "");
 
tabFrames.cooldowns.messageFontString:SetText(settings.message);
end
 
 
-- ****************************************************************************
-- Saves the font settings selected by the user.
-- ****************************************************************************
local function CooldownsTab_SaveFontSettings(settings)
local eventType = "NOTIFICATION_COOLDOWN";
MSBTProfiles.SetOption("events." .. eventType, "fontName", settings.normalFontName);
MSBTProfiles.SetOption("events." .. eventType, "outlineIndex", settings.normalOutlineIndex);
MSBTProfiles.SetOption("events." .. eventType, "fontSize", settings.normalFontSize);
MSBTProfiles.SetOption("events." .. eventType, "fontAlpha", settings.normalFontAlpha);
end
 
 
-- ****************************************************************************
-- Creates the cooldowns tab frame contents.
-- ****************************************************************************
local function CooldownsTab_Create()
local tabFrame = tabFrames.cooldowns;
tabFrame.controls = {};
local controls = tabFrame.controls;
 
-- Colorswatch.
local colorswatch = MSBTControls.CreateColorswatch(tabFrame);
colorswatch:SetPoint("TOPLEFT", tabFrame, "TOPLEFT", 5, -10);
colorswatch:SetColorChangedHandler(
function (this)
local eventType = "NOTIFICATION_COOLDOWN";
MSBTProfiles.SetOption("events." .. eventType, "colorR", this.r, 1);
MSBTProfiles.SetOption("events." .. eventType, "colorG", this.g, 1);
MSBTProfiles.SetOption("events." .. eventType, "colorB", this.b, 1);
end
);
controls.colorSwatch = colorswatch;
 
-- Enable checkbox.
local checkbox = MSBTControls.CreateCheckbox(tabFrame);
local objLocale = MSBTLocale.CHECKBOXES["enableCooldowns"];
checkbox:Configure(24, objLocale.label, objLocale.tooltip);
checkbox:SetPoint("LEFT", colorswatch, "RIGHT", 5, 0);
checkbox:SetPoint("RIGHT", tabFrame, "TOPLEFT", 190, -10);
checkbox:SetClickHandler(
function (this, isChecked)
MSBTProfiles.SetOption("events.NOTIFICATION_COOLDOWN", "disabled", not isChecked);
if (isChecked) then MSBTCooldowns.Enable(); else MSBTCooldowns.Disable(); end
end
);
controls.enableCheckbox = checkbox;
 
-- Event settings button.
local button = MSBTControls.CreateIconButton(tabFrame, "Configure");
objLocale = MSBTLocale.BUTTONS["eventSettings"];
button:SetTooltip(objLocale.tooltip);
button:SetPoint("TOPRIGHT", tabFrame, "TOPRIGHT", -10, -5);
button:SetClickHandler(
function (this)
local eventSettings = MSBTProfiles.currentProfile.events.NOTIFICATION_COOLDOWN;
 
EraseTable(configTable);
configTable.title = MSBTLocale.TABS[6].label;
configTable.message = eventSettings.message;
configTable.codes = MSBTLocale.EVENT_CODES["COOLDOWN_NAME"];
configTable.scrollArea = eventSettings.scrollArea or DEFAULT_SCROLL_AREA;
configTable.alwaysSticky = eventSettings.alwaysSticky;
configTable.soundFile = eventSettings.soundFile;
configTable.parentFrame = tabFrame;
configTable.anchorFrame = tabFrame;
configTable.anchorPoint = "TOPRIGHT";
configTable.relativePoint = "TOPRIGHT";
configTable.saveHandler = CooldownsTab_SaveEventSettings;
configTable.hideHandler = CooldownsTab_EnableControls;
DisableControls(controls);
MSBTPopups.ShowEvent(configTable);
end
);
controls[#controls+1] = button;
 
-- Font settings button.
button = MSBTControls.CreateIconButton(tabFrame, "FontSettings");
objLocale = MSBTLocale.BUTTONS["eventFontSettings"];
button:SetTooltip(objLocale.tooltip);
button:SetPoint("RIGHT", controls[#controls], "LEFT", 0, 0);
button:SetClickHandler(
function (this)
local eventSettings = MSBTProfiles.currentProfile.events.NOTIFICATION_COOLDOWN;
local saSettings = MSBTProfiles.currentProfile.scrollAreas[eventSettings.scrollArea];
if (not saSettings) then saSettings = MSBTProfiles.currentProfile.scrollAreas[DEFAULT_SCROLL_AREA]; end
local fonts = MSBTAnimations.fonts;
 
EraseTable(configTable);
configTable.title = MSBTLocale.TABS[6].label;
 
-- Inherit from the correct scroll area.
local fontName = saSettings.normalFontName;
if (not MSBTAnimations.fonts[fontName]) then fontName = MSBTProfiles.currentProfile.normalFontName; end
if (not MSBTAnimations.fonts[fontName]) then fontName = DEFAULT_FONT_NAME; end
configTable.inheritedNormalFontName = fontName;
configTable.inheritedNormalOutlineIndex = saSettings.normalOutlineIndex or MSBTProfiles.currentProfile.normalOutlineIndex;
configTable.inheritedNormalFontSize = saSettings.normalFontSize or MSBTProfiles.currentProfile.normalFontSize;
configTable.inheritedNormalFontAlpha = saSettings.normalFontAlpha or MSBTProfiles.currentProfile.normalFontAlpha;
 
fontName = eventSettings.fontName;
if (not MSBTAnimations.fonts[fontName]) then fontName = nil; end
configTable.normalFontName = fontName;
configTable.normalOutlineIndex = eventSettings.outlineIndex;
configTable.normalFontSize = eventSettings.fontSize;
configTable.normalFontAlpha = eventSettings.fontAlpha;
 
configTable.hideCrit = true;
configTable.parentFrame = tabFrames.cooldowns;
configTable.anchorFrame = tabFrames.cooldowns;
configTable.anchorPoint = "BOTTOM";
configTable.relativePoint = "BOTTOM";
configTable.saveHandler = CooldownsTab_SaveFontSettings;
configTable.hideHandler = CooldownsTab_EnableControls;
DisableControls(controls);
MSBTPopups.ShowFont(configTable);
end
);
controls[#controls+1] = button;
 
-- Message font string.
local fontString = tabFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall");
fontString:SetPoint("LEFT", checkbox, "RIGHT", 10, 0);
fontString:SetPoint("RIGHT", button, "LEFT", -10, 0);
fontString:SetJustifyH("LEFT");
tabFrame.messageFontString = fontString;
 
-- Cooldown threshold slider.
local slider = MSBTControls.CreateSlider(tabFrame);
objLocale = MSBTLocale.SLIDERS["cooldownThreshold"];
slider:Configure(180, objLocale.label, objLocale.tooltip);
slider:SetPoint("TOPLEFT", controls.colorSwatch, "BOTTOMLEFT", 0, -40);
slider:SetMinMaxValues(5, 300);
slider:SetValueStep(5);
slider:SetValueChangedHandler(
function(this, value)
MSBTProfiles.SetOption(nil, "cooldownThreshold", value);
end
);
controls.cooldownSlider = slider;
 
-- Cooldown exclusions button.
button = MSBTControls.CreateOptionButton(tabFrame);
objLocale = MSBTLocale.BUTTONS["cooldownExclusions"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("TOPLEFT", controls.cooldownSlider, "BOTTOMLEFT", 0, -40);
button:SetClickHandler(
function (this)
local listName = "cooldownExclusions";
PopulateSkillList(listName);
EraseTable(configTable);
configTable.title = this:GetText();
configTable.skills = skillsTable;
configTable.parentFrame = tabFrame;
configTable.anchorFrame = tabFrame;
configTable.anchorPoint = "TOPRIGHT";
configTable.relativePoint = "TOPRIGHT";
configTable.saveHandler = SaveSkillList;
configTable.saveArg1 = listName;
configTable.hideHandler = CooldownsTab_EnableControls;
DisableControls(controls);
MSBTPopups.ShowSkillList(configTable);
end
);
controls.cooldownExclusions = button;
 
tabFrame.created = true;
end
 
-- ****************************************************************************
-- Called when the tab frame is shown.
-- ****************************************************************************
local function CooldownsTab_OnShow()
if (not tabFrames.cooldowns.created) then CooldownsTab_Create(); end
 
local tabFrame = tabFrames.cooldowns;
local controls = tabFrame.controls;
local currentProfile = MSBTProfiles.currentProfile;
local eventSettings = currentProfile.events["NOTIFICATION_COOLDOWN"];
 
controls.colorSwatch:SetColor(eventSettings.colorR or 1, eventSettings.colorG or 1, eventSettings.colorB or 1);
controls.enableCheckbox:SetChecked(not eventSettings.disabled);
tabFrame.messageFontString:SetText(eventSettings.message);
controls.cooldownSlider:SetValue(currentProfile.cooldownThreshold);
end
 
-------------------------------------------------------------------------------
-- Skill icons tab functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Creates the skill icons tab frame contents.
-- ****************************************************************************
local function SkillIconsTab_Create()
local tabFrame = tabFrames.skillIcons;
tabFrame.controls = {};
local controls = tabFrame.controls;
 
-- Enable checkbox.
local checkbox = MSBTControls.CreateCheckbox(tabFrame);
local objLocale = MSBTLocale.CHECKBOXES["enableIcons"];
checkbox:Configure(24, objLocale.label, objLocale.tooltip);
checkbox:SetPoint("TOPLEFT", tabFrame, "TOPLEFT", 5, -10);
checkbox:SetClickHandler(
function (this, isChecked)
MSBTProfiles.SetOption(nil, "skillIconsDisabled", not isChecked);
if (isChecked) then controls.exclusiveCheckbox:Enable(); else controls.exclusiveCheckbox:Disable(); end
end
);
controls.enableCheckbox = checkbox;
 
-- Exclusive skills checkbox.
checkbox = MSBTControls.CreateCheckbox(tabFrame);
local objLocale = MSBTLocale.CHECKBOXES["exclusiveSkills"];
checkbox:Configure(24, objLocale.label, objLocale.tooltip);
checkbox:SetPoint("TOPLEFT", controls.enableCheckbox, "BOTTOMLEFT", 20, -10);
checkbox:SetClickHandler(
function (this, isChecked)
MSBTProfiles.SetOption(nil, "exclusiveSkillsDisabled", not isChecked);
end
);
controls.exclusiveCheckbox = checkbox;
 
 
tabFrame.created = true;
end
 
 
-- ****************************************************************************
-- Called when the tab frame is shown.
-- ****************************************************************************
local function SkillIconsTab_OnShow()
if (not tabFrames.skillIcons.created) then SkillIconsTab_Create(); end
 
local tabFrame = tabFrames.skillIcons;
local controls = tabFrame.controls;
local currentProfile = MSBTProfiles.currentProfile;
 
controls.enableCheckbox:SetChecked(not currentProfile.skillIconsDisabled);
controls.exclusiveCheckbox:SetChecked(not currentProfile.exclusiveSkillsDisabled);
 
if (controls.enableCheckbox:GetChecked()) then
controls.exclusiveCheckbox:Enable();
else
controls.exclusiveCheckbox:Disable();
end
end
 
 
 
 
-- ****************************************************************************
-- Called when the module is loaded.
-- ****************************************************************************
local function OnLoad()
-- Create an empty frame for the general tab that will be dynamically created when shown.
local tabFrame = CreateFrame("Frame");
tabFrame:Hide();
tabFrame:SetScript("OnShow", GeneralTab_OnShow);
tabFrames.general = tabFrame;
MSBTOptMain.AddTab(tabFrame, MSBTLocale.TABS[1].label, MSBTLocale.TABS[1].tooltip);
 
-- Create an empty frame for the scroll areas tab that will be dynamically created when shown.
tabFrame = CreateFrame("Frame");
tabFrame:Hide();
tabFrame:SetScript("OnShow", ScrollAreasTab_OnShow);
tabFrames.scrollAreas = tabFrame;
MSBTOptMain.AddTab(tabFrame, MSBTLocale.TABS[2].label, MSBTLocale.TABS[2].tooltip);
 
-- Create an empty frame for the events tab that will be dynamically created when shown.
tabFrame = CreateFrame("Frame");
tabFrame:Hide();
tabFrame:SetScript("OnShow", EventsTab_OnShow);
tabFrames.events = tabFrame;
MSBTOptMain.AddTab(tabFrame, MSBTLocale.TABS[3].label, MSBTLocale.TABS[3].tooltip);
 
-- Create an empty frame for the triggers tab that will be dynamically created when shown.
tabFrame = CreateFrame("Frame");
tabFrame:Hide();
tabFrame:SetScript("OnShow", TriggersTab_OnShow);
tabFrames.triggers = tabFrame;
MSBTOptMain.AddTab(tabFrame, MSBTLocale.TABS[4].label, MSBTLocale.TABS[4].tooltip);
 
-- Create an empty frame for the spam tab that will be dynamically created when shown.
tabFrame = CreateFrame("Frame");
tabFrame:Hide();
tabFrame:SetScript("OnShow", SpamTab_OnShow);
tabFrames.spam = tabFrame;
MSBTOptMain.AddTab(tabFrame, MSBTLocale.TABS[5].label, MSBTLocale.TABS[5].tooltip);
 
-- Create an empty frame for the cooldowns tab that will be dynamically created when shown.
tabFrame = CreateFrame("Frame");
tabFrame:Hide();
tabFrame:SetScript("OnShow", CooldownsTab_OnShow);
tabFrames.cooldowns = tabFrame;
MSBTOptMain.AddTab(tabFrame, MSBTLocale.TABS[6].label, MSBTLocale.TABS[6].tooltip);
 
-- Create an empty frame for the icons tab that will be dynamically created when shown.
tabFrame = CreateFrame("Frame");
tabFrame:Hide();
tabFrame:SetScript("OnShow", SkillIconsTab_OnShow);
tabFrames.skillIcons = tabFrame;
MSBTOptMain.AddTab(tabFrame, MSBTLocale.TABS[7].label, MSBTLocale.TABS[7].tooltip);
end
 
 
 
 
-------------------------------------------------------------------------------
-- Load.
-------------------------------------------------------------------------------
 
OnLoad();
\ No newline at end of file
MSBT5_13/MSBTOptions/localization.fr.lua New file
0,0 → 1,503
-------------------------------------------------------------------------------
-- Title: MSBT Options French Localization
-- Author: Mik
-- French Translation by: Calthas
-------------------------------------------------------------------------------
 
-- Don't do anything if the locale isn't French.
if (GetLocale() ~= "frFR") then return; end
 
-- Local reference for faster access.
local MSBTLocale = MikSBT.Locale;
 
 
-------------------------------------------------------------------------------
-- French localization
-------------------------------------------------------------------------------
 
 
------------------------------
-- Interface messages
------------------------------
 
MSBTLocale.MSG_NEW_PROFILE = "Nouveau Profil";
MSBTLocale.MSG_PROFILE_ALREADY_EXISTS = "Le Profil existe d\195\169j\195\160.";
MSBTLocale.MSG_INVALID_PROFILE_NAME = "Nom de profil invalide.";
MSBTLocale.MSG_NEW_SCROLL_AREA = "Nouveau zone de d\195\169filement";
MSBTLocale.MSG_SCROLL_AREA_ALREADY_EXISTS = "Une zone de d\195\169filement portant ce nom existe d\195\169j\195\160.";
MSBTLocale.MSG_INVALID_SCROLL_AREA_NAME = "Nom de zone de d\195\169filement invalide.";
MSBTLocale.MSG_ACKNOWLEDGE_TEXT = "Etes-vous certain de vouloir effectuer cette action?";
--MSBTLocale.MSG_NORMAL_PREVIEW_TEXT = "Normal";
--MSBTLocale.MSG_INVALID_SOUND_FILE = "Sound must be a .mp3 or .wav file.";
MSBTLocale.MSG_NEW_TRIGGER = "Nouveau d\195\169clencheur";
MSBTLocale.MSG_TRIGGER_CLASSES = "Classes du d\195\169clencheur";
--MSBTLocale.MSG_MAIN_EVENTS = "Main Events";
--MSBTLocale.MSG_TRIGGER_EXCEPTIONS = "Trigger Exceptions";
MSBTLocale.MSG_SKILLS = "Comp\195\169tences";
--MSBTLocale.MSG_SKILL_ALREADY_EXISTS = "Skill name already exists.";
MSBTLocale.MSG_INVALID_SKILL_NAME = "Nom de comp\195\169tence invalide.";
--MSBTLocale.MSG_HOSTILE = "Hostile";
--MSBTLocale.MSG_ANY = "Any";
--MSBTLocale.MSG_RISES_ABOVE = "Rises Above";
--MSBTLocale.MSG_FALLS_BELOW = "Falls Below";
 
 
------------------------------
-- Class Names.
------------------------------
 
local obj = MSBTLocale.CLASS_NAMES;
obj["DRUID"] = "Druide";
obj["HUNTER"] = "Chasseur";
obj["MAGE"] = "Mage";
obj["PALADIN"] = "Paladin";
obj["PRIEST"] = "Pr\195\170tre";
obj["ROGUE"] = "Voleur";
obj["SHAMAN"] = "Chaman";
obj["WARLOCK"] = "D\195\169moniste";
obj["WARRIOR"] = "Guerrier";
 
 
------------------------------
-- Interface tabs
------------------------------
 
-- #2, 3, and 4 need additional translation.
obj = MSBTLocale.TABS;
obj[1] = { label="G\195\169n\195\169ral", tooltip="Afficher les options g\195\169n\195\169rales."};
obj[2] = { label="Zones de d\195\169filement", tooltip="Affiche les options de cr\195\169ation, suppression et configuration des zones de d\195\169filement.\n\nMouse over the icon buttons for more information."};
obj[3] = { label="Ev\195\168nements", tooltip="Affiche les options pour les \195\169v\195\168nements entrants, sortants et de notification.\n\nMouse over the icon buttons for more information."};
obj[4] = { label="D\195\169clencheurs", tooltip="Affiche les options du syst\195\168me de d\195\169clencheurs.\n\nMouse over the icon buttons for more information."};
--obj[5] = { label="Spam Control", tooltip="Display options for controlling spam."};
--obj[6] = { label="Cooldowns", tooltip="Display options for cooldown notifications."};
--obj[7] = { label="Skill Icons", tooltip="Display options for skill icons."};
 
 
------------------------------
-- Interface checkboxes
------------------------------
 
obj = MSBTLocale.CHECKBOXES;
obj["enableMSBT"] = { label="Activer Mik's Scrolling Battle Text", tooltip="Activer MSBT."};
obj["stickyCrits"] = { label="Coups critiques persistants", tooltip="Utiliser le style persistant pour les coups critiques."};
obj["gameDamage"] = { label="Dommages du jeu", tooltip="Afficher les dommages par d\195\169faut du jeu au dessus de la t\195\170te des ennemis."};
obj["gameHealing"] = { label="Soins du jeu", tooltip="Afficher les soins par d\195\169aut du jeu au dessus de la t\195\170te des ennemis."};
obj["enableSounds"] = { label="Activer les sons", tooltip="Utiliser les sons associ\195\169s aux \195\169v\195\168nements et d\195\169clencheurs."};
obj["colorPartialEffects"] = { label="Coloriser les effets partiels", tooltip="Assigner des couleurs aux effets partiels."};
obj["crushing"] = { label="Ecrasements", tooltip="Signaler les \195\169crasements."};
obj["glancing"] = { label="Eraflures", tooltip="Signaler les \195\169raflures."};
obj["absorb"] = { label="Absorptions partielles", tooltip="Afficher la valeur des absorptions partielles."};
obj["block"] = { label="Bloquages partiels", tooltip="Afficher la valeur des bloquages partiels."};
obj["resist"] = { label="R\195\169sistances partielles", tooltip="Afficher la valeur des r\195\169sistances partielles."};
obj["vulnerability"] = { label="Bonus de vuln\195\169rabilit\195\169", tooltip="Afficher la valeur des bonus de vuln\195\169rabilit\195\169."};
obj["overheal"] = { label="Overheals", tooltip="Afficher la valeur d'overheal."};
obj["colorDamageAmounts"] = { label="Valeurs des dommages en couleur", tooltip="Utiliser des couleurs pour la valeur des dommages."};
--obj["colorDamageEntry"] = { tooltip="Enable coloring for this damage type."};
obj["enableScrollArea"] = { tooltip="Activer la zone de d\195\169filement."};
obj["inheritField"] = { label="H\195\169riter", tooltip="H\195\169riter la valeur."};
obj["stickyEvent"] = { label="Toujours Persistant", tooltip="Utiliser le style persistant pour l'\195\169v\195\168nement."};
obj["enableTrigger"] = { tooltip="Activer le d\195\169clencheur."};
--obj["allPowerGains"] = { label="ALL Power Gains", tooltip="Display all power gains including those that are not reported to the combat log.\n\nWARNING: This option is very spammy and will ignore the power threshold and throttling mechanics.\n\nNOT RECOMMENDED."};
--obj["hyperRegen"] = { label="Hyper Regen", tooltip="Display power gains during fast regen abilities such as Innervate and Spirit Tap.\n\nNOTE: The gains shown will not be throttled."};
--obj["abbreviateSkills"] = { label="Abbreviate Skills", tooltip="Abbreviates skill names (English only).\n\nThis can be overriden by each event with the %sl event code."};
--obj["hideSkills"] = { label="Hide Skills", tooltip="Don't display skill names for incoming and outgoing events.\n\nYou will give up some customization capability at the event level if you choose to use this option since it causes the %s event code to be ignored."};
--obj["hideNames"] = { label="Hide Names", tooltip="Don't display unit names for incoming and outgoing events.\n\nYou will give up some customization capability at the event level if you choose to use this option since it causes the %n event code to be ignored."};
obj["allClasses"] = { label="Toutes les classes"};
--obj["enableCooldowns"] = { label="Enable Cooldowns", tooltip="Display notifications when cooldowns complete."};
--obj["enableIcons"] = { label="Enable Skill Icons", tooltip="Displays icons for events that have a skill when possible."};
--obj["exclusiveSkills"] = { label="Exclusive Skill Names", tooltip="Only show skill names when an icon is not available."};
--obj["hostileOnly"] = { label="Hostile Only", tooltip="Only fire the trigger if the selected unit is hostile."};
--obj["reverseLogic"] = { label="Reverse Logic", tooltip="Reverses the meaning of the selected exception. For example, Buff Active would mean Buff Inactive."};
 
 
------------------------------
-- Interface dropdowns
------------------------------
 
obj = MSBTLocale.DROPDOWNS;
obj["profile"] = { label="Profil actuel:", tooltip="Assigne le profil actif."};
obj["normalFont"] = { label="Police normale:", tooltip="Assigne la police de caract\195\168res utilis\195\169e pour les coups non critiques."};
obj["critFont"] = { label="Police critique:", tooltip="Assigne la police de caract\195\168res utilis\195\169e pour les coups critiques."};
obj["normalOutline"] = { label="Contour normal:", tooltip="Assigne le contour utilis\195\169 pour les coups non critiques."};
obj["critOutline"] = { label="Contour critique:", tooltip="Assigne le contour utilis\195\169 pour les coups critiques."};
obj["scrollArea"] = { label="Zone de d\195\169filement:", tooltip="S\195\169lectionne la zone de d\195\169filement \195\160 configurer."};
--obj["sound"] = { label="Sound:", tooltip="Selects the sound to play when the event occurs."};
obj["animationStyle"] = { label="Animations:", tooltip="Style d'animation pour les animations non persistantes dans la zone de d\195\169filement.."};
obj["stickyAnimationStyle"] = { label="Animations persistantes:", tooltip="Style d'animation pour les animations persistantes dans la zone de d\195\169filement."};
--obj["direction"] = { label="Direction:", tooltip="The direction of the animation."};
--obj["behavior"] = { label="Behavior:", tooltip="The behavior of the animation."};
obj["textAlign"] = { label="Alignement du texte:", tooltip="Alignement du texte pour l'animation."};
obj["eventCategory"] = { label="Cat\195\169gorie d'\195\169v\195\168ne:", tooltip="La cat\195\169gorie de l'\195\169v\195\168nement \195\160 configurer."};
obj["outputScrollArea"] = { label="Zone de d\195\169filement sortante:", tooltip="S\195\169lectionne la zone de d\195\169filement \195\160 utiliser pour les informations sortantes."};
--obj["mainEvent"] = { label="Main Event:"};
--obj["affectedUnit"] = { label="Affected Unit:", tooltip="The unit the event must be associated with."};
--obj["eventDirection"] = { label="Direction:", tooltip="The direction associated with the event."};
--obj["triggerException"] = { label="Exception:"};
--obj["warriorStance"] = { label="Warrior Stance:", tooltip="The stance the warrior is currently in."};
 
 
------------------------------
-- Interface buttons
------------------------------
 
obj = MSBTLocale.BUTTONS;
obj["copyProfile"] = { label="Copier", tooltip="Copie le profil sous un nouveau nom."};
obj["resetProfile"] = { label="R\195\169initialiser", tooltip="R\195\169initialise le profil avec les param\195\168tres par d\195\169faut."};
obj["deleteProfile"] = { label="Supprimer", tooltip="Supprime le profil."};
obj["masterFont"] = { label="Police principale", tooltip="Param\195\168tres principaux de police, h\195\169rit\195\169s par toutes les zones de d\195\169filement sauf si surcharg\195\169s."};
obj["partialEffects"] = { label="Effets partiels", tooltip="D\195\169termine les effets partiels affich\195\169s et les param\195\168tres de couleurs."};
obj["damageColors"] = { label="Couleurs des dommages", tooltip="Vous permet de param\195\169trer les couleurs assign\195\169s aux dommages suivant le type de dommage (nature, feu, givre...)"};
obj["inputOkay"] = { label="OK", tooltip="Accepte la saisie."};
obj["inputCancel"] = { label="Annuler", tooltip="Annule la saisie."};
obj["genericSave"] = { label="Enregistrer", tooltip="Enregistre les modifications."};
obj["genericCancel"] = { label="Annuler", tooltip="Annule les modifications."};
obj["addScrollArea"] = { label="Ajouter une zone", tooltip="Ajoute une zone de d\195\169filement \195\160 laquelle des d\195\169clencheurs et \195\169v\195\168nements peuvent \195\170tre assign\195\169s."};
obj["configScrollAreas"] = { label="Configurer les zones", tooltip="Permet de configurer les styles d'animation normales et persistantes, l'alignement du texte, la largeur/hauteur de la zone de d\195\169filement et leur emplacement."};
obj["editScrollAreaName"] = { tooltip="Cliquer pour modifier le nom de la zone de d\195\169filement."};
obj["scrollAreaFontSettings"] = { tooltip="Cliquer pour modifier les param\195\168tres de police pour la zone de d\195\169filement. Ces param\195\168tres seront utilis\195\169s par tous les \195\169v\195\168nements de cette zone \195\160 moins qu'ils ne soient surcharg\195\169s."};
obj["deleteScrollArea"] = { tooltip="Cliquer pour supprimer la zone de d\195\169filement."};
obj["scrollAreasPreview"] = { label="Aper\195\167u", tooltip="Pr\195\169visualiser les modifications."};
--obj["toggleAll"] = { label="Toggle All", tooltip="Toggle the enable state of all events in the selected category."};
--obj["moveAll"] = { label="Move All", tooltip="Moves all of the events in the selected category to the specified scroll area."};
obj["eventFontSettings"] = { tooltip="Cliquer pour \195\169diter les param\195\168tres de police pour l'\195\169v\195\168nement."};
obj["eventSettings"] = { tooltip="Cliquer pour \195\169diter les param\195\168tres de l'\195\169v\195\168nement comme la zone de d\195\169filement, message, sonore, etc."};
--obj["customSound"] = { tooltip="Click to enter a custom sound file." };
obj["addTrigger"] = { label="Ajouter un d\195\169clencheur", tooltip="Ajoute un nouveau d\195\169clencheur."};
obj["triggerSettings"] = { tooltip="Configurer les conditions de ce d\195\169clencheur."};
obj["deleteTrigger"] = { tooltip="Cliquer pour supprimer ce d\195\169clencheur."};
obj["editTriggerClasses"] = { tooltip="D\195\169termine \195\160 quelles classes le d\195\169clencheur s'applique."};
--obj["addMainEvent"] = { label="Add Event", tooltip="When ANY of these events occur and their defined conditions are true, the trigger will fire unless one of the exceptions specified below is true."};
--obj["addTriggerException"] = { label="Add Exception", tooltip="When ANY of these exceptions are true, the trigger will not fire."};
--obj["editEventConditions"] = { tooltip="Click to edit the conditions for the event."};
--obj["deleteMainEvent"] = { tooltip="Click to delete the event."};
--obj["editExceptionConditions"] = { tooltip="Click to edit the conditions for the exception."};
--obj["deleteException"] = { tooltip="Click to delete the exception."};
--obj["triggerEventTypes"] = { label="Ev\195\168nements du d\195\169clencheur", tooltip="D\195\169termine \195\160 quels \195\169v\195\168nements appliquer le mod\195\168le de recherche du d\195\169clencheur."};
--obj["throttleList"] = { label="Throttle List", tooltip="Set custom throttle times for specified skills."};
--obj["mergeExclusions"] = { label="Merge Exclusions", tooltip="Prevents specified skills from being merged."};
--obj["skillSuppressions"] = { label="Skill Suppressions", tooltip="Suppress skills by their name."};
--obj["skillSubstitutions"] = { label="Skill Substitutions", tooltip="Substitute skill names with customized values."};
--obj["addSkill"] = { label="Add Skill", tooltip="Add a new skill to the list."};
--obj["deleteSkill"] = { tooltip="Click to delete the skill."};
--obj["cooldownExclusions"] = { label="Cooldown Exclusions", tooltip="Specify skills that will ignore cooldown tracking."};
 
 
------------------------------
-- Interface editboxes
------------------------------
 
obj = MSBTLocale.EDITBOXES;
obj["copyProfile"] = { label="Nom du nouveau profil:", tooltip="Nom du nouveau profil vers lequel copier le profil courant."};
obj["scrollAreaName"] = { label="Nouveau nom pour la zone de d\195\169filement:", tooltip="Nouveau nom pour la zone de d\195\169filement."};
obj["xOffset"] = { label="D\195\169calage X:", tooltip="Le d\195\169calage horizontale de la zone de d\195\169filement."};
obj["yOffset"] = { label="D\195\169calage Y:", tooltip="Le d\195\169calage vertical de la zone de d\195\169filement."};
obj["eventMessage"] = { label="Message affich\195\169:", tooltip="Le message affich\195\169 pour cet \195\169v\195\168nement."};
--obj["soundFile"] = { label="Sound filename:", tooltip="The name of the sound file to play when the trigger occurs."};
--obj["iconSkill"] = { label="Icon Skill:", tooltip="The name or spell ID of a skill whose icon will be displayed when the event occurs.\n\nMSBT will automatically try to figure out an appropriate icon if one is not specified.\n\nNOTE: A spell ID must be used in place of a name if the skill is not in the spellbook for the class that is playing when the event occurs. Most online databases such as wowhead can be used to discover it."};
--obj["skillName"] = { label="Skill name:", tooltip="The name of the skill to add."};
--obj["substitutionText"] = { label="Substition text:", tooltip="The text to be substituted for the skill name."};
 
 
------------------------------
-- Interface sliders
------------------------------
 
obj = MSBTLocale.SLIDERS;
obj["animationSpeed"] = { label="Vitesse d'animation", tooltip="D\195\169finit la vitesse ma\195\174tre de l'animation."};
obj["normalFontSize"] = { label="Taille normale", tooltip="D\195\169finit la taille de la police pour les coups non critiques."};
--obj["normalFontOpacity"] = { label="Normal Opacity", tooltip="Sets the font opacity for non-crits."};
obj["critFontSize"] = { label="Taille critique", tooltip="D\195\169finit la taille de la police pour les coups critiques."};
--obj["critFontOpacity"] = { label="Crit Opacity", tooltip="Sets the font opacity for crits."};
obj["scrollHeight"] = { label="Hauteur de d\195\169filement", tooltip="La hauteur de la zone de d\195\169filement."};
obj["scrollWidth"] = { label="Largeur de d\195\169filement", tooltip="La largeur de la zone de d\195\169filement."};
obj["scrollAnimationSpeed"] = { label="Vitesse d'animation", tooltip="La vitesse de l'animation pour la zone de d\195\169filement."};
--obj["powerThreshold"] = { label="Power Threshold", tooltip="The threshold that power gains must exceed to be displayed."};
--obj["healThreshold"] = { label="Heal Threshold", tooltip="The threshold that heals must exceed to be displayed."};
--obj["damageThreshold"] = { label="Damage Threshold", tooltip="The threshold that damage must exceed to be displayed."};
--obj["dotThrottleTime"] = { label="DoT Throttle Time", tooltip="The number of seconds to throttle DoTs."};
--obj["hotThrottleTime"] = { label="HoT Throttle Time", tooltip="The number of seconds to throttle HoTs."};
--obj["powerThrottleTime"] = { label="Power Throttle Time", tooltip="The number of seconds to throttle power changes."};
obj["skillThrottleTime"] = { label="D\195\169lai de r\195\169gulation", tooltip="D\195\169lai \195\160 prendre en compte pour la r\195\169gulation des comp\195\169tences."};
--obj["cooldownThreshold"] = { label="Cooldown Threshold", tooltip="Skills with a cooldown less than the specified number of seconds will not be displayed."};
--obj["genericAmount"] = { label="Amount", tooltip="Select the amount."};
 
------------------------------
-- Event categories
------------------------------
obj = MSBTLocale.EVENT_CATEGORIES;
obj[1] = "Entrant player";
obj[2] = "Entrant familier";
obj[3] = "Sortant player";
obj[4] = "Sortant familier";
obj[5] = "Alertes";
 
 
------------------------------
-- Event codes
------------------------------
 
obj = MSBTLocale.EVENT_CODES;
obj["DAMAGE_TAKEN"] = "%a - Quantit\195\169 de dommages.\n";
obj["HEALING_TAKEN"] = "%a - Quantit\195\169 de soins re\195\167us.\n";
obj["DAMAGE_DONE"] = "%a - Dommages inflig\195\169s.\n";
obj["HEALING_DONE"] = "%a - Quantit\195\169 de soins.\n";
obj["ENERGY_AMOUNT"] = "%a - Quantit\195\169 de pouvoir.\n";
obj["CP_AMOUNT"] = "%a - Nombre de points de combo.\n";
obj["HONOR_AMOUNT"] = "%a - Quantit\195\169 de honneur.\n";
obj["REP_AMOUNT"] = "%a - Quantit\195\169 de r\195\169putation.\n";
obj["SKILL_AMOUNT"] = "%a - Nouveau niveau dans la comp\195\169tence.\n";
obj["EXPERIENCE_AMOUNT"] = "%a - Quantit\195\169 de exp\195\169rience.\n";
obj["ATTACKER_NAME"] = "%n - Nom de l'attaquant.\n";
obj["HEALER_NAME"] = "%n - Nom du soigneur.\n";
obj["ATTACKED_NAME"] = "%n - Nom de l'unit\195\169 attaqu\195\169e.\n";
obj["HEALED_NAME"] = "%n - Nom de l'unit\195\169 soign\195\169e.\n";
obj["BUFFED_NAME"] = "%n - Nom de l'unit\195\169.\n";
obj["SKILL_NAME"] = "%s - Nom de la comp\195\169tence.\n";
obj["SPELL_NAME"] = "%s - Nom du sort.\n";
obj["DEBUFF_NAME"] = "%s - Nom du debuff.\n";
obj["BUFF_NAME"] = "%s - Nom du buff.\n";
obj["ITEM_BUFF_NAME"] = "%s - Nom du buff d'objet.\n";
obj["EXTRA_ATTACKS"] = "%s - Attaque suppl\195\169mentaire.\n";
--obj["SKILL_LONG"] = "%sl - Long form of %s. Used to override abbreviation for the event.\n";
obj["DAMAGE_TYPE_TAKEN"] = "%t - Type de dommages.\n";
obj["DAMAGE_TYPE_DONE"] = "%t - Type de dommages faits.\n";
obj["ENVIRONMENTAL_DAMAGE"] = "%e - Nom de la source de dommages (chute, noyade, lave, etc...)\n";
obj["FACTION_NAME"] = "%e - Faction.\n";
obj["UNIT_KILLED"] = "%e - Nom de l'unit\195\169 tu\195\169e.\n";
obj["SHARD_NAME"] = "%e - Fragment d'\195\162me.\n";
--obj["EMOTE_TEXT"] = "%e - The text of the emote.\n";
--obj["MONEY_TEXT"] = "%e - The money gained text.\n";
--obj["COOLDOWN_NAME"] = "%e - The name of skill that is ready.\n"
obj["POWER_TYPE"] = "%p - Type de pouvoir (\195\169nergie, rage, mana).\n";
 
 
------------------------------
-- Incoming events
------------------------------
 
obj = MSBTLocale.INCOMING_PLAYER_EVENTS;
obj[1] = { label="M\195\170l\195\169e", tooltip="Afficher les dommages des attaques de m\195\170l\195\169e."};
obj[2] = { label="M\195\170l\195\169e critiques", tooltip="Afficher les dommages des attaques critiques de m\195\170l\195\169e."};
obj[3] = { label="Manques de m\195\170l\195\169e", tooltip="Afficher les attaques de m\195\170l\195\169e manqu\195\169es."};
obj[4] = { label="Esquives de m\195\170l\195\169e", tooltip="Afficher les attaques de m\195\170l\195\169e esquiv\195\169es."};
obj[5] = { label="Parades de m\195\170l\195\169e", tooltip="Afficher les attaques de m\195\170l\195\169e par\195\169es."};
obj[6] = { label="Bloquage de m\195\170l\195\169e", tooltip="Afficher les dommages en m\195\170l\195\169e bloqu\195\169es."};
obj[7] = { label="Absorption de m\195\170l\195\169e", tooltip="Afficher les dommages en m\195\170l\195\169e absorb\195\169s."};
obj[8] = { label="Immunit\195\169s de m\195\170l\195\169e", tooltip="Afficher les attaques de m\195\170l\195\169e auxquelles vous \195\170tes immunis\195\169."};
obj[9] = { label="Comp\195\169tences", tooltip="Afficher les dommages des comp\195\169tences."};
obj[10] = { label="Comp\195\169tences critiques", tooltip="Afficher les dommages des comp\195\169tences critiques."};
obj[11] = { label="DoTs des comp\195\169tences", tooltip="Afficher les dommages des DoTs de comp\195\169tences."};
obj[12] = { label="Manques comp\195\169tences", tooltip="Afficher les comp\195\169tences qui vous ont manqu\195\169."};
obj[13] = { label="Esquives comp\195\169tences", tooltip="Afficher les comp\195\169tences que vous avez esquiv\195\169."};
obj[14] = { label="Parades comp\195\169tences", tooltip="Afficher les comp\195\169tences que vous avez par\195\169."};
obj[15] = { label="Bloquages comp\195\169tences", tooltip="Afficher les capacit\195\169s que vous avez bloqu\195\169."};
obj[16] = { label="R\195\169sistances aux sorts", tooltip="Afficher les sorts auxquels vous avez r\195\169sist\195\169."};
obj[17] = { label="Absorptions comp\195\169tences", tooltip="Afficher les dommages absorb\195\169s des comp\195\169tences."};
obj[18] = { label="Immunit\195\169s comp\195\169tences", tooltip="Afficher les comp\195\169tences auxquels vous \195\170tes immunis\195\169."};
obj[19] = { label="Comp\195\169tences renvoy\195\169s", tooltip="Afficher les comp\195\169tences que vous avez renvoy\195\169."};
--obj[20] = { label="Spell Interrupts", tooltip="Enable incoming spell interrupts."};
obj[21] = { label="Soins", tooltip="Afficher les soins re\195\167us."};
obj[22] = { label="Soins critiques", tooltip="Afficher les soins critiques re\195\167us."};
obj[23] = { label="Soins sur le temps (HoT)", tooltip="Afficher les soins des soins sur le temps (HoT)."};
obj[24] = { label="Dommages de l'environnement", tooltip="Afficher les effets de l'environnement (chutes, noyades, lave, etc...)."};
 
obj = MSBTLocale.INCOMING_PET_EVENTS;
--obj[1] = { label="M\195\170l\195\169e", tooltip="Enable your pet's incoming melee hits."};
--obj[2] = { label="M\195\170l\195\169e critiques", tooltip="Enable your pet's incoming melee crits."};
--obj[3] = { label="Manques de m\195\170l\195\169e", tooltip="Enable your pet's incoming melee misses."};
--obj[4] = { label="Esquives de m\195\170l\195\169e", tooltip="Enable your pet's incoming melee dodges."};
--obj[5] = { label="Parades de m\195\170l\195\169e", tooltip="Enable your pet's incoming melee parries."};
--obj[6] = { label="Bloquage de m\195\170l\195\169e", tooltip="Enable your pet's incoming melee blocks."};
--obj[7] = { label="Absorption de m\195\170l\195\169e", tooltip="Enable your pet's absorbed incoming melee damage."};
--obj[8] = { label="Immunit\195\169s de m\195\170l\195\169e", tooltip="Enable melee damage your is pet immune to."};
--obj[9] = { label="Comp\195\169tences", tooltip="Enable your pet's incoming skill hits."};
--obj[10] = { label="Comp\195\169tences critiques", tooltip="Enable your pet's incoming skill crits."};
--obj[11] = { label="DoTs des comp\195\169tences", tooltip="Enable your pet's incoming skill damage over time."};
--obj[12] = { label="Manques comp\195\169tences", tooltip="Enable your pet's incoming skill misses."};
--obj[13] = { label="Esquives comp\195\169tences", tooltip="Enable your pet's incoming skill dodges."};
--obj[14] = { label="Parades comp\195\169tences", tooltip="Enable your pet's incoming skill parries."};
--obj[15] = { label="Bloquages comp\195\169tences", tooltip="Enable your pet's incoming skill blocks."};
--obj[16] = { label="R\195\169sistances aux sorts", tooltip="Enable your pet's incoming spell resists."};
--obj[17] = { label="Absorptions comp\195\169tences", tooltip="Enable absorbed damage from your pet's incoming skills."};
--obj[18] = { label="Immunit\195\169s comp\195\169tences", tooltip="Enable incoming skill damage your pet is immune to."};
--obj[19] = { label="Soins", tooltip="Enable your pet's incoming heals."};
--obj[20] = { label="Soins critiques", tooltip="Enable your pet's incoming crit heals."};
--obj[21] = { label="Soins sur le temps (HoT)", tooltip="Enable your pet's incoming heals over time."};
 
 
------------------------------
-- Outgoing events
------------------------------
 
obj = MSBTLocale.OUTGOING_PLAYER_EVENTS;
obj[1] = { label="M\195\170l\195\169e", tooltip="Afficher les dommages inflig\195\169s en m\195\170l\195\169e."};
obj[2] = { label="M\195\170l\195\169e critiques", tooltip="Afficher les dommages critiques inflig\195\169s en m\195\170l\195\169e."};
obj[3] = { label="Manques de m\195\170l\195\169e", tooltip="Afficher vos attaques manquées en m\195\170l\195\169e."};
obj[4] = { label="Esquives de m\195\170l\195\169e", tooltip="Afficher vos attaques esquiv\195\169es en m\195\170l\195\169e."};
obj[5] = { label="Parades de m\195\170l\195\169e", tooltip="Afficher vos attaques par\195\169es en m\195\170l\195\169e."};
obj[6] = { label="Bloquage de m\195\170l\195\169e", tooltip="Afficher vos dommages en m\195\170l\195\169e bloqu\195\169es."};
obj[7] = { label="Absorption de m\195\170l\195\169e", tooltip="Afficher vos dommages en m\195\170l\195\169e absorb\195\169s."};
obj[8] = { label="Immunit\195\169s de m\195\170l\195\169e", tooltip="Afficher vos attaques de m\195\170l\195\169e auxquelles l'ennemi est immunis\195\169."};
obj[9] = { label="Evites de m\195\170l\195\169e", tooltip="Afficher vos attaques de m\195\170l\195\169e evit\195\169es."};
obj[10] = { label="Comp\195\169tences", tooltip="Afficher les dommages de vos comp\195\169tences."};
obj[11] = { label="Comp\195\169tences critiques", tooltip="Afficher les dommages de vos comp\195\169tences critiques."};
obj[12] = { label="DoTs des comp\195\169tences", tooltip="Afficher les dommages sur le temps (DoTs) de vos comp\195\169tences."};
obj[13] = { label="Manques comp\195\169tences", tooltip="Afficher les coups manqu\195\169s de vos comp\195\169tences."};
obj[14] = { label="Esquives comp\195\169tences", tooltip="Afficher vos comp\195\169tences esquiv\195\169es."};
obj[15] = { label="Parades comp\195\169tences", tooltip="Afficher vos comp\195\169tences par\195\169es."};
obj[16] = { label="Bloquages comp\195\169tences", tooltip="Afficher vos comp\195\169tences bloqu\195\169es."};
obj[17] = { label="R\195\169sistances aux sorts", tooltip="Afficher les r\195\169sistances \195\160 vos sorts."};
obj[18] = { label="Absorptions comp\195\169tences", tooltip="Afficher les absorptions de dommages de vos comp\195\169tences."};
obj[19] = { label="Immunit\195\169s comp\195\169tences", tooltip="Afficher les dommages vos comp\195\169tences auxquels l'ennemi est immunis\195\169."};
obj[20] = { label="Comp\195\169tences renvoy\195\169s", tooltip="Afficher les dommages de vos comp\195\169tences qui vous sont renvoy\195\169s."};
--obj[21] = { label="Spell Interrupts", tooltip="Enable outgoing spell interrupts."};
obj[22] = { label="Evites comp\195\169tences", tooltip="Afficher les evites de vos comp\195\169tences."};
obj[23] = { label="Soins", tooltip="Afficher les soins effectu\195\169s."};
obj[24] = { label="Soins critiques", tooltip="Afficher les soins critiques effectu\195\169s."};
obj[25] = { label="Soins sur le temps (HoT)", tooltip="Afficher les soins sur le temps."};
--obj[26] = { label="Dispels", tooltip="Enable outgoing dispels."};
 
obj = MSBTLocale.OUTGOING_PET_EVENTS;
obj[1] = { label="M\195\170l\195\169e", tooltip="Afficher les dommages inflig\195\169s par votre familier."};
obj[2] = { label="M\195\170l\195\169e critiques", tooltip="Afficher les dommages critiques inflig\195\169s par votre familier."};
obj[3] = { label="Manques de m\195\170l\195\169e", tooltip="Afficher les attaques manqu\195\169es par votre familier."};
obj[4] = { label="Esquives de m\195\170l\195\169e", tooltip="Afficher les attaques de m\195\170l\195\169e de votre familier esquiv\195\169es."};
obj[5] = { label="Parades de m\195\170l\195\169e", tooltip="Afficher les attaques de m\195\170l\195\169e de votre familier par\195\169es."};
obj[6] = { label="Bloquage de m\195\170l\195\169e", tooltip="Afficher les attaques de m\195\170l\195\169e de votre familier bloqu\195\169es."};
obj[7] = { label="Absorption de m\195\170l\195\169e", tooltip="Afficher les dommages en m\195\170l\195\169e absorb\195\169s de votre familier."};
obj[8] = { label="Immunit\195\169s de m\195\170l\195\169e", tooltip="Afficher les capacit\195\169s en m\195\170l\195\169e de votre familier auxquelles l'ennemi est immunis\195\169."};
obj[9] = { label="Evites de m\195\170l\195\169e", tooltip="Afficher les evites en m\195\170l\195\169e de votre familier."};
obj[10] = { label="Comp\195\169tences", tooltip="Afficher les dommages des comp\195\169tences de votre familier."};
obj[11] = { label="Comp\195\169tences critiques", tooltip="Afficher les dommages des comp\195\169tences critiques de votre familier."};
obj[12] = { label="DoTs des comp\195\169tences", tooltip="Afficher les dommages sur le temps (DoTs) des comp\195\169tences de votre familier."};
obj[13] = { label="Manques comp\195\169tences", tooltip="Afficher les comp\195\169tences de votre familier qui ont manqu\195\169."};
obj[14] = { label="Esquives comp\195\169tences", tooltip="Afficher les comp\195\169tences de votre familier qui ont \195\169t\195\169 esquiv\195\169es."};
obj[15] = { label="Parades comp\195\169tences", tooltip="Afficher les comp\195\169tences de votre familier qui ont \195\169t\195\169 par\195\169es."};
obj[16] = { label="Bloquages comp\195\169tences", tooltip="Afficher les bloquages des comp\195\169tences de votre familier."};
obj[17] = { label="R\195\169sistances aux sorts", tooltip="Afficher les sorts de votre familier r\195\169sist\195\169."};
obj[18] = { label="Absorptions comp\195\169tences", tooltip="Afficher les comp\195\169tences de votre familier absorb\195\169s."};
obj[19] = { label="Immunit\195\169s comp\195\169tences", tooltip="Afficher les comp\195\169tences de votre familier auxquels l'ennemi est immunis\195\169."};
obj[20] = { label="Evites comp\195\169tences", tooltip="Afficher les \195\169vites des comp\195\169tences de votre familier."};
--obj[21] = { label="Dispels", tooltip="Enable your pet's outgoing dispels."};
 
 
------------------------------
-- Notification events
------------------------------
 
obj = MSBTLocale.NOTIFICATION_EVENTS;
obj[1] = { label="Debuffs", tooltip="Afficher les debuffs par lesquels vous \195\170tes affect\195\169s."};
obj[2] = { label="Buffs", tooltip="Afficher les buffs re\195\167us."};
obj[3] = { label="Buffs des objets", tooltip="Afficher les buffs re\195\167us par les objets."};
obj[4] = { label="Fin des debuffs", tooltip="Signaler la fin des debuffs."};
obj[5] = { label="Fin des buffs", tooltip="Signaler la fin des buffs."};
obj[6] = { label="Fin des buffs d'objets", tooltip="Signaler quand un de vos buffs d'objet se termine."};
obj[7] = { label="D\195\169but combat", tooltip="Signaler l'entr\195\169e en combat."};
obj[8] = { label="Sortie combat", tooltip="Signaler la fin du combat."};
obj[9] = { label="Gains de puissance", tooltip="Signaler les gains de mana, rage et \195\169nergie."};
obj[10] = { label="Pertes de puissance", tooltip="Signaler les pertes de mana, rage et \195\169nergie par des drains."};
obj[11] = { label="Gain de points de combo", tooltip="Signaler les points de combo."};
obj[12] = { label="5 points de combo", tooltip="Signaler quand vous avez atteint 5 points de combo."};
obj[13] = { label="Gains d'honneur", tooltip="Afficher les gains d'honneur."};
obj[14] = { label="Gains de r\195\169putation", tooltip="Afficher les gains de r\195\169putation."};
obj[15] = { label="Pertes de r\195\169putation", tooltip="Afficher les pertes de r\195\169putation."};
obj[16] = { label="Progression de comp\195\169tences", tooltip="Afficher les progressions de comp\195\169tences."};
obj[17] = { label="Gains d'exp\195\169rience", tooltip="Afficher les gains d'exp\195\169rience."};
obj[18] = { label="Coups fatals sur un joueur", tooltip="Afficher vos coups fatals sur les joueurs ennemis."};
obj[19] = { label="Coups fatals sur un PNJ", tooltip="Afficher vos coups fatals sur les personnages non joueurs ennemis."};
obj[20] = { label="Gains de fragments d'\195\162me", tooltip="Afficher les gains de fragments d'\195\162me."};
obj[21] = { label="Attaques suppl\195\169mentaires", tooltip="Afficher les gains d'attaques suppl\195\169mentaires, comme Windfury, etc."};
--obj[22] = { label="Enemy Buff Gains", tooltip="Enable buffs your currently targeted enemy gains."};
--obj[23] = { label="Monster Emotes", tooltip="Enable emotes by the currently targeted monster."};
--obj[24] = { label="Money Gains", tooltip="Enable money you gain."};
 
 
------------------------------
-- Trigger info
------------------------------
 
-- Holds the available trigger main events.
obj = MSBTLocale.TRIGGER_MAIN_EVENTS;
obj["Health"] = "Vie Seuil";
obj["Mana"] = "Mana Seuil";
obj["Energy"] = "Energie Seuil";
--obj["Rage"] = "Rage Threshold";
--obj["Crit"] = "Crit";
--obj["Block"] = "Block";
--obj["Dodge"] = "Dodge";
--obj["Parry"] = "Parry";
--obj["BuffGain"] = "Buff Gain";
--obj["BuffFade"] = "Buff Fade";
--obj["BuffApplication"] = "Buff Application";
--obj["DebuffGain"] = "Debuff Gain";
--obj["DebuffFade"] = "Debuff Fade";
--obj["DebuffApplication"] = "Debuff Application";
--obj["CastStart"] = "Cast Start";
--obj["KillingBlow"] = "Killing Blow";
 
 
-- Holds the available trigger exceptions.
obj = MSBTLocale.TRIGGER_EXCEPTIONS;
--obj["BuffActive"] = "Buff Active";
--obj["InsufficientPower"] = "Insufficient Power";
--obj["InsufficientComboPoints"] = "Insufficient Combo Points";
--obj["NotInArena"] = "Not In Arena";
--obj["NotInPvPZone"] = "Not In PvP Zone";
--obj["RecentlyFired"] = "Trigger Recently Fired";
--obj["SkillUnavailable"] = "Skill Unavailable";
--obj["TrivialTarget"] = "Trivial Target";
--obj["WarriorStance"] = "Warrior Stance";
 
 
------------------------------
-- Font info
------------------------------
 
-- Font outlines.
obj = MSBTLocale.OUTLINES;
obj[1] = "Aucun";
obj[2] = "Fin";
obj[3] = "Epais";
 
-- Text aligns.
obj = MSBTLocale.TEXT_ALIGNS;
obj[1] = "Gauche";
obj[2] = "Centre";
obj[3] = "Droite";
 
 
------------------------------
-- Sound info
------------------------------
 
obj = MSBTLocale.SOUNDS;
obj["LowMana"] = "Mana Faible";
obj["LowHealth"] = "Vie Faible";
 
 
------------------------------
-- Animation style info
------------------------------
 
-- Animation styles
obj = MSBTLocale.ANIMATION_STYLE_DATA;
--obj["Horizontal"] = "Horizontal";
obj["Parabola"] = "Parabole";
obj["Straight"] = "Directement";
obj["Static"] = "Statique";
obj["Pow"] = "Pow";
 
-- Animation style directions.
--obj["Alternate"] = "Alternate";
obj["Left"] = "Gauche";
obj["Right"] = "Droite";
--obj["Up"] = "Up";
--obj["Down"] = "Down";
 
-- Animation style behaviors.
--obj["GrowUp"] = "Grow Upwards";
--obj["GrowDown"] = "Grow Downwards";
--obj["CurvedLeft"] = "Curved Left";
--obj["CurvedRight"] = "Curved Right";
--obj["Jiggle"] = "Jiggle";
--obj["Normal"] = "Normal";
\ No newline at end of file
MSBT5_13/MSBTOptions/localization.de.lua New file
0,0 → 1,505
-------------------------------------------------------------------------------------
-- Title: MSBT Options German Localization
-- Author: Mik
-- German Translation by: Farook
-------------------------------------------------------------------------------------
 
-- Don't do anything if the locale isn't German.
if (GetLocale() ~= "deDE") then return; end
 
-- Local reference for faster access.
local MSBTLocale = MikSBT.Locale;
 
 
-------------------------------------------------------------------------------
-- German localization
-------------------------------------------------------------------------------
 
 
------------------------------
-- Interface messages
------------------------------
 
MSBTLocale.MSG_NEW_PROFILE = "Neues Profil";
MSBTLocale.MSG_PROFILE_ALREADY_EXISTS = "Profil besteht bereits.";
MSBTLocale.MSG_INVALID_PROFILE_NAME = "Ung\195\188ltiger Profil-Name.";
MSBTLocale.MSG_NEW_SCROLL_AREA = "Neues Scroll-Bereich";
MSBTLocale.MSG_SCROLL_AREA_ALREADY_EXISTS = "Name f\195\188r Scroll-Bereich existiert bereits.";
MSBTLocale.MSG_INVALID_SCROLL_AREA_NAME = "Ung\195\188ltiger Name f\195\188r Scroll-Bereich.";
MSBTLocale.MSG_ACKNOWLEDGE_TEXT = "Bist du sicher, dass du diese Aktion durchführen willst?";
--MSBTLocale.MSG_NORMAL_PREVIEW_TEXT = "Normal";
--MSBTLocale.MSG_INVALID_SOUND_FILE = "Sound must be a .mp3 or .wav file.";
MSBTLocale.MSG_NEW_TRIGGER = "Neuer Ausl\195\182ser";
--MSBTLocale.MSG_TRIGGER_CLASSES = "Trigger Classes";
--MSBTLocale.MSG_MAIN_EVENTS = "Main Events";
--MSBTLocale.MSG_TRIGGER_EXCEPTIONS = "Trigger Exceptions";
--MSBTLocale.MSG_SKILLS = "Skills";
--MSBTLocale.MSG_SKILL_ALREADY_EXISTS = "Skill name already exists.";
--MSBTLocale.MSG_INVALID_SKILL_NAME = "Invalid skill name.";
--MSBTLocale.MSG_HOSTILE = "Hostile";
--MSBTLocale.MSG_ANY = "Any";
--MSBTLocale.MSG_RISES_ABOVE = "Rises Above";
--MSBTLocale.MSG_FALLS_BELOW = "Falls Below";
 
 
------------------------------
-- Class Names.
------------------------------
 
local obj = MSBTLocale.CLASS_NAMES;
obj["DRUID"] = "Druide";
obj["HUNTER"] = "J\195\164ger";
obj["MAGE"] = "Magier";
obj["PALADIN"] = "Paladin";
obj["PRIEST"] = "Priester";
obj["ROGUE"] = "Schurke";
obj["SHAMAN"] = "Schamane";
obj["WARLOCK"] = "Hexenmeister";
obj["WARRIOR"] = "Krieger";
 
 
------------------------------
-- Interface tabs
------------------------------
 
-- #2, 3, and 4 need additional translation.
obj = MSBTLocale.TABS;
obj[1] = { label="Allgemein", tooltip="Allgemeine Optionen anzeigen."};
obj[2] = { label="Scrollbereiche", tooltip="Optionen f\195\188r das Erstellen, L\195\182schen, und Konfigurieren der Scroll-Bereiche anzeigen.\n\nMouse over the icon buttons for more information."};
obj[3] = { label="Ereignisse", tooltip="Optionen f\195\188r eingehende, ausgehende und benachrichtigende Ereignisse anzeigen.\n\nMouse over the icon buttons for more information."};
obj[4] = { label="Ausl\195\182ser", tooltip="Optionen f\195\188r das Ausl\195\182ser-System anzeigen.\n\nMouse over the icon buttons for more information."};
--obj[5] = { label="Spam Control", tooltip="Display options for controlling spam."};
--obj[6] = { label="Cooldowns", tooltip="Display options for cooldown notifications."};
--obj[7] = { label="Skill Icons", tooltip="Display options for skill icons."};
 
 
------------------------------
-- Interface checkboxes
------------------------------
 
-- inheritField needs additional translation.
obj = MSBTLocale.CHECKBOXES;
obj["enableMSBT"] = { label="Mik's Scrolling Battle Text aktivieren", tooltip="MSBT aktivieren."};
--obj["stickyCrits"] = { label="Sticky Crits", tooltip="Display crits using the sticky style."};
--obj["gameDamage"] = { label="Game Damage", tooltip="Display blizzard's default damage above the enemy's heads."};
--obj["gameHealing"] = { label="Game Healing", tooltip="Display blizzard's default healing above the target's heads."};
--obj["enableSounds"] = { label="Sounds aktivieren", tooltip="Play sounds that are assigned to events and triggers."};
obj["colorPartialEffects"] = { label="Partielle Effekte einf\195\164rben", tooltip="Partiellen effekte die festgelegten farben."};
--obj["crushing"] = { label="Crushing Blows", tooltip="Display the crushing blows trailer."};
--obj["glancing"] = { label="Glancing Hits", tooltip="Display the glancing hits trailer."};
--obj["absorb"] = { label="Partial Absorbs", tooltip="Display partial absorb amounts."};
--obj["block"] = { label="Partial Blocks", tooltip="Display partial block amounts."};
--obj["resist"] = { label="Partial Resists", tooltip="Display partial resist amounts."};
--obj["vulnerability"] = { label="Vulnerability Bonuses", tooltip="Display vulnerabliity bonus amounts."};
--obj["overheal"] = { label="Overheals", tooltip="Display overhealing amounts."};
--obj["colorDamageAmounts"] = { label="Color Damage Amounts", tooltip="Apply specified colors to damage amounts."};
--obj["colorDamageEntry"] = { tooltip="Enable coloring for this damage type."};
obj["enableScrollArea"] = { tooltip="Scroll-Bereich aktivieren."};
obj["inheritField"] = { label="\195\156bernehmen", tooltip="Inherit the field's value. Uncheck to override."};
obj["stickyEvent"] = { label="Immer Sticky-Style", tooltip="Ereignis im Sticky-Style angezeigt."};
obj["enableTrigger"] = { tooltip="Ausl\195\182ser aktivieren."};
--obj["allPowerGains"] = { label="ALL Power Gains", tooltip="Display all power gains including those that are not reported to the combat log.\n\nWARNING: This option is very spammy and will ignore the power threshold and throttling mechanics.\n\nNOT RECOMMENDED."};
--obj["hyperRegen"] = { label="Hyper Regen", tooltip="Display power gains during fast regen abilities such as Innervate and Spirit Tap.\n\nNOTE: The gains shown will not be throttled."};
--obj["abbreviateSkills"] = { label="Abbreviate Skills", tooltip="Abbreviates skill names (English only).\n\nThis can be overriden by each event with the %sl event code."};
--obj["hideSkills"] = { label="Hide Skills", tooltip="Don't display skill names for incoming and outgoing events.\n\nYou will give up some customization capability at the event level if you choose to use this option since it causes the %s event code to be ignored."};
--obj["hideNames"] = { label="Hide Names", tooltip="Don't display unit names for incoming and outgoing events.\n\nYou will give up some customization capability at the event level if you choose to use this option since it causes the %n event code to be ignored."};
obj["allClasses"] = { label="Alle Klassen"};
--obj["enableCooldowns"] = { label="Enable Cooldowns", tooltip="Display notifications when cooldowns complete."};
--obj["enableIcons"] = { label="Enable Skill Icons", tooltip="Displays icons for events that have a skill when possible."};
obj["exclusiveSkills"] = { label="Exclusive Skill Names", tooltip="Only show skill names when an icon is not available."};
--obj["hostileOnly"] = { label="Hostile Only", tooltip="Only fire the trigger if the selected unit is hostile."};
--obj["reverseLogic"] = { label="Reverse Logic", tooltip="Reverses the meaning of the selected exception. For example, Buff Active would mean Buff Inactive."};
 
 
------------------------------
-- Interface dropdowns
------------------------------
 
obj = MSBTLocale.DROPDOWNS;
obj["profile"] = { label="Aktuelles Profil:", tooltip="Legt das aktuelle Profil fest."};
obj["normalFont"] = { label="Schrift - Normal:", tooltip="Legt die Schriftart f\195\188r Nicht-kritische Treffer."};
obj["critFont"] = { label="Schrift - Kritisch:", tooltip="Legt die Schriftart f\195\188r kritische Treffer."};
obj["normalOutline"] = { label="Kontur - Normal:", tooltip="Legt die Kontur f\195\188r Nicht-kritische Treffer."};
obj["critOutline"] = { label="Kontur - Kritisch:", tooltip="Legt die Kontur f\195\188r kritische Treffer."};
--obj["sound"] = { label="Sound:", tooltip="Selects the sound to play when the event occurs."};
obj["scrollArea"] = { label="Scrollbereich:", tooltip="W\195\164hlt den zu konfigurierenden Scrollbereich aus."};
--obj["animationStyle"] = { label="Animations:", tooltip="The animation style for non-sticky animations in the scroll area."};
--obj["stickyAnimationStyle"] = { label="Sticky Animations:", tooltip="The animation style for sticky animations in the scroll area."};
--obj["direction"] = { label="Direction:", tooltip="The direction of the animation."};
--obj["behavior"] = { label="Behavior:", tooltip="The behavior of the animation."};
obj["textAlign"] = { label="Text ausrichten:", tooltip="Die Ausrichtung des Textes f\195\188r den Animation."};
obj["eventCategory"] = { label="Ereignis-Kategorie:", tooltip="Die Kategorie der zu konfigurienden Ereignisse."};
obj["outputScrollArea"] = { label="Scrollbereich:", tooltip="Den Scrollbereich f\195\188r die Textausgabe ausw\195\164hlen."};
--obj["mainEvent"] = { label="Main Event:"};
--obj["affectedUnit"] = { label="Affected Unit:", tooltip="The unit the event must be associated with."};
--obj["eventDirection"] = { label="Direction:", tooltip="The direction associated with the event."};
--obj["triggerException"] = { label="Exception:"};
--obj["warriorStance"] = { label="Warrior Stance:", tooltip="The stance the warrior is currently in."};
 
 
------------------------------
-- Interface buttons
------------------------------
 
obj = MSBTLocale.BUTTONS;
obj["copyProfile"] = { label="Kopieren", tooltip="Kopiert das aktuelle Profil auf ein neues Profil, dessen Namen du selbst bestimmst."};
obj["resetProfile"] = { label="Zur\195\188cksetzen", tooltip="Setzt das Profil auf die Standardeinstellungen zur\195\188ck."};
obj["deleteProfile"] = { label="L\195\182schen", tooltip="L\195\182scht das Profil."};
--obj["masterFont"] = { label="Master Fonts", tooltip="Allows you to setup the master font settings which will be inherited by all scroll areas and events within them, unless overridden."};
obj["partialEffects"] = { label="Partielle Effekte", tooltip="Erlaubt dir festzulegen welche partiellen Effekte angezeigt werden sollen, ob sie eingef\195\164rbt werden sollen, und wenn ja in welcher Farbe."};
--obj["damageColors"] = { label="Damage Colors", tooltip="Allows you to setup whether or not amounts are color coded by damage type and what colors to use for each type."};
obj["inputOkay"] = { label=OKAY, tooltip="Eingaben \195\188bernehmen."};
obj["inputCancel"] = { label=CANCEL, tooltip="Eingaben zur\195\188cksetzen."};
obj["genericSave"] = { label=SAVE, tooltip="Speichert die \195\132nderungen."};
obj["genericCancel"] = { label=CANCEL, tooltip="Bricht die \195\132nderungen."};
obj["addScrollArea"] = { label="Nueus Scrollbereich", tooltip="Einen neuen Scrollbereich ausw\195\164hlen, dem Ereignisse und Ausl\195\182ser zugewiesen werden k\195\182nnen."};
--obj["configScrollAreas"] = { label="Scrollbereiche konfigurieren", tooltip="Configure the normal and sticky animation styles, text alignment, scroll width/height, and location of the scroll areas."};
obj["editScrollAreaName"] = { tooltip="Klicken, um den Namen des Scrollbereichs zu bearbeiten."};
obj["scrollAreaFontSettings"] = { tooltip="Klicken, um die Schrifteinstellungen des Scrollbereichs zu bearbeiten, welche von allen Ereignissen dieses Bereichs \195\188bernommen werden, sofern sie nicht \195\188berschrieben werden."};
obj["deleteScrollArea"] = { tooltip="Klicken, um den Scrollbereich zu l\195\182schen."};
obj["scrollAreasPreview"] = { label="Vorschau", tooltip="Eine Vorschau auf die \195\132nderungen."};
--obj["toggleAll"] = { label="Toggle All", tooltip="Toggle the enable state of all events in the selected category."};
--obj["moveAll"] = { label="Move All", tooltip="Moves all of the events in the selected category to the specified scroll area."};
obj["eventFontSettings"] = { tooltip="Klicken, um die Schrifteinstellungen f\195\188r das Event zu bearbeiten."};
--obj["eventSettings"] = { tooltip="Click to edit the event settings such as the output scroll area, output message, sound, etc."};
--obj["customSound"] = { tooltip="Click to enter a custom sound file." };
obj["addTrigger"] = { label="Neuen Ausl\195\182ser hinzuf\195\188gen", tooltip="Einen neuen Ausl\195\182ser hinzuf\195\188gen."};
obj["triggerSettings"] = { tooltip="Klicken, um die Ausl\195\182ser-Einstellungen zu konfigurieren."};
obj["deleteTrigger"] = { tooltip="Klicken, um diesen Ausl\195\182ser zu l\195\182schen."};
--obj["editTriggerClasses"] = { tooltip="Click to edit the classes the trigger applies to."};
--obj["addMainEvent"] = { label="Add Event", tooltip="When ANY of these events occur and their defined conditions are true, the trigger will fire unless one of the exceptions specified below is true."};
--obj["addTriggerException"] = { label="Add Exception", tooltip="When ANY of these exceptions are true, the trigger will not fire."};
--obj["editEventConditions"] = { tooltip="Click to edit the conditions for the event."};
--obj["deleteMainEvent"] = { tooltip="Click to delete the event."};
--obj["editExceptionConditions"] = { tooltip="Click to edit the conditions for the exception."};
--obj["deleteException"] = { tooltip="Click to delete the exception."};
obj["triggerEventTypes"] = { label="Ausl\195\182ser: Ereignisarten", tooltip="Legt fest, nach welchen Ereignisarten gesucht werden soll."};
--obj["throttleList"] = { label="Throttle List", tooltip="Set custom throttle times for specified skills."};
--obj["mergeExclusions"] = { label="Merge Exclusions", tooltip="Prevent specified skills from being merged."};
--obj["skillSuppressions"] = { label="Skill Suppressions", tooltip="Suppress skills by their name."};
--obj["skillSubstitutions"] = { label="Skill Substitutions", tooltip="Substitute skill names with customized values."};
--obj["addSkill"] = { label="Add Skill", tooltip="Add a new skill to the list."};
--obj["deleteSkill"] = { tooltip="Click to delete the skill."};
--obj["cooldownExclusions"] = { label="Cooldown Exclusions", tooltip="Specify skills that will ignore cooldown tracking."};
 
 
------------------------------
-- Interface editboxes
------------------------------
 
obj = MSBTLocale.EDITBOXES;
--obj["copyProfile"] = { label="Gib einen neuen Profilnamen ein:", tooltip="Der Name des neuen Profils auf den das eben gew\195\164hlte Profil kopiert werden soll."};
--obj["scrollAreaName"] = { label="Neuen Scrollbereich-Namen eingeben:", tooltip="Neuer Name f\195\188r den Scrollbereichs."};
--obj["xOffset"] = { label="X Offset:", tooltip="The X offset of the selected scroll area."};
--obj["yOffset"] = { label="Y Offset:", tooltip="The Y offset of the selected scroll area."};
--obj["eventMessage"] = { label="Ausgabenachricht eingeben:", tooltip="Die Nachricht die angezeigt wird, wenn das Ereignis vorkommt."};
--obj["soundFile"] = { label="Sound filename:", tooltip="The name of the sound file to play when the event occurs."};
--obj["iconSkill"] = { label="Icon Skill:", tooltip="The name or spell ID of a skill whose icon will be displayed when the event occurs.\n\nMSBT will automatically try to figure out an appropriate icon if one is not specified.\n\nNOTE: A spell ID must be used in place of a name if the skill is not in the spellbook for the class that is playing when the event occurs. Most online databases such as wowhead can be used to discover it."};
--obj["skillName"] = { label="Skill name:", tooltip="The name of the skill to add."};
--obj["substitutionText"] = { label="Substition text:", tooltip="The text to be substituted for the skill name."};
 
 
------------------------------
-- Interface sliders
------------------------------
 
obj = MSBTLocale.SLIDERS;
obj["animationSpeed"] = { label="Animationsgeschwindigkeit", tooltip="Die Master Geschwindigkeit der Animation."};
obj["normalFontSize"] = { label="Normale Schriftgr\195\182\195\159e", tooltip="Die Schriftgr\195\182\195\159e f\195\188r Nicht-kritische Treffer."};
--obj["normalFontOpacity"] = { label="Normal Opacity", tooltip="Sets the font opacity for non-crits."};
obj["critFontSize"] = { label="Kritische Schriftgr\195\182\195\159e", tooltip="Die Schriftgr\195\182\195\159e f\195\188r kritische Treffer."};
--obj["critFontOpacity"] = { label="Crit Opacity", tooltip="Sets the font opacity for crits."};
obj["scrollHeight"] = { label="Scroll-H\195\182he", tooltip="Die H\195\182he des Scrollbereich."};
obj["scrollWidth"] = { label="Scroll Width", tooltip="The width of the scroll area."};
obj["scrollAnimationSpeed"] = { label="Geschwindigkeit", tooltip="Die Geschwindigkeit der Animation des Scrollbereich."};
--obj["powerThreshold"] = { label="Power Threshold", tooltip="The threshold that power gains must exceed to be displayed."};
--obj["healThreshold"] = { label="Heal Threshold", tooltip="The threshold that heals must exceed to be displayed."};
--obj["damageThreshold"] = { label="Damage Threshold", tooltip="The threshold that damage must exceed to be displayed."};
--obj["dotThrottleTime"] = { label="DoT Throttle Time", tooltip="The number of seconds to throttle DoTs."};
--obj["hotThrottleTime"] = { label="HoT Throttle Time", tooltip="The number of seconds to throttle HoTs."};
--obj["powerThrottleTime"] = { label="Power Throttle Time", tooltip="The number of seconds to throttle power changes."};
--obj["powerThrottleTime"] = { label="Throttle Time", tooltip="The number of seconds to throttle power changes."};
--obj["skillThrottleTime"] = { label="Throttle Time", tooltip="The number of seconds to throttle the skill."};
--obj["cooldownThreshold"] = { label="Cooldown Threshold", tooltip="Skills with a cooldown less than the specified number of seconds will not be displayed."};
--obj["genericAmount"] = { label="Amount", tooltip="Select the amount."};
 
------------------------------
-- Event categories
------------------------------
obj = MSBTLocale.EVENT_CATEGORIES;
obj[1] = "Eingehend player";
obj[2] = "Eingehend begleiter";
obj[3] = "Ausgehend player";
obj[4] = "Ausgehend begleiter";
obj[5] = "Benachrichtigung";
 
 
------------------------------
-- Event codes
------------------------------
 
obj = MSBTLocale.EVENT_CODES;
--obj["DAMAGE_TAKEN"] = "%a - Amount of damage taken.\n";
--obj["HEALING_TAKEN"] = "%a - Amount of healing taken.\n";
--obj["DAMAGE_DONE"] = "%a - Amount of damage done.\n";
--obj["HEALING_DONE"] = "%a - Amount of healing done.\n";
--obj["ENERGY_AMOUNT"] = "%a - Amount of energy.\n";
--obj["CP_AMOUNT"] = "%a - Amount of combo points you have.\n";
--obj["HONOR_AMOUNT"] = "%a - Amount of honor.\n";
--obj["REP_AMOUNT"] = "%a - Amount of reputation.\n";
--obj["SKILL_AMOUNT"] = "%a - Amount of points you have in the skill.\n";
--obj["EXPERIENCE_AMOUNT"] = "%a - Amount of experience you gained.\n";
--obj["ATTACKER_NAME"] = "%n - Name of the attacker.\n";
--obj["HEALER_NAME"] = "%n - Name of the healer.\n";
--obj["ATTACKED_NAME"] = "%n - Name of the attacked unit.\n";
--obj["HEALED_NAME"] = "%n - Name of the healed unit.\n";
--obj["BUFFED_NAME"] = "%n - Name of the buffed unit.\n";
--obj["SKILL_NAME"] = "%s - Name of the skill.\n";
--obj["SPELL_NAME"] = "%s - Name of the spell.\n";
--obj["DEBUFF_NAME"] = "%s - Name of the debuff.\n";
--obj["BUFF_NAME"] = "%s - Name of the buff.\n";
--obj["ITEM_BUFF_NAME"] = "%s - Name of the item buff.\n";
--obj["EXTRA_ATTACKS"] = "%s - Name of skill granting the extra attacks.\n";
--obj["SKILL_LONG"] = "%sl - Long form of %s. Used to override abbreviation for the event.\n";
--obj["DAMAGE_TYPE_TAKEN"] = "%t - Type of damage taken.\n";
--obj["DAMAGE_TYPE_DONE"] = "%t - Type of damage done.\n";
--obj["ENVIRONMENTAL_DAMAGE"] = "%e - Name of the source of the damage (falling, drowning, lava, etc...)\n";
--obj["FACTION_NAME"] = "%e - Name of the faction.\n";
--obj["UNIT_KILLED"] = "%e - Name of the unit killed.\n";
--obj["SHARD_NAME"] = "%e - Localized name of the soul shard.\n";
--obj["EMOTE_TEXT"] = "%e - The text of the emote.\n";
--obj["MONEY_TEXT"] = "%e - The money gained text.\n";
--obj["COOLDOWN_NAME"] = "%e - The name of skill that is ready.\n"
--obj["POWER_TYPE"] = "%p - Type of power (energy, rage, mana).\n";
 
 
------------------------------
-- Incoming events
------------------------------
 
obj = MSBTLocale.INCOMING_PLAYER_EVENTS;
--obj[1] = { label="Melee Hits", tooltip="Enable incoming melee hits."};
--obj[2] = { label="Melee Crits", tooltip="Enable incoming melee crits."};
--obj[3] = { label="Melee Misses", tooltip="Enable incoming melee misses."};
--obj[4] = { label="Melee Dodges", tooltip="Enable incoming melee dodges."};
--obj[5] = { label="Melee Parries", tooltip="Enable incoming melee parries."};
--obj[6] = { label="Melee Blocks", tooltip="Enable incoming melee blocks."};
--obj[7] = { label="Melee Absorbs", tooltip="Enable absorbed incoming melee damage."};
--obj[8] = { label="Melee Immunes", tooltip="Enable incoming melee damage you are immune to."};
--obj[9] = { label="Skill Hits", tooltip="Enable incoming skill hits."};
--obj[10] = { label="Skill Crits", tooltip="Enable incoming skill damage."};
--obj[11] = { label="Skill DoTs", tooltip="Enable incoming skill damage over time."};
--obj[12] = { label="Skill Misses", tooltip="Enable incoming skill misses."};
--obj[13] = { label="Skill Dodges", tooltip="Enable incoming skill dodges."};
--obj[14] = { label="Skill Parries", tooltip="Enable incoming skill parries."};
--obj[15] = { label="Skill Blocks", tooltip="Enable incoming skill blocks."};
--obj[16] = { label="Spell Resists", tooltip="Enable incoming spell resists."};
--obj[17] = { label="Skill Absorbs", tooltip="Enable absorbed damage from incoming skills."};
--obj[18] = { label="Skill Immunes", tooltip="Enable incoming skill damage you are immune to."};
--obj[19] = { label="Skill Reflects", tooltip="Enable incoming skill damage you reflected."};
--obj[20] = { label="Spell Interrupts", tooltip="Enable incoming spell interrupts."};
--obj[21] = { label="Heals", tooltip="Enable incoming heals."};
--obj[22] = { label="Crit Heals", tooltip="Enable incoming crit heals."};
--obj[23] = { label="Heals Over Time", tooltip="Enable incoming heals over time."};
--obj[24] = { label="Environmental Damage", tooltip="Enable environmental (falling, drowning, lava, etc...) damage."};
 
obj = MSBTLocale.INCOMING_PET_EVENTS;
--obj[1] = { label="Melee Hits", tooltip="Enable your pet's incoming melee hits."};
--obj[2] = { label="Melee Crits", tooltip="Enable your pet's incoming melee crits."};
--obj[3] = { label="Melee Misses", tooltip="Enable your pet's incoming melee misses."};
--obj[4] = { label="Melee Dodges", tooltip="Enable your pet's incoming melee dodges."};
--obj[5] = { label="Melee Parries", tooltip="Enable your pet's incoming melee parries."};
--obj[6] = { label="Melee Blocks", tooltip="Enable your pet's incoming melee blocks."};
--obj[7] = { label="Melee Absorbs", tooltip="Enable your pet's absorbed incoming melee damage."};
--obj[8] = { label="Melee Immunes", tooltip="Enable melee damage your is pet immune to."};
--obj[9] = { label="Skill Hits", tooltip="Enable your pet's incoming skill hits."};
--obj[10] = { label="Skill Crits", tooltip="Enable your pet's incoming skill crits."};
--obj[11] = { label="Skill DoTs", tooltip="Enable your pet's incoming skill damage over time."};
--obj[12] = { label="Skill Misses", tooltip="Enable your pet's incoming skill misses."};
--obj[13] = { label="Skill Dodges", tooltip="Enable your pet's incoming skill dodges."};
--obj[14] = { label="Skill Parries", tooltip="Enable your pet's incoming skill parries."};
--obj[15] = { label="Skill Blocks", tooltip="Enable your pet's incoming skill blocks."};
--obj[16] = { label="Spell Resists", tooltip="Enable your pet's incoming spell resists."};
--obj[17] = { label="Skill Absorbs", tooltip="Enable absorbed damage from your pet's incoming skills."};
--obj[18] = { label="Skill Immunes", tooltip="Enable incoming skill damage your pet is immune to."};
--obj[19] = { label="Heals", tooltip="Enable your pet's incoming heals."};
--obj[20] = { label="Crit Heals", tooltip="Enable your pet's incoming crit heals."};
--obj[21] = { label="Heals Over Time", tooltip="Enable your pet's incoming heals over time."};
 
 
------------------------------
-- Outgoing events
------------------------------
 
obj = MSBTLocale.OUTGOING_PLAYER_EVENTS;
--obj[1] = { label="Melee Hits", tooltip="Enable outgoing melee hits."};
--obj[2] = { label="Melee Crits", tooltip="Enable outgoing melee crits."};
--obj[3] = { label="Melee Misses", tooltip="Enable outgoing melee misses."};
--obj[4] = { label="Melee Dodges", tooltip="Enable outgoing melee dodges."};
--obj[5] = { label="Melee Parries", tooltip="Enable outgoing melee parries."};
--obj[6] = { label="Melee Blocks", tooltip="Enable outgoing melee blocks."};
--obj[7] = { label="Melee Absorbs", tooltip="Enable absorbed outgoing melee damage."};
--obj[8] = { label="Melee Immunes", tooltip="Enable outgoing melee damage the enemy is immune to."};
--obj[9] = { label="Melee Evades", tooltip="Enable outgoing melee evades."};
--obj[10] = { label="Skill Hits", tooltip="Enable outgoing skill hits."};
--obj[11] = { label="Skill Crits", tooltip="Enable outgoing skill crits."};
--obj[12] = { label="Skill DoTs", tooltip="Enable outgoing skill damage over time."};
--obj[13] = { label="Skill Misses", tooltip="Enable outgoing skill misses."};
--obj[14] = { label="Skill Dodges", tooltip="Enable outgoing skill dodges."};
--obj[15] = { label="Skill Parries", tooltip="Enable outgoing skill parries."};
--obj[16] = { label="Skill Blocks", tooltip="Enable outgoing skill blocks."};
--obj[17] = { label="Spell Resists", tooltip="Enable outgoing spell resists."};
--obj[18] = { label="Skill Absorbs", tooltip="Enable absorbed damage from outgoing skills."};
--obj[19] = { label="Skill Immunes", tooltip="Enable outgoing skill damage the enemy is immune to."};
--obj[20] = { label="Skill Reflects", tooltip="Enable outgoing skill damage reflected back to you."};
--obj[21] = { label="Spell Interrupts", tooltip="Enable outgoing spell interrupts."};
--obj[22] = { label="Skill Evades", tooltip="Enable outgoing skill evades."};
--obj[23] = { label="Heals", tooltip="Enable outgoing heals."};
--obj[24] = { label="Crit Heals", tooltip="Enable outgoing crit heals."};
--obj[25] = { label="Heals Over Time", tooltip="Enable outgoing heals over time."};
--obj[26] = { label="Dispels", tooltip="Enable outgoing dispels."};
 
obj = MSBTLocale.OUTGOING_PET_EVENTS;
--obj[1] = { label="Melee Hits", tooltip="Enable your pet's outgoing melee hits."};
--obj[2] = { label="Melee Crits", tooltip="Enable your pet's outgoing melee crits."};
--obj[3] = { label="Melee Misses", tooltip="Enable your pet's outgoing melee misses."};
--obj[4] = { label="Melee Dodges", tooltip="Enable your pet's outgoing melee dodges."};
--obj[5] = { label="Melee Parries", tooltip="Enable your pet's outgoing melee parries."};
--obj[6] = { label="Melee Blocks", tooltip="Enable your pet's outgoing melee blocks."};
--obj[7] = { label="Melee Absorbs", tooltip="Enable your pet's absorbed outgoing melee damage."};
--obj[8] = { label="Melee Immunes", tooltip="Enable your pet's outgoing melee damage the enemy is immune to."};
--obj[9] = { label="Melee Evades", tooltip="Enable your pet's outgoing melee evades."};
--obj[10] = { label="Skill Hits", tooltip="Enable your pet's outgoing skill hits."};
--obj[11] = { label="Skill Crits", tooltip="Enable your pet's outgoing skill crits."};
--obj[12] = { label="Skill DoTs", tooltip="Enable outgoing skill damage over time."};
--obj[13] = { label="Skill Misses", tooltip="Enable your pet's outgoing skill misses."};
--obj[14] = { label="Skill Dodges", tooltip="Enable your pet's outgoing skill dodges."};
--obj[15] = { label="Skill Parries", tooltip="Enable your pet's outgoing ability parries."};
--obj[16] = { label="Skill Blocks", tooltip="Enable your pet's outgoing skill blocks."};
--obj[17] = { label="Spell Resists", tooltip="Enable your pet's outgoing spell resists."};
--obj[18] = { label="Skill Absorbs", tooltip="Enable your pet's absorbed damage from outgoing skills."};
--obj[19] = { label="Skill Immunes", tooltip="Enable your pet's outgoing skill damage the enemy is immune to."};
--obj[20] = { label="Skill Evades", tooltip="Enable your pet's outgoing skill evades."};
--obj[21] = { label="Dispels", tooltip="Enable your pet's outgoing dispels."};
 
 
------------------------------
-- Notification events
------------------------------
 
obj = MSBTLocale.NOTIFICATION_EVENTS;
--obj[1] = { label="Debuffs", tooltip="Enable debuffs you are afflicted by."};
--obj[2] = { label="Buffs", tooltip="Enable buffs you receive."};
--obj[3] = { label="Item Buffs", tooltip="Enable buffs your items receive."};
--obj[4] = { label="Debuff Fades", tooltip="Enable debuffs that have faded from you."};
--obj[5] = { label="Buff Fades", tooltip="Enable buffs that have faded from you."};
--obj[6] = { label="Item Buff Fades", tooltip="Enable item buffs that have faded from you."};
--obj[7] = { label="Enter Combat", tooltip="Enable when you have entered combat."};
--obj[8] = { label="Leave Combat", tooltip="Enable when you have left combat."};
--obj[9] = { label="Power Gains", tooltip="Enable when you gain extra mana, rage, or energy."};
--obj[10] = { label="Power Losses", tooltip="Enable when you lose mana, rage, or energy from drains."};
--obj[11] = { label="Combo Point Gains", tooltip="Enable when you gain combo points."};
--obj[12] = { label="Combo Points Full", tooltip="Enable when you attain full combo points."};
--obj[13] = { label="Honor Gains", tooltip="Enable when you gain honor."};
--obj[14] = { label="Reputation Gains", tooltip="Enable when you gain reputation."};
--obj[15] = { label="Reputation Losses", tooltip="Enable when you lose reputation."};
--obj[16] = { label="Skill Gains", tooltip="Enable when you gain skill points."};
--obj[17] = { label="Experience Gains", tooltip="Enable when you gain experience points."};
--obj[18] = { label="Player Killing Blows", tooltip="Enable when you get a killing blow against a hostile player."};
--obj[19] = { label="NPC Killing Blows", tooltip="Enable when you get a killing blow against an NPC."};
--obj[20] = { label="Soul Shard Gains", tooltip="Enable when you gain a soul shard."};
--obj[21] = { label="Extra Attacks", tooltip="Enable when you gain extra attacks such as windfury, thrash, sword spec, etc."};
--obj[22] = { label="Enemy Buff Gains", tooltip="Enable buffs your currently targeted enemy gains."};
--obj[23] = { label="Monster Emotes", tooltip="Enable emotes by the currently targeted monster."};
--obj[24] = { label="Money Gains", tooltip="Enable money you gain."};
 
 
------------------------------
-- Trigger info
------------------------------
 
-- Holds the available trigger main events.
obj = MSBTLocale.TRIGGER_MAIN_EVENTS;
--obj["Health"] = "Health Threshold";
--obj["Mana"] = "Mana Threshold";
--obj["Energy"] = "Energy Threshold";
--obj["Rage"] = "Rage Threshold";
--obj["Crit"] = "Crit";
--obj["Block"] = "Block";
--obj["Dodge"] = "Dodge";
--obj["Parry"] = "Parry";
--obj["BuffGain"] = "Buff Gain";
--obj["BuffFade"] = "Buff Fade";
--obj["BuffApplication"] = "Buff Application";
--obj["DebuffGain"] = "Debuff Gain";
--obj["DebuffFade"] = "Debuff Fade";
--obj["DebuffApplication"] = "Debuff Application";
--obj["CastStart"] = "Cast Start";
--obj["KillingBlow"] = "Killing Blow";
 
 
-- Holds the available trigger exceptions.
obj = MSBTLocale.TRIGGER_EXCEPTIONS;
--obj["BuffActive"] = "Buff Active";
--obj["InsufficientPower"] = "Insufficient Power";
--obj["InsufficientComboPoints"] = "Insufficient Combo Points";
--obj["NotInArena"] = "Not In Arena";
--obj["NotInPvPZone"] = "Not In PvP Zone";
--obj["RecentlyFired"] = "Trigger Recently Fired";
--obj["SkillUnavailable"] = "Skill Unavailable";
--obj["TrivialTarget"] = "Trivial Target";
--obj["WarriorStance"] = "Warrior Stance";
 
 
------------------------------
-- Font info
------------------------------
 
-- Font outlines.
obj = MSBTLocale.OUTLINES;
obj[1] = "Kein";
obj[2] = "D\195\188nn";
obj[3] = "Dick";
 
-- Text aligns.
obj = MSBTLocale.TEXT_ALIGNS;
obj[1] = "Links";
obj[2] = "Zentriert";
obj[3] = "Rechts";
 
 
------------------------------
-- Sound info
------------------------------
 
obj = MSBTLocale.SOUNDS;
obj["LowMana"] = "Mana Niedrig";
obj["LowHealth"] = "Gesundheit Niedrig";
 
 
------------------------------
-- Animation style info
------------------------------
 
-- Animation styles
obj = MSBTLocale.ANIMATION_STYLE_DATA;
obj["Horizontal"] = "Horizontale";
obj["Parabola"] = "Parabel";
obj["Straight"] = "Gerade";
obj["Static"] = "Statisch";
--obj["Pow"] = "Pow";
 
-- Animation style directions.
--obj["Alternate"] = "Alternate";
obj["Left"] = "Links";
obj["Right"] = "Rechts";
obj["Up"] = "Bis";
obj["Down"] = "Hinunter";
 
-- Animation style behaviors.
--obj["GrowUp"] = "Grow Upwards";
--obj["GrowDown"] = "Grow Downwards";
--obj["CurvedLeft"] = "Curved Left";
--obj["CurvedRight"] = "Curved Right";
--obj["Jiggle"] = "Jiggle";
--obj["Normal"] = "Normal";
\ No newline at end of file
MSBT5_13/MSBTOptions/MSBTOptions.toc New file
0,0 → 1,15
## Interface: 20400
## Version: 5.13
## Title: MSBT [|cffffff80Options|r]
## Author: Mik
## Notes: Load on demand options for Mik's Scrolling Battle Text
## Dependencies: MikScrollingBattleText
## LoadOnDemand: 1
localization.lua
localization.de.lua
localization.fr.lua
localization.zhcn.lua
MSBTOptionsControls.lua
MSBTOptionsPopups.lua
MSBTOptionsMain.lua
MSBTOptionsTabs.lua
\ No newline at end of file
MSBT5_13/MSBTOptions/MSBTOptionsControls.lua New file
0,0 → 1,1912
-------------------------------------------------------------------------------
-- Title: MSBT Options Controls
-- Author: Mik
-------------------------------------------------------------------------------
 
-- Create module and set its name.
local module = {};
local moduleName = "Controls";
MSBTOptions[moduleName] = module;
 
 
-------------------------------------------------------------------------------
-- Private variables.
-------------------------------------------------------------------------------
 
-- Backdrop table to be reused for sliders.
local sliderBackdrop;
 
-- Emphasis shown when a listbox entry is moused over.
local emphasizeFrame;
 
-- Listbox used for dropdowns.
local dropdownListboxFrame;
 
-- Used for correctly calculating string widths.
local calcFontString;
 
 
-------------------------------------------------------------------------------
-- Listbox functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Shows the highlight frame over the passed line.
-- ****************************************************************************
local function Listbox_ShowHighlight(this, line)
local highlight = this.highlightFrame;
highlight:ClearAllPoints();
highlight:SetParent(line);
highlight:SetPoint("TOPLEFT");
highlight:SetPoint("BOTTOMRIGHT");
highlight:Show();
 
if (emphasizeFrame:GetParent() == line) then emphasizeFrame:Hide(); end
end
 
 
-- ****************************************************************************
-- Shows or hides the scroll bar and resizes the display area as necessary.
-- ****************************************************************************
local function Listbox_HandleScrollbar(this)
-- Show or hide the scroll bar if there are more items than will fit on the page.
local display = this.displayFrame;
local slider = this.sliderFrame;
if (#this.items <= #this.lines) then
slider:Hide();
display:SetPoint("BOTTOMRIGHT");
else
display:SetPoint("BOTTOMRIGHT", display:GetParent(), "BOTTOMRIGHT", -16, 0);
slider:Show();
end
end
 
 
-- ****************************************************************************
-- Returns whether the listbox is fully configured.
-- ****************************************************************************
local function Listbox_IsConfigured(this)
return this.configured and this.lineHandler and this.displayHandler;
end
 
 
-- ****************************************************************************
-- Returns the current offset.
-- ****************************************************************************
local function Listbox_GetOffset(this)
return this.sliderFrame:GetValue();
end
 
 
-- ****************************************************************************
-- Returns the current offset.
-- ****************************************************************************
local function Listbox_SetOffset(this, offset)
this.sliderFrame:SetValue(offset);
end
 
 
-- ****************************************************************************
-- Called when the listbox needs to be refreshed.
-- ****************************************************************************
local function Listbox_Refresh(this)
-- Don't do anything if the listbox isn't configured.
if (not Listbox_IsConfigured(this)) then return; end
 
-- Handle scroll bar showing / resizing.
Listbox_HandleScrollbar(this);
 
-- Hide the highlight.
this.highlightFrame:Hide();
 
-- Show or hide the correct lines depending on how many items there are and
-- apply a highlight to the selected item.
local selectedItem = this.selectedItem;
local isSelected;
for lineNum, line in ipairs(this.lines) do
if (lineNum > #this.items) then
line:Hide();
else
line.itemNumber = lineNum + Listbox_GetOffset(this);
line:Show();
 
-- Move the highlight to the selected line and show it.
if (selectedItem == line.itemNumber) then
Listbox_ShowHighlight(this, line);
isSelected = true
else
isSelected = false;
end
 
if (this.displayHandler) then this:displayHandler(line, this.items[line.itemNumber], isSelected); end
end
end
end
 
 
-- ****************************************************************************
-- Called when the listbox is scrolled up.
-- ****************************************************************************
local function Listbox_ScrollUp(this)
local slider = this.sliderFrame;
slider:SetValue(slider:GetValue() - slider:GetValueStep());
end
 
 
-- ****************************************************************************
-- Called when the listbox is scrolled down.
-- ****************************************************************************
local function Listbox_ScrollDown(this)
local slider = this.sliderFrame;
slider:SetValue(slider:GetValue() + slider:GetValueStep());
end
 
 
-- ****************************************************************************
-- Called when one of the lines in the listbox is clicked.
-- ****************************************************************************
local function Listbox_OnClickLine(this)
local listbox = this:GetParent():GetParent();
listbox.selectedItem = this.lineNumber + Listbox_GetOffset(listbox);
 
Listbox_ShowHighlight(listbox, this);
 
if (listbox.clickHandler) then listbox:clickHandler(this, listbox.items[listbox.selectedItem]); end
end
 
 
-- ****************************************************************************
-- Called when the mouse enters a line.
-- ****************************************************************************
local function Listbox_OnEnterLine(this)
local listbox = this:GetParent():GetParent();
if (this.itemNumber ~= listbox.selectedItem) then
emphasizeFrame:ClearAllPoints();
emphasizeFrame:SetParent(this);
emphasizeFrame:SetPoint("TOPLEFT");
emphasizeFrame:SetPoint("BOTTOMRIGHT");
emphasizeFrame:Show();
end
 
if (this.tooltip) then
GameTooltip:SetOwner(this, this.tooltipAnchor or "ANCHOR_RIGHT");
GameTooltip:SetText(this.tooltip, nil, nil, nil, nil, 1);
end
end
 
 
-- ****************************************************************************
-- Called when the mouse leaves a line.
-- ****************************************************************************
local function Listbox_OnLeaveLine(this)
emphasizeFrame:Hide();
GameTooltip:Hide();
end
 
 
-- ****************************************************************************
-- Called when the scroll up button is pressed.
-- ****************************************************************************
local function Listbox_OnClickUp(this)
local listbox = this:GetParent():GetParent();
Listbox_ScrollUp(listbox);
PlaySound("UChatScrollButton");
end
 
 
-- ****************************************************************************
-- Called when the scroll down button is pressed.
-- ****************************************************************************
local function Listbox_OnClickDown(this)
local listbox = this:GetParent():GetParent();
Listbox_ScrollDown(listbox);
PlaySound("UChatScrollButton");
end
 
 
-- ****************************************************************************
-- Called when the mouse wheel is scrolled in the display frame.
-- ****************************************************************************
local function Listbox_OnMouseWheel(this, delta)
local listbox = this:GetParent();
if (delta < 0) then
Listbox_ScrollDown(listbox);
elseif (delta > 0) then
Listbox_ScrollUp(listbox);
end
end
 
 
-- ****************************************************************************
-- Called when the scroll bar slider is changed.
-- ****************************************************************************
local function Listbox_OnValueChanged(this, value)
Listbox_Refresh(this:GetParent());
end
 
 
-- ****************************************************************************
-- Creates a new line using the register create line handler.
-- ****************************************************************************
local function Listbox_CreateLine(this)
-- Get a line from cache if there are any otherwise call the registered line
-- handler to create a new line.
local lineCache = this.lineCache;
local line = (#lineCache > 0) and table.remove(lineCache) or this:lineHandler();
 
line:SetParent(this.displayFrame);
line:SetHeight(this.lineHeight);
line:ClearAllPoints();
line:SetScript("OnClick", Listbox_OnClickLine);
line:SetScript("OnEnter", Listbox_OnEnterLine);
line:SetScript("OnLeave", Listbox_OnLeaveLine);
 
local lines = this.lines;
if (#lines == 0) then
line:SetPoint("TOPLEFT");
line:SetPoint("TOPRIGHT");
else
line:SetPoint("TOPLEFT", lines[#lines], "BOTTOMLEFT");
line:SetPoint("TOPRIGHT", lines[#lines], "BOTTOMRIGHT");
end
 
lines[#lines+1] = line;
line.lineNumber = #lines;
end
 
 
-- ****************************************************************************
-- Reconfigures the listbox if it was already configured.
-- ****************************************************************************
local function Listbox_Reconfigure(this, width, height, lineHeight)
-- Don't allow negative widths.
if (width < 0) then width = 0; end
 
-- Setup container frame.
this:SetWidth(width);
this:SetHeight(height);
 
-- Setup line calculations.
this.lineHeight = lineHeight;
this.linesPerPage = math.floor(height / lineHeight);
 
-- Resize the line height of existing lines.
for _, line in ipairs(this.lines) do
line:SetHeight(this.lineHeight);
end
 
-- Add lines if more will fit on the page and they are needed.
local lines = this.lines;
if (#this.items > #lines) then
while (#lines < this.linesPerPage and #this.items > #lines) do
Listbox_CreateLine(this);
end
end
 
-- Remove and cache lines that will no longer fit on the page.
local lineCache = this.lineCache;
for x = this.linesPerPage+1, #lines do
lines[#lines]:Hide();
lineCache[#lineCache+1] = table.remove(lines);
end
 
-- Setup slider frame.
local slider = this.sliderFrame;
slider:Hide();
slider:SetMinMaxValues(0, math.max(#this.items - #this.lines, 0));
slider:SetValue(0);
 
Listbox_Refresh(this);
end
 
 
-- ****************************************************************************
-- Configures the listbox.
-- ****************************************************************************
local function Listbox_Configure(this, width, height, lineHeight)
-- Don't do anything if required parameters are invalid.
if (not width or not height or not lineHeight) then return; end
 
if (Listbox_IsConfigured(this)) then Listbox_Reconfigure(this, width, height, lineHeight); return; end
 
-- Don't allow negative widths.
if (width < 0) then width = 0; end
 
-- Setup container frame.
this:SetWidth(width);
this:SetHeight(height);
 
-- Setup slider frame.
local slider = this.sliderFrame;
slider:SetMinMaxValues(0, 0);
slider:SetValue(0);
 
-- Setup line calculations.
this.lineHeight = lineHeight;
this.linesPerPage = math.floor(height / lineHeight);
 
this.configured = true;
end
 
 
-- ****************************************************************************
-- Set the function to be called when a new line needs to be created. The
-- called function must return a "Button" frame.
-- ****************************************************************************
local function Listbox_SetCreateLineHandler(this, handler)
this.lineHandler = handler;
end
 
 
-- ****************************************************************************
-- Set the function to be called when a line is being displayed.
-- It is passed the line frame to be populated, and the value associated
-- with that line.
-- ****************************************************************************
local function Listbox_SetDisplayHandler(this, handler)
this.displayHandler = handler;
end
 
 
-- ****************************************************************************
-- Set the function to be called when a line in the listbox is clicked.
-- It is passed the line frame, and the value associated with that line.
-- ****************************************************************************
local function Listbox_SetClickHandler(this, handler)
this.clickHandler = handler;
end
 
 
-- ****************************************************************************
-- Returns the passed item number from the listbox.
-- ****************************************************************************
local function Listbox_GetItem(this, itemNumber)
return this.items[itemNumber];
end
 
 
-- ****************************************************************************
-- Adds the passed item to the listbox.
-- ****************************************************************************
local function Listbox_AddItem(this, key, forceVisible)
-- Don't do anything if the listbox isn't configured.
if (not Listbox_IsConfigured(this)) then return; end
 
-- Add the passed key to the items list.
local items = this.items;
items[#items + 1] = key;
 
-- Create a new line if the max number allowed per page hasn't been reached.
local lines = this.lines;
if (#lines < this.linesPerPage) then
Listbox_CreateLine(this);
end
 
-- Set the new max offset value.
local maxOffset = math.max(#items - #lines, 0);
this.sliderFrame:SetMinMaxValues(0, maxOffset);
 
-- Make sure the newly added item is visible if the force flag is set.
if (forceVisible) then Listbox_SetOffset(this, maxOffset); end
 
Listbox_Refresh(this);
end
 
 
-- ****************************************************************************
-- Removes the passed item number from the listbox.
-- ****************************************************************************
local function Listbox_RemoveItem(this, itemNumber)
-- Don't do anything if the listbox isn't configured.
if (not Listbox_IsConfigured(this)) then return; end
 
local items = this.items;
table.remove(items, itemNumber);
 
-- Set the new max offset value.
this.sliderFrame:SetMinMaxValues(0, math.max(#items - #this.lines, 0));
 
Listbox_Refresh(this);
end
 
 
-- ****************************************************************************
-- Returns the number of items in the listbox.
-- ****************************************************************************
local function Listbox_GetNumItems(this)
return #this.items;
end
 
 
-- ****************************************************************************
-- Returns the selected item from the listbox.
-- ****************************************************************************
local function Listbox_GetSelectedItem(this)
if (this.selectedItem ~= 0) then return this.items[this.selectedItem]; end
end
 
 
-- ****************************************************************************
-- Sets the selected item for the listbox.
-- ****************************************************************************
local function Listbox_SetSelectedItem(this, itemNumber)
-- Don't do anything if the listbox isn't configured.
if (not Listbox_IsConfigured(this)) then return; end
 
this.selectedItem = itemNumber <= #this.items and itemNumber or 0;
 
-- Highlight the selected line if it's visible.
local line = this.lines[this.selectedItem - this.sliderFrame:GetValue()];
if (line) then Listbox_ShowHighlight(this, line); end
end
 
 
-- ****************************************************************************
-- Returns the line object from the listbox.
-- ****************************************************************************
local function Listbox_GetLine(this, lineNumber)
local lines = this.lines;
if (lineNumber <= #lines) then return lines[lineNumber]; end
end
 
 
-- ****************************************************************************
-- Returns the number of lines in the listbox.
-- ****************************************************************************
local function Listbox_GetNumLines(this)
return math.min(#this.lines, #this.items);
end
 
 
-- ****************************************************************************
-- Clears the listbox contents.
-- ****************************************************************************
local function Listbox_Clear(this)
-- Don't do anything if the listbox isn't configured.
if (not Listbox_IsConfigured(this)) then return; end
 
local items = this.items;
for k, v in ipairs(items) do
items[k] = nil;
end
 
-- Set the new max offset value.
this.sliderFrame:SetMinMaxValues(0, 0);
 
this.selectedItem = 0;
 
Listbox_Refresh(this);
end
 
 
-- ****************************************************************************
-- Disables the listbox.
-- ****************************************************************************
local function Listbox_Disable(this)
this.displayFrame:EnableMouseWheel(false);
this.sliderFrame:EnableMouse(false);
this.upButton:Disable();
this.downButton:Disable();
end
 
 
-- ****************************************************************************
-- Enables the listbox.
-- ****************************************************************************
local function Listbox_Enable(this)
this.displayFrame:EnableMouseWheel(true);
this.sliderFrame:EnableMouse(true);
this.upButton:Enable();
this.downButton:Enable();
end
 
 
-- ****************************************************************************
-- Creates and returns a listbox object ready to be configured.
-- ****************************************************************************
local function CreateListbox(parent)
-- Create the frame used to emphasize the entry the mouse is over.
if (not emphasizeFrame) then
emphasizeFrame = CreateFrame("Frame");
 
local texture = emphasizeFrame:CreateTexture(nil, "ARTWORK");
texture:SetTexture("Interface\\QuestFrame\\UI-QuestLogTitleHighlight");
texture:SetBlendMode("ADD");
texture:SetPoint("TOPLEFT", emphasizeFrame, "TOPLEFT");
texture:SetPoint("BOTTOMRIGHT", emphasizeFrame, "BOTTOMRIGHT");
end
 
-- Create container frame.
local listbox = CreateFrame("Frame", nil, parent);
 
-- Highlight frame.
local highlight = CreateFrame("Frame");
 
local texture = highlight:CreateTexture(nil, "ARTWORK");
texture:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight");
texture:SetBlendMode("ADD");
texture:SetPoint("TOPLEFT", highlight, "TOPLEFT");
texture:SetPoint("BOTTOMRIGHT", highlight, "BOTTOMRIGHT");
 
-- Create display area.
local display = CreateFrame("Frame", nil, listbox);
display:SetPoint("TOPLEFT", listbox, "TOPLEFT");
display:SetPoint("BOTTOMRIGHT", listbox, "BOTTOMRIGHT");
 
 
-- Create slider to track the position.
local slider = CreateFrame("Slider", nil, listbox);
slider:Hide();
slider:SetWidth(16);
slider:SetPoint("TOPRIGHT", listbox, "TOPRIGHT", 0, -16);
slider:SetPoint("BOTTOMRIGHT", listbox, "BOTTOMRIGHT", 0, 16);
slider:SetThumbTexture("Interface\\Buttons\\UI-ScrollBar-Knob");
slider:SetValueStep(1);
slider:SetScript("OnValueChanged", Listbox_OnValueChanged);
 
-- Up button.
local upButton = CreateFrame("Button", nil, slider, "UIPanelScrollUpButtonTemplate");
upButton:SetPoint("BOTTOM", slider, "TOP");
upButton:SetScript("OnClick", Listbox_OnClickUp);
 
-- Down button.
local downButton = CreateFrame("Button", nil, slider, "UIPanelScrollDownButtonTemplate");
downButton:SetPoint("TOP", slider, "BOTTOM");
downButton:SetScript("OnClick", Listbox_OnClickDown);
 
 
-- Make it work with the mouse wheel.
display:EnableMouseWheel(true);
display:SetScript("OnMouseWheel", Listbox_OnMouseWheel);
 
 
-- Extension functions.
listbox.Configure = Listbox_Configure;
listbox.SetCreateLineHandler = Listbox_SetCreateLineHandler;
listbox.SetDisplayHandler = Listbox_SetDisplayHandler;
listbox.SetClickHandler = Listbox_SetClickHandler;
listbox.GetOffset = Listbox_GetOffset;
listbox.SetOffset = Listbox_SetOffset;
listbox.GetItem = Listbox_GetItem;
listbox.AddItem = Listbox_AddItem;
listbox.RemoveItem = Listbox_RemoveItem;
listbox.GetNumItems = Listbox_GetNumItems;
listbox.GetSelectedItem = Listbox_GetSelectedItem;
listbox.SetSelectedItem = Listbox_SetSelectedItem;
listbox.GetLine = Listbox_GetLine;
listbox.GetNumLines = Listbox_GetNumLines;
listbox.Refresh = Listbox_Refresh;
listbox.Clear = Listbox_Clear;
listbox.Disable = Listbox_Disable;
listbox.Enable = Listbox_Enable;
 
-- Track internal values.
listbox.displayFrame = display;
listbox.sliderFrame = slider;
listbox.upButton = upButton;
listbox.downButton = downButton;
listbox.highlightFrame = highlight;
listbox.items = {};
listbox.lines = {};
listbox.lineCache = {};
listbox.selectedItem = 0;
return listbox;
end
 
 
-------------------------------------------------------------------------------
-- Checkbox functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Called when the internal checkbutton is clicked.
-- ****************************************************************************
local function Checkbox_OnClick(this)
local isChecked = this:GetChecked() and true or false;
if (isChecked) then PlaySound("igMainMenuOptionCheckBoxOn"); else PlaySound("igMainMenuOptionCheckBoxOff"); end
 
local checkbox = this:GetParent();
if (checkbox.clickHandler) then checkbox:clickHandler(isChecked); end
end
 
 
-- ****************************************************************************
-- Called when the mouse enters the internal checkbutton.
-- ****************************************************************************
local function Checkbox_OnEnter(this)
if (this.tooltip) then
GameTooltip:SetOwner(this, this.tooltipAnchor or "ANCHOR_RIGHT");
GameTooltip:SetText(this.tooltip, nil, nil, nil, nil, 1);
end
end
 
 
-- ****************************************************************************
-- Called when the mouse leaves the internal checkbutton.
-- ****************************************************************************
local function Checkbox_OnLeave(this)
GameTooltip:Hide();
end
 
 
-- ****************************************************************************
-- Sets the label for the checkbox.
-- ****************************************************************************
local function Checkbox_SetLabel(this, label)
local fontString = this.fontString;
fontString:SetText(label or "");
calcFontString:SetText(label or "");
local width = this.checkFrame:GetWidth() + calcFontString:GetStringWidth() + 2;
this:SetWidth(math.ceil(width));
end
 
 
-- ****************************************************************************
-- Sets the tooltip for the checkbox.
-- ****************************************************************************
local function Checkbox_SetTooltip(this, tooltip)
this.checkFrame.tooltip = tooltip;
end
 
 
-- ****************************************************************************
-- Configures the checkbox.
-- ****************************************************************************
local function Checkbox_Configure(this, size, label, tooltip)
-- Don't do anything if required parameters are invalid.
if (not size) then return; end
 
-- Setup the container frame.
this:SetHeight(size);
 
-- Setup the checkbox dimensions.
local check = this.checkFrame;
check:SetWidth(size);
check:SetHeight(size);
 
-- Setup the label and tooltip.
Checkbox_SetLabel(this, label);
Checkbox_SetTooltip(this, tooltip);
 
this.configured = true;
end
 
 
-- ****************************************************************************
-- Sets the function to be called when the checkbox is clicked.
-- It is passed the checkbox and whether or not it's checked.
-- ****************************************************************************
local function Checkbox_SetClickHandler(this, handler)
this.clickHandler = handler;
end
 
 
-- ****************************************************************************
-- Returns whether or not the checkbox is checked.
-- ****************************************************************************
local function Checkbox_GetChecked(this)
return this.checkFrame:GetChecked() and true or false;
end
 
 
-- ****************************************************************************
-- Sets the checked state.
-- ****************************************************************************
local function Checkbox_SetChecked(this, isChecked)
this.checkFrame:SetChecked(isChecked);
end
 
 
-- ****************************************************************************
-- Disables the checkbox.
-- ****************************************************************************
local function Checkbox_Disable(this)
this.checkFrame:Disable();
this.fontString:SetTextColor(0.5, 0.5, 0.5);
end
 
 
-- ****************************************************************************
-- Enables the checkbox.
-- ****************************************************************************
local function Checkbox_Enable(this)
this.checkFrame:Enable();
this.fontString:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
end
 
 
-- ****************************************************************************
-- Creates and returns a checkbox object ready to be configured.
-- ****************************************************************************
local function CreateCheckbox(parent)
-- XXX Hack to work around apparent WoW API bug not returning correct string width.
if (not calcFontString) then
calcFontString = UIParent:CreateFontString(nil, "ARTWORK", "GameFontNormalSmall");
end
 
-- Create container frame.
local checkbox = CreateFrame("Frame", nil, parent);
 
-- Create check button.
local checkbutton = CreateFrame("CheckButton", nil, checkbox);
checkbutton:SetPoint("TOPLEFT");
checkbutton:SetNormalTexture("Interface\\Buttons\\UI-CheckBox-Up");
checkbutton:SetPushedTexture("Interface\\Buttons\\UI-CheckBox-Down");
checkbutton:SetHighlightTexture("Interface\\Buttons\\UI-CheckBox-Highlight");
checkbutton:SetDisabledCheckedTexture("Interface\\Buttons\\UI-CheckBox-Check-Disabled");
checkbutton:SetCheckedTexture("Interface\\Buttons\\UI-CheckBox-Check");
checkbutton:SetScript("OnClick", Checkbox_OnClick);
checkbutton:SetScript("OnEnter", Checkbox_OnEnter);
checkbutton:SetScript("OnLeave", Checkbox_OnLeave);
 
-- Label.
local fontString = checkbox:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall");
fontString:SetPoint("LEFT", checkbutton, "RIGHT", 2, 0)
fontString:SetPoint("RIGHT", checkbox, "RIGHT", 0, 0);
fontString:SetJustifyH("LEFT");
 
 
-- Extension functions.
checkbox.Configure = Checkbox_Configure;
checkbox.SetLabel = Checkbox_SetLabel;
checkbox.SetTooltip = Checkbox_SetTooltip;
checkbox.SetClickHandler = Checkbox_SetClickHandler;
checkbox.GetChecked = Checkbox_GetChecked;
checkbox.SetChecked = Checkbox_SetChecked;
checkbox.Disable = Checkbox_Disable;
checkbox.Enable = Checkbox_Enable;
 
-- Track internal values.
checkbox.checkFrame = checkbutton;
checkbox.fontString = fontString;
return checkbox;
end
 
 
 
-------------------------------------------------------------------------------
-- Button functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Called when the button is clicked.
-- ****************************************************************************
local function Button_OnClick(this)
PlaySound("igMainMenuOptionCheckBoxOn");
if (this.clickHandler) then this:clickHandler(); end
end
 
 
-- ****************************************************************************
-- Called when the mouse enters the button.
-- ****************************************************************************
local function Button_OnEnter(this)
if (this.tooltip) then
GameTooltip:SetOwner(this, "ANCHOR_RIGHT");
GameTooltip:SetText(this.tooltip, nil, nil, nil, nil, 1);
end
end
 
 
-- ****************************************************************************
-- Called when the mouse leaves the button.
-- ****************************************************************************
local function Button_OnLeave(this)
GameTooltip:Hide();
end
 
 
-- ****************************************************************************
-- Sets the tooltip for the button.
-- ****************************************************************************
local function Button_SetTooltip(this, tooltip)
this.tooltip = tooltip;
end
 
 
-- ****************************************************************************
-- Sets the function to be called when the button is clicked.
-- ****************************************************************************
local function Button_SetClickHandler(this, handler)
this.clickHandler = handler;
end
 
 
 
-- ****************************************************************************
-- Creates and returns a generic button object. Only used internally.
-- ****************************************************************************
local function CreateButton(parent)
-- Create button frame.
local button = CreateFrame("Button", nil, parent);
button:SetScript("OnClick", Button_OnClick);
button:SetScript("OnEnter", Button_OnEnter);
button:SetScript("OnLeave", Button_OnLeave);
 
-- Extension functions.
button.SetClickHandler = Button_SetClickHandler;
button.SetTooltip = Button_SetTooltip;
 
return button;
end
 
 
-------------------------------------------------------------------------------
-- OptionButton functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Set the label for the option button.
-- ****************************************************************************
local function OptionButton_SetLabel(this, label)
this:SetText(label or "");
this:SetWidth(this:GetFontString():GetStringWidth() + 50);
end
 
 
-- ****************************************************************************
-- Configures the option button.
-- ****************************************************************************
local function OptionButton_Configure(this, height, label, tooltip)
this:SetHeight(height);
OptionButton_SetLabel(this, label);
Button_SetTooltip(this, tooltip);
end
 
 
-- ****************************************************************************
-- Creates and returns a push button object ready to be configured.
-- ****************************************************************************
local function CreateOptionButton(parent)
-- Create generic button.
local button = CreateButton(parent);
local fontString = button:CreateFontString(nil, "OVERLAY");
fontString:SetPoint("CENTER");
button:SetFontString(fontString);
button:SetTextFontObject(GameFontNormalSmall);
button:SetHighlightFontObject(GameFontHighlightSmall);
button:SetDisabledFontObject(GameFontDisableSmall);
button:SetNormalTexture("Interface\\Buttons\\UI-Panel-Button-Up");
button:SetPushedTexture("Interface\\Buttons\\UI-Panel-Button-Down");
button:SetDisabledTexture("Interface\\Buttons\\UI-Panel-Button-Disabled");
button:SetHighlightTexture("Interface\\Buttons\\UI-Panel-Button-Highlight");
button:GetNormalTexture():SetTexCoord(0, 0.625, 0, 0.6875);
button:GetPushedTexture():SetTexCoord(0, 0.625, 0, 0.6875);
button:GetDisabledTexture():SetTexCoord(0, 0.625, 0, 0.6875);
button:GetHighlightTexture():SetTexCoord(0, 0.625, 0, 0.6875);
 
 
-- Extension functions.
button.SetLabel = OptionButton_SetLabel;
button.Configure = OptionButton_Configure;
 
return button;
end
 
 
-------------------------------------------------------------------------------
-- IconButton functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Creates and returns an icon button object ready to be configured.
-- ****************************************************************************
local function CreateIconButton(parent, buttonType)
-- Create generic button.
local button = CreateButton(parent);
button:SetWidth(24);
button:SetHeight(24);
button:SetNormalTexture("Interface\\Addons\\MSBTOptions\\Artwork\\" .. buttonType .. "Icon");
button:SetDisabledTexture("Interface\\Addons\\MSBTOptions\\Artwork\\" .. buttonType .. "IconDisable");
button:SetHighlightTexture("Interface\\Addons\\MSBTOptions\\Artwork\\" .. buttonType .. "IconHighlight");
 
return button;
end
 
 
-------------------------------------------------------------------------------
-- Slider functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Called when the value of the slider changes.
-- ****************************************************************************
local function Slider_OnValueChanged(this, value)
local slider = this:GetParent();
if (slider.labelText ~= "") then
slider.labelFontString:SetText(slider.labelText .. ": " .. value);
else
slider.labelFontString:SetText(value);
end
if (slider.valueChangedHandler) then slider:valueChangedHandler(value); end
end
 
 
-- ****************************************************************************
-- Called when the mouse enters the slider.
-- ****************************************************************************
local function Slider_OnEnter(this)
if (this.tooltip) then
GameTooltip:SetOwner(this, this.tooltipAnchor or "ANCHOR_RIGHT");
GameTooltip:SetText(this.tooltip, nil, nil, nil, nil, 1);
end
end
 
 
-- ****************************************************************************
-- Called when the mouse leaves the slider.
-- ****************************************************************************
local function Slider_OnLeave(this)
GameTooltip:Hide();
end
 
 
-- ****************************************************************************
-- Sets the label for the slider.
-- ****************************************************************************
local function Slider_SetLabel(this, label)
this.labelText = label or "";
if (this.labelText ~= "") then
this.labelFontString:SetText(this.labelText .. ": " .. this:GetValue());
else
this.labelFontString:SetText(this:GetValue());
end
end
 
 
-- ****************************************************************************
-- Sets the tooltip for the slider.
-- ****************************************************************************
local function Slider_SetTooltip(this, tooltip)
this.sliderFrame.tooltip = tooltip;
end
 
 
-- ****************************************************************************
-- Configures the slider.
-- ****************************************************************************
local function Slider_Configure(this, width, label, tooltip)
this:SetWidth(width);
Slider_SetLabel(this, label);
Slider_SetTooltip(this, tooltip);
end
 
 
-- ****************************************************************************
-- Sets the function to be called when the value of the slider is changed.
-- It is passed the slider and the new value.
-- ****************************************************************************
local function Slider_SetValueChangedHandler(this, handler)
this.valueChangedHandler = handler;
end
 
 
-- ****************************************************************************
-- Sets the minimum and maximum values for the slider.
-- ****************************************************************************
local function Slider_SetMinMaxValues(this, minValue, maxValue)
this.sliderFrame:SetMinMaxValues(minValue, maxValue);
end
 
 
-- ****************************************************************************
-- Sets how far the slider moves with each "tick."
-- ****************************************************************************
local function Slider_SetValueStep(this, value)
this.sliderFrame:SetValueStep(value);
end
 
 
-- ****************************************************************************
-- Sets the current value of the slider.
-- ****************************************************************************
local function Slider_GetValue(this)
return this.sliderFrame:GetValue();
end
 
 
-- ****************************************************************************
-- Sets the current value of the slider.
-- ****************************************************************************
local function Slider_SetValue(this, value)
this.sliderFrame:SetValue(value);
end
 
 
-- ****************************************************************************
-- Disables the slider.
-- ****************************************************************************
local function Slider_Disable(this)
this.sliderFrame:EnableMouse(false);
this.labelFontString:SetTextColor(0.5, 0.5, 0.5);
end
 
 
-- ****************************************************************************
-- Enables the slider.
-- ****************************************************************************
local function Slider_Enable(this)
this.sliderFrame:EnableMouse(true);
this.labelFontString:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
end
 
 
-- ****************************************************************************
-- Creates and returns a slider object ready to be configured.
-- ****************************************************************************
local function CreateSlider(parent)
-- Create the backdrop table if it hasn't already been so it can be reused.
if (not sliderBackdrop) then
sliderBackdrop = {
bgFile = "Interface\\Buttons\\UI-SliderBar-Background",
edgeFile = "Interface\\Buttons\\UI-SliderBar-Border",
tile = true, tileSize = 8, edgeSize = 8,
insets = {left=3, right=3, top=6, bottom=6},
}
end
 
-- Create container frame.
local slider = CreateFrame("Frame", nil, parent);
slider:SetHeight(30);
 
-- Create slider.
local sliderFrame = CreateFrame("Slider", nil, slider);
sliderFrame:SetOrientation("HORIZONTAL");
sliderFrame:SetThumbTexture("Interface\\Buttons\\UI-SliderBar-Button-Horizontal");
sliderFrame:SetPoint("LEFT");
sliderFrame:SetPoint("RIGHT");
sliderFrame:SetHeight(16);
sliderFrame:SetBackdrop(sliderBackdrop);
sliderFrame:SetScript("OnValueChanged", Slider_OnValueChanged);
sliderFrame:SetScript("OnEnter", Slider_OnEnter);
sliderFrame:SetScript("OnLeave", Slider_OnLeave);
 
 
-- Label.
local label = slider:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall");
label:SetPoint("BOTTOM", sliderFrame, "TOP", 0, 0);
 
-- Extension functions.
slider.Configure = Slider_Configure;
slider.SetLabel = Slider_SetLabel;
slider.SetTooltip = Slider_SetTooltip;
slider.SetValueChangedHandler = Slider_SetValueChangedHandler;
slider.SetMinMaxValues = Slider_SetMinMaxValues;
slider.SetValueStep = Slider_SetValueStep;
slider.GetValue = Slider_GetValue;
slider.SetValue = Slider_SetValue;
slider.Enable = Slider_Enable;
slider.Disable = Slider_Disable;
 
 
-- Track internal values.
slider.sliderFrame = sliderFrame;
slider.labelFontString = label;
slider.labelText = "";
return slider;
end
 
 
-------------------------------------------------------------------------------
-- Dropdown functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Hides the dropdown listbox frame that holds the selections.
-- ****************************************************************************
local function Dropdown_HideSelections(this)
if (dropdownListboxFrame:IsShown() and dropdownListboxFrame.dropdown == this) then
dropdownListboxFrame:Hide();
end
end
 
-- ****************************************************************************
-- Called when the mouse enters the dropdown.
-- ****************************************************************************
local function Dropdown_OnEnter(this)
if (this.tooltip) then
GameTooltip:SetOwner(this, this.tooltipAnchor or "ANCHOR_RIGHT");
GameTooltip:SetText(this.tooltip, nil, nil, nil, nil, 1);
end
end
 
 
-- ****************************************************************************
-- Called when the mouse leaves the dropdown.
-- ****************************************************************************
local function Dropdown_OnLeave(this)
GameTooltip:Hide();
end
 
 
-- ****************************************************************************
-- Called when the dropdown is hidden.
-- ****************************************************************************
local function Dropdown_OnHide(this)
Dropdown_HideSelections(this);
end
 
 
-- ****************************************************************************
-- Called when the button for the dropdown is pressed.
-- ****************************************************************************
local function Dropdown_OnClick(this)
-- Close the listbox and exit if it's already open for the dropdown.
local dropdown = this:GetParent();
if (dropdownListboxFrame:IsShown() and dropdownListboxFrame.dropdown == dropdown) then
dropdownListboxFrame:Hide();
return;
end
 
-- Resize and move the dropdown listbox frame for the clicked dropdown.
local height = #dropdown.items * 20;
local listboxHeight = dropdown.listboxHeight or 140;
local listboxWidth = dropdown.listboxWidth or dropdown:GetWidth() + 20;
height = math.max(math.min(height, listboxHeight), 20);
dropdownListboxFrame:SetParent(dropdown:GetParent());
dropdownListboxFrame:SetHeight(height + 24);
dropdownListboxFrame:SetWidth(listboxWidth);
dropdownListboxFrame:ClearAllPoints();
dropdownListboxFrame:SetPoint("TOPLEFT", dropdown, "BOTTOMLEFT");
dropdownListboxFrame.dropdown = dropdown;
 
-- Setup the listbox.
local listbox = dropdownListboxFrame.listbox;
Listbox_Clear(listbox);
listbox:SetPoint("TOPLEFT", dropdownListboxFrame, "TOPLEFT", 8, -12);
listbox:SetPoint("BOTTOMRIGHT", dropdownListboxFrame, "BOTTOMRIGHT", -12, 12);
Listbox_Configure(listbox, 0, height, 20);
for itemNum in ipairs(dropdown.items) do
Listbox_AddItem(listbox, itemNum);
end
Listbox_SetSelectedItem(listbox, dropdown.selectedItem);
Listbox_SetOffset(listbox, dropdown.selectedItem - 1);
 
dropdownListboxFrame:Show();
dropdownListboxFrame:Raise();
end
 
 
-- ****************************************************************************
-- Called by listbox to create a line.
-- ****************************************************************************
local function Dropdown_CreateLine(this)
local frame = CreateFrame("Button", nil, this);
 
local fontString = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall");
fontString:SetPoint("LEFT", frame, "LEFT");
fontString:SetPoint("RIGHT", frame, "RIGHT");
 
frame.fontString = fontString;
return frame;
end
 
 
-- ****************************************************************************
-- Called by listbox to display a line.
-- ****************************************************************************
local function Dropdown_DisplayLine(this, line, key, isSelected)
line.fontString:SetText(dropdownListboxFrame.dropdown.items[key]);
local color = isSelected and HIGHLIGHT_FONT_COLOR or NORMAL_FONT_COLOR;
line.fontString:SetTextColor(color.r, color.g, color.b);
end
 
 
-- ****************************************************************************
-- Called when a line is clicked.
-- ****************************************************************************
local function Dropdown_OnClickLine(this, line, value)
local dropdown = dropdownListboxFrame.dropdown;
dropdown.selectedFontString:SetText(dropdown.items[value]);
dropdown.selectedItem = value;
dropdownListboxFrame:Hide();
 
-- Call the registered change handler for the dropdown.
if (dropdown.changeHandler) then dropdown:changeHandler(dropdown.itemIDs[value]); end
end
 
 
-- ****************************************************************************
-- Sets the label for the dropdown.
-- ****************************************************************************
local function Dropdown_SetLabel(this, label)
this.labelFontString:SetText(label or "");
end
 
 
-- ****************************************************************************
-- Sets the tooltip for the dropdown.
-- ****************************************************************************
local function Dropdown_SetTooltip(this, tooltip)
this.tooltip = tooltip;
end
 
 
-- ****************************************************************************
-- Configures the dropdown.
-- ****************************************************************************
local function Dropdown_Configure(this, width, label, tooltip)
-- Don't do anything if required parameters are invalid.
if (not width) then return; end
 
-- Set the width of the dropdown and the max height of the listbox is shown.
this:SetWidth(width);
 
Dropdown_SetLabel(this, label);
Dropdown_SetTooltip(this, tooltip);
end
 
 
-- ****************************************************************************
-- Sets the max height the listbox frame can be for the dropdown.
-- ****************************************************************************
local function Dropdown_SetListboxHeight(this, height)
this.listboxHeight = height;
end
 
-- ****************************************************************************
-- Sets the width of the listbox frame for the dropdown.
-- ****************************************************************************
local function Dropdown_SetListboxWidth(this, width)
this.listboxWidth = width;
end
 
 
-- ****************************************************************************
-- Sets the function to be called when one of the dropdown's options is
-- selected. It is passed the ID for the selected item.
-- ****************************************************************************
local function Dropdown_SetChangeHandler(this, handler)
this.changeHandler = handler;
end
 
 
-- ****************************************************************************
-- Adds the passed text and id to the dropdown.
-- ****************************************************************************
local function Dropdown_AddItem(this, text, id)
this.items[#this.items+1] = text;
this.itemIDs[#this.items] = id;
end
 
 
-- ****************************************************************************
-- Remove the passed item id from the dropdown.
-- ****************************************************************************
local function Dropdown_RemoveItem(this, id)
for itemNum, itemID in ipairs(this.itemIDs) do
if (itemID == id) then
-- Hide dropdown if it is shown.
Dropdown_HideSelections(this);
 
-- Clear the selected item if it's the item being removed.
if (itemNum == this.selectedItem) then
this.selectedItem = 0;
this.selectedFontString:SetText("");
end
 
table.remove(this.items, itemNum);
table.remove(this.itemIDs, itemNum);
return;
end
end
end
 
 
-- ****************************************************************************
-- Clears the dropdown.
-- ****************************************************************************
local function Dropdown_Clear(this)
local items = this.items;
for k, v in ipairs(items) do
items[k] = nil;
end
 
local itemIDs = this.itemIDs;
for k, v in ipairs(itemIDs) do
itemIDs[k] = nil;
end
 
this.selectedFontString:SetText(nil);
end
 
 
-- ****************************************************************************
-- Gets the selected text from the dropdown.
-- ****************************************************************************
local function Dropdown_GetSelectedText(this)
return this.selectedFontString:GetText();
end
 
 
-- ****************************************************************************
-- Gets the selected id from the dropdown.
-- ****************************************************************************
local function Dropdown_GetSelectedID(this)
if (this.selectedItem) then return this.itemIDs[this.selectedItem]; end
end
 
 
-- ****************************************************************************
-- Sets the selected item for the listbox.
-- ****************************************************************************
local function Dropdown_SetSelectedID(this, id)
for itemNum, itemID in ipairs(this.itemIDs) do
if (itemID == id) then
this.selectedFontString:SetText(this.items[itemNum]);
this.selectedItem = itemNum;
return;
end
end
end
 
 
-- ****************************************************************************
-- Sorts the contents of the dropdown.
-- ****************************************************************************
local function Dropdown_Sort(this)
local selectedID = Dropdown_GetSelectedID(this);
 
-- Sort the dropdown items and associated IDs using an insertion sort.
local items = this.items;
local itemIDs = this.itemIDs;
local tempItem, tempID, j;
for i = 2, #items do
tempItem = items[i];
tempID = itemIDs[i];
j = i - 1;
while (j > 0 and items[j] > tempItem) do
items[j + 1] = items[j];
itemIDs[j + 1] = itemIDs[j];
j = j - 1;
end
items[j + 1] = tempItem;
itemIDs[j + 1] = tempID;
end
 
Dropdown_SetSelectedID(this, selectedID);
end
 
 
-- ****************************************************************************
-- Disables the dropdown.
-- ****************************************************************************
local function Dropdown_Disable(this)
Dropdown_HideSelections(this);
this.buttonFrame:Disable();
this:EnableMouse(false);
this.labelFontString:SetTextColor(0.5, 0.5, 0.5);
this.selectedFontString:SetTextColor(0.5, 0.5, 0.5);
end
 
 
-- ****************************************************************************
-- Enables the dropdown.
-- ****************************************************************************
local function Dropdown_Enable(this)
this:EnableMouse(true);
this.buttonFrame:Enable();
this.labelFontString:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
this.selectedFontString:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
end
 
 
-- ****************************************************************************
-- Creates the listbox frame that dropdowns use.
-- ****************************************************************************
local function Dropdown_CreateListboxFrame()
dropdownListboxFrame = CreateFrame("Frame", nil, UIParent);
dropdownListboxFrame:EnableMouse(true);
dropdownListboxFrame:SetToplevel(true);
dropdownListboxFrame:SetFrameStrata("FULLSCREEN_DIALOG");
dropdownListboxFrame:SetBackdrop{
bgFile = "Interface\\Addons\\MSBTOptions\\Artwork\\PlainBackdrop",
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
insets = {left = 6, right = 6, top = 6, bottom = 6},
};
dropdownListboxFrame:Hide();
 
local listbox = CreateListbox(dropdownListboxFrame);
listbox:SetToplevel(true);
listbox:SetCreateLineHandler(Dropdown_CreateLine);
listbox:SetDisplayHandler(Dropdown_DisplayLine);
listbox:SetClickHandler(Dropdown_OnClickLine);
 
dropdownListboxFrame.listbox = listbox;
end
 
 
-- ****************************************************************************
-- Creates and returns a dropdown object ready to be configured.
-- ****************************************************************************
local function CreateDropdown(parent)
-- Create dropdown listbox if it hasn't already been.
if (not dropdownListboxFrame) then Dropdown_CreateListboxFrame(); end
 
 
-- Create container frame.
local dropdown = CreateFrame("Frame", nil, parent);
dropdown:SetHeight(38);
dropdown:EnableMouse(true);
dropdown:SetScript("OnEnter", Dropdown_OnEnter);
dropdown:SetScript("OnLeave", Dropdown_OnLeave);
dropdown:SetScript("OnHide", Dropdown_OnHide);
 
 
-- Left border.
local left = dropdown:CreateTexture(nil, "BACKGROUND");
left:SetTexture("Interface\\Glues\\CharacterCreate\\CharacterCreate-LabelFrame");
left:SetWidth(9);
left:SetHeight(25);
left:SetPoint("BOTTOMLEFT");
left:SetTexCoord(0.125, 0.1953125, 0.28125, 0.671875);
 
-- Right border.
local right = dropdown:CreateTexture(nil, "BACKGROUND");
right:SetTexture("Interface\\Glues\\CharacterCreate\\CharacterCreate-LabelFrame");
right:SetWidth(9);
right:SetHeight(25);
right:SetPoint("BOTTOMRIGHT");
right:SetTexCoord(0.7890625, 0.859375, 0.28125, 0.671875);
 
-- Middle border.
local middle = dropdown:CreateTexture(nil, "BACKGROUND");
middle:SetTexture("Interface\\Glues\\CharacterCreate\\CharacterCreate-LabelFrame");
middle:SetWidth(76);
middle:SetHeight(25);
middle:SetPoint("LEFT", left, "RIGHT", 0, 0);
middle:SetPoint("RIGHT", right, "LEFT", 0, 0);
middle:SetTexCoord(0.1953125, 0.7890625, 0.28125, 0.671875);
 
-- Label.
local label = dropdown:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall");
label:SetPoint("BOTTOMLEFT", left, "TOPLEFT", 2, 2);
 
 
-- Dropdown button.
local button = CreateFrame("Button", nil, dropdown);
button:SetWidth(24);
button:SetHeight(24);
button:SetPoint("BOTTOMRIGHT");
button:SetNormalTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Up");
button:SetPushedTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Down");
button:SetDisabledTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Disabled");
button:SetHighlightTexture("Interface\\Buttons\\UI-Common-MouseHilight");
button:GetHighlightTexture():SetBlendMode("ADD");
button:SetScript("OnClick", Dropdown_OnClick);
 
 
-- Selected text.
local selected = dropdown:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall");
selected:SetPoint("LEFT", left, "RIGHT");
selected:SetPoint("RIGHT", button, "LEFT");
selected:SetJustifyH("RIGHT");
 
 
-- Extension functions.
dropdown.Configure = Dropdown_Configure;
dropdown.SetListboxHeight = Dropdown_SetListboxHeight;
dropdown.SetListboxWidth = Dropdown_SetListboxWidth;
dropdown.SetLabel = Dropdown_SetLabel;
dropdown.SetTooltip = Dropdown_SetTooltip;
dropdown.SetChangeHandler = Dropdown_SetChangeHandler;
dropdown.HideSelections = Dropdown_HideSelections;
dropdown.AddItem = Dropdown_AddItem;
dropdown.RemoveItem = Dropdown_RemoveItem;
dropdown.Clear = Dropdown_Clear;
dropdown.GetSelectedText = Dropdown_GetSelectedText;
dropdown.GetSelectedID = Dropdown_GetSelectedID;
dropdown.SetSelectedID = Dropdown_SetSelectedID;
dropdown.Sort = Dropdown_Sort;
dropdown.Disable = Dropdown_Disable;
dropdown.Enable = Dropdown_Enable;
 
-- Track internal values.
dropdown.selectedFontString = selected;
dropdown.buttonFrame = button;
dropdown.labelFontString = label;
dropdown.items = {};
dropdown.itemIDs = {};
dropdown.selectedItem = 0;
return dropdown;
end
 
 
-------------------------------------------------------------------------------
-- Editbox functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Called when the editbox has focus and escape is pressed.
-- ****************************************************************************
local function Editbox_OnEscape(this)
this:ClearFocus();
local editbox = this:GetParent();
if (editbox.escapeHandler) then editbox:escapeHandler(); end
end
 
 
-- ****************************************************************************
-- Called when the editbox loses focus.
-- ****************************************************************************
local function Editbox_OnFocusLost(this)
this:HighlightText(0, 0);
end
 
 
-- ****************************************************************************
-- Called when the editbox gains focus.
-- ****************************************************************************
local function Editbox_OnFocusGained(this)
this:HighlightText();
end
 
 
-- ****************************************************************************
-- Called when the text in the editbox changes.
-- ****************************************************************************
local function Editbox_OnTextChanged(this)
local editbox = this:GetParent();
if (editbox.textChangedHandler) then editbox:textChangedHandler(); end
end
 
 
-- ****************************************************************************
-- Called when the mouse enters the editbox.
-- ****************************************************************************
local function Editbox_OnEnter(this)
if (this.tooltip) then
GameTooltip:SetOwner(this, this.tooltipAnchor or "ANCHOR_RIGHT");
GameTooltip:SetText(this.tooltip, nil, nil, nil, nil, 1);
end
end
 
 
-- ****************************************************************************
-- Called when the mouse leaves the editbox.
-- ****************************************************************************
local function Editbox_OnLeave(this)
GameTooltip:Hide();
end
 
 
-- ****************************************************************************
-- Sets the label for the editbox.
-- ****************************************************************************
local function Editbox_SetLabel(this, label)
this.labelFontString:SetText(label);
end
 
 
-- ****************************************************************************
-- Sets the tooltip for the editbox.
-- ****************************************************************************
local function Editbox_SetTooltip(this, tooltip)
this.editboxFrame.tooltip = tooltip;
end
 
 
-- ****************************************************************************
-- Configures the editbox.
-- ****************************************************************************
local function Editbox_Configure(this, width, label, tooltip)
-- Don't do anything if required parameters are invalid.
if (not width) then return; end
 
this:SetWidth(width);
Editbox_SetLabel(this, label);
Editbox_SetTooltip(this, tooltip);
end
 
 
-- ****************************************************************************
-- Sets the handler to be called when the enter button is pressed.
-- ****************************************************************************
local function Editbox_SetEnterHandler(this, handler)
this.editboxFrame:SetScript("OnEnterPressed", handler);
end
 
 
-- ****************************************************************************
-- Sets the handler to be called when the escape button is pressed.
-- ****************************************************************************
local function Editbox_SetEscapeHandler(this, handler)
this.escapeHandler = handler;
end
 
 
-- ****************************************************************************
-- Sets the handler to be called when the text in the editbox changes.
-- ****************************************************************************
local function Editbox_SetTextChangedHandler(this, handler)
this.textChangedHandler = handler;
end
 
 
-- ****************************************************************************
-- Sets the focus to the editbox.
-- ****************************************************************************
local function Editbox_SetFocus(this)
this.editboxFrame:SetFocus();
end
 
 
-- ****************************************************************************
-- Gets the text entered in the editbox.
-- ****************************************************************************
local function Editbox_GetText(this)
return this.editboxFrame:GetText();
end
 
 
-- ****************************************************************************
-- Sets the text entered in the editbox.
-- ****************************************************************************
local function Editbox_SetText(this, text)
return this.editboxFrame:SetText(text or "");
end
 
 
-- ****************************************************************************
-- Disables the editbox.
-- ****************************************************************************
local function Editbox_Disable(this)
this.editboxFrame:EnableMouse(false);
this.labelFontString:SetTextColor(0.5, 0.5, 0.5);
end
 
-- ****************************************************************************
-- Enables the editbox.
-- ****************************************************************************
local function Editbox_Enable(this)
this.editboxFrame:EnableMouse(true);
this.labelFontString:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
end
 
 
-- ****************************************************************************
-- Creates and returns an editbox object ready to be configured.
-- ****************************************************************************
local function CreateEditbox(parent)
-- Create container frame.
local editbox = CreateFrame("Frame", nil, parent);
editbox:SetHeight(32);
 
-- Create editbox frame.
local editboxFrame = CreateFrame("Editbox", nil, editbox);
editboxFrame:SetHeight(20);
editboxFrame:SetPoint("BOTTOMLEFT", editbox, "BOTTOMLEFT", 5, 0);
editboxFrame:SetPoint("BOTTOMRIGHT");
editboxFrame:SetAutoFocus(false);
editboxFrame:SetFontObject(ChatFontNormal);
editboxFrame:SetScript("OnEscapePressed", Editbox_OnEscape);
editboxFrame:SetScript("OnEditFocusLost", Editbox_OnFocusLost);
editboxFrame:SetScript("OnEditFocusGained", Editbox_OnFocusGained);
editboxFrame:SetScript("OnTextChanged", Editbox_OnTextChanged);
editboxFrame:SetScript("OnEnter", Editbox_OnEnter);
editboxFrame:SetScript("OnLeave", Editbox_OnLeave);
 
-- Left border.
local left = editboxFrame:CreateTexture(nil, "BACKGROUND");
left:SetTexture("Interface\\Common\\Common-Input-Border");
left:SetWidth(8);
left:SetHeight(20);
left:SetPoint("LEFT", editboxFrame, "LEFT", -5, 0);
left:SetTexCoord(0, 0.0625, 0, 0.625);
 
-- Right border.
local right = editboxFrame:CreateTexture(nil, "BACKGROUND");
right:SetTexture("Interface\\Common\\Common-Input-Border");
right:SetWidth(8);
right:SetHeight(20);
right:SetPoint("RIGHT");
right:SetTexCoord(0.9375, 1, 0, 0.625);
 
-- Middle border.
local middle = editboxFrame:CreateTexture(nil, "BACKGROUND");
middle:SetTexture("Interface\\Common\\Common-Input-Border");
middle:SetWidth(10);
middle:SetHeight(20);
middle:SetPoint("LEFT", left, "RIGHT", 0, 0);
middle:SetPoint("RIGHT", right, "LEFT", 0, 0);
middle:SetTexCoord(0.0625, 0.9375, 0, 0.625);
 
 
-- Label.
local label = editbox:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall");
label:SetPoint("TOPLEFT");
label:SetPoint("TOPRIGHT");
label:SetJustifyH("LEFT");
 
 
-- Extension functions.
editbox.Configure = Editbox_Configure;
editbox.SetLabel = Editbox_SetLabel;
editbox.SetTooltip = Editbox_SetTooltip;
editbox.SetEnterHandler = Editbox_SetEnterHandler;
editbox.SetEscapeHandler = Editbox_SetEscapeHandler;
editbox.SetTextChangedHandler = Editbox_SetTextChangedHandler;
editbox.SetFocus = Editbox_SetFocus;
editbox.GetText = Editbox_GetText;
editbox.SetText = Editbox_SetText;
editbox.Disable = Editbox_Disable;
editbox.Enable = Editbox_Enable;
 
 
-- Track internal values.
editbox.editboxFrame = editboxFrame;
editbox.labelFontString = label;
return editbox;
end
 
 
-------------------------------------------------------------------------------
-- Colorswatch functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Sets the color of the colorswatch.
-- ****************************************************************************
local function Colorswatch_SetColor(this, r, g, b)
this.r = r;
this.g = g;
this.b = b;
this:GetNormalTexture():SetVertexColor(r, g, b);
end
 
 
-- ****************************************************************************
-- Called when the color picker values change.
-- ****************************************************************************
local function Colorswatch_ColorPickerOnChange(this)
local colorswatch = ColorPickerFrame.associatedColorSwatch;
if (not colorswatch) then return; end
 
Colorswatch_SetColor(colorswatch, ColorPickerFrame:GetColorRGB());
if (colorswatch.colorChangedHandler) then colorswatch:colorChangedHandler(); end
end
 
 
-- ****************************************************************************
-- Called when the color picker values change.
-- ****************************************************************************
local function Colorswatch_ColorPickerOnCancel(previousValues)
local colorswatch = ColorPickerFrame.associatedColorSwatch;
if (not colorswatch) then return; end
 
Colorswatch_SetColor(colorswatch, previousValues.r, previousValues.g, previousValues.b);
if (colorswatch.colorChangedHandler) then colorswatch:colorChangedHandler(); end
end
 
 
-- ****************************************************************************
-- Called when the colorswatch is clicked.
-- ****************************************************************************
local function Colorswatch_OnClick(this)
local tempR = this.r or 1;
local tempG = this.g or 1;
local tempB = this.b or 1;
 
ColorPickerFrame.associatedColorSwatch = this;
ColorPickerFrame.hasOpacity = false;
ColorPickerFrame.opacity = 1;
ColorPickerFrame.previousValues = {r = tempR, g = tempG, b = tempB};
ColorPickerFrame.func = Colorswatch_ColorPickerOnChange;
ColorPickerFrame.cancelFunc = Colorswatch_ColorPickerOnCancel;
ColorPickerFrame:SetColorRGB(tempR, tempG, tempB);
ColorPickerFrame:ClearAllPoints();
ColorPickerFrame:SetPoint("CENTER", this, "CENTER");
ColorPickerFrame:Show();
end
 
 
-- ****************************************************************************
-- Called when the mouse enters the colorswatch.
-- ****************************************************************************
local function Colorswatch_OnEnter(this)
if (this.tooltip) then
GameTooltip:SetOwner(this, this.tooltipAnchor or "ANCHOR_RIGHT");
GameTooltip:SetText(this.tooltip, nil, nil, nil, nil, 1);
end
 
this.borderTexture:SetVertexColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
end
 
 
-- ****************************************************************************
-- Called when the mouse leaves the colorswatch.
-- ****************************************************************************
local function Colorswatch_OnLeave(this)
GameTooltip:Hide();
this.borderTexture:SetVertexColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
end
 
 
-- ****************************************************************************
-- Sets the handler to be called when the color changes.
-- ****************************************************************************
local function Colorswatch_SetColorChangedHandler(this, handler)
this.colorChangedHandler = handler;
end
 
 
-- ****************************************************************************
-- Sets the tooltip for the colorswatch.
-- ****************************************************************************
local function Colorswatch_SetTooltip(this, tooltip)
this.tooltip = tooltip;
end
 
 
-- ****************************************************************************
-- Disables the colorswatch.
-- ****************************************************************************
local function Colorswatch_Disable(this)
this:GetNormalTexture():SetVertexColor(0.5, 0.5, 0.5);
this:oldDisableHandler();
end
 
 
-- ****************************************************************************
-- Enables the colorswatch.
-- ****************************************************************************
local function Colorswatch_Enable(this)
this:oldEnableHandler();
this:GetNormalTexture():SetVertexColor(this.r, this.g, this.b);
end
 
 
-- ****************************************************************************
-- Creates and returns a colorswatch object ready to be configured.
-- ****************************************************************************
local function CreateColorswatch(parent)
-- Create button frame.
local colorswatch = CreateFrame("Button", nil, parent);
colorswatch:SetWidth(16);
colorswatch:SetHeight(16);
colorswatch:SetNormalTexture("Interface\\ChatFrame\\ChatFrameColorSwatch");
colorswatch:SetScript("OnClick", Colorswatch_OnClick);
colorswatch:SetScript("OnEnter", Colorswatch_OnEnter);
colorswatch:SetScript("OnLeave", Colorswatch_OnLeave);
 
 
-- Border texture.
local texture = colorswatch:CreateTexture(nil, "BACKGROUND");
texture:SetTexture("Interface\\ChatFrame\\ChatFrameBackground");
texture:SetWidth(14);
texture:SetHeight(14);
texture:SetPoint("CENTER");
texture:SetVertexColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
 
-- Save old disable/enable handlers.
colorswatch.oldDisableHandler = colorswatch.Disable;
colorswatch.oldEnableHandler = colorswatch.Enable;
 
-- Extension functions.
colorswatch.SetColorChangedHandler = Colorswatch_SetColorChangedHandler;
colorswatch.SetTooltip = Colorswatch_SetTooltip;
colorswatch.SetColor = Colorswatch_SetColor;
colorswatch.Disable = Colorswatch_Disable;
colorswatch.Enable = Colorswatch_Enable;
 
-- Track internal values.
colorswatch.borderTexture = texture;
return colorswatch;
end
 
 
 
 
-------------------------------------------------------------------------------
-- Module interface.
-------------------------------------------------------------------------------
 
-- Protected Functions.
module.CreateListbox = CreateListbox;
module.CreateCheckbox = CreateCheckbox;
module.CreateOptionButton = CreateOptionButton;
module.CreateIconButton = CreateIconButton;
module.CreateSlider = CreateSlider;
module.CreateDropdown = CreateDropdown;
module.CreateEditbox = CreateEditbox;
module.CreateColorswatch = CreateColorswatch;
\ No newline at end of file
MSBT5_13/MSBTOptions/MSBTOptionsMain.lua New file
0,0 → 1,325
-------------------------------------------------------------------------------
-- Title: MSBT Options Main
-- Author: Mik
-------------------------------------------------------------------------------
 
-- Create module and set its name.
local module = {}
local moduleName = "Main";
MSBTOptions[moduleName] = module;
 
 
-------------------------------------------------------------------------------
-- Constants.
-------------------------------------------------------------------------------
 
local WINDOW_TITLE = "Mik's Scrolling Battle Text " .. MikSBT.VERSION_STRING;
 
 
-------------------------------------------------------------------------------
-- Private variables.
-------------------------------------------------------------------------------
 
-- The main options frame.
local mainFrame;
 
-- Holds all registered popup frames.
local popupFrames = {};
 
-- Tab info.
local tabData = {};
local tabListbox;
 
 
-------------------------------------------------------------------------------
-- Imports.
-------------------------------------------------------------------------------
 
-- Local references to certain modules for faster access.
local MSBTLocale = MikSBT.Locale;
local MSBTControls = MSBTOptions.Controls;
 
 
-------------------------------------------------------------------------------
-- Tab functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Initializes the frame that is shown when the tab is clicked.
-- ****************************************************************************
local function InitTab(tabInfo)
local frame = tabInfo.frame;
frame:SetParent(mainFrame);
frame:SetPoint("TOPLEFT", mainFrame, "TOPLEFT", 190, -78);
frame:SetWidth(400);
frame:SetHeight(350);
end
 
 
-- ****************************************************************************
-- Adds a new tab to the main options frame that will show the passed frame
-- when selected.
-- ****************************************************************************
local function AddTab(frame, text, tooltip)
local tabInfo = {};
tabInfo.text = text;
tabInfo.frame = frame;
tabInfo.tooltip = tooltip;
 
tabData[#tabData+1] = tabInfo;
 
if (tabListbox) then
InitTab(tabInfo);
tabListbox:AddItem(#tabData);
end
end
 
 
-- ****************************************************************************
-- Called by listbox to create a line for the tabs on the left.
-- ****************************************************************************
local function CreateTabLine(this)
local frame = CreateFrame("Button", nil, this);
 
local fontString = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall");
fontString:SetPoint("LEFT", frame, "LEFT");
fontString:SetPoint("RIGHT", frame, "RIGHT");
 
frame.fontString = fontString;
frame.tooltipAnchor = "ANCHOR_LEFT";
return frame;
end
 
 
-- ****************************************************************************
-- Called by listbox to display a line for the tabs on the left.
-- ****************************************************************************
local function DisplayTabLine(this, line, key, isSelected)
line.fontString:SetText(tabData[key].text);
line.tooltip = tabData[key].tooltip;
local color = isSelected and HIGHLIGHT_FONT_COLOR or NORMAL_FONT_COLOR;
line.fontString:SetTextColor(color.r, color.g, color.b);
end
 
 
-- ****************************************************************************
-- Called when a tab line is clicked.
-- ****************************************************************************
local function OnClickTabLine(this, line, value)
-- Hide all the tab frames.
for _, info in ipairs(tabData) do
info.frame:Hide();
end
 
-- Hide the registered popup frames.
for frame in pairs(popupFrames) do
frame:Hide();
end
 
-- Show the tab's associated frame.
local frame = tabData[value].frame;
if (frame) then frame:Show(); end
 
-- Force a refresh to the listbox to update the highlight font color.
tabListbox:Refresh();
end
 
 
-------------------------------------------------------------------------------
-- Main options frame functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Called when the main options frame is hidden.
-- ****************************************************************************
local function OnHideMainFrame(this)
-- Hide the registered popup frames.
for frame in pairs(popupFrames) do
frame:Hide();
end
end
 
 
-- ****************************************************************************
-- Creates the main options frame.
-- ****************************************************************************
local function CreateMainFrame()
-- Main frame.
mainFrame = CreateFrame("Frame", "MSBTMainOptionsFrame", UIParent);
mainFrame:SetMovable(true);
mainFrame:EnableMouse(true);
mainFrame:SetToplevel(true);
mainFrame:SetClampedToScreen(true);
mainFrame:SetWidth(608);
mainFrame:SetHeight(440);
mainFrame:SetPoint("CENTER");
mainFrame:SetHitRectInsets(0, 35, 0, 0);
mainFrame:SetScript("OnHide", OnHideMainFrame);
 
-- Title region.
local titleRegion = mainFrame:CreateTitleRegion();
titleRegion:SetWidth(525);
titleRegion:SetHeight(20);
titleRegion:SetPoint("TOPLEFT", mainFrame, "TOPLEFT", 50, -10);
 
-- Scroll Icon.
local texture = mainFrame:CreateTexture(nil, "BACKGROUND");
texture:SetTexture("Interface\\FriendsFrame\\FriendsFrameScrollIcon");
texture:SetWidth(64);
texture:SetHeight(64);
texture:SetPoint("TOPLEFT", mainFrame, "TOPLEFT", 8, 1);
 
-- Top left.
texture = mainFrame:CreateTexture(nil, "ARTWORK");
texture:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-General-TopLeft");
texture:SetWidth(256);
texture:SetHeight(256);
texture:SetPoint("TOPLEFT");
 
-- Top center left.
texture = mainFrame:CreateTexture(nil, "ARTWORK");
texture:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-General-TopLeft");
texture:SetWidth(128);
texture:SetHeight(256);
texture:SetPoint("TOPLEFT", mainFrame, "TOPLEFT", 256, 0);
texture:SetTexCoord(0.38, 0.88, 0, 1);
 
-- Top center right.
texture = mainFrame:CreateTexture(nil, "ARTWORK");
texture:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-General-TopLeft");
texture:SetWidth(128);
texture:SetHeight(256);
texture:SetPoint("TOPLEFT", mainFrame, "TOPLEFT", 384, 0);
texture:SetTexCoord(0.45, 0.95, 0, 1);
 
-- Top right.
texture = mainFrame:CreateTexture(nil, "ARTWORK");
texture:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-General-TopRight");
texture:SetWidth(100);
texture:SetHeight(256);
texture:SetPoint("TOPRIGHT");
texture:SetTexCoord(0, 0.78125, 0, 1);
 
-- Bottom left.
texture = mainFrame:CreateTexture(nil, "ARTWORK");
texture:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-General-BottomLeft");
texture:SetWidth(256);
texture:SetHeight(184);
texture:SetPoint("BOTTOMLEFT");
texture:SetTexCoord(0, 1, 0, 0.71875);
 
-- Bottom center left.
texture = mainFrame:CreateTexture(nil, "ARTWORK");
texture:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-General-BottomLeft");
texture:SetWidth(128);
texture:SetHeight(184);
texture:SetPoint("BOTTOMLEFT", mainFrame, "BOTTOMLEFT", 256, 0);
texture:SetTexCoord(0.5, 1, 0, 0.71875);
 
-- Bottom center right.
texture = mainFrame:CreateTexture(nil, "ARTWORK");
texture:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-General-BottomLeft");
texture:SetWidth(128);
texture:SetHeight(184);
texture:SetPoint("BOTTOMLEFT", mainFrame, "BOTTOMLEFT", 384, 0);
texture:SetTexCoord(0.5, 1, 0, 0.71875);
 
-- Bottom right.
texture = mainFrame:CreateTexture(nil, "ARTWORK");
texture:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-General-BottomRight");
texture:SetWidth(100);
texture:SetHeight(184);
texture:SetPoint("BOTTOMRIGHT");
texture:SetTexCoord(0, 0.78125, 0, 0.71875);
 
-- Top vertical.
texture = mainFrame:CreateTexture(nil, "OVERLAY");
texture:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-General-TopRight");
texture:SetWidth(8);
texture:SetHeight(184);
texture:SetPoint("TOPLEFT", mainFrame, "TOPLEFT", 180, -72);
texture:SetTexCoord(0.648437, 0.7109375, 0.28125, 1.0);
 
-- Bottom vertical.
texture = mainFrame:CreateTexture(nil, "OVERLAY");
texture:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-General-TopRight");
texture:SetWidth(8);
texture:SetHeight(174);
texture:SetPoint("TOPLEFT", mainFrame, "TOPLEFT", 180, -256);
texture:SetTexCoord(0.648437, 0.7109375, 0.3203125, 1.0);
 
-- Window title.
local fontString = mainFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal");
fontString:SetText(WINDOW_TITLE);
fontString:SetPoint("TOP", mainFrame, "TOP", 0, -18);
 
-- Close Button.
local frame = CreateFrame("Button", nil, mainFrame, "UIPanelCloseButton");
frame:SetPoint("TOPRIGHT", mainFrame, "TOPRIGHT", -3, -8);
 
 
-- Setup the tabs listbox.
tabListbox = MSBTControls.CreateListbox(mainFrame);
tabListbox:Configure(150, 350, 20);
tabListbox:SetPoint("TOPLEFT", mainFrame, "TOPLEFT", 30, -78);
tabListbox:SetCreateLineHandler(CreateTabLine);
tabListbox:SetDisplayHandler(DisplayTabLine);
tabListbox:SetClickHandler(OnClickTabLine);
 
-- Add registered tabs.
for k, tabInfo in ipairs(tabData) do
InitTab(tabInfo);
tabListbox:AddItem(k);
end
 
-- Select the first tab.
tabListbox:SetSelectedItem(1);
tabListbox:Refresh();
tabData[1].frame:Show();
 
-- Insert the frame name into the UISpecialFrames array so it closes when
-- the escape key is pressed.
table.insert(UISpecialFrames, mainFrame:GetName());
end
 
 
-- ****************************************************************************
-- Shows the main options frame after creating it (if it hasn't already been).
-- ****************************************************************************
local function ShowMainFrame()
if (not mainFrame) then CreateMainFrame(); end
if (not MSBTScrollAreasConfigFrame or not MSBTScrollAreasConfigFrame:IsShown()) then
mainFrame:Show();
end
end
 
 
-- ****************************************************************************
-- Hides the main options frame.
-- ****************************************************************************
local function HideMainFrame()
mainFrame:Hide();
end
 
 
-- ****************************************************************************
-- Registers frames that float above the main options window.
-- These frames will be hidden when a tab is selected or the main options
-- window is hidden.
-- ****************************************************************************
local function RegisterPopupFrame(frame)
if (not popupFrames[frame]) then popupFrames[frame] = true; end
end
 
 
 
 
-------------------------------------------------------------------------------
-- Module interface.
-------------------------------------------------------------------------------
 
-- Protected Functions.
module.ShowMainFrame = ShowMainFrame;
module.HideMainFrame = HideMainFrame;
module.RegisterPopupFrame = RegisterPopupFrame;
module.AddTab = AddTab;
\ No newline at end of file
MSBT5_13/MSBTOptions/MSBTOptionsPopups.lua New file
0,0 → 1,3582
-------------------------------------------------------------------------------
-- Title: MSBT Options Popups
-- Author: Mik
-------------------------------------------------------------------------------
 
-- Create module and set its name.
local module = {};
local moduleName = "Popups";
MSBTOptions[moduleName] = module;
 
 
-------------------------------------------------------------------------------
-- Private constants.
-------------------------------------------------------------------------------
 
local OUTLINE_MAP = {"", "OUTLINE", "THICKOUTLINE"};
local DEFAULT_TEXT_ALIGN_INDEX = 2;
local DEFAULT_SCROLL_HEIGHT = 260;
local DEFAULT_SCROLL_WIDTH = 40;
local DEFAULT_ANIMATION_STYLE = "Straight";
local DEFAULT_STICKY_ANIMATION_STYLE = "Pow";
 
 
-------------------------------------------------------------------------------
-- Private variables.
-------------------------------------------------------------------------------
 
local popupFrames = {};
 
-- Backdrop to reuse for the popup frames.
local popupBackdrop = {
bgFile = "Interface\\Addons\\MSBTOptions\\Artwork\\PlainBackdrop",
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
insets = {left = 6, right = 6, top = 6, bottom = 6},
};
 
-- Backdrop to reuse for the scroll area mover frame.
local moverBackdrop = {
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
};
 
-- Reusable table for return settings.
local returnSettings = {};
 
-- Reusable table to configure popup frames.
local tempConfig = {};
 
 
-------------------------------------------------------------------------------
-- Imports.
-------------------------------------------------------------------------------
 
-- Local references to certain modules for faster access.
local MSBTControls = MSBTOptions.Controls;
local MSBTLocale = MikSBT.Locale;
local MSBTProfiles = MikSBT.Profiles;
local MSBTAnimations = MikSBT.Animations;
local MSBTTriggers = MikSBT.Triggers;
 
-- Local references to certain functions for faster access.
local EraseTable = MikSBT.EraseTable;
local ConvertType = MSBTTriggers.ConvertType;
 
 
-------------------------------------------------------------------------------
-- Utility functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Returns an iterator for the passed table sorted by its keys.
-- ****************************************************************************
local function PairsByKeys(t)
local temp = {};
for k in pairs(t) do temp[#temp+1] = k; end
table.sort(temp);
 
local position = 0;
local iterator = function ()
position = position + 1
if temp[position] == nil then
return nil;
else
return temp[position], t[temp[position]]
end
end
return iterator
end
 
 
-- ****************************************************************************
-- Called when a popup is hidden.
-- ****************************************************************************
local function OnHidePopup(this)
if (this.hideHandler) then this.hideHandler(); end
end
 
 
-- ****************************************************************************
-- Creates a new generic popup.
-- ****************************************************************************
local function CreatePopup()
local frame = CreateFrame("Frame", nil, UIParent);
frame:Hide();
frame:SetMovable(true);
frame:EnableMouse(true);
frame:SetToplevel(true);
frame:SetClampedToScreen(true);
frame:SetBackdrop(popupBackdrop);
frame:SetScript("OnHide", OnHidePopup);
 
-- Title region.
local titleRegion = frame:CreateTitleRegion();
titleRegion:SetAllPoints(frame);
 
-- Register the frame with the main module.
MSBTOptions.Main.RegisterPopupFrame(frame);
return frame;
end
 
 
-- ****************************************************************************
-- Changes the passed popup frame's parent.
-- ****************************************************************************
local function ChangePopupParent(frame, parent)
-- Changing the parent can cause the frame to be hidden, so ensure the hide
-- handler isn't called.
local oldHandler = frame.hideHandler;
frame.hideHandler = nil;
frame:SetParent(parent or UIParent);
frame.hideHandler = oldHandler;
end
 
 
-- ****************************************************************************
-- Disables the controls in the passed table.
-- ****************************************************************************
local function DisableControls(controlsTable)
for _, frame in pairs(controlsTable) do
if (frame.Disable) then frame:Disable(); end
end
end
 
 
-- ****************************************************************************
-- Toggles the state of a font dropdown control when an inherit checkbox is
-- changed.
-- ****************************************************************************
local function ToggleDropdownInheritState(dropdown, isInherited, inheritedValue)
if (isInherited) then
dropdown:SetSelectedID(inheritedValue);
dropdown:Disable();
dropdown:SetAlpha(0.3);
else
dropdown:SetAlpha(1);
dropdown:Enable();
end
end
 
 
-- ****************************************************************************
-- Toggles the state of a font slider control when an inherit checkbox is
-- changed.
-- ****************************************************************************
local function ToggleSliderInheritState(slider, isInherited, inheritedValue)
if (isInherited) then
slider:SetValue(inheritedValue);
slider:Disable();
slider:SetAlpha(0.3);
else
slider:SetAlpha(1);
slider:Enable();
end
end
 
 
 
 
-------------------------------------------------------------------------------
-- Input frame functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Called when the text in the input frame editbox changes to allow validation.
-- ****************************************************************************
local function ValidateInput(this)
local frame = popupFrames.inputFrame;
 
-- Clear validation message and enable okay button.
frame.validateFontString:SetText("");
frame.okayButton:Enable();
 
if (frame.validateHandler) then
local message = frame.validateHandler(this:GetText());
 
-- Disable the save button and display the validation message if validation failed.
if (message) then
frame.validateFontString:SetText(message);
frame.okayButton:Disable();
end
end
end
 
 
-- ****************************************************************************
-- Calls the save handler with the entered input.
-- ****************************************************************************
local function SaveInput()
local frame = popupFrames.inputFrame;
if (frame.saveHandler and frame.okayButton:IsEnabled() ~= 0) then
EraseTable(returnSettings);
returnSettings.inputText = frame.inputEditbox:GetText();
returnSettings.secondInputText = frame.secondInputEditbox:GetText();
returnSettings.saveArg1 = frame.saveArg1;
frame.saveHandler(returnSettings);
frame:Hide();
end
end
 
 
-- ****************************************************************************
-- Creates the popup input frame.
-- ****************************************************************************
local function CreateInput()
local frame = CreatePopup();
frame:SetWidth(350);
frame:SetHeight(130);
 
-- Input editbox.
local editbox = MSBTControls.CreateEditbox(frame);
editbox:SetPoint("TOPLEFT", frame, "TOPLEFT", 20, -25);
editbox:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -20, -25);
editbox:SetEscapeHandler(
function (this)
frame:Hide();
end
);
editbox:SetEnterHandler(SaveInput);
editbox:SetTextChangedHandler(ValidateInput);
frame.inputEditbox = editbox;
 
-- Second input editbox.
editbox = MSBTControls.CreateEditbox(frame);
editbox:SetPoint("TOPLEFT", frame.inputEditbox, "BOTTOMLEFT", 0, -10);
editbox:SetPoint("TOPRIGHT", frame.inputEditbox, "BOTTOMRIGHT", 0, -10);
editbox:SetEscapeHandler(
function (this)
frame:Hide();
end
);
editbox:SetEnterHandler(SaveInput);
frame.secondInputEditbox = editbox;
 
 
-- Okay button.
local button = MSBTControls.CreateOptionButton(frame);
local objLocale = MSBTLocale.BUTTONS["inputOkay"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("BOTTOMRIGHT", frame, "BOTTOM", -10, 40);
button:SetClickHandler(SaveInput);
frame.okayButton = button;
 
-- Cancel button.
button = MSBTControls.CreateOptionButton(frame);
objLocale = MSBTLocale.BUTTONS["inputCancel"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("BOTTOMLEFT", frame, "BOTTOM", 10, 40);
button:SetClickHandler(
function (this)
frame:Hide();
end
);
 
-- Validation text.
local fontString = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall");
fontString:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", 30, 20);
fontString:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -30, 20);
frame.validateFontString = fontString;
 
return frame;
end
 
 
-- ****************************************************************************
-- Shows the popup input frame using the passed config.
-- ****************************************************************************
local function ShowInput(configTable)
-- Don't do anything if required parameters weren't passed.
if (not configTable or not configTable.anchorFrame or not configTable.parentFrame) then return; end
 
-- Create the frame if it hasn't already been.
if (not popupFrames.inputFrame) then popupFrames.inputFrame = CreateInput(); end
 
-- Set parent.
local frame = popupFrames.inputFrame;
ChangePopupParent(frame, configTable.parentFrame)
 
-- Populate.
local editbox = frame.inputEditbox
editbox:SetLabel(configTable.editboxLabel);
editbox:SetTooltip(configTable.editboxTooltip);
editbox:SetText("");
editbox:SetText(configTable.defaultText);
 
editbox = frame.secondInputEditbox;
if (configTable.showSecondEditbox) then
editbox:Show();
editbox:SetLabel(configTable.secondEditboxLabel);
editbox:SetTooltip(configTable.secondEditboxTooltip);
editbox:SetText(configTable.secondDefaultText);
frame:SetHeight(170);
else
editbox:SetText(nil);
editbox:Hide();
frame:SetHeight(130);
end
 
 
-- Configure the frame.
frame.showSecondEditbox = configTable.showSecondEditbox;
frame.validateHandler = configTable.validateHandler;
frame.saveHandler = configTable.saveHandler;
frame.saveArg1 = configTable.saveArg1;
frame.hideHandler = configTable.hideHandler;
frame:ClearAllPoints();
frame:SetPoint(configTable.anchorPoint or "TOPLEFT", configTable.anchorFrame, configTable.relativePoint or "BOTTOMLEFT");
frame:Show();
frame:Raise();
frame.inputEditbox:SetFocus();
end
 
 
-------------------------------------------------------------------------------
-- Acknowledge frame functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Creates the popup acknowledge frame.
-- ****************************************************************************
local function CreateAcknowledge()
local frame = CreatePopup();
frame:SetWidth(350);
frame:SetHeight(90);
 
-- Acknowledge text.
local fontString = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall");
fontString:SetPoint("TOPLEFT", frame, "TOPLEFT", 30, -20);
fontString:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -30, -20);
fontString:SetText(MSBTLocale.MSG_ACKNOWLEDGE_TEXT);
 
-- Yes button.
local button = MSBTControls.CreateOptionButton(frame);
button:Configure(20, YES, nil);
button:SetPoint("BOTTOMRIGHT", frame, "BOTTOM", -10, 15);
button:SetClickHandler(
function (this)
if (frame.acknowledgeHandler) then
frame.acknowledgeHandler(frame.saveArg1);
frame:Hide();
end
end
);
 
-- No button.
button = MSBTControls.CreateOptionButton(frame);
button:Configure(20, NO, nil);
button:SetPoint("BOTTOMLEFT", frame, "BOTTOM", 10, 15);
button:SetClickHandler(
function (this)
frame:Hide();
end
);
 
return frame;
end
 
 
-- ****************************************************************************
-- Shows the popup acknowledge frame using the passed config.
-- ****************************************************************************
local function ShowAcknowledge(configTable)
-- Don't do anything if required parameters weren't passed.
if (not configTable or not configTable.anchorFrame or not configTable.parentFrame) then return; end
 
-- Create the frame if it hasn't already been.
if (not popupFrames.acknowledgeFrame) then popupFrames.acknowledgeFrame = CreateAcknowledge(); end
 
 
-- Set parent.
local frame = popupFrames.acknowledgeFrame;
ChangePopupParent(frame, configTable.parentFrame)
 
-- Configure the frame.
frame.acknowledgeHandler = configTable.acknowledgeHandler;
frame.saveArg1 = configTable.saveArg1;
frame.hideHandler = configTable.hideHandler;
frame:ClearAllPoints();
frame:SetPoint(configTable.anchorPoint or "TOPLEFT", configTable.anchorFrame, configTable.relativePoint or "BOTTOMLEFT");
frame:Show();
frame:Raise();
end
 
 
-------------------------------------------------------------------------------
-- Font frame functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Updates the return settings table with the selected font values.
-- ****************************************************************************
local function UpdateFontSettings()
local frame = popupFrames.fontFrame;
 
EraseTable(returnSettings);
 
if (not frame.hideNormal) then
returnSettings.normalFontName = not frame.normalFontCheckbox:GetChecked() and frame.normalFontDropdown:GetSelectedID() or nil;
returnSettings.normalOutlineIndex = not frame.normalOutlineCheckbox:GetChecked() and frame.normalOutlineDropdown:GetSelectedID() or nil;
returnSettings.normalFontSize = not frame.normalFontSizeCheckbox:GetChecked() and frame.normalFontSizeSlider:GetValue() or nil;
returnSettings.normalFontAlpha = not frame.normalFontOpacityCheckbox:GetChecked() and frame.normalFontOpacitySlider:GetValue() or nil;
end
 
if (not frame.hideCrit) then
returnSettings.critFontName = not frame.critFontCheckbox:GetChecked() and frame.critFontDropdown:GetSelectedID() or nil;
returnSettings.critOutlineIndex = not frame.critOutlineCheckbox:GetChecked() and frame.critOutlineDropdown:GetSelectedID() or nil;
returnSettings.critFontSize = not frame.critFontSizeCheckbox:GetChecked() and frame.critFontSizeSlider:GetValue() or nil;
returnSettings.critFontAlpha = not frame.critFontOpacityCheckbox:GetChecked() and frame.critFontOpacitySlider:GetValue() or nil;
end
end
 
 
-- ****************************************************************************
-- Updates the normal and crit font previews.
-- ****************************************************************************
local function UpdateFontPreviews()
local frame = popupFrames.fontFrame;
local fonts = MSBTAnimations.fonts;
 
local fontPath, fontSize, outline;
 
if (not frame.hideNormal) then
fontPath = fonts[frame.normalFontDropdown:GetSelectedID()];
fontSize = frame.normalFontSizeSlider:GetValue();
outline = OUTLINE_MAP[frame.normalOutlineDropdown:GetSelectedID()];
frame.normalPreviewFontString:SetFont(fontPath, fontSize, outline);
frame.normalPreviewFontString:SetAlpha(frame.normalFontOpacitySlider:GetValue() / 100);
end
 
if (not frame.hideCrit) then
fontPath = fonts[frame.critFontDropdown:GetSelectedID()];
fontSize = frame.critFontSizeSlider:GetValue();
outline = OUTLINE_MAP[frame.critOutlineDropdown:GetSelectedID()];
if (fontPath and outline) then frame.critPreviewFontString:SetFont(fontPath, fontSize, outline); end
frame.critPreviewFontString:SetAlpha(frame.critFontOpacitySlider:GetValue() / 100);
end
end
 
 
-- ****************************************************************************
-- Creates the popup font frame.
-- ****************************************************************************
local function CreateFontPopup()
local frame = CreatePopup();
frame:SetWidth(450);
frame:SetHeight(380);
 
-- Title text.
local fontString = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall");
fontString:SetPoint("TOP", frame, "TOP", 0, -20);
frame.titleFontString = fontString;
 
 
-- Normal container frame.
local normalFrame = CreateFrame("Frame", nil, frame);
normalFrame:SetWidth(195);
normalFrame:SetPoint("TOPLEFT", frame, "TOPLEFT", 20, -60);
normalFrame:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", 20, 40);
frame.normalFrame = normalFrame;
 
 
-- Normal controls container frame.
local normalControlsFrame = CreateFrame("Frame", nil, normalFrame);
normalControlsFrame:SetWidth(155);
normalControlsFrame:SetPoint("TOPLEFT");
normalControlsFrame:SetPoint("BOTTOMLEFT");
frame.normalControlsFrame = normalControlsFrame;
 
-- Normal font dropdown.
local dropdown = MSBTControls.CreateDropdown(normalControlsFrame);
objLocale = MSBTLocale.DROPDOWNS["normalFont"];
dropdown:Configure(150, objLocale.label, objLocale.tooltip);
dropdown:SetListboxHeight(200);
dropdown:SetPoint("TOPLEFT");
dropdown:SetChangeHandler(
function (this, id)
UpdateFontPreviews();
end
);
frame.normalFontDropdown = dropdown;
 
-- Normal outline dropdown.
dropdown = MSBTControls.CreateDropdown(normalControlsFrame);
objLocale = MSBTLocale.DROPDOWNS["normalOutline"];
dropdown:Configure(150, objLocale.label, objLocale.tooltip);
dropdown:SetPoint("TOPLEFT", frame.normalFontDropdown, "BOTTOMLEFT", 0, -20);
dropdown:SetChangeHandler(
function (this, id)
UpdateFontPreviews();
end
);
for outlineIndex, outlineName in ipairs(MSBTLocale.OUTLINES) do
dropdown:AddItem(outlineName, outlineIndex);
end
frame.normalOutlineDropdown = dropdown;
 
-- Normal font size slider.
local slider = MSBTControls.CreateSlider(normalControlsFrame);
objLocale = MSBTLocale.SLIDERS["normalFontSize"];
slider:Configure(150, objLocale.label, objLocale.tooltip);
slider:SetPoint("TOPLEFT", frame.normalOutlineDropdown, "BOTTOMLEFT", 0, -30);
slider:SetMinMaxValues(4, 38);
slider:SetValueStep(1);
slider:SetValueChangedHandler(
function(this, value)
UpdateFontPreviews();
end
);
frame.normalFontSizeSlider = slider;
 
-- Normal font opacity slider.
slider = MSBTControls.CreateSlider(normalControlsFrame);
objLocale = MSBTLocale.SLIDERS["normalFontOpacity"];
slider:Configure(150, objLocale.label, objLocale.tooltip);
slider:SetPoint("TOPLEFT", frame.normalFontSizeSlider, "BOTTOMLEFT", 0, -10);
slider:SetMinMaxValues(1, 100);
slider:SetValueStep(1);
slider:SetValueChangedHandler(
function(this, value)
UpdateFontPreviews();
end
);
frame.normalFontOpacitySlider = slider;
 
-- Normal preview.
fontString = normalControlsFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall");
fontString:SetPoint("BOTTOM", normalControlsFrame, "BOTTOM", 0, 10);
fontString:SetText(MSBTLocale.MSG_NORMAL_PREVIEW_TEXT);
frame.normalPreviewFontString = fontString;
 
 
 
-- Normal inherit container frame.
local normalInheritFrame = CreateFrame("Frame", nil, normalFrame);
normalInheritFrame:SetWidth(40);
normalInheritFrame:SetPoint("TOPLEFT", normalControlsFrame, "TOPRIGHT");
normalInheritFrame:SetPoint("BOTTOMLEFT", normalControlsFrame, "BOTTOMRIGHT");
frame.normalInheritFrame = normalInheritFrame;
 
-- Inherit normal font name checkbox.
local checkbox = MSBTControls.CreateCheckbox(normalInheritFrame);
objLocale = MSBTLocale.CHECKBOXES["inheritField"];
checkbox:Configure(20, nil, objLocale.tooltip);
checkbox:SetPoint("BOTTOMLEFT", frame.normalFontDropdown, "BOTTOMRIGHT", 10, 0);
checkbox:SetClickHandler(
function (this, isChecked)
ToggleDropdownInheritState(frame.normalFontDropdown, isChecked, frame.inheritedNormalFontName);
UpdateFontPreviews();
end
);
frame.normalFontCheckbox = checkbox;
 
-- Inherit normal outline index checkbox.
checkbox = MSBTControls.CreateCheckbox(normalInheritFrame);
checkbox:Configure(20, nil, objLocale.tooltip);
checkbox:SetPoint("BOTTOMLEFT", frame.normalOutlineDropdown, "BOTTOMRIGHT", 10, 0);
checkbox:SetClickHandler(
function (this, isChecked)
ToggleDropdownInheritState(frame.normalOutlineDropdown, isChecked, frame.inheritedNormalOutlineIndex);
UpdateFontPreviews();
end
);
frame.normalOutlineCheckbox = checkbox;
 
-- Inherit normal font size checkbox.
checkbox = MSBTControls.CreateCheckbox(normalInheritFrame);
checkbox:Configure(20, nil, objLocale.tooltip);
checkbox:SetPoint("BOTTOMLEFT", frame.normalFontSizeSlider, "BOTTOMRIGHT", 10, 5);
checkbox:SetClickHandler(
function (this, isChecked)
ToggleSliderInheritState(frame.normalFontSizeSlider, isChecked, frame.inheritedNormalFontSize);
UpdateFontPreviews();
end
);
frame.normalFontSizeCheckbox = checkbox;
 
-- Inherit normal font opacity checkbox.
checkbox = MSBTControls.CreateCheckbox(normalInheritFrame);
checkbox:Configure(20, nil, objLocale.tooltip);
checkbox:SetPoint("BOTTOMLEFT", frame.normalFontOpacitySlider, "BOTTOMRIGHT", 10, 5);
checkbox:SetClickHandler(
function (this, isChecked)
ToggleSliderInheritState(frame.normalFontOpacitySlider, isChecked, frame.inheritedNormalFontAlpha);
UpdateFontPreviews();
end
);
frame.normalFontOpacityCheckbox = checkbox;
 
-- Inherit normal column label.
fontString = normalInheritFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall");
fontString:SetPoint("BOTTOM", frame.normalFontCheckbox, "TOP", 0, 7);
fontString:SetText(MSBTLocale.CHECKBOXES["inheritField"].label);
 
 
 
 
-- Crit container frame.
local critFrame = CreateFrame("Frame", nil, frame);
critFrame:SetWidth(195);
critFrame:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -20, -60);
critFrame:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -20, 40);
frame.critFrame = critFrame;
 
 
-- Crit controls container frame.
local critControlsFrame = CreateFrame("Frame", nil, critFrame);
critControlsFrame:SetWidth(155);
critControlsFrame:SetPoint("TOPLEFT");
critControlsFrame:SetPoint("BOTTOMLEFT");
frame.critControlsFrame = critControlsFrame;
 
-- Crit font dropdown.
dropdown = MSBTControls.CreateDropdown(critControlsFrame);
objLocale = MSBTLocale.DROPDOWNS["critFont"];
dropdown:Configure(150, objLocale.label, objLocale.tooltip);
dropdown:SetListboxHeight(200);
dropdown:SetPoint("TOPLEFT");
dropdown:SetChangeHandler(
function (this, id)
UpdateFontPreviews();
end
);
frame.critFontDropdown = dropdown;
 
-- Crit outline dropdown.
dropdown = MSBTControls.CreateDropdown(critControlsFrame);
objLocale = MSBTLocale.DROPDOWNS["critOutline"];
dropdown:Configure(150, objLocale.label, objLocale.tooltip);
dropdown:SetPoint("TOPLEFT", frame.critFontDropdown, "BOTTOMLEFT", 0, -20);
dropdown:SetChangeHandler(
function (this, id)
UpdateFontPreviews();
end
);
for outlineIndex, outlineName in ipairs(MSBTLocale.OUTLINES) do
dropdown:AddItem(outlineName, outlineIndex);
end
frame.critOutlineDropdown = dropdown;
 
-- Crit font size slider.
slider = MSBTControls.CreateSlider(critControlsFrame);
objLocale = MSBTLocale.SLIDERS["critFontSize"];
slider:Configure(150, objLocale.label, objLocale.tooltip);
slider:SetPoint("TOPLEFT", frame.critOutlineDropdown, "BOTTOMLEFT", 0, -30);
slider:SetMinMaxValues(4, 38);
slider:SetValueStep(1);
slider:SetValueChangedHandler(
function(this, value)
UpdateFontPreviews();
end
);
frame.critFontSizeSlider = slider;
 
-- Crit font opacity slider.
slider = MSBTControls.CreateSlider(critControlsFrame);
objLocale = MSBTLocale.SLIDERS["critFontOpacity"];
slider:Configure(150, objLocale.label, objLocale.tooltip);
slider:SetPoint("TOPLEFT", frame.critFontSizeSlider, "BOTTOMLEFT", 0, -10);
slider:SetMinMaxValues(1, 100);
slider:SetValueStep(1);
slider:SetValueChangedHandler(
function(this, value)
UpdateFontPreviews();
end
);
frame.critFontOpacitySlider = slider;
 
-- Crit Preview.
fontString = critControlsFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall");
fontString:SetPoint("BOTTOM", critControlsFrame, "BOTTOM", 0, 10);
fontString:SetText(MSBTLocale.MSG_CRIT);
frame.critPreviewFontString = fontString;
 
 
 
-- Crit inherit container frame.
local critInheritFrame = CreateFrame("Frame", nil, critFrame);
critInheritFrame:SetWidth(40);
critInheritFrame:SetPoint("TOPLEFT", critControlsFrame, "TOPRIGHT");
critInheritFrame:SetPoint("BOTTOMLEFT", critControlsFrame, "BOTTOMRIGHT");
frame.critInheritFrame = critInheritFrame;
 
 
-- Inherit crit font name checkbox.
local checkbox = MSBTControls.CreateCheckbox(critInheritFrame);
objLocale = MSBTLocale.CHECKBOXES["inheritField"];
checkbox:Configure(20, nil, objLocale.tooltip);
checkbox:SetPoint("BOTTOMLEFT", frame.critFontDropdown, "BOTTOMRIGHT", 10, 0);
checkbox:SetClickHandler(
function (this, isChecked)
ToggleDropdownInheritState(frame.critFontDropdown, isChecked, frame.inheritedCritFontName);
UpdateFontPreviews();
end
);
frame.critFontCheckbox = checkbox;
 
-- Inherit crit outline index checkbox.
checkbox = MSBTControls.CreateCheckbox(critInheritFrame);
checkbox:Configure(20, nil, objLocale.tooltip);
checkbox:SetPoint("BOTTOMLEFT", frame.critOutlineDropdown, "BOTTOMRIGHT", 10, 0);
checkbox:SetClickHandler(
function (this, isChecked)
ToggleDropdownInheritState(frame.critOutlineDropdown, isChecked, frame.inheritedCritOutlineIndex);
UpdateFontPreviews();
end
);
frame.critOutlineCheckbox = checkbox;
 
-- Inherit crit font size checkbox.
checkbox = MSBTControls.CreateCheckbox(critInheritFrame);
checkbox:Configure(20, nil, objLocale.tooltip);
checkbox:SetPoint("BOTTOMLEFT", frame.critFontSizeSlider, "BOTTOMRIGHT", 10, 5);
checkbox:SetClickHandler(
function (this, isChecked)
ToggleSliderInheritState(frame.critFontSizeSlider, isChecked, frame.inheritedCritFontSize);
UpdateFontPreviews();
end
);
frame.critFontSizeCheckbox = checkbox;
 
-- Inherit crit font opacity checkbox.
checkbox = MSBTControls.CreateCheckbox(critInheritFrame);
checkbox:Configure(20, nil, objLocale.tooltip);
checkbox:SetPoint("BOTTOMLEFT", frame.critFontOpacitySlider, "BOTTOMRIGHT", 10, 5);
checkbox:SetClickHandler(
function (this, isChecked)
ToggleSliderInheritState(frame.critFontOpacitySlider, isChecked, frame.inheritedCritFontAlpha);
UpdateFontPreviews();
end
);
frame.critFontOpacityCheckbox = checkbox;
 
-- Inherit normal column label.
fontString = critInheritFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall");
fontString:SetPoint("BOTTOM", frame.critFontCheckbox, "TOP", 0, 7);
fontString:SetText(MSBTLocale.CHECKBOXES["inheritField"].label);
 
-- Save button.
local button = MSBTControls.CreateOptionButton(frame);
objLocale = MSBTLocale.BUTTONS["genericSave"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("BOTTOMRIGHT", frame, "BOTTOM", -10, 20);
button:SetClickHandler(
function (this)
UpdateFontSettings();
if (frame.saveHandler) then frame.saveHandler(returnSettings, frame.saveArg1); end
frame:Hide();
end
);
 
-- Cancel button.
button = MSBTControls.CreateOptionButton(frame);
objLocale = MSBTLocale.BUTTONS["genericCancel"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("BOTTOMLEFT", frame, "BOTTOM", 10, 20);
button:SetClickHandler(
function (this)
frame:Hide();
end
);
 
 
-- Register the frame with the main module.
MSBTOptions.Main.RegisterPopupFrame(frame);
return frame;
end
 
 
-- ****************************************************************************
-- Shows the popup font frame using the passed config.
-- ****************************************************************************
local function ShowFont(configTable)
-- Don't do anything if required parameters weren't passed.
if (not configTable or not configTable.anchorFrame or not configTable.parentFrame) then return; end
 
-- Create the frame if it hasn't already been.
if (not popupFrames.fontFrame) then popupFrames.fontFrame = CreateFontPopup(); end
 
-- Set parent.
local frame = popupFrames.fontFrame;
ChangePopupParent(frame, configTable.parentFrame)
 
-- Show / Hide appropriate controls.
if (configTable.hideNormal) then frame.normalFrame:Hide(); else frame.normalFrame:Show(); end
if (configTable.hideCrit) then frame.critFrame:Hide(); else frame.critFrame:Show(); end
if (configTable.hideInherit) then frame.normalInheritFrame:Hide(); else frame.normalInheritFrame:Show(); end
if (configTable.hideInherit) then frame.critInheritFrame:Hide(); else frame.critInheritFrame:Show(); end
frame.hideNormal = configTable.hideNormal;
frame.hideCrit = configTable.hideCrit;
 
 
-- Populate data.
local dropdown, checkbox, slider;
frame.titleFontString:SetText(configTable.title);
 
if (not configTable.hideNormal) then
-- Normal font name.
dropdown = frame.normalFontDropdown;
dropdown:Clear();
for fontName in pairs(MSBTAnimations.fonts) do
dropdown:AddItem(fontName, fontName);
end
dropdown:Sort();
checkbox = frame.normalFontCheckbox;
checkbox:SetChecked(not configTable.normalFontName or false);
if (configTable.normalFontName) then dropdown:SetSelectedID(configTable.normalFontName); end
ToggleDropdownInheritState(dropdown, checkbox:GetChecked(), configTable.inheritedNormalFontName);
 
-- Normal outline index.
dropdown = frame.normalOutlineDropdown;
checkbox = frame.normalOutlineCheckbox;
checkbox:SetChecked(not configTable.normalOutlineIndex or false);
if (configTable.normalOutlineIndex) then dropdown:SetSelectedID(configTable.normalOutlineIndex); end
ToggleDropdownInheritState(dropdown, checkbox:GetChecked(), configTable.inheritedNormalOutlineIndex);
 
-- Normal font size.
slider = frame.normalFontSizeSlider;
checkbox = frame.normalFontSizeCheckbox;
checkbox:SetChecked(not configTable.normalFontSize or false);
if (configTable.normalFontSize) then slider:SetValue(configTable.normalFontSize); end
ToggleSliderInheritState(slider, checkbox:GetChecked(), configTable.inheritedNormalFontSize);
 
-- Normal font opacity.
slider = frame.normalFontOpacitySlider;
checkbox = frame.normalFontOpacityCheckbox;
checkbox:SetChecked(not configTable.normalFontAlpha or false);
if (configTable.normalFontAlpha) then slider:SetValue(configTable.normalFontAlpha); end
ToggleSliderInheritState(slider, checkbox:GetChecked(), configTable.inheritedNormalFontAlpha);
end
 
 
if (not configTable.hideCrit) then
-- Crit font name.
dropdown = frame.critFontDropdown;
dropdown:Clear();
for fontName in pairs(MSBTAnimations.fonts) do
dropdown:AddItem(fontName, fontName);
end
dropdown:Sort();
checkbox = frame.critFontCheckbox;
checkbox:SetChecked(not configTable.critFontName or false);
if (configTable.critFontName) then dropdown:SetSelectedID(configTable.critFontName); end
ToggleDropdownInheritState(dropdown, checkbox:GetChecked(), configTable.inheritedCritFontName);
 
-- Crit outline index.
dropdown = frame.critOutlineDropdown;
checkbox = frame.critOutlineCheckbox;
checkbox:SetChecked(not configTable.critOutlineIndex or false);
if (configTable.critOutlineIndex) then dropdown:SetSelectedID(configTable.critOutlineIndex); end
ToggleDropdownInheritState(dropdown, checkbox:GetChecked(), configTable.inheritedCritOutlineIndex);
 
-- Crit font size.
slider = frame.critFontSizeSlider;
checkbox = frame.critFontSizeCheckbox;
checkbox:SetChecked(not configTable.critFontSize or false);
if (configTable.critFontSize) then slider:SetValue(configTable.critFontSize); end
ToggleSliderInheritState(slider, checkbox:GetChecked(), configTable.inheritedCritFontSize);
 
-- Crit font opacity.
slider = frame.critFontOpacitySlider;
checkbox = frame.critFontOpacityCheckbox;
checkbox:SetChecked(not configTable.critFontAlpha or false);
if (configTable.critFontAlpha) then slider:SetValue(configTable.critFontAlpha); end
ToggleSliderInheritState(slider, checkbox:GetChecked(), configTable.inheritedCritFontAlpha);
end
 
 
-- Store inherited settings.
frame.inheritedNormalFontName = configTable.inheritedNormalFontName;
frame.inheritedNormalOutlineIndex = configTable.inheritedNormalOutlineIndex;
frame.inheritedNormalFontSize = configTable.inheritedNormalFontSize;
frame.inheritedNormalFontAlpha = configTable.inheritedNormalFontAlpha;
frame.inheritedCritFontName = configTable.inheritedCritFontName;
frame.inheritedCritOutlineIndex = configTable.inheritedCritOutlineIndex;
frame.inheritedCritFontSize = configTable.inheritedCritFontSize;
frame.inheritedCritFontAlpha = configTable.inheritedCritFontAlpha;
 
 
-- Configure the frame.
frame.saveHandler = configTable.saveHandler;
frame.saveArg1 = configTable.saveArg1;
frame.hideHandler = configTable.hideHandler;
frame:ClearAllPoints();
frame:SetPoint(configTable.anchorPoint or "TOPLEFT", configTable.anchorFrame, configTable.relativePoint or "BOTTOMLEFT");
frame:Show();
frame:Raise();
 
UpdateFontPreviews();
end
 
 
-------------------------------------------------------------------------------
-- Partial effects frame functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Creates the popup partial effects frame.
-- ****************************************************************************
local function CreatePartialEffects()
local frame = CreatePopup();
frame:SetWidth(270);
frame:SetHeight(240);
 
-- Close button.
local button = CreateFrame("Button", nil, frame, "UIPanelCloseButton");
button:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -2, -2);
 
-- Color partial effects.
local checkbox = MSBTControls.CreateCheckbox(frame);
local objLocale = MSBTLocale.CHECKBOXES["colorPartialEffects"];
checkbox:Configure(24, objLocale.label, objLocale.tooltip);
checkbox:SetPoint("TOPLEFT", frame, "TOPLEFT", 20, -20);
checkbox:SetClickHandler(
function (this, isChecked)
MSBTProfiles.SetOption(nil, "partialColoringDisabled", not isChecked);
end
);
frame.colorCheckbox = checkbox;
 
 
-- Partial effects.
local anchor = checkbox;
local colorswatch;
for effectType in string.gmatch("crushing glancing absorb block resist overheal", "[^%s]+") do
colorswatch = MSBTControls.CreateColorswatch(frame);
colorswatch:SetPoint("TOPLEFT", anchor, "BOTTOMLEFT", anchor == checkbox and 20 or 0, -10);
colorswatch:SetColorChangedHandler(
function (this)
MSBTProfiles.SetOption(effectType, "colorR", this.r);
MSBTProfiles.SetOption(effectType, "colorG", this.g);
MSBTProfiles.SetOption(effectType, "colorB", this.b);
end
);
checkbox = MSBTControls.CreateCheckbox(frame);
objLocale = MSBTLocale.CHECKBOXES[effectType];
checkbox:Configure(24, objLocale.label, objLocale.tooltip);
checkbox:SetPoint("LEFT", colorswatch, "RIGHT", 5, 0);
checkbox:SetClickHandler(
function (this, isChecked)
MSBTProfiles.SetOption(effectType, "disabled", not isChecked);
end
);
frame[effectType .. "Colorswatch"] = colorswatch;
frame[effectType .. "Checkbox"] = checkbox;
 
anchor = colorswatch;
end
 
return frame;
end
 
 
-- ****************************************************************************
-- Shows the popup damage partial effects frame using the passed config.
-- ****************************************************************************
local function ShowPartialEffects(configTable)
-- Don't do anything if required parameters weren't passed.
if (not configTable or not configTable.anchorFrame or not configTable.parentFrame) then return; end
 
-- Create the frame if it hasn't already been.
if (not popupFrames.partialEffectsFrame) then popupFrames.partialEffectsFrame = CreatePartialEffects(); end
 
-- Set parent.
local frame = popupFrames.partialEffectsFrame;
ChangePopupParent(frame, configTable.parentFrame)
 
-- Populate data.
frame.colorCheckbox:SetChecked(not MSBTProfiles.currentProfile.partialColoringDisabled);
 
local profileEntry;
for effectType in string.gmatch("crushing glancing absorb block resist overheal", "[^%s]+") do
profileEntry = MSBTProfiles.currentProfile[effectType];
frame[effectType .. "Colorswatch"]:SetColor(profileEntry.colorR, profileEntry.colorG, profileEntry.colorB);
frame[effectType .. "Checkbox"]:SetChecked(not profileEntry.disabled);
end
 
-- Configure the frame.
frame.hideHandler = configTable.hideHandler;
frame:ClearAllPoints();
frame:SetPoint(configTable.anchorPoint or "TOPLEFT", configTable.anchorFrame, configTable.relativePoint or "BOTTOMLEFT");
frame:Show();
frame:Raise();
end
 
 
-------------------------------------------------------------------------------
-- Damage color frame functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Creates the popup damage colors frame.
-- ****************************************************************************
local function CreateDamageColors()
local frame = CreatePopup();
frame:SetWidth(260);
frame:SetHeight(220);
 
-- Close button.
local button = CreateFrame("Button", nil, frame, "UIPanelCloseButton");
button:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -2, -2);
 
-- Color damage amounts.
local checkbox = MSBTControls.CreateCheckbox(frame);
local objLocale = MSBTLocale.CHECKBOXES["colorDamageAmounts"];
checkbox:Configure(24, objLocale.label, objLocale.tooltip);
checkbox:SetPoint("TOPLEFT", frame, "TOPLEFT", 20, -20);
checkbox:SetClickHandler(
function (this, isChecked)
MSBTProfiles.SetOption(nil, "damageColoringDisabled", not isChecked);
end
);
frame.colorCheckbox = checkbox;
 
 
-- Damage types.
local anchor = checkbox;
local globalStringSchoolIndex = 0;
local colorswatch, fontString;
for damageType in string.gmatch("physical holy fire nature frost shadow arcane", "[^%s]+") do
colorswatch = MSBTControls.CreateColorswatch(frame);
colorswatch:SetPoint("TOPLEFT", anchor, "BOTTOMLEFT", anchor == checkbox and 20 or 0, anchor == checkbox and -10 or -5);
colorswatch:SetColorChangedHandler(
function (this)
MSBTProfiles.SetOption(damageType, "colorR", this.r);
MSBTProfiles.SetOption(damageType, "colorG", this.g);
MSBTProfiles.SetOption(damageType, "colorB", this.b);
end
);
checkbox = MSBTControls.CreateCheckbox(frame);
objLocale = MSBTLocale.CHECKBOXES["colorDamageEntry"];
checkbox:Configure(24, _G["SPELL_SCHOOL" .. globalStringSchoolIndex .. "_CAP"], objLocale.tooltip);
checkbox:SetPoint("LEFT", colorswatch, "RIGHT", 5, 0);
checkbox:SetClickHandler(
function (this, isChecked)
MSBTProfiles.SetOption(damageType, "disabled", not isChecked);
end
);
frame[damageType .. "Colorswatch"] = colorswatch;
frame[damageType .. "Checkbox"] = checkbox;
 
anchor = colorswatch;
globalStringSchoolIndex = globalStringSchoolIndex + 1;
end
 
return frame;
end
 
 
-- ****************************************************************************
-- Shows the popup damage type colors frame using the passed config.
-- ****************************************************************************
local function ShowDamageColors(configTable)
-- Don't do anything if required parameters weren't passed.
if (not configTable or not configTable.anchorFrame or not configTable.parentFrame) then return; end
 
-- Create the frame if it hasn't already been.
if (not popupFrames.damageColorsFrame) then popupFrames.damageColorsFrame = CreateDamageColors(); end
 
-- Set parent.
local frame = popupFrames.damageColorsFrame;
ChangePopupParent(frame, configTable.parentFrame)
 
-- Populate data.
frame.colorCheckbox:SetChecked(not MSBTProfiles.currentProfile.damageColoringDisabled);
 
local profileEntry;
for damageType in string.gmatch("physical holy fire nature frost shadow arcane", "[^%s]+") do
profileEntry = MSBTProfiles.currentProfile[damageType];
frame[damageType .. "Colorswatch"]:SetColor(profileEntry.colorR, profileEntry.colorG, profileEntry.colorB);
frame[damageType .. "Checkbox"]:SetChecked(not profileEntry.disabled);
end
 
-- Configure the frame.
frame.hideHandler = configTable.hideHandler;
frame:ClearAllPoints();
frame:SetPoint(configTable.anchorPoint or "TOPLEFT", configTable.anchorFrame, configTable.relativePoint or "BOTTOMLEFT");
frame:Show();
frame:Raise();
end
 
 
-------------------------------------------------------------------------------
-- Scroll area config frame functions.
-------------------------------------------------------------------------------
 
-- **********************************************************************************
-- This function copies the current scroll area settings into the passed table key.
-- **********************************************************************************
local function CopyTempScrollAreaSettings(settingsTable)
local frame = popupFrames.scrollAreaConfigFrame;
EraseTable(settingsTable);
 
-- Get the original settings.
local tempSettings;
for saKey, saSettings in pairs(MSBTAnimations.scrollAreas) do
settingsTable[saKey] = {};
tempSettings = settingsTable[saKey];
 
-- Normal.
tempSettings.animationStyle = saSettings.animationStyle or DEFAULT_ANIMATION_STYLE;
tempSettings.direction = saSettings.direction;
tempSettings.behavior = saSettings.behavior;
tempSettings.textAlignIndex = saSettings.textAlignIndex or DEFAULT_TEXT_ALIGN_INDEX;
 
-- Sticky.
tempSettings.stickyAnimationStyle = saSettings.stickyAnimationStyle or DEFAULT_STICKY_ANIMATION_STYLE;
tempSettings.stickyDirection = saSettings.stickyDirection;
tempSettings.stickyBehavior = saSettings.stickyBehavior;
tempSettings.stickyTextAlignIndex = saSettings.stickyTextAlignIndex or DEFAULT_TEXT_ALIGN_INDEX;
 
-- Positioning.
tempSettings.scrollHeight = saSettings.scrollHeight or DEFAULT_SCROLL_HEIGHT;
tempSettings.scrollWidth = saSettings.scrollWidth or DEFAULT_SCROLL_WIDTH;
tempSettings.offsetX = saSettings.offsetX or 0;
tempSettings.offsetY = saSettings.offsetY or 0;
 
-- Speed.
tempSettings.inheritedAnimationSpeed = MSBTProfiles.currentProfile.animationSpeed;
tempSettings.animationSpeed = saSettings.animationSpeed;
end
end
 
 
-- ****************************************************************************
-- Changes the normal animation style to the passed value.
-- ****************************************************************************
local function ChangeAnimationStyle(styleKey)
local frame = popupFrames.scrollAreaConfigFrame;
local styleSettings = MSBTAnimations.animationStyles[styleKey];
local firstEntry, name, objLocale;
 
-- Normal direction.
frame.directionDropdown:Clear();
if (styleSettings.availableDirections) then
for direction in string.gmatch(styleSettings.availableDirections, "[^;]+") do
if (not firstEntry) then firstEntry = direction; end
objLocale = styleSettings.localizationTable;
name = objLocale and objLocale[direction] or MSBTLocale.ANIMATION_STYLE_DATA[direction] or direction;
frame.directionDropdown:AddItem(name, direction);
end
frame.directionDropdown:SetSelectedID(firstEntry);
else
-- No available directions, so just add a normal entry.
frame.directionDropdown:AddItem(MSBTLocale.ANIMATION_STYLE_DATA["Normal"], "MSBT_NORMAL");
frame.directionDropdown:SetSelectedID("MSBT_NORMAL");
end
 
-- Normal behavior.
firstEntry = nil;
frame.behaviorDropdown:Clear();
if (styleSettings.availableBehaviors) then
for behavior in string.gmatch(styleSettings.availableBehaviors, "[^;]+") do
if (not firstEntry) then firstEntry = behavior; end
objLocale = styleSettings.localizationTable;
name = objLocale and objLocale[behavior] or MSBTLocale.ANIMATION_STYLE_DATA[behavior] or behavior;
frame.behaviorDropdown:AddItem(name, behavior);
end
frame.behaviorDropdown:SetSelectedID(firstEntry);
else
-- No available behaviors, so just add a normal entry.
frame.behaviorDropdown:AddItem(MSBTLocale.ANIMATION_STYLE_DATA["Normal"], "MSBT_NORMAL");
frame.behaviorDropdown:SetSelectedID("MSBT_NORMAL");
end
end
 
 
-- ****************************************************************************
-- Changes the sticky animation style to the passed value.
-- ****************************************************************************
local function ChangeStickyAnimationStyle(styleKey)
local frame = popupFrames.scrollAreaConfigFrame;
local styleSettings = MSBTAnimations.stickyAnimationStyles[styleKey];
local firstEntry, name, objLocale;
 
-- Sticky direction.
frame.stickyDirectionDropdown:Clear();
if (styleSettings.availableDirections) then
for direction in string.gmatch(styleSettings.availableDirections, "[^;]+") do
if (not firstEntry) then firstEntry = direction; end
objLocale = styleSettings.localizationTable;
name = objLocale and objLocale[direction] or MSBTLocale.ANIMATION_STYLE_DATA[direction] or direction;
frame.stickyDirectionDropdown:AddItem(name, direction);
end
frame.stickyDirectionDropdown:SetSelectedID(firstEntry);
else
-- No available directions, so just add a normal entry.
frame.stickyDirectionDropdown:AddItem(MSBTLocale.ANIMATION_STYLE_DATA["Normal"], "MSBT_NORMAL");
frame.stickyDirectionDropdown:SetSelectedID("MSBT_NORMAL");
end
 
-- Sticky behavior.
firstEntry = nil;
frame.stickyBehaviorDropdown:Clear();
if (styleSettings.availableBehaviors) then
for behavior in string.gmatch(styleSettings.availableBehaviors, "[^;]+") do
if (not firstEntry) then firstEntry = behavior; end
objLocale = styleSettings.localizationTable;
name = objLocale and objLocale[behavior] or MSBTLocale.ANIMATION_STYLE_DATA[behavior] or behavior;
frame.stickyBehaviorDropdown:AddItem(name, behavior);
end
frame.stickyBehaviorDropdown:SetSelectedID(firstEntry);
else
-- No available behaviors, so just add a normal entry.
frame.stickyBehaviorDropdown:AddItem(MSBTLocale.ANIMATION_STYLE_DATA["Normal"], "MSBT_NORMAL");
frame.stickyBehaviorDropdown:SetSelectedID("MSBT_NORMAL");
end
end
 
 
-- ****************************************************************************
-- Changes the scroll area to configure to the passed value.
-- ****************************************************************************
local function ChangeConfigScrollArea(scrollArea)
local frame = popupFrames.scrollAreaConfigFrame;
frame.currentScrollArea = scrollArea;
local saSettings = frame.previewSettings[scrollArea];
local name, objLocale;
 
-- Normal animation style.
frame.animationStyleDropdown:Clear();
for styleKey, settings in pairs(MSBTAnimations.animationStyles) do
objLocale = settings.localizationTable;
name = objLocale and objLocale[styleKey] or MSBTLocale.ANIMATION_STYLE_DATA[styleKey] or styleKey;
frame.animationStyleDropdown:AddItem(name, styleKey);
end
frame.animationStyleDropdown:SetSelectedID(saSettings.animationStyle);
ChangeAnimationStyle(saSettings.animationStyle);
 
-- Normal direction, behavior, and text align.
if (saSettings.direction) then frame.directionDropdown:SetSelectedID(saSettings.direction); end
if (saSettings.behavior) then frame.behaviorDropdown:SetSelectedID(saSettings.behavior); end
frame.textAlignDropdown:SetSelectedID(saSettings.textAlignIndex);
 
 
-- Sticky animation style.
frame.stickyAnimationStyleDropdown:Clear();
for styleKey, settings in pairs(MSBTAnimations.stickyAnimationStyles) do
objLocale = settings.localizationTable;
name = objLocale and objLocale[styleKey] or MSBTLocale.ANIMATION_STYLE_DATA[styleKey] or styleKey;
frame.stickyAnimationStyleDropdown:AddItem(name, styleKey);
end
frame.stickyAnimationStyleDropdown:SetSelectedID(saSettings.stickyAnimationStyle);
ChangeStickyAnimationStyle(saSettings.stickyAnimationStyle);
 
-- Sticky direction, behavior, and text align.
if (saSettings.stickyDirection) then frame.stickyDirectionDropdown:SetSelectedID(saSettings.stickyDirection); end
if (saSettings.stickyBehavior) then frame.stickyBehaviorDropdown:SetSelectedID(saSettings.stickyBehavior); end
frame.stickyTextAlignDropdown:SetSelectedID(saSettings.stickyTextAlignIndex);
 
-- Scroll height and width.
frame.scrollHeightSlider:SetValue(saSettings.scrollHeight);
frame.scrollWidthSlider:SetValue(saSettings.scrollWidth);
 
-- Animation speed
local isSpeedInherited = not saSettings.animationSpeed or saSettings.animationSpeed == saSettings.inheritedAnimationSpeed;
frame.animationSpeedCheckbox:SetChecked(isSpeedInherited);
if (saSettings.animationSpeed) then frame.animationSpeedSlider:SetValue(saSettings.animationSpeed); end
ToggleSliderInheritState(frame.animationSpeedSlider, isSpeedInherited , saSettings.inheritedAnimationSpeed);
 
-- X and Y offset.
frame.xOffsetEditbox:SetText(saSettings.offsetX);
frame.yOffsetEditbox:SetText(saSettings.offsetY);
 
-- Reset the backdrop color of all the scroll area mover frames to grey.
for _, moverFrame in pairs(frame.moverFrames) do
moverFrame:SetBackdropColor(0.8, 0.8, 0.8, 1.0);
end
 
-- Set the selected scroll area mover frame to red and raise it.
frame.moverFrames[scrollArea]:SetBackdropColor(0.5, 0.05, 0.05, 1.0);
frame.moverFrames[scrollArea]:Raise();
end
 
 
-- **********************************************************************************
-- This function repositions the mover frame for the passed scroll area.
-- **********************************************************************************
local function RepositionScrollAreaMoverFrame(scrollArea)
local configFrame = popupFrames.scrollAreaConfigFrame;
local frame = configFrame.moverFrames[scrollArea];
local saSettings = configFrame.previewSettings[scrollArea];
 
frame:ClearAllPoints();
frame:SetPoint("BOTTOMLEFT", UIParent, "CENTER", saSettings.offsetX, saSettings.offsetY);
frame:SetHeight(saSettings.scrollHeight);
frame:SetWidth(saSettings.scrollWidth);
frame.fontString:SetText(MSBTAnimations.scrollAreas[scrollArea].name .. " (" .. saSettings.offsetX .. ", " .. saSettings.offsetY .. ")");
frame:Show();
end
 
 
-- **********************************************************************************
-- Save the coordinates of a scroll area mover.
-- **********************************************************************************
local function SaveScrollAreaMoverCoordinates(frame)
-- Get the UIParent center x and y coords.
local uiParentX, uiParentY = UIParent:GetCenter();
local xOffset = math.ceil(this:GetLeft() - uiParentX);
local yOffset = math.ceil(this:GetBottom() - uiParentY);
 
-- Save the x and y offsets.
local configFrame = popupFrames.scrollAreaConfigFrame;
configFrame.previewSettings[frame.scrollArea].offsetX = xOffset;
configFrame.previewSettings[frame.scrollArea].offsetY = yOffset;
 
-- Populate the x and y offset editboxes if the moved frame is the selected one.
if (frame.scrollArea == configFrame.scrollAreaDropdown:GetSelectedID()) then
configFrame.xOffsetEditbox:SetText(xOffset);
configFrame.yOffsetEditbox:SetText(yOffset);
end
 
-- Reposition the scroll area mover frames to update the coordinates.
RepositionScrollAreaMoverFrame(frame.scrollArea);
end
 
 
-- **********************************************************************************
-- Called when a mouse button is pressed on a mover frame.
-- **********************************************************************************
local function MoverFrameOnMouseDown(this, button)
if (button == "LeftButton") then this:StartMoving(); end
end
 
 
-- **********************************************************************************
-- Called when a mouse button is released on a mover frame.
-- **********************************************************************************
local function MoverFrameOnMouseUp(this)
this:StopMovingOrSizing();
SaveScrollAreaMoverCoordinates(this);
 
local configFrame = popupFrames.scrollAreaConfigFrame;
if (this.scrollArea ~= configFrame.scrollAreaDropdown:GetSelectedID()) then
configFrame.scrollAreaDropdown:SetSelectedID(this.scrollArea);
ChangeConfigScrollArea(this.scrollArea);
end
end
 
 
-- **********************************************************************************
-- This function creates a scroll area mover frame for the passed scroll area if
-- it hasn't already been
-- **********************************************************************************
local function CreateScrollAreaMoverFrame(scrollArea)
local moverFrames = popupFrames.scrollAreaConfigFrame.moverFrames;
 
if (not moverFrames[scrollArea]) then
local frame = CreateFrame("FRAME", nil, UIParent);
frame:Hide();
frame:SetMovable(true);
frame:EnableMouse(true);
frame:SetToplevel(true);
frame:SetClampedToScreen(true);
frame:SetBackdrop(moverBackdrop);
frame:SetScript("OnMouseDown", MoverFrameOnMouseDown);
frame:SetScript("OnMouseUp", MoverFrameOnMouseUp);
 
local fontString = frame:CreateFontString(nil, "OVERLAY");
fontString:SetFont("Fonts\\ARIALN.TTF", 12);
fontString:SetPoint("CENTER");
frame.fontString = fontString;
 
frame.scrollArea = scrollArea;
moverFrames[scrollArea] = frame;
end
end
 
 
-- **********************************************************************************
-- Save the passed table to the scroll area settings.
-- **********************************************************************************
local function SaveScrollAreaSettings(settingsTable)
local frame = popupFrames.scrollAreaConfigFrame;
 
-- Save the settings in the passed table to the current profile.
for saKey, saSettings in pairs(settingsTable) do
-- Normal.
MSBTProfiles.SetOption("scrollAreas." .. saKey, "animationStyle", saSettings.animationStyle, DEFAULT_ANIMATION_STYLE);
MSBTProfiles.SetOption("scrollAreas." .. saKey, "direction", saSettings.direction, "MSBT_NORMAL");
MSBTProfiles.SetOption("scrollAreas." .. saKey, "behavior", saSettings.behavior, "MSBT_NORMAL");
MSBTProfiles.SetOption("scrollAreas." .. saKey, "textAlignIndex", saSettings.textAlignIndex, DEFAULT_TEXT_ALIGN_INDEX);
 
-- Sticky.
MSBTProfiles.SetOption("scrollAreas." .. saKey, "stickyAnimationStyle", saSettings.stickyAnimationStyle, DEFAULT_STICKY_ANIMATION_STYLE);
MSBTProfiles.SetOption("scrollAreas." .. saKey, "stickyDirection", saSettings.stickyDirection, "MSBT_NORMAL");
MSBTProfiles.SetOption("scrollAreas." .. saKey, "stickyBehavior", saSettings.stickyBehavior, "MSBT_NORMAL");
MSBTProfiles.SetOption("scrollAreas." .. saKey, "stickyTextAlignIndex", saSettings.stickyTextAlignIndex, DEFAULT_TEXT_ALIGN_INDEX);
 
-- Position.
MSBTProfiles.SetOption("scrollAreas." .. saKey, "scrollHeight", saSettings.scrollHeight, DEFAULT_SCROLL_HEIGHT);
MSBTProfiles.SetOption("scrollAreas." .. saKey, "scrollWidth", saSettings.scrollWidth, DEFAULT_SCROLL_WIDTH);
MSBTProfiles.SetOption("scrollAreas." .. saKey, "offsetX", saSettings.offsetX);
MSBTProfiles.SetOption("scrollAreas." .. saKey, "offsetY", saSettings.offsetY);
 
-- Animation speed.
local animationSpeed = saSettings.animationSpeed;
MSBTProfiles.SetOption("scrollAreas." .. saKey, "animationSpeed", animationSpeed, saSettings.inheritedAnimationSpeed);
end
MSBTAnimations.UpdateScrollAreas();
end
 
 
-- ****************************************************************************
-- Creates the popup scroll areas config frames.
-- ****************************************************************************
local function CreateScrollAreaConfig()
local frame = CreatePopup();
frame:SetWidth(320);
frame:SetHeight(535);
frame:SetPoint("RIGHT");
frame:SetScript("OnHide",
function (this)
for _, moverFrame in pairs(this.moverFrames) do
moverFrame:Hide();
end
MSBTOptions.Main.ShowMainFrame();
end
);
 
-- Scroll area dropdown.
local dropdown = MSBTControls.CreateDropdown(frame);
objLocale = MSBTLocale.DROPDOWNS["scrollArea"];
dropdown:Configure(200, objLocale.label, objLocale.tooltip);
dropdown:SetPoint("TOP", frame, "TOP", 0, -20);
dropdown:SetChangeHandler(
function (this, id)
ChangeConfigScrollArea(id);
end
);
frame.scrollAreaDropdown = dropdown;
 
 
-- Top horizontal bar.
local texture = frame:CreateTexture(nil, "ARTWORK");
texture:SetTexture("Interface\\PaperDollInfoFrame\\SkillFrame-BotLeft");
texture:SetHeight(4);
texture:SetPoint("TOPLEFT", frame, "TOPLEFT", 10, -70);
texture:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -10, -70);
texture:SetTexCoord(0.078125, 1, 0.59765625, 0.61328125);
 
 
-- Normal animation style dropdown.
dropdown = MSBTControls.CreateDropdown(frame);
objLocale = MSBTLocale.DROPDOWNS["animationStyle"];
dropdown:Configure(135, objLocale.label, objLocale.tooltip);
dropdown:SetPoint("TOPLEFT", texture, "BOTTOMLEFT", 5, -15);
dropdown:SetChangeHandler(
function (this, id)
ChangeAnimationStyle(id);
frame.previewSettings[frame.currentScrollArea].animationStyle = id;
frame.previewSettings[frame.currentScrollArea].direction = frame.directionDropdown:GetSelectedID();
frame.previewSettings[frame.currentScrollArea].behavior = frame.behaviorDropdown:GetSelectedID();
end
);
frame.animationStyleDropdown = dropdown;
 
-- Sticky animation style dropdown.
dropdown = MSBTControls.CreateDropdown(frame);
objLocale = MSBTLocale.DROPDOWNS["stickyAnimationStyle"];
dropdown:Configure(135, objLocale.label, objLocale.tooltip);
dropdown:SetPoint("LEFT", frame.animationStyleDropdown, "RIGHT", 15, 0);
dropdown:SetChangeHandler(
function (this, id)
ChangeStickyAnimationStyle(id);
frame.previewSettings[frame.currentScrollArea].stickyAnimationStyle = id;
frame.previewSettings[frame.currentScrollArea].stickyDirection = frame.stickyDirectionDropdown:GetSelectedID();
frame.previewSettings[frame.currentScrollArea].stickyBehavior = frame.stickyBehaviorDropdown:GetSelectedID();
end
);
frame.stickyAnimationStyleDropdown = dropdown;
 
-- Normal direction dropdown.
dropdown = MSBTControls.CreateDropdown(frame);
objLocale = MSBTLocale.DROPDOWNS["direction"];
dropdown:Configure(135,objLocale.label, objLocale.tooltip);
dropdown:SetPoint("TOPLEFT", frame.animationStyleDropdown, "BOTTOMLEFT", 0, -10);
dropdown:SetChangeHandler(
function (this, id)
frame.previewSettings[frame.currentScrollArea].direction = id;
end
);
frame.directionDropdown = dropdown;
 
-- Sticky direction dropdown.
dropdown = MSBTControls.CreateDropdown(frame);
objLocale = MSBTLocale.DROPDOWNS["direction"];
dropdown:Configure(135, objLocale.label, objLocale.tooltip);
dropdown:SetPoint("TOPLEFT", frame.stickyAnimationStyleDropdown, "BOTTOMLEFT", 0, -10);
dropdown:SetChangeHandler(
function (this, id)
frame.previewSettings[frame.scrollAreaDropdown:GetSelectedID()].stickyDirection = id;
end
);
frame.stickyDirectionDropdown = dropdown;
 
-- Normal behavior dropdown.
dropdown = MSBTControls.CreateDropdown(frame);
objLocale = MSBTLocale.DROPDOWNS["behavior"];
dropdown:Configure(135, objLocale.label, objLocale.tooltip);
dropdown:SetPoint("TOPLEFT", frame.directionDropdown, "BOTTOMLEFT", 0, -10);
dropdown:SetChangeHandler(
function (this, id)
frame.previewSettings[frame.currentScrollArea].behavior = id;
end
);
frame.behaviorDropdown = dropdown;
 
-- Sticky behavior dropdown.
dropdown = MSBTControls.CreateDropdown(frame);
objLocale = MSBTLocale.DROPDOWNS["behavior"];
dropdown:Configure(135, objLocale.label, objLocale.tooltip);
dropdown:SetPoint("TOPLEFT", frame.stickyDirectionDropdown, "BOTTOMLEFT", 0, -10);
dropdown:SetChangeHandler(
function (this, id)
frame.previewSettings[frame.currentScrollArea].stickyBehavior = id;
end
);
frame.stickyBehaviorDropdown = dropdown;
 
-- Normal text align dropdown.
dropdown = MSBTControls.CreateDropdown(frame);
objLocale = MSBTLocale.DROPDOWNS["textAlign"];
dropdown:Configure(135, objLocale.label, objLocale.tooltip);
dropdown:SetPoint("TOPLEFT", frame.behaviorDropdown, "BOTTOMLEFT", 0, -10);
dropdown:SetChangeHandler(
function (this, id)
frame.previewSettings[frame.currentScrollArea].textAlignIndex = id;
end
);
for index, anchorPoint in ipairs(MSBTLocale.TEXT_ALIGNS) do
dropdown:AddItem(anchorPoint, index);
end
frame.textAlignDropdown = dropdown;
 
-- Sticky text align dropdown.
dropdown = MSBTControls.CreateDropdown(frame);
objLocale = MSBTLocale.DROPDOWNS["textAlign"];
dropdown:Configure(135, objLocale.label, objLocale.tooltip);
dropdown:SetPoint("TOPLEFT", frame.stickyBehaviorDropdown, "BOTTOMLEFT", 0, -10);
dropdown:SetChangeHandler(
function (this, id)
frame.previewSettings[frame.currentScrollArea].stickyTextAlignIndex = id;
end
);
for index, anchorPoint in ipairs(MSBTLocale.TEXT_ALIGNS) do
dropdown:AddItem(anchorPoint, index);
end
frame.stickyTextAlignDropdown = dropdown;
 
 
-- Middle horizontal bar.
texture = frame:CreateTexture(nil, "ARTWORK");
texture:SetTexture("Interface\\PaperDollInfoFrame\\SkillFrame-BotLeft");
texture:SetHeight(4);
texture:SetPoint("TOPLEFT", frame, "TOPLEFT", 10, -295);
texture:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -10, -295);
texture:SetTexCoord(0.078125, 1, 0.59765625, 0.61328125);
 
 
-- Scroll height slider.
local slider = MSBTControls.CreateSlider(frame);
objLocale = MSBTLocale.SLIDERS["scrollHeight"];
slider:Configure(135, objLocale.label, objLocale.tooltip);
slider:SetPoint("TOPLEFT", texture, "BOTTOMLEFT", 5, -15);
slider:SetMinMaxValues(50, 600);
slider:SetValueStep(5);
slider:SetValueChangedHandler(
function(this, value)
frame.previewSettings[frame.currentScrollArea].scrollHeight = value;
RepositionScrollAreaMoverFrame(frame.currentScrollArea);
end
);
frame.scrollHeightSlider = slider;
 
-- Scroll width slider.
slider = MSBTControls.CreateSlider(frame);
objLocale = MSBTLocale.SLIDERS["scrollWidth"];
slider:Configure(135, objLocale.label, objLocale.tooltip);
slider:SetPoint("LEFT", frame.scrollHeightSlider, "RIGHT", 15, 0);
slider:SetMinMaxValues(10, 800);
slider:SetValueStep(10);
slider:SetValueChangedHandler(
function(this, value)
frame.previewSettings[frame.currentScrollArea].scrollWidth = value;
RepositionScrollAreaMoverFrame(frame.currentScrollArea);
end
);
frame.scrollWidthSlider = slider;
 
-- Animation speed slider.
slider = MSBTControls.CreateSlider(frame);
objLocale = MSBTLocale.SLIDERS["scrollAnimationSpeed"];
slider:Configure(135, objLocale.label, objLocale.tooltip);
slider:SetPoint("TOPLEFT", frame.scrollHeightSlider, "BOTTOMLEFT", 0, -10);
slider:SetMinMaxValues(20, 250);
slider:SetValueStep(10);
slider:SetValueChangedHandler(
function(this, value)
frame.previewSettings[frame.currentScrollArea].animationSpeed = value;
end
);
frame.animationSpeedSlider = slider;
 
-- Inherit animation speed checkbox.
checkbox = MSBTControls.CreateCheckbox(frame);
objLocale = MSBTLocale.CHECKBOXES["inheritField"];
checkbox:Configure(20, objLocale.label, objLocale.tooltip);
checkbox:SetPoint("BOTTOMLEFT", frame.animationSpeedSlider, "BOTTOMRIGHT", 10, 5);
checkbox:SetClickHandler(
function (this, isChecked)
ToggleSliderInheritState(frame.animationSpeedSlider, isChecked, frame.previewSettings[frame.currentScrollArea].inheritedAnimationSpeed);
end
);
frame.animationSpeedCheckbox = checkbox;
 
 
-- X offset editbox.
local editbox = MSBTControls.CreateEditbox(frame);
objLocale = MSBTLocale.EDITBOXES["xOffset"];
editbox:Configure(135, objLocale.label, objLocale.tooltip);
editbox:SetPoint("TOPLEFT", frame.animationSpeedSlider, "BOTTOMLEFT", 0, -10);
editbox:SetTextChangedHandler(
function (this)
local newOffset = tonumber(this:GetText());
if (newOffset) then
frame.previewSettings[frame.currentScrollArea].offsetX = newOffset;
RepositionScrollAreaMoverFrame(frame.currentScrollArea);
end
end
);
frame.xOffsetEditbox = editbox;
 
-- Y offset editbox.
editbox = MSBTControls.CreateEditbox(frame);
objLocale = MSBTLocale.EDITBOXES["yOffset"];
editbox:Configure(135, objLocale.label, objLocale.tooltip);
editbox:SetPoint("LEFT", frame.xOffsetEditbox, "RIGHT", 15, 0);
editbox:SetTextChangedHandler(
function (this)
local newOffset = tonumber(this:GetText());
if (newOffset) then
frame.previewSettings[frame.currentScrollArea].offsetY = newOffset;
RepositionScrollAreaMoverFrame(frame.currentScrollArea);
end
end
);
frame.yOffsetEditbox = editbox;
 
 
-- Bottom horizontal bar.
texture = frame:CreateTexture(nil, "ARTWORK");
texture:SetTexture("Interface\\PaperDollInfoFrame\\SkillFrame-BotLeft");
texture:SetHeight(4);
texture:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", 10, 80);
texture:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -10, 80);
texture:SetTexCoord(0.078125, 1, 0.59765625, 0.61328125);
 
 
-- Preview button.
button = MSBTControls.CreateOptionButton(frame);
objLocale = MSBTLocale.BUTTONS["scrollAreasPreview"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("BOTTOM", frame, "BOTTOM", 0, 50);
button:SetClickHandler(
function (this)
SaveScrollAreaSettings(frame.previewSettings);
local name;
for saKey in pairs(frame.previewSettings) do
name = MSBTAnimations.scrollAreas[saKey].name;
MikSBT.DisplayMessage(name, saKey, nil, 255, 0, 0);
MikSBT.DisplayMessage(name, saKey, nil, 255, 255, 255);
MikSBT.DisplayMessage(name, saKey, true, 0, 0, 255);
end
end
);
 
-- Save button.
local button = MSBTControls.CreateOptionButton(frame);
objLocale = MSBTLocale.BUTTONS["genericSave"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("BOTTOMRIGHT", frame, "BOTTOM", -10, 20);
button:SetClickHandler(
function (this)
SaveScrollAreaSettings(frame.previewSettings);
frame:Hide();
end
);
 
-- Cancel button.
button = MSBTControls.CreateOptionButton(frame);
objLocale = MSBTLocale.BUTTONS["genericCancel"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("BOTTOMLEFT", frame, "BOTTOM", 10, 20);
button:SetClickHandler(
function (this)
SaveScrollAreaSettings(frame.originalSettings);
frame:Hide();
end
);
 
-- Track internal values.
frame.moverFrames = {};
frame.originalSettings = {};
frame.previewSettings = {};
 
-- Give the frame a global name.
_G["MSBTScrollAreasConfigFrame"] = frame;
return frame;
end
 
 
-- ****************************************************************************
-- Shows the popup scroll area config screen.
-- ****************************************************************************
local function ShowScrollAreaConfig()
-- Create the frame if it hasn't already been.
if (not popupFrames.scrollAreaConfigFrame) then popupFrames.scrollAreaConfigFrame = CreateScrollAreaConfig(); end
 
local frame = popupFrames.scrollAreaConfigFrame;
 
-- Backup the original settings for previewing and cancelling.
CopyTempScrollAreaSettings(frame.originalSettings);
CopyTempScrollAreaSettings(frame.previewSettings);
 
-- Populate the scroll areas and setup the mover frames.
frame.scrollAreaDropdown:Clear();
for saKey, saSettings in pairs(MSBTAnimations.scrollAreas) do
frame.scrollAreaDropdown:AddItem(saSettings.name, saKey);
 
-- Create and reposition the scroll area mover frames.
CreateScrollAreaMoverFrame(saKey);
RepositionScrollAreaMoverFrame(saKey);
end
frame.scrollAreaDropdown:Sort();
frame.currentScrollArea = "Incoming";
frame.scrollAreaDropdown:SetSelectedID(frame.currentScrollArea);
ChangeConfigScrollArea(frame.currentScrollArea);
 
frame:Show();
end
 
 
-------------------------------------------------------------------------------
-- Scroll area selection frame functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Creates the popup scroll area selection frame.
-- ****************************************************************************
local function CreateScrollAreaSelection()
local frame = CreatePopup();
frame:SetWidth(350);
frame:SetHeight(150);
 
-- Title text.
local fontString = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall");
fontString:SetPoint("TOP", frame, "TOP", 0, -20);
frame.titleFontString = fontString;
 
 
-- Scroll area dropdown.
local dropdown = MSBTControls.CreateDropdown(frame);
objLocale = MSBTLocale.DROPDOWNS["outputScrollArea"];
dropdown:Configure(150, objLocale.label, objLocale.tooltip);
dropdown:SetPoint("TOPLEFT", frame, "TOPLEFT", 20, -45);
frame.scrollAreaDropdown = dropdown;
 
 
-- Okay button.
local button = MSBTControls.CreateOptionButton(frame);
local objLocale = MSBTLocale.BUTTONS["inputOkay"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("BOTTOMRIGHT", frame, "BOTTOM", -10, 20);
button:SetClickHandler(
function (this)
if (frame.saveHandler) then frame.saveHandler(frame.scrollAreaDropdown:GetSelectedID(), frame.saveArg1); end
frame:Hide();
end
);
frame.okayButton = button;
 
-- Cancel button.
button = MSBTControls.CreateOptionButton(frame);
objLocale = MSBTLocale.BUTTONS["inputCancel"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("BOTTOMLEFT", frame, "BOTTOM", 10, 20);
button:SetClickHandler(
function (this)
frame:Hide();
end
);
 
return frame;
end
 
 
-- ****************************************************************************
-- Shows the popup scroll area selection frame using the passed config.
-- ****************************************************************************
local function ShowScrollAreaSelection(configTable)
-- Don't do anything if required parameters weren't passed.
if (not configTable or not configTable.anchorFrame or not configTable.parentFrame) then return; end
 
-- Create the frame if it hasn't already been.
if (not popupFrames.scrollAreaSelectionFrame) then popupFrames.scrollAreaSelectionFrame = CreateScrollAreaSelection(); end
 
-- Set parent.
local frame = popupFrames.scrollAreaSelectionFrame;
ChangePopupParent(frame, configTable.parentFrame)
 
-- Populate data.
frame.titleFontString:SetText(configTable.title);
 
-- Scroll areas.
frame.scrollAreaDropdown:Clear();
for saKey, saSettings in pairs(MSBTAnimations.scrollAreas) do
frame.scrollAreaDropdown:AddItem(saSettings.name, saKey);
end
frame.scrollAreaDropdown:Sort();
frame.scrollAreaDropdown:SetSelectedID("Incoming");
 
 
-- Configure the frame.
frame.saveHandler = configTable.saveHandler;
frame.saveArg1 = configTable.saveArg1;
frame.hideHandler = configTable.hideHandler;
frame:ClearAllPoints();
frame:SetPoint(configTable.anchorPoint or "TOPLEFT", configTable.anchorFrame, configTable.relativePoint or "BOTTOMLEFT");
frame:Show();
frame:Raise();
end
 
 
-------------------------------------------------------------------------------
-- Event frame functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Populates the available sounds for the event along with the passed custom
-- sound file.
-- ****************************************************************************
local function PopulateEventSounds(selectedSound)
local controls = popupFrames.eventFrame.controls;
 
local isCustomSound = selectedSound and true;
controls.soundDropdown:Clear();
for soundName in pairs(MSBTAnimations.sounds) do
if (soundName ~= NONE) then controls.soundDropdown:AddItem(MSBTLocale.SOUNDS[soundName] or soundName, soundName); end
if (soundName == selectedSound) then isCustomSound = nil; end
end
controls.soundDropdown:AddItem(NONE, "");
controls.soundDropdown:Sort();
if (isCustomSound) then controls.soundDropdown:AddItem(selectedSound, selectedSound); end
controls.soundDropdown:SetSelectedID(selectedSound or "");
end
 
 
-- ****************************************************************************
-- Enables the controls on the event popup.
-- ****************************************************************************
local function EnableEventControls()
for name, frame in pairs(popupFrames.eventFrame.controls) do
if (frame.Enable) then frame:Enable(); end
end
end
 
 
-- ****************************************************************************
-- Validates if the passed skill name does not already exist and is valid.
-- ****************************************************************************
local function ValidateSoundFileName(fileName)
if (not string.find(fileName, ".mp3") and not string.find(fileName, ".wav")) then
return MSBTLocale.MSG_INVALID_SOUND_FILE;
end
end
 
 
-- ****************************************************************************
-- Adds a custom sound file to for the event.
-- ****************************************************************************
local function AddCustomSoundFile(settings)
PopulateEventSounds(settings.inputText);
end
 
 
-- ****************************************************************************
-- Creates the popup event settings frame.
-- ****************************************************************************
local function CreateEvent()
local frame = CreatePopup();
frame:SetWidth(320);
frame:SetHeight(370);
frame.controls = {};
local controls = frame.controls;
 
-- Title text.
local fontString = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall");
fontString:SetPoint("TOP", frame, "TOP", 0, -20);
frame.titleFontString = fontString;
 
-- Scroll area dropdown.
local dropdown = MSBTControls.CreateDropdown(frame);
objLocale = MSBTLocale.DROPDOWNS["outputScrollArea"];
dropdown:Configure(150, objLocale.label, objLocale.tooltip);
dropdown:SetPoint("TOPLEFT", frame, "TOPLEFT", 20, -60);
controls.scrollAreaDropdown = dropdown;
 
-- Output message editbox.
local editbox = MSBTControls.CreateEditbox(frame);
local objLocale = MSBTLocale.EDITBOXES["eventMessage"];
editbox:Configure(250, objLocale.label, nil);
editbox:SetPoint("TOPLEFT", controls.scrollAreaDropdown, "BOTTOMLEFT", 0, -20);
controls.messageEditbox = editbox;
 
-- Sound dropdown.
local dropdown = MSBTControls.CreateDropdown(frame);
objLocale = MSBTLocale.DROPDOWNS["sound"];
dropdown:Configure(150, objLocale.label, objLocale.tooltip);
dropdown:SetPoint("TOPLEFT", controls.messageEditbox, "BOTTOMLEFT", 0, -20);
controls.soundDropdown = dropdown;
 
-- Edit trigger classes button.
local button = MSBTControls.CreateIconButton(frame, "Configure");
local objLocale = MSBTLocale.BUTTONS["customSound"];
button:SetTooltip(objLocale.tooltip);
button:SetPoint("LEFT", controls.soundDropdown, "RIGHT", 10, -5);
button:SetClickHandler(
function (this)
local objLocale = MSBTLocale.EDITBOXES["soundFile"];
EraseTable(tempConfig);
tempConfig.editboxLabel = objLocale.label;
tempConfig.editboxTooltip = objLocale.tooltip;
tempConfig.parentFrame = frame;
tempConfig.anchorFrame = this;
tempConfig.anchorPoint = "BOTTOMRIGHT";
tempConfig.relativePoint = "TOPRIGHT";
tempConfig.validateHandler = ValidateSoundFileName;
tempConfig.saveHandler = AddCustomSoundFile;
tempConfig.hideHandler = EnableEventControls;
DisableControls(controls);
ShowInput(tempConfig);
end
);
controls[#controls+1] = button;
 
-- Always sticky checkbox.
local checkbox = MSBTControls.CreateCheckbox(frame);
objLocale = MSBTLocale.CHECKBOXES["stickyEvent"];
checkbox:Configure(28, objLocale.label, objLocale.tooltip);
checkbox:SetPoint("TOPLEFT", controls.soundDropdown, "BOTTOMLEFT", 0, -20);
controls.stickyCheckbox = checkbox;
 
 
-- Icon skill editbox.
editbox = MSBTControls.CreateEditbox(frame);
local objLocale = MSBTLocale.EDITBOXES["iconSkill"];
editbox:Configure(250, objLocale.label, objLocale.tooltip);
editbox:SetPoint("TOPLEFT", controls.stickyCheckbox, "BOTTOMLEFT", 0, -20);
controls.iconSkillEditbox = editbox;
 
 
 
-- Save button.
button = MSBTControls.CreateOptionButton(frame);
objLocale = MSBTLocale.BUTTONS["genericSave"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("BOTTOMRIGHT", frame, "BOTTOM", -10, 20);
button:SetClickHandler(
function (this)
EraseTable(returnSettings);
returnSettings.scrollArea = controls.scrollAreaDropdown:GetSelectedID();
returnSettings.message = controls.messageEditbox:GetText();
returnSettings.soundFile = controls.soundDropdown:GetSelectedID();
returnSettings.alwaysSticky = controls.stickyCheckbox:GetChecked();
returnSettings.iconSkill = controls.iconSkillEditbox:GetText();
if (frame.saveHandler) then frame.saveHandler(returnSettings, frame.saveArg1); end
frame:Hide();
end
);
controls[#controls+1] = button;
 
-- Cancel button.
button = MSBTControls.CreateOptionButton(frame);
objLocale = MSBTLocale.BUTTONS["genericCancel"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("BOTTOMLEFT", frame, "BOTTOM", 10, 20);
button:SetClickHandler(
function (this)
frame:Hide();
end
);
controls[#controls+1] = button;
 
return frame;
end
 
 
-- ****************************************************************************
-- Shows the popup event settings frame using the passed config.
-- ****************************************************************************
local function ShowEvent(configTable)
-- Don't do anything if required parameters weren't passed.
if (not configTable or not configTable.anchorFrame or not configTable.parentFrame) then return; end
 
-- Create the frame if it hasn't already been.
if (not popupFrames.eventFrame) then popupFrames.eventFrame = CreateEvent(); end
 
-- Set parent.
local frame = popupFrames.eventFrame;
ChangePopupParent(frame, configTable.parentFrame)
 
-- Populate data.
frame.titleFontString:SetText(configTable.title);
 
local controls = frame.controls;
controls.scrollAreaDropdown:Clear();
for saKey, saSettings in pairs(MSBTAnimations.scrollAreas) do
controls.scrollAreaDropdown:AddItem(saSettings.name, saKey);
end
controls.scrollAreaDropdown:Sort();
controls.scrollAreaDropdown:SetSelectedID(configTable.scrollArea);
 
local objLocale = MSBTLocale.EDITBOXES["eventMessage"];
controls.messageEditbox:SetText(configTable.message);
controls.messageEditbox:SetTooltip(objLocale.tooltip .. "\n\n" .. (configTable.codes or ""));
PopulateEventSounds(configTable.soundFile);
controls.stickyCheckbox:SetChecked(configTable.alwaysSticky);
controls.iconSkillEditbox:SetText(configTable.iconSkill);
 
 
-- Show / hide always sticky checkbox depending on if the event is a crit or not.
if (configTable.isCrit) then controls.stickyCheckbox:Hide(); else controls.stickyCheckbox:Show(); end
 
-- Show / hide icon skill editbox.
if (configTable.showIconSkillEditbox) then
frame:SetHeight(370);
controls.iconSkillEditbox:Show();
else
controls.iconSkillEditbox:Hide();
frame:SetHeight(310);
end
 
-- Configure the frame.
frame.saveHandler = configTable.saveHandler;
frame.saveArg1 = configTable.saveArg1;
frame.hideHandler = configTable.hideHandler;
frame:ClearAllPoints();
frame:SetPoint(configTable.anchorPoint or "TOPLEFT", configTable.anchorFrame, configTable.relativePoint or "BOTTOMLEFT");
frame:Show();
frame:Raise();
end
 
 
-------------------------------------------------------------------------------
-- Trigger classes frame functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Creates the popup classes frame.
-- ****************************************************************************
local function CreateClasses()
local frame = CreatePopup();
frame:SetWidth(270);
frame:SetHeight(320);
frame.classCheckboxes = {};
local classCheckboxes = frame.classCheckboxes;
 
-- Close button.
local button = CreateFrame("Button", nil, frame, "UIPanelCloseButton");
button:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -2, -2);
 
-- All classes checkbox.
local checkbox = MSBTControls.CreateCheckbox(frame);
objLocale = MSBTLocale.CHECKBOXES["allClasses"];
checkbox:Configure(24, objLocale.label, objLocale.tooltip);
checkbox:SetPoint("TOPLEFT", frame, "TOPLEFT", 20, -40);
checkbox:SetClickHandler(
function (this, isChecked)
frame.classes["ALL"] = isChecked and true or nil;
if (isChecked) then
for name, checkFrame in pairs(frame.classCheckboxes) do
checkFrame:SetChecked(true);
checkFrame:Disable();
end
else
for name, checkFrame in pairs(classCheckboxes) do
checkFrame:Enable();
checkFrame:SetChecked(frame.classes[checkFrame.associatedClass]);
end
end
if (frame.updateHandler) then frame.updateHandler(); end
end
);
frame.allClassesCheckbox = checkbox;
 
local anchor = checkbox;
for class in string.gmatch("DRUID HUNTER MAGE PALADIN PRIEST ROGUE SHAMAN WARLOCK WARRIOR", "[^ ]+") do
checkbox = MSBTControls.CreateCheckbox(frame);
checkbox:Configure(24, MSBTLocale.CLASS_NAMES[class], nil);
checkbox:SetPoint("TOPLEFT", anchor, "BOTTOMLEFT", anchor == frame.allClassesCheckbox and 20 or 0, anchor == frame.allClassesCheckbox and -10 or 0);
checkbox:SetClickHandler(
function (this, isChecked)
frame.classes[this.associatedClass] = isChecked and true or nil;
if (frame.updateHandler) then frame.updateHandler(); end
end
);
checkbox.associatedClass = class;
anchor = checkbox;
classCheckboxes[class .. "Checkbox"] = checkbox;
end
 
return frame;
end
 
 
-- ****************************************************************************
-- Shows the popup classes frame.
-- ****************************************************************************
local function ShowClasses(configTable)
-- Don't do anything if required parameters weren't passed.
if (not configTable or not configTable.anchorFrame or not configTable.parentFrame or not configTable.classes) then return; end
 
-- Create the frame if it hasn't already been.
if (not popupFrames.classesFrame) then popupFrames.classesFrame = CreateClasses(); end
 
-- Set parent.
local frame = popupFrames.classesFrame;
ChangePopupParent(frame, configTable.parentFrame)
 
-- Populate data.
if (configTable.classes["ALL"]) then
frame.allClassesCheckbox:SetChecked(true);
for name, checkFrame in pairs(frame.classCheckboxes) do
checkFrame:SetChecked(true);
checkFrame:Disable();
end
else
frame.allClassesCheckbox:SetChecked(false);
for name, checkFrame in pairs(frame.classCheckboxes) do
checkFrame:Enable();
checkFrame:SetChecked(configTable.classes[checkFrame.associatedClass]);
end
end
 
 
-- Configure the frame.
frame.classes = configTable.classes;
frame.updateHandler = configTable.updateHandler;
frame.hideHandler = configTable.hideHandler;
frame:ClearAllPoints();
frame:SetPoint(configTable.anchorPoint or "TOPLEFT", configTable.anchorFrame, configTable.relativePoint or "BOTTOMLEFT");
frame:Show();
frame:Raise();
end
 
 
-------------------------------------------------------------------------------
-- Trigger main event frame functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Sets up the controls on the passed frame using the passed control map
-- control values.
-- ****************************************************************************
local function SetupControls(frame, controlMap, controlValues)
-- Loop through the controls in the passed control map.
local control, controlType, value;
for _, controlData in ipairs(controlMap) do
control = frame[controlData.controlName];
if (control) then
controlType = controlData.controlType;
value = controlValues and controlValues[controlData.paramField];
 
-- Editbox.
if (controlType == "Editbox") then
if (controlData.locals) then control:SetLabel(controlData.locals.label); control:SetTooltip(controlData.locals.tooltip); end
control:SetText(value);
control:Show();
 
-- Slider.
elseif (controlType == "Slider") then
if (controlData.locals) then control:SetLabel(controlData.locals.label); control:SetTooltip(controlData.locals.tooltip); end
control:SetMinMaxValues(controlData.minValue, controlData.maxValue)
control:SetValueStep(controlData.step);
control:SetValue(value or controlData.default);
control:Show();
 
-- Dropdown.
elseif (controlType == "Dropdown") then
if (controlData.locals) then control:SetLabel(controlData.locals.label); control:SetTooltip(controlData.locals.tooltip); end
control:HideSelections();
control:Clear();
for k, v in pairs(controlData.dropdownItems) do
control:AddItem(v, k);
end
control:Sort();
control:Show();
control:SetSelectedID(value or controlData.default);
 
-- Checkbox.
elseif (controlType == "Checkbox") then
if (controlData.locals) then control:SetLabel(controlData.locals.label); control:SetTooltip(controlData.locals.tooltip); end
control:SetChecked(value);
control:Show();
end
end -- Control exists check.
end -- Controls loop.
end
 
 
-- ****************************************************************************
-- Sets up the controls for the selected main event.
-- ****************************************************************************
local function SetupMainEventControls(eventConditions)
-- Hide all controls and only show the ones for the category.
local frame = popupFrames.mainEventFrame;
frame.unitDropdown:Hide();
frame.hostileCheckbox:Hide();
frame.parameterEditbox:Hide();
frame.directionDropdown:Hide();
frame.parameterSlider:Hide();
 
local eventCategory = popupFrames.triggerFrame.mainEventCategories[frame.mainEventDropdown:GetSelectedID()];
local controlMap = frame.controlMap[eventCategory];
if (not controlMap) then return; end
 
SetupControls(frame, controlMap, eventConditions);
end
 
 
-- ****************************************************************************
-- Returns a table with the selected main event conditions set.
-- ****************************************************************************
local function GetMainEventConditions()
local frame = popupFrames.mainEventFrame;
local eventConditions = {};
 
local eventCategory = popupFrames.triggerFrame.mainEventCategories[frame.mainEventDropdown:GetSelectedID()];
local controlMap = frame.controlMap[eventCategory];
if (not controlMap) then return eventConditions; end
 
-- Loop through the controls for the condition type.
local control, controlType, value;
for _, controlData in ipairs(controlMap) do
control = frame[controlData.controlName];
 
if (control) then
controlType = controlData.controlType;
 
-- Editbox.
if (controlType == "Editbox") then
value = control:GetText();
 
-- Slider.
elseif (controlType == "Slider") then
value = control:GetValue();
 
-- Dropdown.
elseif (controlType == "Dropdown") then
value = control:GetSelectedID();
 
-- Checkbox.
elseif (controlType == "Checkbox") then
value = control:GetChecked() and true or nil;
end
end -- Control exists check.
 
-- Set the value for the parameter field.
eventConditions[controlData.paramField] = value;
end -- Controls loop.
 
return eventConditions;
end
 
 
-- ****************************************************************************
-- Creates the popup main event frame.
-- ****************************************************************************
local function CreateMainEvent()
local frame = CreatePopup();
frame:SetWidth(350);
frame:SetHeight(325);
 
-- Main event dropdown.
local dropdown = MSBTControls.CreateDropdown(frame);
local objLocale = MSBTLocale.DROPDOWNS["mainEvent"];
dropdown:Configure(200, objLocale.label, nil);
dropdown:SetListboxHeight(200);
dropdown:SetPoint("TOPLEFT", frame, "TOPLEFT", 20, -40);
dropdown:SetChangeHandler(
function (this, id)
SetupMainEventControls();
end
);
for eventType, eventName in pairs(MSBTLocale.TRIGGER_MAIN_EVENTS) do
dropdown:AddItem(eventName, eventType);
end
dropdown:Sort();
frame.mainEventDropdown = dropdown;
 
-- Unit dropdown.
local dropdown = MSBTControls.CreateDropdown(frame);
objLocale = MSBTLocale.DROPDOWNS["affectedUnit"];
dropdown:Configure(150, objLocale.label, objLocale.tooltip);
dropdown:SetListboxHeight(120);
dropdown:SetPoint("TOPLEFT", frame.mainEventDropdown, "BOTTOMLEFT", 0, -20);
frame.unitDropdown = dropdown;
 
-- Hostile checkbox.
local checkbox = MSBTControls.CreateCheckbox(frame);
objLocale = MSBTLocale.CHECKBOXES["hostileOnly"];
checkbox:Configure(20, objLocale.label, objLocale.tooltip);
checkbox:SetPoint("LEFT", frame.unitDropdown, "RIGHT", 20, -5);
frame.hostileCheckbox = checkbox;
 
-- Parameter editbox.
local editbox = MSBTControls.CreateEditbox(frame);
objLocale = MSBTLocale.EDITBOXES["skillName"];
editbox:Configure(0, objLocale.label, objLocale.tooltip);
editbox:SetPoint("TOPLEFT", dropdown, "BOTTOMLEFT", 0, -20);
editbox:SetPoint("RIGHT", frame, "RIGHT", -35, 0);
frame.parameterEditbox = editbox;
 
-- Direction dropdown.
local dropdown = MSBTControls.CreateDropdown(frame);
objLocale = MSBTLocale.DROPDOWNS["eventDirection"];
dropdown:Configure(150, objLocale.label, objLocale.tooltip);
dropdown:SetListboxHeight(120);
dropdown:SetPoint("TOPLEFT", frame.unitDropdown, "BOTTOMLEFT", 0, -20);
frame.directionDropdown = dropdown;
 
-- Parameter slider.
local slider = MSBTControls.CreateSlider(frame);
objLocale = MSBTLocale.SLIDERS["genericAmount"];
slider:Configure(180, objLocale.label, objLocale.tooltip);
slider:SetPoint("TOPLEFT", editbox, "BOTTOMLEFT", 0, -30);
frame.parameterSlider = slider;
 
 
-- Save button.
local button = MSBTControls.CreateOptionButton(frame);
objLocale = MSBTLocale.BUTTONS["genericSave"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("BOTTOMRIGHT", frame, "BOTTOM", -10, 20);
button:SetClickHandler(
function (this)
EraseTable(returnSettings);
returnSettings.eventType = frame.mainEventDropdown:GetSelectedID();
returnSettings.eventConditions = GetMainEventConditions();
if (frame.saveHandler) then frame.saveHandler(returnSettings, frame.saveArg1); end
frame:Hide();
end
);
 
-- Cancel button.
button = MSBTControls.CreateOptionButton(frame);
objLocale = MSBTLocale.BUTTONS["genericCancel"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("BOTTOMLEFT", frame, "BOTTOM", 10, 20);
button:SetClickHandler(
function (this)
frame:Hide();
end
);
 
 
local thresholdUnits = popupFrames.triggerFrame.thresholdUnits;
local typicalUnits = popupFrames.triggerFrame.typicalUnits;
local threholdDirections = {rising = MSBTLocale.MSG_RISES_ABOVE, declining = MSBTLocale.MSG_FALLS_BELOW};
local directions = {incoming = MSBTLocale.MSG_INCOMING, outgoing = MSBTLocale.MSG_OUTGOING};
 
-- Controls to show for each main event category.
local controlMap = {
auraapplication = {
{controlType="Dropdown", controlName="unitDropdown", dropdownItems=typicalUnits, paramField="unit", default="player"},
{controlType="Checkbox", controlName="hostileCheckbox", paramField="hostile"},
{controlType="Editbox", controlName="parameterEditbox", paramField="effect"},
{controlType="Slider", controlName="parameterSlider", paramField="amount", minValue=1, maxValue=10, step=1, default=1},
},
 
aurafade = {
{controlType="Dropdown", controlName="unitDropdown", dropdownItems=typicalUnits, paramField="unit", default="player"},
{controlType="Checkbox", controlName="hostileCheckbox", paramField="hostile"},
{controlType="Editbox", controlName="parameterEditbox", paramField="effect"},
},
 
threshold = {
{controlType="Dropdown", controlName="unitDropdown", dropdownItems=thresholdUnits, paramField="unit", default="player"},
{controlType="Checkbox", controlName="hostileCheckbox", paramField="hostile"},
{controlType="Dropdown", controlName="directionDropdown", dropdownItems=threholdDirections, paramField="direction", default="declining"},
{controlType="Slider", controlName="parameterSlider", paramField="threshold", minValue=1, maxValue=100, step=1, default=35},
},
 
inout = {
{controlType="Dropdown", controlName="directionDropdown", dropdownItems=directions, paramField="direction", default="incoming"},
},
 
cast = {
{controlType="Dropdown", controlName="unitDropdown", dropdownItems=typicalUnits, paramField="unit", default="player"},
{controlType="Editbox", controlName="parameterEditbox", paramField="effect"},
{controlType="Checkbox", controlName="hostileCheckbox", paramField="hostile"},
},
};
 
frame.controlMap = controlMap;
return frame;
end
 
 
-- ****************************************************************************
-- Shows the popup main event frame.
-- ****************************************************************************
local function ShowMainEvent(configTable)
-- Don't do anything if required parameters weren't passed.
if (not configTable or not configTable.anchorFrame or not configTable.parentFrame) then return; end
 
-- Create the frame if it hasn't already been.
if (not popupFrames.mainEventFrame) then popupFrames.mainEventFrame = CreateMainEvent(); end
 
-- Set parent.
local frame = popupFrames.mainEventFrame;
ChangePopupParent(frame, configTable.parentFrame)
 
-- Populate data.
frame.mainEventDropdown:SetSelectedID(configTable.eventType);
SetupMainEventControls(configTable.eventConditions);
 
-- Configure the frame.
frame.saveHandler = configTable.saveHandler;
frame.saveArg1 = configTable.saveArg1;
frame.hideHandler = configTable.hideHandler;
frame:ClearAllPoints();
frame:SetPoint(configTable.anchorPoint or "TOPLEFT", configTable.anchorFrame, configTable.relativePoint or "BOTTOMLEFT");
frame:Show();
frame:Raise();
end
 
 
-------------------------------------------------------------------------------
-- Trigger exception frame functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Sets up the controls for the selected trigger exception.
-- ****************************************************************************
local function SetupTriggerExceptionControls(exceptionConditions)
-- Hide all controls and only show the ones for the category.
local frame = popupFrames.triggerExceptionFrame;
frame.parameterEditbox:Hide();
frame.parameterSlider:Hide();
frame.parameterDropdown:Hide();
frame.reverseCheckbox:Hide();
 
local exceptionType = frame.exceptionDropdown:GetSelectedID();
local controlMap = frame.controlMap[exceptionType];
if (not controlMap) then return; end
 
SetupControls(frame, controlMap, exceptionConditions);
end
 
 
-- ****************************************************************************
-- Returns a table with the selected exception conditions set.
-- ****************************************************************************
local function GetExceptionConditions()
local frame = popupFrames.triggerExceptionFrame;
local exceptionConditions = {};
 
local exceptionType = frame.exceptionDropdown:GetSelectedID();
local controlMap = frame.controlMap[exceptionType];
if (not controlMap) then return exceptionConditions; end
 
-- Loop through the controls for the condition type.
local control, controlType, value;
for _, controlData in ipairs(controlMap) do
control = frame[controlData.controlName];
 
if (control) then
controlType = controlData.controlType;
 
-- Editbox.
if (controlType == "Editbox") then
value = control:GetText();
 
-- Slider.
elseif (controlType == "Slider") then
value = control:GetValue();
 
-- Dropdown.
elseif (controlType == "Dropdown") then
value = control:GetSelectedID();
 
-- Checkbox.
elseif (controlType == "Checkbox") then
value = control:GetChecked() and true or nil;
end
end -- Control exists check.
 
-- Set the value for the parameter field.
exceptionConditions[controlData.paramField] = value;
end -- Controls loop.
 
return exceptionConditions;
end
 
 
-- ****************************************************************************
-- Creates the popup main event frame.
-- ****************************************************************************
local function CreateTriggerException()
local frame = CreatePopup();
frame:SetWidth(350);
frame:SetHeight(240);
 
-- Exception dropdown.
local dropdown = MSBTControls.CreateDropdown(frame);
local objLocale = MSBTLocale.DROPDOWNS["triggerException"];
dropdown:Configure(200, objLocale.label, nil);
dropdown:SetListboxHeight(200);
dropdown:SetPoint("TOPLEFT", frame, "TOPLEFT", 20, -40);
dropdown:SetChangeHandler(
function (this, id)
SetupTriggerExceptionControls();
end
);
for exceptionType, exceptionName in pairs(MSBTLocale.TRIGGER_EXCEPTIONS) do
dropdown:AddItem(exceptionName, exceptionType);
end
dropdown:Sort();
frame.exceptionDropdown = dropdown;
 
-- Parameter editbox.
local editbox = MSBTControls.CreateEditbox(frame);
editbox:Configure(0, nil, nil);
editbox:SetPoint("TOPLEFT", dropdown, "BOTTOMLEFT", 0, -20);
editbox:SetPoint("RIGHT", frame, "RIGHT", -35, 0);
frame.parameterEditbox = editbox;
 
-- Parameter slider.
local slider = MSBTControls.CreateSlider(frame);
slider:Configure(180, nil, nil);
slider:SetPoint("TOPLEFT", dropdown, "BOTTOMLEFT", 0, -30);
frame.parameterSlider = slider;
 
-- Parameter dropdown.
local dropdown = MSBTControls.CreateDropdown(frame);
dropdown:Configure(150, nil, nil);
dropdown:SetListboxHeight(120);
dropdown:SetPoint("TOPLEFT", frame.exceptionDropdown, "BOTTOMLEFT", 0, -20);
frame.parameterDropdown = dropdown;
 
-- Reverse Logic checkbox.
local checkbox = MSBTControls.CreateCheckbox(frame);
checkbox:Configure(20, nil, nil);
checkbox:SetPoint("TOPLEFT", frame.parameterDropdown, "BOTTOMLEFT", 0, -20);
frame.reverseCheckbox = checkbox;
 
 
-- Save button.
local button = MSBTControls.CreateOptionButton(frame);
objLocale = MSBTLocale.BUTTONS["genericSave"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("BOTTOMRIGHT", frame, "BOTTOM", -10, 20);
button:SetClickHandler(
function (this)
EraseTable(returnSettings);
returnSettings.exceptionType = frame.exceptionDropdown:GetSelectedID();
returnSettings.exceptionConditions = GetExceptionConditions();
if (frame.saveHandler) then frame.saveHandler(returnSettings, frame.saveArg1); end
frame:Hide();
end
);
 
-- Cancel button.
button = MSBTControls.CreateOptionButton(frame);
objLocale = MSBTLocale.BUTTONS["genericCancel"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("BOTTOMLEFT", frame, "BOTTOM", 10, 20);
button:SetClickHandler(
function (this)
frame:Hide();
end
);
 
-- Get the localized warrior stances.
local warriorStances = {
[1] = GetSpellInfo(2457),
[2] = GetSpellInfo(71),
[3] = GetSpellInfo(2458),
};
 
-- Controls to show for exception category.
local controlMap = {
BuffActive = {
{controlType="Editbox", controlName="parameterEditbox", paramField="effect", locals=MSBTLocale.EDITBOXES["skillName"]},
{controlType="Checkbox", controlName="reverseCheckbox", paramField="reversed", locals=MSBTLocale.CHECKBOXES["reverseLogic"]},
},
 
InsufficientPower = {
{controlType="Slider", controlName="parameterSlider", paramField="amount", minValue=1, maxValue=100, step=1, default=20, locals=MSBTLocale.SLIDERS["genericAmount"]},
{controlType="Checkbox", controlName="reverseCheckbox", paramField="reversed", locals=MSBTLocale.CHECKBOXES["reverseLogic"]},
},
 
InsufficientComboPoints = {
{controlType="Slider", controlName="parameterSlider", paramField="amount", minValue=1, maxValue=5, step=1, default=5, locals=MSBTLocale.SLIDERS["genericAmount"]},
{controlType="Checkbox", controlName="reverseCheckbox", paramField="reversed", locals=MSBTLocale.CHECKBOXES["reverseLogic"]},
},
 
NotInArena = {
{controlType="Checkbox", controlName="reverseCheckbox", paramField="reversed", locals=MSBTLocale.CHECKBOXES["reverseLogic"]},
},
 
NotInPvPZone = {
{controlType="Checkbox", controlName="reverseCheckbox", paramField="reversed", locals=MSBTLocale.CHECKBOXES["reverseLogic"]},
},
 
RecentlyFired = {
{controlType="Slider", controlName="parameterSlider", paramField="duration", minValue=1, maxValue=10, step=1, default=5, locals=MSBTLocale.SLIDERS["genericAmount"]},
},
 
SkillUnavailable = {
{controlType="Editbox", controlName="parameterEditbox", paramField="effect", locals=MSBTLocale.EDITBOXES["skillName"]},
{controlType="Checkbox", controlName="reverseCheckbox", paramField="reversed", locals=MSBTLocale.CHECKBOXES["reverseLogic"]},
},
 
TrivialTarget = {
{controlType="Checkbox", controlName="reverseCheckbox", paramField="reversed", locals=MSBTLocale.CHECKBOXES["reverseLogic"]},
},
 
WarriorStance = {
{controlType="Dropdown", controlName="parameterDropdown", dropdownItems=warriorStances, paramField="stance", default=1, locals=MSBTLocale.DROPDOWNS["warriorStance"]},
{controlType="Checkbox", controlName="reverseCheckbox", paramField="reversed", locals=MSBTLocale.CHECKBOXES["reverseLogic"]},
},
};
 
frame.controlMap = controlMap;
return frame;
end
 
 
-- ****************************************************************************
-- Shows the popup trigger exception frame.
-- ****************************************************************************
local function ShowTriggerException(configTable)
-- Don't do anything if required parameters weren't passed.
if (not configTable or not configTable.anchorFrame or not configTable.parentFrame) then return; end
 
-- Create the frame if it hasn't already been.
if (not popupFrames.triggerExceptionFrame) then popupFrames.triggerExceptionFrame = CreateTriggerException(); end
 
-- Set parent.
local frame = popupFrames.triggerExceptionFrame;
ChangePopupParent(frame, configTable.parentFrame)
 
-- Populate data.
frame.exceptionDropdown:SetSelectedID(configTable.exceptionType);
SetupTriggerExceptionControls(configTable.exceptionConditions);
 
-- Configure the frame.
frame.saveHandler = configTable.saveHandler;
frame.saveArg1 = configTable.saveArg1;
frame.hideHandler = configTable.hideHandler;
frame:ClearAllPoints();
frame:SetPoint(configTable.anchorPoint or "TOPLEFT", configTable.anchorFrame, configTable.relativePoint or "BOTTOMLEFT");
frame:Show();
frame:Raise();
end
 
 
 
-------------------------------------------------------------------------------
-- Trigger frame functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Updates the classes font string based on what classes are selected.
-- ****************************************************************************
local function UpdateClassesText()
local frame = popupFrames.triggerFrame;
 
-- Get localized list of seleced classes.
local selectedClasses = "";
if (frame.classes["ALL"]) then
selectedClasses = MSBTLocale.CHECKBOXES["allClasses"].label;
else
for className in pairs(frame.classes) do
selectedClasses = selectedClasses .. MSBTLocale.CLASS_NAMES[className] .. ", ";
end
 
-- Strip off the extra comma and space.
selectedClasses = string.sub(selectedClasses, 1, -3);
end
 
frame.classesFontString:SetText(selectedClasses);
end
 
 
-- ****************************************************************************
-- Updates the main events listbox.
-- ****************************************************************************
local function UpdateMainEvents()
local frame = popupFrames.triggerFrame;
frame.mainEventsListbox:Clear();
for index, mainEvent in pairs(frame.mainEvents) do
frame.mainEventsListbox:AddItem(index)
end
end
 
 
-- ****************************************************************************
-- Updates the exceptions listbox.
-- ****************************************************************************
local function UpdateExceptions()
local frame = popupFrames.triggerFrame;
frame.exceptionsListbox:Clear();
for index in pairs(frame.exceptions) do
frame.exceptionsListbox:AddItem(index)
end
end
 
 
-- ****************************************************************************
-- Enables the controls on the trigger popup.
-- ****************************************************************************
local function EnableTriggerControls()
for name, frame in pairs(popupFrames.triggerFrame.controls) do
if (frame.Enable) then frame:Enable(); end
end
end
 
 
-- ****************************************************************************
-- Saves the main event the user entered to the trigger main event frame.
-- ****************************************************************************
local function SaveMainEvent(settings, eventNum)
local frame = popupFrames.triggerFrame;
frame.mainEvents[eventNum] = settings.eventType;
frame.eventConditions[eventNum] = settings.eventConditions;
UpdateMainEvents();
end
 
 
-- ****************************************************************************
-- Saves the exception the user entered to the trigger exception frame.
-- ****************************************************************************
local function SaveException(settings, exceptionNum)
local frame = popupFrames.triggerFrame;
frame.exceptions[exceptionNum] = settings.exceptionType;
frame.exceptionConditions[exceptionNum] = settings.exceptionConditions;
UpdateExceptions();
end
 
 
-- ****************************************************************************
-- Called when one of the main event edit buttons is clicked.
-- ****************************************************************************
local function EditMainEventButtonOnClick(this)
local frame = popupFrames.triggerFrame;
local line = this:GetParent();
 
EraseTable(tempConfig);
tempConfig.eventType = frame.mainEvents[line.eventNum];
tempConfig.eventConditions = frame.eventConditions[line.eventNum];
tempConfig.saveHandler = SaveMainEvent;
tempConfig.saveArg1 = line.eventNum;
tempConfig.parentFrame = frame;
tempConfig.anchorFrame = this;
tempConfig.hideHandler = EnableTriggerControls;
DisableControls(frame.controls);
ShowMainEvent(tempConfig);
end
 
 
-- ****************************************************************************
-- Called when one of the main event edit buttons is clicked.
-- ****************************************************************************
local function EditExceptionButtonOnClick(this)
local frame = popupFrames.triggerFrame;
local line = this:GetParent();
 
EraseTable(tempConfig);
tempConfig.exceptionType = frame.exceptions[line.exceptionNum];
tempConfig.exceptionConditions = frame.exceptionConditions[line.exceptionNum];
tempConfig.saveHandler = SaveException;
tempConfig.saveArg1 = line.exceptionNum;
tempConfig.parentFrame = frame;
tempConfig.anchorFrame = this;
tempConfig.anchorPoint = "BOTTOMLEFT";
tempConfig.relativePoint = "TOPLEFT";
tempConfig.hideHandler = EnableTriggerControls;
DisableControls(frame.controls);
ShowTriggerException(tempConfig);
end
 
 
-- ****************************************************************************
-- Called when one of the main event delete buttons is clicked.
-- ****************************************************************************
local function DeleteMainEventButtonOnClick(this)
local frame = popupFrames.triggerFrame;
local line = this:GetParent();
table.remove(frame.mainEvents, line.eventNum);
table.remove(frame.eventConditions, line.eventNum);
UpdateMainEvents();
end
 
 
-- ****************************************************************************
-- Called when one of the exception delete buttons is clicked.
-- ****************************************************************************
local function DeleteExceptionButtonOnClick(this)
local frame = popupFrames.triggerFrame;
local line = this:GetParent();
table.remove(frame.exceptions, line.exceptionNum);
table.remove(frame.exceptionConditions, line.exceptionNum);
UpdateExceptions();
end
 
 
-- ****************************************************************************
-- Called by listbox to create a line for main events.
-- ****************************************************************************
local function CreateMainEventsLine(this)
local controls = popupFrames.triggerFrame.controls;
local frame = CreateFrame("Button", nil, this);
frame:EnableMouse(false);
 
-- Edit event button.
local button = MSBTControls.CreateIconButton(frame, "Configure");
local objLocale = MSBTLocale.BUTTONS["editEventConditions"];
button:SetTooltip(objLocale.tooltip);
button:SetPoint("LEFT", frame, "LEFT", 0, 0);
button:SetClickHandler(EditMainEventButtonOnClick);
frame.editEventButton = button;
controls[#controls+1] = button;
 
 
-- Delete event button.
button = MSBTControls.CreateIconButton(frame, "Delete");
objLocale = MSBTLocale.BUTTONS["deleteMainEvent"];
button:SetTooltip(objLocale.tooltip);
button:SetPoint("RIGHT", frame, "RIGHT", -10, 0);
button:SetClickHandler(DeleteMainEventButtonOnClick);
controls[#controls+1] = button;
 
-- Event text.
local fontString = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall");
fontString:SetPoint("LEFT", frame.editEventButton, "RIGHT", 5, 0);
fontString:SetPoint("RIGHT", controls[#controls], "LEFT", -10, 0);
fontString:SetJustifyH("LEFT");
fontString:SetTextColor(1, 1, 1);
frame.eventFontString = fontString;
 
return frame;
end
 
 
-- ****************************************************************************
-- Called by listbox to create a line for main events.
-- ****************************************************************************
local function CreateExceptionsLine(this)
local controls = popupFrames.triggerFrame.controls;
local frame = CreateFrame("Button", nil, this);
frame:EnableMouse(false);
 
-- Edit exception button.
local button = MSBTControls.CreateIconButton(frame, "Configure");
local objLocale = MSBTLocale.BUTTONS["editExceptionConditions"];
button:SetTooltip(objLocale.tooltip);
button:SetPoint("LEFT", frame, "LEFT", 0, 0);
button:SetClickHandler(EditExceptionButtonOnClick);
frame.editExceptionButton = button;
controls[#controls+1] = button;
 
 
-- Delete exception button.
button = MSBTControls.CreateIconButton(frame, "Delete");
objLocale = MSBTLocale.BUTTONS["deleteException"];
button:SetTooltip(objLocale.tooltip);
button:SetPoint("RIGHT", frame, "RIGHT", -10, 0);
button:SetClickHandler(DeleteExceptionButtonOnClick);
controls[#controls+1] = button;
 
-- Exception text.
local fontString = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall");
fontString:SetPoint("LEFT", frame.editExceptionButton, "RIGHT", 5, 0);
fontString:SetPoint("RIGHT", controls[#controls], "LEFT", -10, 0);
fontString:SetJustifyH("LEFT");
fontString:SetTextColor(1, 1, 1);
frame.exceptionFontString = fontString;
 
return frame;
end
 
 
-- ****************************************************************************
-- Called by listbox to display a main event line.
-- ****************************************************************************
local function DisplayMainEventsLine(this, line, key, isSelected)
line.eventNum = key;
 
local frame = popupFrames.triggerFrame;
local eventType = frame.mainEvents[key];
local eventCategory = frame.mainEventCategories[eventType];
local eventText = MSBTLocale.TRIGGER_MAIN_EVENTS[eventType] or UNKNOWN;
local eventConditions = frame.eventConditions[key];
 
-- Threshold trigger.
if (eventCategory == "threshold") then
if (eventConditions.threshold) then eventText = eventText .. " - " .. tostring(eventConditions.threshold); end
if (eventConditions.unit) then eventText = eventText .. " - " .. frame.thresholdUnits[eventConditions.unit]; end
if (eventConditions.hostile) then eventText = eventText .. " - " .. MSBTLocale.MSG_HOSTILE; end
 
-- Incoming/Outgoing trigger.
elseif (eventCategory == "inout") then
if (eventConditions.direction == "incoming") then
eventText = eventText .. " - " .. MSBTLocale.MSG_INCOMING;
elseif (eventConditions.direction == "outgoing") then
eventText = eventText .. " - " .. MSBTLocale.MSG_OUTGOING;
end
 
-- Aura application trigger.
elseif (eventCategory == "auraapplication") then
if (eventConditions.effect) then eventText = eventText .. " - " .. eventConditions.effect; end
if (eventConditions.amount) then eventText = eventText .. " - " .. eventConditions.amount; end
if (eventConditions.unit) then eventText = eventText .. " - " .. frame.typicalUnits[eventConditions.unit]; end
if (eventConditions.hostile) then eventText = eventText .. " - " .. MSBTLocale.MSG_HOSTILE; end
 
 
-- Aura fade/Cast trigger.
elseif (eventCategory == "aurafade" or eventCategory == "cast") then
if (eventConditions.effect) then eventText = eventText .. " - " .. eventConditions.effect; end
if (eventConditions.unit) then eventText = eventText .. " - " .. frame.typicalUnits[eventConditions.unit]; end
if (eventConditions.hostile) then eventText = eventText .. " - " .. MSBTLocale.MSG_HOSTILE; end
end
 
line.eventFontString:SetText(eventText);
end
 
 
-- ****************************************************************************
-- Called by listbox to display an exception line.
-- ****************************************************************************
local function DisplayExceptionsLine(this, line, key, isSelected)
line.exceptionNum = key;
 
local frame = popupFrames.triggerFrame;
local exceptionType = frame.exceptions[key];
local exceptionCategory = frame.exceptionCategories[exceptionType];
local exceptionText = MSBTLocale.TRIGGER_EXCEPTIONS[exceptionType] or UNKNOWN;
local exceptionConditions = frame.exceptionConditions[key];
 
-- Skill condition.
if (exceptionCategory == "skill") then
if (exceptionConditions.effect) then exceptionText = exceptionText .. " - " .. exceptionConditions.effect; end
 
-- Amount condition.
elseif (exceptionCategory == "amount") then
if (exceptionConditions.amount) then exceptionText = exceptionText .. " - " .. exceptionConditions.amount; end
 
-- Duration condition.
elseif (exceptionCategory == "duration") then
if (exceptionConditions.duration) then exceptionText = exceptionText .. " - " .. exceptionConditions.duration; end
 
-- Stance condition.
elseif (exceptionCategory == "stance") then
if (exceptionConditions.stance) then exceptionText = exceptionText .. " - " .. exceptionConditions.stance; end
end
 
-- Logic Reversed.
if (exceptionConditions.reversed) then exceptionText = exceptionText .. " - " .. MSBTLocale.CHECKBOXES["reverseLogic"].label; end
 
line.exceptionFontString:SetText(exceptionText);
end
 
 
-- ****************************************************************************
-- Creates the popup trigger settings frame.
-- ****************************************************************************
local function CreateTriggerPopup()
local frame = CreatePopup();
frame:SetWidth(450);
frame:SetHeight(460);
frame.controls = {};
local controls = frame.controls;
 
-- Title text.
local fontString = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall");
fontString:SetPoint("TOP", frame, "TOP", 0, -20);
frame.titleFontString = fontString;
 
-- Trigger classes label.
fontString = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall");
fontString:SetPoint("TOPLEFT", frame, "TOPLEFT", 20, -50);
fontString:SetText(MSBTLocale.MSG_TRIGGER_CLASSES .. ":");
frame.classesLabel = fontString;
 
-- Edit trigger classes button.
local button = MSBTControls.CreateIconButton(frame, "Configure");
local objLocale = MSBTLocale.BUTTONS["editTriggerClasses"];
button:SetTooltip(objLocale.tooltip);
button:SetPoint("TOPLEFT", frame.classesLabel, "BOTTOMLEFT", 10, -5);
button:SetClickHandler(
function (this)
EraseTable(tempConfig);
tempConfig.parentFrame = frame;
tempConfig.anchorFrame = this;
tempConfig.classes = frame.classes;
tempConfig.updateHandler = UpdateClassesText;
tempConfig.hideHandler = EnableTriggerControls;
DisableControls(controls);
ShowClasses(tempConfig);
end
);
controls[#controls+1] = button;
 
-- Classes text.
fontString = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall");
fontString:SetPoint("LEFT", controls[#controls], "RIGHT", 10, -5);
fontString:SetPoint("RIGHT", frame, "RIGHT", -20, 0);
fontString:SetHeight(30);
fontString:SetJustifyH("LEFT");
fontString:SetJustifyV("TOP");
fontString:SetTextColor(1, 1, 1);
frame.classesFontString = fontString;
 
-- Main events label.
fontString = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall");
fontString:SetPoint("TOPLEFT", controls[#controls], "BOTTOMLEFT", -10, -15);
fontString:SetText(MSBTLocale.MSG_MAIN_EVENTS .. ":");
frame.mainEventsLabel = fontString;
 
-- Add main events button.
button = MSBTControls.CreateOptionButton(frame);
objLocale = MSBTLocale.BUTTONS["addMainEvent"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("LEFT", frame.mainEventsLabel, "RIGHT", 10, 0);
button:SetClickHandler(
function (this)
EraseTable(tempConfig);
tempConfig.eventType = "BuffApplication";
tempConfig.eventConditions = {amount=1, unit="player"};
tempConfig.saveHandler = SaveMainEvent;
tempConfig.saveArg1 = #frame.mainEvents + 1;
tempConfig.parentFrame = frame;
tempConfig.anchorFrame = this;
tempConfig.hideHandler = EnableTriggerControls;
DisableControls(frame.controls);
ShowMainEvent(tempConfig);
end
);
controls[#controls+1] = button;
 
-- Main events listbox.
local listbox = MSBTControls.CreateListbox(frame);
listbox:Configure(400, 100, 25);
listbox:SetPoint("TOPLEFT", frame.mainEventsLabel, "BOTTOMLEFT", 10, -10);
listbox:SetCreateLineHandler(CreateMainEventsLine);
listbox:SetDisplayHandler(DisplayMainEventsLine);
frame.mainEventsListbox = listbox;
controls[#controls+1] = listbox;
 
 
-- Trigger exceptions label.
fontString = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall");
fontString:SetPoint("TOPLEFT", frame.mainEventsListbox, "BOTTOMLEFT", -10, -15);
fontString:SetText(MSBTLocale.MSG_TRIGGER_EXCEPTIONS .. ":");
frame.triggerExceptionsLabel = fontString;
 
-- Add trigger exceptions button.
button = MSBTControls.CreateOptionButton(frame);
objLocale = MSBTLocale.BUTTONS["addTriggerException"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("LEFT", frame.triggerExceptionsLabel, "RIGHT", 10, 0);
button:SetClickHandler(
function (this)
EraseTable(tempConfig);
tempConfig.exceptionType = "RecentlyFired";
tempConfig.exceptionConditions = {duration=5};
tempConfig.saveHandler = SaveException;
tempConfig.saveArg1 = #frame.exceptions + 1;
tempConfig.parentFrame = frame;
tempConfig.anchorFrame = this;
tempConfig.anchorPoint = "BOTTOMLEFT";
tempConfig.relativePoint = "TOPLEFT";
tempConfig.hideHandler = EnableTriggerControls;
DisableControls(frame.controls);
ShowTriggerException(tempConfig);
end
);
controls[#controls+1] = button;
 
-- Trigger exceptions listbox.
listbox = MSBTControls.CreateListbox(frame);
listbox:Configure(400, 100, 25);
listbox:SetPoint("TOPLEFT", frame.triggerExceptionsLabel, "BOTTOMLEFT", 10, -10);
listbox:SetCreateLineHandler(CreateExceptionsLine);
listbox:SetDisplayHandler(DisplayExceptionsLine);
frame.exceptionsListbox = listbox;
controls[#controls+1] = listbox;
 
-- Save button.
button = MSBTControls.CreateOptionButton(frame);
objLocale = MSBTLocale.BUTTONS["genericSave"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("BOTTOMRIGHT", frame, "BOTTOM", -10, 20);
button:SetClickHandler(
function (this)
EraseTable(returnSettings);
-- Make the classes string.
if (not frame.classes["ALL"]) then
local sortedClasses = frame.sortedClasses;
EraseTable(sortedClasses);
for class in pairs(frame.classes) do
sortedClasses[#sortedClasses+1] = class;
end
table.sort(sortedClasses);
returnSettings.classes = table.concat(sortedClasses, ",");
end
 
-- Make the main events string.
if (next(frame.mainEvents)) then
local events = "";
for eventNum, eventType in ipairs(frame.mainEvents) do
events = events .. eventType .. "["
if (next(frame.eventConditions[eventNum])) then
for conditionName, conditionValue in PairsByKeys(frame.eventConditions[eventNum]) do
events = events .. conditionName .. "=" .. tostring(conditionValue) .. ";;";
end
events = string.sub(events, 1, -3);
end
events = events .. "]&&";
end
returnSettings.mainEvents = string.sub(events, 1, -3);
end
 
 
-- Make the exceptions string.
if (next(frame.exceptions)) then
local exceptions = "";
for exceptionNum, exceptionType in ipairs(frame.exceptions) do
exceptions = exceptions .. exceptionType .. "["
if (next(frame.exceptionConditions[exceptionNum])) then
for conditionName, conditionValue in PairsByKeys(frame.exceptionConditions[exceptionNum]) do
exceptions = exceptions .. conditionName .. "=" .. tostring(conditionValue) .. ";;";
end
exceptions = string.sub(exceptions, 1, -3);
end
exceptions = exceptions .. "]&&";
end
returnSettings.exceptions = string.sub(exceptions, 1, -3);
end
 
if (frame.saveHandler) then frame.saveHandler(returnSettings, frame.saveArg1); end
frame:Hide();
end
);
controls[#controls+1] = button;
 
-- Cancel button.
button = MSBTControls.CreateOptionButton(frame);
objLocale = MSBTLocale.BUTTONS["genericCancel"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("BOTTOMLEFT", frame, "BOTTOM", 10, 20);
button:SetClickHandler(
function (this)
frame:Hide();
end
);
controls[#controls+1] = button;
 
frame.classes = {};
frame.sortedClasses = {};
frame.mainEvents = {};
frame.eventConditions = {};
frame.exceptions = {};
frame.exceptionConditions = {};
frame.sortedKeys = {};
 
-- Localized unit types.
frame.thresholdUnits = { player = YOU, target = TARGET, focus = FOCUS, pet = PET };
frame.typicalUnits = { player = YOU, target = TARGET, focus = FOCUS, any = MSBTLocale.MSG_ANY };
 
 
-- Categories for main event.
frame.mainEventCategories = {
Health = "threshold", Mana = "threshold", Energy = "threshold", Rage = "threshold",
Crit = "inout", Block = "inout", Dodge = "inout", Parry = "inout",
BuffApplication = "auraapplication", BuffFade = "aurafade", DebuffApplication = "auraapplication", DebuffFade = "aurafade",
CastStart = "cast",
};
 
-- Categories for exceptions.
frame.exceptionCategories = {
BuffActive = "skill", InsufficientPower = "amount", InsufficientComboPoints = "amount",
RecentlyFired = "duration", SkillUnavailable = "skill", WarriorStance = "stance",
};
 
return frame;
end
 
 
-- ****************************************************************************
-- Shows the popup trigger settings frame using the passed config.
-- ****************************************************************************
local function ShowTrigger(configTable)
-- Don't do anything if required parameters weren't passed.
if (not configTable or not configTable.anchorFrame or not configTable.parentFrame) then return; end
 
-- Create the frame if it hasn't already been.
if (not popupFrames.triggerFrame) then popupFrames.triggerFrame = CreateTriggerPopup(); end
 
-- Set parent.
local frame = popupFrames.triggerFrame;
ChangePopupParent(frame, configTable.parentFrame)
 
 
-- Populate data.
local triggerKey = configTable.triggerKey;
local settings = MSBTProfiles.currentProfile.triggers[triggerKey];
frame.titleFontString:SetText(configTable.title);
 
-- Classes.
EraseTable(frame.classes);
if (settings.classes) then
for className in string.gmatch(settings.classes, "[^,]+") do
frame.classes[className] = true;
end
else
frame.classes["ALL"] = true;
end
UpdateClassesText();
 
-- Main events.
local conditions;
EraseTable(frame.mainEvents);
EraseTable(frame.eventConditions);
if (settings.mainEvents) then
for eventType, eventConditions in string.gmatch(settings.mainEvents .. "&&", "(.-)%[(.-)%]&&") do
frame.mainEvents[#frame.mainEvents+1] = eventType;
conditions = {};
for conditionName, conditionValue in string.gmatch(eventConditions .. ";;", "(.-)=(.-);;") do
conditions[conditionName] = ConvertType(conditionValue);
end
frame.eventConditions[#frame.eventConditions+1] = conditions;
end
end
UpdateMainEvents();
 
-- Exceptions.
EraseTable(frame.exceptions);
EraseTable(frame.exceptionConditions);
if (settings.exceptions) then
for exceptionType, exceptionConditions in string.gmatch(settings.exceptions .. "&&", "(.-)%[(.-)%]&&") do
frame.exceptions[#frame.exceptions+1] = exceptionType;
conditions = {};
for conditionName, conditionValue in string.gmatch(exceptionConditions .. ";;", "(.-)=(.-);;") do
conditions[conditionName] = ConvertType(conditionValue);
end
frame.exceptionConditions[#frame.exceptionConditions+1] = conditions;
end
end
UpdateExceptions();
 
-- Configure the frame.
frame.saveHandler = configTable.saveHandler;
frame.saveArg1 = configTable.saveArg1;
frame.hideHandler = configTable.hideHandler;
frame:ClearAllPoints();
frame:SetPoint(configTable.anchorPoint or "TOPLEFT", configTable.anchorFrame, configTable.relativePoint or "BOTTOMLEFT");
frame:Show();
frame:Raise();
end
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
-------------------------------------------------------------------------------
-- Skill list frame functions.
-------------------------------------------------------------------------------
 
-- ****************************************************************************
-- Enables the controls on the skill list popup.
-- ****************************************************************************
local function EnableSkillListControls()
for name, frame in pairs(popupFrames.skillListFrame.controls) do
if (frame.Enable) then frame:Enable(); end
end
end
 
 
-- ****************************************************************************
-- Validates if the passed skill name does not already exist and is valid.
-- ****************************************************************************
local function ValidateSkillListName(skillName)
if (not skillName or skillName == "") then
return MSBTLocale.MSG_INVALID_SKILL_NAME;
end
 
if (popupFrames.skillListFrame.skills[skillName]) then
return MSBTLocale.MSG_SKILL_ALREADY_EXISTS;
end
end
 
 
-- ****************************************************************************
-- Adds the passed skill name to the list of skills.
-- ****************************************************************************
local function SaveSkillListName(settings)
local skillName = settings.inputText;
local frame = popupFrames.skillListFrame;
if (frame.listType == "throttle") then
frame.skills[skillName] = 3;
elseif (frame.listType == "substitution") then
frame.skills[skillName] = settings.secondInputText;
else
frame.skills[skillName] = true;
end
 
frame.skillsListbox:AddItem(skillName, true);
end
 
 
-- ****************************************************************************
-- Called when one of the delete skill buttons is pressed.
-- ****************************************************************************
local function DeleteSkillButtonOnClick(this)
local line = this:GetParent();
popupFrames.skillListFrame.skills[line.skillName] = false;
popupFrames.skillListFrame.skillsListbox:RemoveItem(line.itemNumber);
end
 
 
-- ****************************************************************************
-- Called when one of the time slider changes.
-- ****************************************************************************
local function TimeSliderOnValueChanged(this, value)
local line = this:GetParent();
popupFrames.skillListFrame.skills[line.skillName] = value;
end
 
 
-- ****************************************************************************
-- Called by listbox to create a line for skill list popup.
-- ****************************************************************************
local function CreateSkillListLine(this)
local controls = popupFrames.skillListFrame.controls;
local frame = CreateFrame("Button", nil, this);
frame:EnableMouse(false);
 
-- Delete skill button.
local button = MSBTControls.CreateIconButton(frame, "Delete");
objLocale = MSBTLocale.BUTTONS["deleteSkill"];
button:SetTooltip(objLocale.tooltip);
button:SetPoint("RIGHT", frame, "RIGHT", -10, 0);
button:SetClickHandler(DeleteSkillButtonOnClick);
frame.deleteButton = button;
controls[#controls+1] = button;
 
-- Time slider.
local slider = MSBTControls.CreateSlider(frame);
objLocale = MSBTLocale.SLIDERS["skillThrottleTime"];
slider:Configure(120, objLocale.label, objLocale.tooltip);
slider:SetPoint("RIGHT", frame.deleteButton, "LEFT", -10, -5);
slider:SetMinMaxValues(1, 5);
slider:SetValueStep(1);
slider:SetValueChangedHandler(TimeSliderOnValueChanged);
frame.timeSlider = slider;
controls[#controls+1] = slider;
 
-- Skill name text.
local fontString = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall");
fontString:SetPoint("LEFT", frame, "LEFT", 5, 0);
fontString:SetPoint("RIGHT", frame.timeSlider, "LEFT", -10, 0);
fontString:SetJustifyH("LEFT");
fontString:SetTextColor(1, 1, 1);
frame.skillFontString = fontString;
 
return frame;
end
 
 
-- ****************************************************************************
-- Called by listbox to display a line.
-- ****************************************************************************
local function DisplaySkillListLine(this, line, key, isSelected)
local frame = popupFrames.skillListFrame;
line.skillName = key;
if (frame.listType == "throttle") then
line.skillFontString:SetText(key);
line.skillFontString:SetPoint("RIGHT", line.timeSlider, "LEFT", -10, 0);
line.timeSlider:Show();
line.timeSlider:SetValue(frame.skills[key] or 3);
elseif (frame.listType == "substitution") then
line.skillFontString:SetText(key .. " - " .. tostring(frame.skills[key]));
line.skillFontString:SetPoint("RIGHT", line.deleteButton, "LEFT", -10, 0);
line.timeSlider:Hide();
else
line.skillFontString:SetText(key);
line.skillFontString:SetPoint("RIGHT", line.deleteButton, "LEFT", -10, 0);
line.timeSlider:Hide();
end
end
 
 
-- ****************************************************************************
-- Creates the popup skill list frame.
-- ****************************************************************************
local function CreateSkillList()
local frame = CreatePopup();
frame:SetWidth(400);
frame:SetHeight(300);
frame.controls = {};
local controls = frame.controls;
 
-- Title text.
local fontString = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall");
fontString:SetPoint("TOP", frame, "TOP", 0, -20);
frame.titleFontString = fontString;
 
fontString = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall");
fontString:SetPoint("TOPLEFT", frame, "TOPLEFT", 20, -50);
fontString:SetText(MSBTLocale.MSG_SKILLS .. ":");
frame.skillsFontString = fontString;
 
-- Add skill button.
local button = MSBTControls.CreateOptionButton(frame);
objLocale = MSBTLocale.BUTTONS["addSkill"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("LEFT", frame.skillsFontString, "RIGHT", 10, 0);
button:SetClickHandler(
function (this)
local objLocale = MSBTLocale.EDITBOXES["skillName"];
EraseTable(tempConfig);
tempConfig.editboxLabel = objLocale.label;
tempConfig.editboxTooltip = objLocale.tooltip;
tempConfig.parentFrame = frame;
tempConfig.anchorFrame = this;
tempConfig.validateHandler = ValidateSkillListName;
tempConfig.saveHandler = SaveSkillListName;
tempConfig.hideHandler = EnableSkillListControls;
if (frame.listType == "substitution") then
objLocale = MSBTLocale.EDITBOXES["substitutionText"];
tempConfig.showSecondEditbox = true;
tempConfig.secondEditboxLabel = objLocale.label;
tempConfig.secondEditboxTooltip = objLocale.tooltip;
end
DisableControls(controls);
ShowInput(tempConfig);
end
);
frame.addSkillButton = button;
controls[#controls+1] = button;
 
-- Skills listbox.
local listbox = MSBTControls.CreateListbox(frame);
listbox:Configure(355, 180, 30);
listbox:SetPoint("TOPLEFT", frame.skillsFontString, "BOTTOMLEFT", 10, -10);
listbox:SetCreateLineHandler(CreateSkillListLine);
listbox:SetDisplayHandler(DisplaySkillListLine);
frame.skillsListbox = listbox;
controls[#controls+1] = listbox;
 
-- Save button.
button = MSBTControls.CreateOptionButton(frame);
objLocale = MSBTLocale.BUTTONS["genericSave"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("BOTTOMRIGHT", frame, "BOTTOM", -10, 20);
button:SetClickHandler(
function (this)
if (frame.saveHandler) then frame.saveHandler(frame.saveArg1); end
frame:Hide();
end
);
controls[#controls+1] = button;
 
-- Cancel button.
button = MSBTControls.CreateOptionButton(frame);
objLocale = MSBTLocale.BUTTONS["genericCancel"];
button:Configure(20, objLocale.label, objLocale.tooltip);
button:SetPoint("BOTTOMLEFT", frame, "BOTTOM", 10, 20);
button:SetClickHandler(
function (this)
frame:Hide();
end
);
controls[#controls+1] = button;
 
return frame;
end
 
 
-- ****************************************************************************
-- Shows the popup skill list frame using the passed config.
-- ****************************************************************************
local function ShowSkillList(configTable)
-- Don't do anything if required parameters weren't passed.
if (not configTable or not configTable.anchorFrame or not configTable.parentFrame or not configTable.skills) then return; end
 
-- Create the frame if it hasn't already been.
if (not popupFrames.skillListFrame) then popupFrames.skillListFrame = CreateSkillList(); end
 
-- Set parent.
local frame = popupFrames.skillListFrame;
ChangePopupParent(frame, configTable.parentFrame)
 
 
-- Populate data.
frame.titleFontString:SetText(configTable.title);
 
-- Skills.
frame.listType = configTable.listType;
frame.skills = configTable.skills;
frame.skillsListbox:Clear();
for skillName, value in pairs(configTable.skills) do
if (value) then frame.skillsListbox:AddItem(skillName); end
end
 
-- Configure the frame.
frame.saveHandler = configTable.saveHandler;
frame.saveArg1 = configTable.saveArg1;
frame.hideHandler = configTable.hideHandler;
frame:ClearAllPoints();
frame:SetPoint(configTable.anchorPoint or "TOPLEFT", configTable.anchorFrame, configTable.relativePoint or "BOTTOMLEFT");
frame:Show();
frame:Raise();
end
 
 
 
 
-------------------------------------------------------------------------------
-- Module interface.
-------------------------------------------------------------------------------
 
-- Protected Functions.
module.DisableControls = DisableControls;
module.ShowInput = ShowInput;
module.ShowAcknowledge = ShowAcknowledge;
module.ShowFont = ShowFont;
module.ShowPartialEffects = ShowPartialEffects;
module.ShowDamageColors = ShowDamageColors;
module.ShowScrollAreaConfig = ShowScrollAreaConfig;
module.ShowScrollAreaSelection = ShowScrollAreaSelection;
module.ShowEvent = ShowEvent;
module.ShowTrigger = ShowTrigger;
module.ShowSkillList = ShowSkillList;
module.ShowSubstitutionList = ShowSubstitutionList;
\ No newline at end of file
MSBT5_13/MSBTOptions/localization.lua New file
0,0 → 1,526
-------------------------------------------------------------------------------
-- Title: MSBT Options English Localization
-- Author: Mik
-------------------------------------------------------------------------------
 
-- Create options namespace.
MSBTOptions = {};
 
-- Local reference for faster access.
local MSBTLocale = MikSBT.Locale;
 
 
------------------------------
-- Interface object tables
------------------------------
 
MSBTLocale.CLASS_NAMES = {};
MSBTLocale.TABS = {};
MSBTLocale.CHECKBOXES = {};
MSBTLocale.DROPDOWNS = {};
MSBTLocale.BUTTONS = {};
MSBTLocale.EDITBOXES = {};
MSBTLocale.SLIDERS = {};
MSBTLocale.EVENT_CATEGORIES = {};
MSBTLocale.EVENT_CODES = {};
MSBTLocale.INCOMING_PLAYER_EVENTS = {};
MSBTLocale.INCOMING_PET_EVENTS = {};
MSBTLocale.OUTGOING_PLAYER_EVENTS = {};
MSBTLocale.OUTGOING_PET_EVENTS = {};
MSBTLocale.NOTIFICATION_EVENTS = {};
MSBTLocale.TRIGGER_MAIN_EVENTS = {};
MSBTLocale.TRIGGER_EXCEPTIONS = {};
MSBTLocale.OUTLINES = {};
MSBTLocale.TEXT_ALIGNS = {};
MSBTLocale.SOUNDS = {};
MSBTLocale.ANIMATION_STYLE_DATA = {};
 
 
-------------------------------------------------------------------------------
-- English Localization (Default)
-------------------------------------------------------------------------------
 
 
------------------------------
-- Interface messages
------------------------------
 
MSBTLocale.MSG_NEW_PROFILE = "New Profile";
MSBTLocale.MSG_PROFILE_ALREADY_EXISTS = "Profile already exists.";
MSBTLocale.MSG_INVALID_PROFILE_NAME = "Invalid profile name.";
MSBTLocale.MSG_NEW_SCROLL_AREA = "New Scroll Area";
MSBTLocale.MSG_SCROLL_AREA_ALREADY_EXISTS = "Scroll area name already exists.";
MSBTLocale.MSG_INVALID_SCROLL_AREA_NAME = "Invalid scroll area name.";
MSBTLocale.MSG_ACKNOWLEDGE_TEXT = "Are you sure you wish to perform this action?";
MSBTLocale.MSG_NORMAL_PREVIEW_TEXT = "Normal";
MSBTLocale.MSG_INVALID_SOUND_FILE = "Sound must be a .mp3 or .wav file.";
MSBTLocale.MSG_NEW_TRIGGER = "New Trigger";
MSBTLocale.MSG_TRIGGER_CLASSES = "Trigger Classes";
MSBTLocale.MSG_MAIN_EVENTS = "Main Events";
MSBTLocale.MSG_TRIGGER_EXCEPTIONS = "Trigger Exceptions";
MSBTLocale.MSG_SKILLS = "Skills";
MSBTLocale.MSG_SKILL_ALREADY_EXISTS = "Skill name already exists.";
MSBTLocale.MSG_INVALID_SKILL_NAME = "Invalid skill name.";
MSBTLocale.MSG_HOSTILE = "Hostile";
MSBTLocale.MSG_ANY = "Any";
MSBTLocale.MSG_RISES_ABOVE = "Rises Above";
MSBTLocale.MSG_FALLS_BELOW = "Falls Below";
 
 
------------------------------
-- Class Names.
------------------------------
 
local obj = MSBTLocale.CLASS_NAMES;
obj["DRUID"] = "Druid";
obj["HUNTER"] = "Hunter";
obj["MAGE"] = "Mage";
obj["PALADIN"] = "Paladin";
obj["PRIEST"] = "Priest";
obj["ROGUE"] = "Rogue";
obj["SHAMAN"] = "Shaman";
obj["WARLOCK"] = "Warlock";
obj["WARRIOR"] = "Warrior";
 
 
------------------------------
-- Interface tabs
------------------------------
 
obj = MSBTLocale.TABS;
obj[1] = { label="General", tooltip="Display general options."};
obj[2] = { label="Scroll Areas", tooltip="Display options for creating, deleting, and configuring scroll areas.\n\nMouse over the icon buttons for more information."};
obj[3] = { label="Events", tooltip="Display options for incoming, outgoing, and notification events.\n\nMouse over the icon buttons for more information."};
obj[4] = { label="Triggers", tooltip="Display options for the trigger system.\n\nMouse over the icon buttons for more information."};
obj[5] = { label="Spam Control", tooltip="Display options for controlling spam."};
obj[6] = { label="Cooldowns", tooltip="Display options for cooldown notifications."};
obj[7] = { label="Skill Icons", tooltip="Display options for skill icons."};
 
 
------------------------------
-- Interface checkboxes
------------------------------
 
obj = MSBTLocale.CHECKBOXES;
obj["enableMSBT"] = { label="Enable Mik's Scrolling Battle Text", tooltip="Enable MSBT."};
obj["stickyCrits"] = { label="Sticky Crits", tooltip="Display crits using the sticky style."};
obj["gameDamage"] = { label="Game Damage", tooltip="Display blizzard's default damage above the enemy's heads."};
obj["gameHealing"] = { label="Game Healing", tooltip="Display blizzard's default healing above the target's heads."};
obj["enableSounds"] = { label="Enable Sounds", tooltip="Play sounds that are assigned to events and triggers."};
obj["colorPartialEffects"] = { label="Color Partial Effects", tooltip="Apply specified colors to partial effects."};
obj["crushing"] = { label="Crushing Blows", tooltip="Display the crushing blows trailer."};
obj["glancing"] = { label="Glancing Hits", tooltip="Display the glancing hits trailer."};
obj["absorb"] = { label="Partial Absorbs", tooltip="Display partial absorb amounts."};
obj["block"] = { label="Partial Blocks", tooltip="Display partial block amounts."};
obj["resist"] = { label="Partial Resists", tooltip="Display partial resist amounts."};
obj["vulnerability"] = { label="Vulnerability Bonuses", tooltip="Display vulnerabliity bonus amounts."};
obj["overheal"] = { label="Overheals", tooltip="Display overhealing amounts."};
obj["colorDamageAmounts"] = { label="Color Damage Amounts", tooltip="Apply specified colors to damage amounts."};
obj["colorDamageEntry"] = { tooltip="Enable coloring for this damage type."};
obj["enableScrollArea"] = { tooltip="Enable the scroll area."};
obj["inheritField"] = { label="Inherit", tooltip="Inherit the field's value. Uncheck to override."};
obj["stickyEvent"] = { label="Always Sticky", tooltip="Always display the event using the sticky style."};
obj["enableTrigger"] = { tooltip="Enable the trigger."};
obj["allPowerGains"] = { label="ALL Power Gains", tooltip="Display all power gains including those that are not reported to the combat log.\n\nWARNING: This option is very spammy and will ignore the power threshold and throttling mechanics.\n\nNOT RECOMMENDED."};
obj["hyperRegen"] = { label="Hyper Regen", tooltip="Display power gains during fast regen abilities such as Innervate and Spirit Tap.\n\nNOTE: The gains shown will not be throttled."};
obj["abbreviateSkills"] = { label="Abbreviate Skills", tooltip="Abbreviates skill names (English only).\n\nThis can be overriden by each event with the %sl event code."};
obj["hideSkills"] = { label="Hide Skills", tooltip="Don't display skill names for incoming and outgoing events.\n\nYou will give up some customization capability at the event level if you choose to use this option since it causes the %s event code to be ignored."};
obj["hideNames"] = { label="Hide Names", tooltip="Don't display unit names for incoming and outgoing events.\n\nYou will give up some customization capability at the event level if you choose to use this option since it causes the %n event code to be ignored."};
obj["allClasses"] = { label="All Classes"};
obj["enableCooldowns"] = { label="Enable Cooldowns", tooltip="Display notifications when cooldowns complete."};
obj["enableIcons"] = { label="Enable Skill Icons", tooltip="Displays icons for events that have a skill when possible."};
obj["exclusiveSkills"] = { label="Exclusive Skill Names", tooltip="Only show skill names when an icon is not available."};
obj["hostileOnly"] = { label="Hostile Only", tooltip="Only fire the trigger if the selected unit is hostile."};
obj["reverseLogic"] = { label="Reverse Logic", tooltip="Reverses the meaning of the selected exception. For example, Buff Active would mean Buff Inactive."};
 
 
------------------------------
-- Interface dropdowns
------------------------------
 
obj = MSBTLocale.DROPDOWNS;
obj["profile"] = { label="Current Profile:", tooltip="Sets the current profile."};
obj["normalFont"] = { label="Normal Font:", tooltip="Sets the font that will be used for non-crits."};
obj["critFont"] = { label="Crit Font:", tooltip="Sets the font that will be used for crits."};
obj["normalOutline"] = { label="Normal Outline:", tooltip="Sets the outline style that will be used for non-crits."};
obj["critOutline"] = { label="Crit Outline:", tooltip="Sets the outline style that will be used for crits."};
obj["scrollArea"] = { label="Scroll Area:", tooltip="Selects the scroll area to configure."};
obj["sound"] = { label="Sound:", tooltip="Selects the sound to play when the event occurs."};
obj["animationStyle"] = { label="Animation Style:", tooltip="The animation style for non-sticky animations in the scroll area."};
obj["stickyAnimationStyle"] = { label="Sticky Style:", tooltip="The animation style for sticky animations in the scroll area."};
obj["direction"] = { label="Direction:", tooltip="The direction of the animation."};
obj["behavior"] = { label="Behavior:", tooltip="The behavior of the animation."};
obj["textAlign"] = { label="Text Align:", tooltip="The alignment of the text for the animation."};
obj["eventCategory"] = { label="Event Category:", tooltip="The category of events to configure."};
obj["outputScrollArea"] = { label="Output Scroll Area:", tooltip="Selects the scroll area to use for output."};
obj["mainEvent"] = { label="Main Event:"};
obj["affectedUnit"] = { label="Affected Unit:", tooltip="The unit the event must be associated with."};
obj["eventDirection"] = { label="Direction:", tooltip="The direction associated with the event."};
obj["triggerException"] = { label="Exception:"};
obj["warriorStance"] = { label="Warrior Stance:", tooltip="The stance the warrior is currently in."};
 
 
------------------------------
-- Interface buttons
------------------------------
 
obj = MSBTLocale.BUTTONS;
obj["copyProfile"] = { label="Copy Profile", tooltip="Copies the profile to a new profile with the name you specify."};
obj["resetProfile"] = { label="Reset Profile", tooltip="Resets the profile to the default settings."};
obj["deleteProfile"] = { label="Delete Profile", tooltip="Deletes the profile."};
obj["masterFont"] = { label="Master Fonts", tooltip="Allows you to setup the master font settings which will be inherited by all scroll areas and events within them, unless overridden."};
obj["partialEffects"] = { label="Partial Effects", tooltip="Allows you to setup which partial effects will be shown, if they are color coded, and in what color."};
obj["damageColors"] = { label="Damage Colors", tooltip="Allows you to setup whether or not amounts are color coded by damage type and what colors to use for each type."};
obj["inputOkay"] = { label=OKAY, tooltip="Accepts the input."};
obj["inputCancel"] = { label=CANCEL, tooltip="Cancels the input."};
obj["genericSave"] = { label=SAVE, tooltip="Saves the changes."};
obj["genericCancel"] = { label=CANCEL, tooltip="Cancels the changes."};
obj["addScrollArea"] = { label="Add Scroll Area", tooltip="Add a new scroll area the events and triggers can be assigned to."};
obj["configScrollAreas"] = { label="Configure Scroll Areas", tooltip="Configure the normal and sticky animation styles, text alignment, scroll width/height, and location of the scroll areas."};
obj["editScrollAreaName"] = { tooltip="Click to edit the name of the scroll area."};
obj["scrollAreaFontSettings"] = { tooltip="Click to edit the font settings for the scroll area which will be inherited by all events shown in the scroll area, unless overriden."};
obj["deleteScrollArea"] = { tooltip="Click to delete the scroll area."};
obj["scrollAreasPreview"] = { label="Preview", tooltip="Previews the changes."};
obj["toggleAll"] = { label="Toggle All", tooltip="Toggle the enable state of all events in the selected category."};
obj["moveAll"] = { label="Move All", tooltip="Moves all of the events in the selected category to the specified scroll area."};
obj["eventFontSettings"] = { tooltip="Click to edit the font settings for the event."};
obj["eventSettings"] = { tooltip="Click to edit the event settings such as the output scroll area, output message, sound, etc."};
obj["customSound"] = { tooltip="Click to enter a custom sound file." };
obj["addTrigger"] = { label="Add New Trigger", tooltip="Add a new trigger."};
obj["triggerSettings"] = { tooltip="Click to configure the trigger conditions."};
obj["deleteTrigger"] = { tooltip="Click to delete the trigger."};
obj["editTriggerClasses"] = { tooltip="Click to edit the classes the trigger applies to."};
obj["addMainEvent"] = { label="Add Event", tooltip="When ANY of these events occur and their defined conditions are true, the trigger will fire unless one of the exceptions specified below is true."};
obj["addTriggerException"] = { label="Add Exception", tooltip="When ANY of these exceptions are true, the trigger will not fire."};
obj["editEventConditions"] = { tooltip="Click to edit the conditions for the event."};
obj["deleteMainEvent"] = { tooltip="Click to delete the event."};
obj["editExceptionConditions"] = { tooltip="Click to edit the conditions for the exception."};
obj["deleteException"] = { tooltip="Click to delete the exception."};
obj["triggerEventTypes"] = { label="Trigger Event Types", tooltip="Sets which event types to search for the entered search pattern(s)."};
obj["throttleList"] = { label="Throttle List", tooltip="Set custom throttle times for specified skills."};
obj["mergeExclusions"] = { label="Merge Exclusions", tooltip="Prevent specified skills from being merged."};
obj["skillSuppressions"] = { label="Skill Suppressions", tooltip="Suppress skills by their name."};
obj["skillSubstitutions"] = { label="Skill Substitutions", tooltip="Substitute skill names with customized values."};
obj["addSkill"] = { label="Add Skill", tooltip="Add a new skill to the list."};
obj["deleteSkill"] = { tooltip="Click to delete the skill."};
obj["cooldownExclusions"] = { label="Cooldown Exclusions", tooltip="Specify skills that will ignore cooldown tracking."};
 
 
------------------------------
-- Interface editboxes
------------------------------
 
obj = MSBTLocale.EDITBOXES;
obj["copyProfile"] = { label="New profile name:", tooltip="Name of the new profile to copy the currently selected one to."};
obj["scrollAreaName"] = { label="New scroll area name:", tooltip="New name for the scroll area."};
obj["xOffset"] = { label="X Offset:", tooltip="The X offset of the selected scroll area."};
obj["yOffset"] = { label="Y Offset:", tooltip="The Y offset of the selected scroll area."};
obj["eventMessage"] = { label="Output message:", tooltip="The message that will be displayed when the event occurs."};
obj["soundFile"] = { label="Sound filename:", tooltip="The name of the sound file to play when the event occurs."};
obj["iconSkill"] = { label="Icon Skill:", tooltip="The name or spell ID of a skill whose icon will be displayed when the event occurs.\n\nMSBT will automatically try to figure out an appropriate icon if one is not specified.\n\nNOTE: A spell ID must be used in place of a name if the skill is not in the spellbook for the class that is playing when the event occurs. Most online databases such as wowhead can be used to discover it."};
obj["skillName"] = { label="Skill name:", tooltip="The name of the skill to add."};
obj["substitutionText"] = { label="Substition text:", tooltip="The text to be substituted for the skill name."};
 
 
------------------------------
-- Interface sliders
------------------------------
 
obj = MSBTLocale.SLIDERS;
obj["animationSpeed"] = { label="Animation Speed", tooltip="Sets the master animation speed.\n\nEach scroll area may also be configured to have its own independent speed."};
obj["normalFontSize"] = { label="Normal Size", tooltip="Sets the font size for non-crits."};
obj["normalFontOpacity"] = { label="Normal Opacity", tooltip="Sets the font opacity for non-crits."};
obj["critFontSize"] = { label="Crit Font Size", tooltip="Sets the font size for crits."};
obj["critFontOpacity"] = { label="Crit Opacity", tooltip="Sets the font opacity for crits."};
obj["scrollHeight"] = { label="Scroll Height", tooltip="The height of the scroll area."};
obj["scrollWidth"] = { label="Scroll Width", tooltip="The width of the scroll area."};
obj["scrollAnimationSpeed"] = { label="Animation Speed", tooltip="Sets the animation speed for the scroll area."};
obj["powerThreshold"] = { label="Power Threshold", tooltip="The threshold that power gains must exceed to be displayed."};
obj["healThreshold"] = { label="Heal Threshold", tooltip="The threshold that heals must exceed to be displayed."};
obj["damageThreshold"] = { label="Damage Threshold", tooltip="The threshold that damage must exceed to be displayed."};
obj["dotThrottleTime"] = { label="DoT Throttle Time", tooltip="The number of seconds to throttle DoTs."};
obj["hotThrottleTime"] = { label="HoT Throttle Time", tooltip="The number of seconds to throttle HoTs."};
obj["powerThrottleTime"] = { label="Power Throttle Time", tooltip="The number of seconds to throttle power changes."};
obj["skillThrottleTime"] = { label="Throttle Time", tooltip="The number of seconds to throttle the skill."};
obj["cooldownThreshold"] = { label="Cooldown Threshold", tooltip="Skills with a cooldown less than the specified number of seconds will not be displayed."};
obj["genericAmount"] = { label="Amount", tooltip="Select the amount."};
 
 
------------------------------
-- Event categories
------------------------------
obj = MSBTLocale.EVENT_CATEGORIES;
obj[1] = "Incoming Player";
obj[2] = "Incoming Pet";
obj[3] = "Outgoing Player";
obj[4] = "Outgoing Pet";
obj[5] = "Notification";
 
 
------------------------------
-- Event codes
------------------------------
 
obj = MSBTLocale.EVENT_CODES;
obj["DAMAGE_TAKEN"] = "%a - Amount of damage taken.\n";
obj["HEALING_TAKEN"] = "%a - Amount of healing taken.\n";
obj["DAMAGE_DONE"] = "%a - Amount of damage done.\n";
obj["HEALING_DONE"] = "%a - Amount of healing done.\n";
obj["ENERGY_AMOUNT"] = "%a - Amount of energy.\n";
obj["CP_AMOUNT"] = "%a - Amount of combo points you have.\n";
obj["HONOR_AMOUNT"] = "%a - Amount of honor.\n";
obj["REP_AMOUNT"] = "%a - Amount of reputation.\n";
obj["SKILL_AMOUNT"] = "%a - Amount of points you have in the skill.\n";
obj["EXPERIENCE_AMOUNT"] = "%a - Amount of experience you gained.\n";
obj["ATTACKER_NAME"] = "%n - Name of the attacker.\n";
obj["HEALER_NAME"] = "%n - Name of the healer.\n";
obj["ATTACKED_NAME"] = "%n - Name of the attacked unit.\n";
obj["HEALED_NAME"] = "%n - Name of the healed unit.\n";
obj["BUFFED_NAME"] = "%n - Name of the buffed unit.\n";
obj["SKILL_NAME"] = "%s - Name of the skill.\n";
obj["SPELL_NAME"] = "%s - Name of the spell.\n";
obj["DEBUFF_NAME"] = "%s - Name of the debuff.\n";
obj["BUFF_NAME"] = "%s - Name of the buff.\n";
obj["ITEM_BUFF_NAME"] = "%s - Name of the item buff.\n";
obj["EXTRA_ATTACKS"] = "%s - Name of skill granting the extra attacks.\n";
obj["SKILL_LONG"] = "%sl - Long form of %s. Used to override abbreviation for the event.\n";
obj["DAMAGE_TYPE_TAKEN"] = "%t - Type of damage taken.\n";
obj["DAMAGE_TYPE_DONE"] = "%t - Type of damage done.\n";
obj["ENVIRONMENTAL_DAMAGE"] = "%e - Name of the source of the damage (falling, drowning, lava, etc...)\n";
obj["FACTION_NAME"] = "%e - Name of the faction.\n";
obj["UNIT_KILLED"] = "%e - Name of the unit killed.\n";
obj["SHARD_NAME"] = "%e - Localized name of the soul shard.\n";
obj["EMOTE_TEXT"] = "%e - The text of the emote.\n";
obj["MONEY_TEXT"] = "%e - The money gained text.\n";
obj["COOLDOWN_NAME"] = "%e - The name of skill that is ready.\n"
obj["POWER_TYPE"] = "%p - Type of power (energy, rage, mana).\n";
 
 
------------------------------
-- Incoming events
------------------------------
 
obj = MSBTLocale.INCOMING_PLAYER_EVENTS;
obj[1] = { label="Melee Hits", tooltip="Enable incoming melee hits."};
obj[2] = { label="Melee Crits", tooltip="Enable incoming melee crits."};
obj[3] = { label="Melee Misses", tooltip="Enable incoming melee misses."};
obj[4] = { label="Melee Dodges", tooltip="Enable incoming melee dodges."};
obj[5] = { label="Melee Parries", tooltip="Enable incoming melee parries."};
obj[6] = { label="Melee Blocks", tooltip="Enable incoming melee blocks."};
obj[7] = { label="Melee Absorbs", tooltip="Enable absorbed incoming melee damage."};
obj[8] = { label="Melee Immunes", tooltip="Enable incoming melee damage you are immune to."};
obj[9] = { label="Skill Hits", tooltip="Enable incoming skill hits."};
obj[10] = { label="Skill Crits", tooltip="Enable incoming skill damage."};
obj[11] = { label="Skill DoTs", tooltip="Enable incoming skill damage over time."};
obj[12] = { label="Skill Misses", tooltip="Enable incoming skill misses."};
obj[13] = { label="Skill Dodges", tooltip="Enable incoming skill dodges."};
obj[14] = { label="Skill Parries", tooltip="Enable incoming skill parries."};
obj[15] = { label="Skill Blocks", tooltip="Enable incoming skill blocks."};
obj[16] = { label="Spell Resists", tooltip="Enable incoming spell resists."};
obj[17] = { label="Skill Absorbs", tooltip="Enable absorbed damage from incoming skills."};
obj[18] = { label="Skill Immunes", tooltip="Enable incoming skill damage you are immune to."};
obj[19] = { label="Skill Reflects", tooltip="Enable incoming skill damage you reflected."};
obj[20] = { label="Spell Interrupts", tooltip="Enable incoming spell interrupts."};
obj[21] = { label="Heals", tooltip="Enable incoming heals."};
obj[22] = { label="Crit Heals", tooltip="Enable incoming crit heals."};
obj[23] = { label="Heals Over Time", tooltip="Enable incoming heals over time."};
obj[24] = { label="Environmental Damage", tooltip="Enable environmental (falling, drowning, lava, etc...) damage."};
 
obj = MSBTLocale.INCOMING_PET_EVENTS;
obj[1] = { label="Melee Hits", tooltip="Enable your pet's incoming melee hits."};
obj[2] = { label="Melee Crits", tooltip="Enable your pet's incoming melee crits."};
obj[3] = { label="Melee Misses", tooltip="Enable your pet's incoming melee misses."};
obj[4] = { label="Melee Dodges", tooltip="Enable your pet's incoming melee dodges."};
obj[5] = { label="Melee Parries", tooltip="Enable your pet's incoming melee parries."};
obj[6] = { label="Melee Blocks", tooltip="Enable your pet's incoming melee blocks."};
obj[7] = { label="Melee Absorbs", tooltip="Enable your pet's absorbed incoming melee damage."};
obj[8] = { label="Melee Immunes", tooltip="Enable melee damage your is pet immune to."};
obj[9] = { label="Skill Hits", tooltip="Enable your pet's incoming skill hits."};
obj[10] = { label="Skill Crits", tooltip="Enable your pet's incoming skill crits."};
obj[11] = { label="Skill DoTs", tooltip="Enable your pet's incoming skill damage over time."};
obj[12] = { label="Skill Misses", tooltip="Enable your pet's incoming skill misses."};
obj[13] = { label="Skill Dodges", tooltip="Enable your pet's incoming skill dodges."};
obj[14] = { label="Skill Parries", tooltip="Enable your pet's incoming skill parries."};
obj[15] = { label="Skill Blocks", tooltip="Enable your pet's incoming skill blocks."};
obj[16] = { label="Spell Resists", tooltip="Enable your pet's incoming spell resists."};
obj[17] = { label="Skill Absorbs", tooltip="Enable absorbed damage from your pet's incoming skills."};
obj[18] = { label="Skill Immunes", tooltip="Enable incoming skill damage your pet is immune to."};
obj[19] = { label="Heals", tooltip="Enable your pet's incoming heals."};
obj[20] = { label="Crit Heals", tooltip="Enable your pet's incoming crit heals."};
obj[21] = { label="Heals Over Time", tooltip="Enable your pet's incoming heals over time."};
 
 
------------------------------
-- Outgoing events
------------------------------
 
obj = MSBTLocale.OUTGOING_PLAYER_EVENTS;
obj[1] = { label="Melee Hits", tooltip="Enable outgoing melee hits."};
obj[2] = { label="Melee Crits", tooltip="Enable outgoing melee crits."};
obj[3] = { label="Melee Misses", tooltip="Enable outgoing melee misses."};
obj[4] = { label="Melee Dodges", tooltip="Enable outgoing melee dodges."};
obj[5] = { label="Melee Parries", tooltip="Enable outgoing melee parries."};
obj[6] = { label="Melee Blocks", tooltip="Enable outgoing melee blocks."};
obj[7] = { label="Melee Absorbs", tooltip="Enable absorbed outgoing melee damage."};
obj[8] = { label="Melee Immunes", tooltip="Enable outgoing melee damage the enemy is immune to."};
obj[9] = { label="Melee Evades", tooltip="Enable outgoing melee evades."};
obj[10] = { label="Skill Hits", tooltip="Enable outgoing skill hits."};
obj[11] = { label="Skill Crits", tooltip="Enable outgoing skill crits."};
obj[12] = { label="Skill DoTs", tooltip="Enable outgoing skill damage over time."};
obj[13] = { label="Skill Misses", tooltip="Enable outgoing skill misses."};
obj[14] = { label="Skill Dodges", tooltip="Enable outgoing skill dodges."};
obj[15] = { label="Skill Parries", tooltip="Enable outgoing skill parries."};
obj[16] = { label="Skill Blocks", tooltip="Enable outgoing skill blocks."};
obj[17] = { label="Spell Resists", tooltip="Enable outgoing spell resists."};
obj[18] = { label="Skill Absorbs", tooltip="Enable absorbed damage from outgoing skills."};
obj[19] = { label="Skill Immunes", tooltip="Enable outgoing skill damage the enemy is immune to."};
obj[20] = { label="Skill Reflects", tooltip="Enable outgoing skill damage reflected back to you."};
obj[21] = { label="Spell Interrupts", tooltip="Enable outgoing spell interrupts."};
obj[22] = { label="Skill Evades", tooltip="Enable outgoing skill evades."};
obj[23] = { label="Heals", tooltip="Enable outgoing heals."};
obj[24] = { label="Crit Heals", tooltip="Enable outgoing crit heals."};
obj[25] = { label="Heals Over Time", tooltip="Enable outgoing heals over time."};
obj[26] = { label="Dispels", tooltip="Enable outgoing dispels."};
 
obj = MSBTLocale.OUTGOING_PET_EVENTS;
obj[1] = { label="Melee Hits", tooltip="Enable your pet's outgoing melee hits."};
obj[2] = { label="Melee Crits", tooltip="Enable your pet's outgoing melee crits."};
obj[3] = { label="Melee Misses", tooltip="Enable your pet's outgoing melee misses."};
obj[4] = { label="Melee Dodges", tooltip="Enable your pet's outgoing melee dodges."};
obj[5] = { label="Melee Parries", tooltip="Enable your pet's outgoing melee parries."};
obj[6] = { label="Melee Blocks", tooltip="Enable your pet's outgoing melee blocks."};
obj[7] = { label="Melee Absorbs", tooltip="Enable your pet's absorbed outgoing melee damage."};
obj[8] = { label="Melee Immunes", tooltip="Enable your pet's outgoing melee damage the enemy is immune to."};
obj[9] = { label="Melee Evades", tooltip="Enable your pet's outgoing melee evades."};
obj[10] = { label="Skill Hits", tooltip="Enable your pet's outgoing skill hits."};
obj[11] = { label="Skill Crits", tooltip="Enable your pet's outgoing skill crits."};
obj[12] = { label="Skill DoTs", tooltip="Enable outgoing skill damage over time."};
obj[13] = { label="Skill Misses", tooltip="Enable your pet's outgoing skill misses."};
obj[14] = { label="Skill Dodges", tooltip="Enable your pet's outgoing skill dodges."};
obj[15] = { label="Skill Parries", tooltip="Enable your pet's outgoing ability parries."};
obj[16] = { label="Skill Blocks", tooltip="Enable your pet's outgoing skill blocks."};
obj[17] = { label="Spell Resists", tooltip="Enable your pet's outgoing spell resists."};
obj[18] = { label="Skill Absorbs", tooltip="Enable your pet's absorbed damage from outgoing skills."};
obj[19] = { label="Skill Immunes", tooltip="Enable your pet's outgoing skill damage the enemy is immune to."};
obj[20] = { label="Skill Evades", tooltip="Enable your pet's outgoing skill evades."};
obj[21] = { label="Dispels", tooltip="Enable your pet's outgoing dispels."};
 
 
------------------------------
-- Notification events
------------------------------
 
obj = MSBTLocale.NOTIFICATION_EVENTS;
obj[1] = { label="Debuffs", tooltip="Enable debuffs you are afflicted by."};
obj[2] = { label="Buffs", tooltip="Enable buffs you receive."};
obj[3] = { label="Item Buffs", tooltip="Enable buffs your items receive."};
obj[4] = { label="Debuff Fades", tooltip="Enable debuffs that have faded from you."};
obj[5] = { label="Buff Fades", tooltip="Enable buffs that have faded from you."};
obj[6] = { label="Item Buff Fades", tooltip="Enable item buffs that have faded from you."};
obj[7] = { label="Enter Combat", tooltip="Enable when you have entered combat."};
obj[8] = { label="Leave Combat", tooltip="Enable when you have left combat."};
obj[9] = { label="Power Gains", tooltip="Enable when you gain extra mana, rage, or energy."};
obj[10] = { label="Power Losses", tooltip="Enable when you lose mana, rage, or energy from drains."};
obj[11] = { label="Combo Point Gains", tooltip="Enable when you gain combo points."};
obj[12] = { label="Combo Points Full", tooltip="Enable when you attain full combo points."};
obj[13] = { label="Honor Gains", tooltip="Enable when you gain honor."};
obj[14] = { label="Reputation Gains", tooltip="Enable when you gain reputation."};
obj[15] = { label="Reputation Losses", tooltip="Enable when you lose reputation."};
obj[16] = { label="Skill Gains", tooltip="Enable when you gain skill points."};
obj[17] = { label="Experience Gains", tooltip="Enable when you gain experience points."};
obj[18] = { label="Player Killing Blows", tooltip="Enable when you get a killing blow against a hostile player."};
obj[19] = { label="NPC Killing Blows", tooltip="Enable when you get a killing blow against an NPC."};
obj[20] = { label="Soul Shard Gains", tooltip="Enable when you gain a soul shard."};
obj[21] = { label="Extra Attacks", tooltip="Enable when you gain extra attacks such as windfury, thrash, sword spec, etc."};
obj[22] = { label="Enemy Buff Gains", tooltip="Enable buffs your currently targeted enemy gains."};
obj[23] = { label="Monster Emotes", tooltip="Enable emotes by the currently targeted monster."};
obj[24] = { label="Money Gains", tooltip="Enable money you gain."};
 
 
------------------------------
-- Trigger info
------------------------------
 
-- Holds the available trigger main events.
obj = MSBTLocale.TRIGGER_MAIN_EVENTS;
obj["Health"] = "Health Threshold";
obj["Mana"] = "Mana Threshold";
obj["Energy"] = "Energy Threshold";
obj["Rage"] = "Rage Threshold";
obj["Crit"] = "Crit";
obj["Block"] = "Block";
obj["Dodge"] = "Dodge";
obj["Parry"] = "Parry";
obj["BuffApplication"] = "Buff Application";
obj["BuffFade"] = "Buff Fade";
obj["DebuffApplication"] = "Debuff Application";
obj["DebuffFade"] = "Debuff Fade";
obj["CastStart"] = "Cast Start";
obj["KillingBlow"] = "Killing Blow";
 
 
-- Holds the available trigger exceptions.
obj = MSBTLocale.TRIGGER_EXCEPTIONS;
obj["BuffActive"] = "Buff Active";
obj["InsufficientPower"] = "Insufficient Power";
obj["InsufficientComboPoints"] = "Insufficient Combo Points";
obj["NotInArena"] = "Not In Arena";
obj["NotInPvPZone"] = "Not In PvP Zone";
obj["RecentlyFired"] = "Trigger Recently Fired";
obj["SkillUnavailable"] = "Skill Unavailable";
obj["TrivialTarget"] = "Trivial Target";
obj["WarriorStance"] = "Warrior Stance";
 
 
------------------------------
-- Font info
------------------------------
 
-- Font outlines.
obj = MSBTLocale.OUTLINES;
obj[1] = "None";
obj[2] = "Thin";
obj[3] = "Thick";
 
-- Text aligns.
obj = MSBTLocale.TEXT_ALIGNS;
obj[1] = "Left";
obj[2] = "Center";
obj[3] = "Right";
 
 
------------------------------
-- Sound info
------------------------------
 
obj = MSBTLocale.SOUNDS;
obj["LowMana"] = "Low Mana";
obj["LowHealth"] = "Low Health";
 
 
------------------------------
-- Animation style info
------------------------------
 
-- Animation styles
obj = MSBTLocale.ANIMATION_STYLE_DATA;
obj["Horizontal"] = "Horizontal";
obj["Parabola"] = "Parabola";
obj["Straight"] = "Straight";
obj["Static"] = "Static";
obj["Pow"] = "Pow";
 
-- Animation style directions.
obj["Alternate"] = "Alternate";
obj["Left"] = "Left";
obj["Right"] = "Right";
obj["Up"] = "Up";
obj["Down"] = "Down";
 
-- Animation style behaviors.
obj["GrowUp"] = "Grow Upwards";
obj["GrowDown"] = "Grow Downwards";
obj["CurvedLeft"] = "Curved Left";
obj["CurvedRight"] = "Curved Right";
obj["Jiggle"] = "Jiggle";
obj["Normal"] = "Normal";
\ No newline at end of file