├── .gitignore ├── docs ├── commands │ ├── reload.md │ ├── stopattack.md │ ├── startattack.md │ ├── stopcasting.md │ ├── petattack.md │ ├── unshift.md │ ├── equip.md │ ├── use.md │ └── target.md ├── conditions │ ├── combat.md │ ├── channeled.md │ ├── raid.md │ ├── isnpc.md │ ├── party.md │ ├── isplayer.md │ ├── stealth.md │ ├── cooldown.md │ ├── help_harm.md │ ├── dead.md │ ├── attacks.md │ ├── group.md │ ├── hp.md │ ├── mod.md │ ├── type.md │ ├── power.md │ ├── stance.md │ ├── buffs.md │ ├── equipped.md │ └── target.md ├── commands.md ├── showtooltip.md ├── index.md ├── toggable_abilities_and_channelled_spells.md ├── about.md ├── macro_invoking.md ├── compatibility.md └── conditions.md ├── Widgets.xml ├── Compatibility ├── SuperMacro.lua └── pfUI.lua ├── Extensions ├── Mouseover │ ├── sRaidFrames.lua │ ├── GameTooltip.lua │ ├── DiscordUnitFrames.lua │ ├── CT_UnitFrames.lua │ ├── FocusFrame.lua │ ├── ag_UnitFrames.lua │ ├── NotGrid.lua │ ├── CT_RaidAssist.lua │ ├── Blizzard.lua │ ├── pfUI.lua │ ├── Grid.lua │ └── PerfectRaid.lua └── Tooltip │ └── Generic.lua ├── Roid-Macros.toc ├── LICENSE ├── README.md ├── mkdocs.yml ├── Console.lua ├── Utility.lua ├── ExtensionsManager.lua ├── Localization.lua ├── Core.lua └── Conditionals.lua /.gitignore: -------------------------------------------------------------------------------- 1 | /site 2 | -------------------------------------------------------------------------------- /docs/commands/reload.md: -------------------------------------------------------------------------------- 1 | # /rl 2 | 3 | `/rl` tells the client to reload all Addons. This is mainly used for debugging. -------------------------------------------------------------------------------- /docs/commands/stopattack.md: -------------------------------------------------------------------------------- 1 | # /stopattack 2 | 3 | `/stopattack` will make you stop attacking with your melee weapons. Spammable. 4 | 5 | ## Examples 6 | 7 | ```lua 8 | /cast Gouge 9 | /stopattack 10 | ``` 11 | 12 | You will cast Gouge and immediately stop attacking. 13 | -------------------------------------------------------------------------------- /docs/commands/startattack.md: -------------------------------------------------------------------------------- 1 | # /startattack 2 | 3 | `/startattack` will make you attack with your melee weapons. Spammable. 4 | 5 | ## Examples 6 | 7 | ```lua 8 | /startattack 9 | /cast Heroic Strike 10 | ``` 11 | 12 | You will start attacking and cast Heroic Strike whenever it is ready. 13 | -------------------------------------------------------------------------------- /docs/commands/stopcasting.md: -------------------------------------------------------------------------------- 1 | # /stopcasting 2 | 3 | `/stopcasting` will interrupt your current spell. 4 | 5 | ## Examples 6 | 7 | ```lua 8 | /stopcasting 9 | /cast [@mouseover] Flash Heal 10 | ``` 11 | 12 | You will interrupt your current cast and cast Flash Heal at your mouseover 13 | target instead. -------------------------------------------------------------------------------- /Widgets.xml: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /docs/conditions/combat.md: -------------------------------------------------------------------------------- 1 | # combat / nocombat 2 | 3 | May only be used in combat. Can be inverted by adding `no` in front of `combat`. 4 | 5 | ## Example: 6 | 7 | ```lua 8 | /cast [nocombat] Starfire; Wrath 9 | ``` 10 | 11 | Your Oomkin will cast Starfire when you are not in combat and Wrath once you are. 12 | -------------------------------------------------------------------------------- /docs/conditions/channeled.md: -------------------------------------------------------------------------------- 1 | # channeled / nochanneled 2 | 3 | This condition will only fire when you currently are [not] casting any 4 | channeled spells. 5 | 6 | ## Examples 7 | 8 | ```lua 9 | /cast [nochanneled] Shadow Bolt 10 | ``` 11 | 12 | You will cast Shadow Bolt whenever you're not casting any channeled spells. 13 | -------------------------------------------------------------------------------- /docs/conditions/raid.md: -------------------------------------------------------------------------------- 1 | # raid 2 | 3 | The condition will only fire when your target is in your raid. 4 | 5 | ## Examples 6 | 7 | ```lua 8 | /cast [raid] Arcane Brilliance; Arcane Intellect 9 | ``` 10 | 11 | This macro will cast Arcane Brilliance when your current target is in your 12 | raid. If your target isn't, it will cast Arcane Intellect on it instead. -------------------------------------------------------------------------------- /docs/conditions/isnpc.md: -------------------------------------------------------------------------------- 1 | # isnpc 2 | 3 | This condition will only fire when the specified UnitID is a npc. 4 | 5 | ## Parameters 6 | 7 | The target's UnitID. Refer to [target condition](target.md). 8 | 9 | ## Examples 10 | 11 | ```lua 12 | /cast [isnpc:target] {Yes} 13 | ``` 14 | 15 | This will execute the Macro with the name `Yes` if your target is a npc. 16 | -------------------------------------------------------------------------------- /docs/conditions/party.md: -------------------------------------------------------------------------------- 1 | # party 2 | 3 | The condition will only fire when your target is in your party. 4 | 5 | ## Examples 6 | 7 | ```lua 8 | /cast [party] Arcane Brilliance; Arcane Intellect 9 | ``` 10 | 11 | This macro will cast Arcane Brilliance when your current target is in your 12 | party. If your target isn't, it will cast Arcane Intellect on it instead. -------------------------------------------------------------------------------- /docs/conditions/isplayer.md: -------------------------------------------------------------------------------- 1 | # isplayer 2 | 3 | This condition will only fire when the specified UnitID is a player. 4 | 5 | ## Parameters 6 | 7 | The target's UnitID. Refer to [target condition](target.md). 8 | 9 | ## Examples 10 | 11 | ```lua 12 | /cast [isplayer:target] {Yes} 13 | ``` 14 | 15 | This will execute the Macro with the name `Yes` if your target is a player. 16 | -------------------------------------------------------------------------------- /docs/commands.md: -------------------------------------------------------------------------------- 1 | # Chat Commands 2 | 3 | * [/petattack](commands/petattack.md) 4 | * [/equip](commands/equip.md) 5 | * [/startattack](commands/startattack.md) 6 | * [/stopattack](commands/stopattack.md) 7 | * [/stopcasting](commands/stopcasting.md) 8 | * [/target](commands/target.md) 9 | * [/unshift](commands/unshift.md) 10 | * [/use](commands/use.md) 11 | * [/rl](commands/reload.md) -------------------------------------------------------------------------------- /docs/showtooltip.md: -------------------------------------------------------------------------------- 1 | # The #showtooltip instruction 2 | 3 | You can re-enable tooltips using the #showtooltip [item name or spell name] 4 | instruction. 5 | 6 | ## Examples 7 | 8 | ```lua 9 | #showtooltip Cone of Cold(Rank 1) 10 | /cast [mypower>200] Cone of Cold(Rank 1) 11 | ``` 12 | 13 | ```lua 14 | #showtooltip Mish'undare, Circlet of the Mind Flayer 15 | /use Linen Bandage 16 | ``` 17 | -------------------------------------------------------------------------------- /docs/commands/petattack.md: -------------------------------------------------------------------------------- 1 | # /petattack 2 | 3 | `/petattack` makes your pet attack. 4 | 5 | ## Examples 6 | 7 | ```lua 8 | /petattack [@focus] 9 | ``` 10 | You pet will attack your focus target (Refer to the [Compatibility Notes](/../compatibility.md)). 11 | 12 | --- 13 | 14 | ```lua 15 | /petattack [@mouseover harm nodead] 16 | ``` 17 | Your pet will attack your mouseover target if it is attackable and not dead. -------------------------------------------------------------------------------- /docs/conditions/stealth.md: -------------------------------------------------------------------------------- 1 | # stealth / nostealth 2 | 3 | The condition will only pass when your character is stealthed. May be inverted by adding `no` in front of `stealth`. 4 | 5 | ## Example 6 | 7 | ```lua 8 | /cast [stealth @player] Healing Touch; Shadowmeld 9 | ``` 10 | 11 | If your character is stealthed, he or she will cast Healing Touch. If your character is not stealthed, Shadowmeld will be cast instead. 12 | -------------------------------------------------------------------------------- /docs/conditions/cooldown.md: -------------------------------------------------------------------------------- 1 | # cooldown / nocooldown 2 | 3 | This condition will only fire when the given name of a spell or item is 4 | off/on cooldown. 5 | 6 | ## Parameters 7 | 8 | The name of the spell. White spaces must be replaced with an underscore `_`. 9 | 10 | ## Examples 11 | 12 | ```lua 13 | /cast [nocooldown:Spell_Lock] Spell Lock 14 | ``` 15 | 16 | Your Felhunter will cast Spell Lock when it is off cooldown. 17 | -------------------------------------------------------------------------------- /docs/conditions/help_harm.md: -------------------------------------------------------------------------------- 1 | # help / harm 2 | 3 | The [help] condition is true when the unit can receive a beneficial effect, 4 | e.g., a healing spell. The [harm] condition is true when the unit would get an 5 | adverse effect, e.g., a damaging spell. 6 | 7 | ## Example: 8 | 9 | ```lua 10 | /cast [harm] Frost Shock; [help] Healing Wave 11 | ``` 12 | 13 | This will cast Frost Shock on hostile targets and Healing Wave on friendly targets. -------------------------------------------------------------------------------- /docs/conditions/dead.md: -------------------------------------------------------------------------------- 1 | # dead / nodead 2 | 3 | May only be used when your target is dead. Can be inverted by adding `no` in 4 | front of `dead`. 5 | 6 | ## Examples: 7 | 8 | ```lua 9 | /cast [dead] Resurrection; Flash Heal 10 | ``` 11 | 12 | Will cast Resurrection if your current target is dead. If it isn't you will cast Flash Heal instead. 13 | 14 | --- 15 | 16 | ```lua 17 | /cast [nodead] Flash Heal; Resurrection 18 | ``` 19 | 20 | The same as above just the other way around. -------------------------------------------------------------------------------- /docs/conditions/attacks.md: -------------------------------------------------------------------------------- 1 | # attacks / noattacks 2 | 3 | This condition will only fire when your target's target is [not] the 4 | specified target. 5 | 6 | ## Parameters 7 | 8 | The UnitID of the target that must [not] be attacking you. Refer to 9 | [target condition](target.md) 10 | 11 | ## Examples 12 | 13 | ```lua 14 | /cast [attacks:player] {Yes}; {No} 15 | ``` 16 | 17 | This will execute the Macro with the name `Yes`, if your target is currently 18 | attacking you, and the Macro named `No` when it is not. -------------------------------------------------------------------------------- /docs/conditions/group.md: -------------------------------------------------------------------------------- 1 | # group 2 | 3 | This condition will only fire when you're in a party or raid. 4 | 5 | ## Parameters 6 | 7 | May take one of the following parameters: 8 | 9 | * party - You must be in a party 10 | * raid - You must be in a raid 11 | 12 | ## Examples 13 | 14 | ```lua 15 | /cast [group:party] Arcane Brilliance; [group:raid] Arcane Intellect 16 | ``` 17 | 18 | This macro will cast Arcane Brilliance when you are in a party. It will cast Arcane Intellect instead when you are in a raid. 19 | -------------------------------------------------------------------------------- /docs/commands/unshift.md: -------------------------------------------------------------------------------- 1 | # /unshift 2 | 3 | `/unshift` make you leave your shapeshift form. 4 | 5 | ## Examples 6 | 7 | ```lua 8 | /unshift [stance:1/2/4] 9 | ``` 10 | This macro will cause you to exit your shapeshift form if you're either in [Dire] Bear Form, Aquatic Form, or Travel Form. 11 | 12 | --- 13 | 14 | ```lua 15 | /unshift [stance:1/2/4] 16 | /cast [stance:0] Cat Form; [nocombat nostealth] Prowl 17 | ``` 18 | You will exit any form other than Cat Form. Then, if you're not shapeshifted, you'll go into Cat Form. If you are in Cat Form you'll cast Prowl. -------------------------------------------------------------------------------- /docs/commands/equip.md: -------------------------------------------------------------------------------- 1 | # /equip and /equipoh 2 | 3 | `/equip` puts an item with the given name into the main hand slot. 4 | 5 | `/equipoh` puts an item with the given name into the off hand slot. 6 | 7 | ## Examples 8 | 9 | ```lua 10 | /equip Elementium Reinforced Bulwark 11 | ``` 12 | 13 | Will equip the Elementium Reinforced Bulwark if it can be found in the inventory. 14 | 15 | --- 16 | 17 | ```lua 18 | /equipoh [equipped:Shields] Iblis, Blade of the Fallen Seraph 19 | ``` 20 | 21 | Will equip Iblis, Blade of the Fallen Seraph if you currently have a shield equipped. -------------------------------------------------------------------------------- /Compatibility/SuperMacro.lua: -------------------------------------------------------------------------------- 1 | local _G = _G or getfenv(0) 2 | local Roids = _G.Roids or {} 3 | 4 | local Extension = Roids.RegisterExtension("Compatibility_SuperMacro"); 5 | Extension.RegisterEvent("ADDON_LOADED", "OnLoad"); 6 | 7 | function Extension.RunMacro(name) 8 | Roids.ExecuteMacroByName(name) 9 | end 10 | 11 | function Extension.OnLoad() 12 | if not SuperMacroFrame then 13 | return; 14 | end 15 | 16 | Extension.Hook("RunMacro", "RunMacro", true); 17 | Extension.UnregisterEvent("ADDON_LOADED", "Onload"); 18 | end 19 | 20 | 21 | _G["Roids"] = Roids; -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # Roid Macros 2 | 3 | Vanilla macros on steroids! 4 | 5 | --- 6 | 7 | ## Overview 8 | 9 | Roid Macros is aimed to provide TBC like macros (including conditions!) 10 | while abusing Vanilla WoW's Lua API to go even further including things 11 | like executing macros from within macros! 12 | 13 | ## Further Information 14 | 15 | * [Chat Commands](commands.md) 16 | * [Conditions](conditions.md) 17 | * [#showtooltip](showtooltip.md) 18 | * [Macro invocation](macro_invoking.md) 19 | * [Toggable abilities and channelled spells](toggable_abilities_and_channelled_spells.md) -------------------------------------------------------------------------------- /Extensions/Mouseover/sRaidFrames.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Author: Dennis Werner Garske (DWG) 3 | License: MIT License 4 | ]] 5 | local _G = _G or getfenv(0) 6 | local Roids = _G.Roids or {} 7 | Roids.mouseoverUnit = Roids.mouseoverUnit or nil; 8 | 9 | local Extension = Roids.RegisterExtension("sRaidFrames"); 10 | Extension.RegisterEvent("ADDON_LOADED", "OnLoad"); 11 | 12 | function Extension:OnEnter(frame) 13 | Roids.mouseoverUnit = frame.unit; 14 | end 15 | 16 | function Extension.OnLoad() 17 | if arg1 ~= "sRaidFrames" then 18 | return; 19 | end 20 | 21 | Extension.HookMethod(sRaidFrames, "UnitTooltip", "OnEnter"); 22 | end 23 | 24 | _G["Roids"] = Roids; -------------------------------------------------------------------------------- /docs/commands/use.md: -------------------------------------------------------------------------------- 1 | # /use 2 | 3 | `/use` allows you to use items from your inventory or equipped ones. 4 | 5 | ## Examples 6 | 7 | ```lua 8 | /use Juju Flurry 9 | ``` 10 | 11 | Will use Juju Flurry if it can be found in the inventory. 12 | 13 | --- 14 | 15 | ```lua 16 | /use [@player] Runecloth Bandage 17 | ``` 18 | 19 | This macro will search for Runecloth Bandages in your inventory and if it finds them use them upon your character. 20 | 21 | --- 22 | 23 | ```lua 24 | /use [combat] Major Mana Potion 25 | ``` 26 | 27 | With this line you'll never again use a Major Mana Potion accidentally when you're not in combat! 28 | 29 | --- 30 | 31 | ```lua 32 | ``` 33 | 34 | --- 35 | 36 | ```lua 37 | ``` 38 | -------------------------------------------------------------------------------- /docs/conditions/hp.md: -------------------------------------------------------------------------------- 1 | # [my]hp 2 | 3 | Checks whether or not you (myhp) or the specified target (hp) has the given amount of hit points. 4 | 5 | ## Parameters 6 | 7 | A less than `<` or greater than `>` sign followed by the percentage of hp that 8 | is required. 9 | 10 | ## Examples 11 | 12 | ```lua 13 | /cast [myhp<40 @player] Flash Heal; Flash heal 14 | ``` 15 | 16 | Will cast Flash Heal either on yourself, when you have less than 40% health, or 17 | on your current target if you have more hp. 18 | 19 | --- 20 | 21 | ```lua 22 | /cast [hp<20] Execute; Bloodthirst 23 | ``` 24 | 25 | Will cast Bloodthirst until your target has less than 20% health. At that point 26 | the macro will only cast Execute. 27 | -------------------------------------------------------------------------------- /docs/conditions/mod.md: -------------------------------------------------------------------------------- 1 | # mod 2 | 3 | Modifier keys are a convenient way to save action bar space and make certain 4 | decisions. 5 | 6 | ## Parameters 7 | 8 | May take a number of parameters seperated by slashes `/`. 9 | 10 | * ctrl - the CTRL key is pressed down 11 | * shift - the SHIFT key is pressed down 12 | * alt - the ALT key is pressed down 13 | 14 | ## Examples: 15 | 16 | ```lua 17 | /cast [mod:ctrl] Healing Wave; Healing Wave (Rank 1) 18 | ``` 19 | 20 | This will cast your highest rank of Healing Wave whenever you have the CTRL key pressed, otherwise Healing Wave rank 1. 21 | 22 | --- 23 | 24 | ```lua 25 | /cast [mod:ctrl/shift] Healing Wave 26 | ``` 27 | 28 | You will cast Healing Wave when you have CTRL and SHIFT pressed. 29 | -------------------------------------------------------------------------------- /Extensions/Mouseover/GameTooltip.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Author: Dennis Werner Garske (DWG) 3 | License: MIT License 4 | ]] 5 | local _G = _G or getfenv(0) 6 | local Roids = _G.Roids or {} 7 | Roids.mouseoverUnit = Roids.mouseoverUnit or nil; 8 | 9 | local Extension = Roids.RegisterExtension("BlizzardPartyFrame"); 10 | 11 | function Extension.SetUnit(_, unit) 12 | Roids.mouseoverUnit = unit; 13 | end 14 | 15 | 16 | function Extension.OnClose() 17 | Roids.mouseoverUnit = nil; 18 | end 19 | 20 | function Extension.OnLoad() 21 | Extension.HookMethod(_G["GameTooltip"], "SetUnit", "SetUnit"); 22 | Extension.HookMethod(_G["GameTooltip"], "Hide", "OnClose"); 23 | Extension.HookMethod(_G["GameTooltip"], "FadeOut", "OnClose"); 24 | end 25 | 26 | _G["Roids"] = Roids; -------------------------------------------------------------------------------- /docs/conditions/type.md: -------------------------------------------------------------------------------- 1 | # type 2 | 3 | Checks whether the target of our action has the given CreatureTypeId. 4 | 5 | ## Parameters 6 | 7 | These CreatureTypeIds are available: 8 | 9 | * Beast 10 | * Critter 11 | * Demon 12 | * Dragonkin 13 | * Elemental 14 | * Giant 15 | * Humanoid 16 | * Mechanical 17 | * Not_Specified 18 | * Totem 19 | * Undead 20 | 21 | You may also use your respective localized names instead. 22 | 23 | **Note:** I've taken the localized names from the legion version of wowwiki, so they may be incorrect. If you spot any mistakes, please forward the correctly localized names to me! 24 | 25 | ## Examples 26 | 27 | ```lua 28 | /cast [@target type:Beast] Hibernate; Entangling Roots 29 | ``` 30 | 31 | Will cast Hibernate if your current target is a Beast. If not Entangling Roots will be cast instead. 32 | -------------------------------------------------------------------------------- /docs/toggable_abilities_and_channelled_spells.md: -------------------------------------------------------------------------------- 1 | # Toggleable abilities and channelled spells 2 | 3 | This AddOn allows you to ensure that channelled spells aren't cast again until 4 | they're finished or interrupted. In addition, this also works for auto 5 | attacking, shooting wands or shooting ranged weapons. This can be done by 6 | putting an exclamation mark at the beginning of the spells name. 7 | 8 | ## Examples 9 | 10 | ```lua 11 | /cast !Mind Flay 12 | ``` 13 | 14 | You may now spam that button and Mind Flay will only be re-cast when the last 15 | one has finished or gets interrupted. 16 | 17 | --- 18 | 19 | ```lua 20 | /cast !Attack 21 | ``` 22 | 23 | ```lua 24 | /cast !Shoot 25 | ``` 26 | 27 | ```lua 28 | /cast !Auto Shot 29 | ``` 30 | 31 | Again, using this macro will ensure that your Attack ability is active without deactivating it. 32 | -------------------------------------------------------------------------------- /docs/conditions/power.md: -------------------------------------------------------------------------------- 1 | # [my]power / [my]rawpower 2 | 3 | Checks whether or not you (mypower) or the specified target (power) has the 4 | given amount of its power type. 5 | 6 | ## Parameters 7 | 8 | A less than `<` or greater than `>` sign followed by the amount of actual power 9 | ([my]rawpower) or the percentage ([my]power) that is required. 10 | 11 | ## Examples 12 | 13 | ```lua 14 | /cast [mypower>60] Heroic Strike 15 | ``` 16 | 17 | Will cast Heroic Strike when you have more than 60% rage. 18 | 19 | --- 20 | 21 | ```lua 22 | /cast [harm @target power>10] Mana Burn 23 | ``` 24 | 25 | Will cast Mana Burn as long as your current target has more than 10% power. 26 | 27 | --- 28 | 29 | ```lua 30 | /cast [myrawpower<390] Arcane Explosion(Rank 1); Arcane Explosion 31 | ``` 32 | 33 | Will cast max rank Arcane Explosion as long as you have the mana to do so and 34 | will cast Arcane Explosion Rank 1 when you don't. 35 | -------------------------------------------------------------------------------- /Roid-Macros.toc: -------------------------------------------------------------------------------- 1 | ## Interface: 11200 2 | ## Author: DWG 3 | ## Title: Roid Macros 4 | ## Notes: Vanilla macros on steroids! 5 | ## Title-deDE: Roid Macros 6 | ## Notes-deDE: Vanilla Macros auf Steroide! 7 | ## OptionalDeps: ClassicFocus, FocusFrame 8 | Widgets.xml 9 | Localization.lua 10 | Utility.lua 11 | Core.lua 12 | Console.lua 13 | Conditionals.lua 14 | ExtensionsManager.lua 15 | 16 | Compatibility\SuperMacro.lua 17 | Compatibility\pfUI.lua 18 | 19 | Extensions\Mouseover\GameTooltip.lua 20 | Extensions\Mouseover\Blizzard.lua 21 | Extensions\Mouseover\CT_RaidAssist.lua 22 | Extensions\Mouseover\CT_UnitFrames.lua 23 | Extensions\Mouseover\DiscordUnitFrames.lua 24 | Extensions\Mouseover\FocusFrame.lua 25 | Extensions\Mouseover\Grid.lua 26 | Extensions\Mouseover\NotGrid.lua 27 | Extensions\Mouseover\PerfectRaid.lua 28 | Extensions\Mouseover\pfUI.lua 29 | Extensions\Mouseover\sRaidFrames.lua 30 | Extensions\Mouseover\ag_UnitFrames.lua 31 | 32 | Extensions\Tooltip\Generic.lua 33 | -------------------------------------------------------------------------------- /docs/conditions/stance.md: -------------------------------------------------------------------------------- 1 | # stance 2 | 3 | Allows you to check whether or not you are in the given stance or shapeshift 4 | form. 5 | 6 | ## Parameters 7 | 8 | May take a number of parameters seperated by slashes `/`. 9 | 10 | * 0 - You're in no stance 11 | * 1, 2, ..., n - You're in stance 1, 2, ..., n where n is the total number of 12 | stances or shapeshift form availlable 13 | 14 | ## Examples 15 | 16 | ```lua 17 | /cast [stance:0] Cat Form 18 | ``` 19 | 20 | Enter Cat Form when not shapeshifted. 21 | 22 | --- 23 | 24 | ```lua 25 | /cast [stance:1] Enrage; Dire Bear Form 26 | ``` 27 | 28 | This macro will cast Enrage if you are in your (Dire) Bear Form. If not it will 29 | go into said Form. 30 | 31 | --- 32 | 33 | ```lua 34 | /cast [stance:1/2] Shield Bash; Defensive Stance 35 | ``` 36 | If you are in either the Battle Stance or the Defensive Stance, you will cast 37 | Shield Bash. If you are in the Berserker Stance, however, you will switch into 38 | Defensive Stance. 39 | -------------------------------------------------------------------------------- /docs/conditions/buffs.md: -------------------------------------------------------------------------------- 1 | # [no]buff / [no]mybuff / [no]debuff / [no]mydebuff 2 | 3 | Ensures that you (mybuff/mydebuff) or the specified target (buff/debuff) has 4 | the given buff or debuff. May be inverted by adding a 'no' at the beginning. 5 | 6 | ## Parameters 7 | 8 | The name of the buff or debuff. May be abbreviated and mustn't contain anything 9 | that isn't a letter from the English alphabet. White spaces must be replaced by 10 | an underscore `_`. 11 | 12 | ## Examples 13 | 14 | ```lua 15 | /cast [nobuff:Fortitude @mouseover] Power Word: Fortitude 16 | ``` 17 | 18 | Will cast Power Word: Fortitude on your mouseover target if no such buff could be found on it. 19 | 20 | --- 21 | 22 | ```lua 23 | /cast [mybuff:Blood_Fury] Healing Wave 24 | ``` 25 | 26 | Will cast Healing Wave on yourself only while Blood Fury is active. 27 | 28 | --- 29 | 30 | ```lua 31 | /cast [debuff:Curse_of_Weakness @player] Healing Wave 32 | ``` 33 | 34 | Will cast Healing Wave on yourself as long as Curse of Weakness is active. -------------------------------------------------------------------------------- /Compatibility/pfUI.lua: -------------------------------------------------------------------------------- 1 | local _G = _G or getfenv(0) 2 | local Roids = _G.Roids or {} 3 | 4 | local Extension = Roids.RegisterExtension("Compatibility_pfUI"); 5 | Extension.RegisterEvent("ADDON_LOADED", "OnLoad"); 6 | Extension.Debug = 1; 7 | 8 | function Extension.RunMacro(name) 9 | Roids.ExecuteMacroByName(name); 10 | end 11 | 12 | function Extension.DLOG(msg) 13 | if Extension.Debug then 14 | DEFAULT_CHAT_FRAME:AddMessage("|cffcccc33[R]: |cffffff55" .. ( msg )) 15 | end 16 | end 17 | 18 | function Extension.FocusNameHook() 19 | local hook = Extension.internal.memberHooks[Roids]["GetFocusName"] 20 | local target = hook.origininal() 21 | 22 | if pfUI and pfUI.uf and pfUI.uf.focus and pfUI.uf.focus.unitname then 23 | target = pfUI.uf.focus.unitname 24 | end 25 | 26 | --Extension.DLOG(target) 27 | 28 | return target 29 | end 30 | 31 | function Extension.OnLoad() 32 | Extension.DLOG("Extension pfUI Loaded.") 33 | Extension.HookMethod(Roids, "GetFocusName", "FocusNameHook", true) 34 | Extension.UnregisterEvent("ADDON_LOADED", "Onload"); 35 | end 36 | 37 | 38 | _G["Roids"] = Roids; 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Dennis Werner Garske (DWG) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /docs/about.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Dennis Werner Garske (DWG) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Roid Macros 2 | 3 | This addon allows you to use a small subset of the macro conditions, first introduced in the TBC expansion, in your 1.12.1 Vanilla client. 4 | 5 | Demo videos: 6 | 7 | [![Example Video](https://i9.ytimg.com/vi/xHTe4Df77MY/mq2.jpg?sqp=CJjhi5kG&rs=AOn4CLA0OYCKrr3Cj2p_ccYLYfUA_i9MOQ)](https://www.youtube.com/watch?v=xHTe4Df77MY) 8 | [![Example Video2](https://i9.ytimg.com/vi/0w5nePeJlPU/mq2.jpg?sqp=CJjhi5kG&rs=AOn4CLBzPjcmu5zGYpT3vR5ieDvVyuE-iw)](https://www.youtube.com/watch?v=0w5nePeJlPU) 9 | 10 | ### Installation 11 | 12 | - Make sure ClassicMouseover is not installed or disable it in the character select screen! 13 | - [Download](https://github.com/DennisWG/Roid-Macros/archive/master.zip) the latest version of Roid Macros directly from the repository and extract it into your `WoW/Interface/AddOns/` folder. 14 | - Rename `Roid-Macros-master` to `Roid-Macros` 15 | - Run World of Warcraft and make sure to enable this addon in the character select screen 16 | 17 | ### Explanations and more information 18 | 19 | For an in-depth explanation please visit [the documentation](https://denniswg.github.io/Roid-Macros/). 20 | 21 | License 22 | ---- 23 | 24 | MIT 25 | -------------------------------------------------------------------------------- /Extensions/Mouseover/DiscordUnitFrames.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Author: Dennis Werner Garske (DWG) 3 | License: MIT License 4 | ]] 5 | local _G = _G or getfenv(0) 6 | local Roids = _G.Roids or {} 7 | Roids.mouseoverUnit = Roids.mouseoverUnit or nil; 8 | 9 | local Extension = Roids.RegisterExtension("DiscordUnitFrames"); 10 | Extension.RegisterEvent("ADDON_LOADED", "OnLoad"); 11 | 12 | function Extension.OnEnterFrame() 13 | Roids.mouseoverUnit = this.unit; 14 | end 15 | 16 | function Extension.OnLeaveFrame() 17 | Roids.mouseoverUnit = nil; 18 | end 19 | 20 | function Extension.OnEnterElement() 21 | Roids.mouseoverUnit = this:GetParent().unit; 22 | end 23 | 24 | function Extension.OnLeaveElement() 25 | Roids.mouseoverUnit = nil; 26 | end 27 | 28 | function Extension.OnLoad() 29 | if arg1 ~= "DiscordUnitFrames" then 30 | return; 31 | end 32 | 33 | Roids.ClearHooks(); 34 | Extension.Hook("DUF_UnitFrame_OnEnter", "OnEnterFrame"); 35 | Extension.Hook("DUF_UnitFrame_OnLeave", "OnLeaveFrame"); 36 | 37 | Extension.Hook("DUF_Element_OnEnter", "OnEnterElement"); 38 | Extension.Hook("DUF_Element_OnLeave", "OnLeaveElement"); 39 | end 40 | 41 | _G["Roids"] = Roids; -------------------------------------------------------------------------------- /docs/conditions/equipped.md: -------------------------------------------------------------------------------- 1 | # equipped / noequipped / worn / noworn 2 | 3 | Ensures that the given item type is equipped/worn. Can be inverted by adding `no` in front of `equipped` or `worn` 4 | 5 | ## Parameters 6 | 7 | May take a single parameter from the following list: 8 | 9 | * Daggers - Looks for a dagger in your mainhand 10 | * Fists - Looks for a fist weapon in your mainhand 11 | * Axes - Looks for an axe in your mainhand 12 | * Swords - Looks for a sword in your mainhand 13 | * Staffs - Looks for a staff in your mainhand 14 | * Maces - Looks for a mace in your mainhand 15 | * Polearms - Looks for a polearm in your mainhand 16 | * Shields - Looks for a shield in your offhand 17 | * Guns - Looks for a gun in your ranged slot 18 | * Crossbows - Looks for a crossbow in your ranged slot 19 | * Bows - Looks for a cow in your ranged slot 20 | * Thrown - Looks for a thrown weapon in your ranged slot 21 | * Wands - Looks for a wand in your ranged slot 22 | 23 | ## Examples 24 | 25 | ```lua 26 | /cast [equipped:Bows] Shoot Bow; [equipped:Crossbows] Shoot Crossbow; [equipped:Guns] Shoot Gun; [equipped:Thrown] Throw 27 | ``` 28 | 29 | Will use your ranged shoot ability depending on what ranged weapon you 30 | currently have equipped. 31 | -------------------------------------------------------------------------------- /Extensions/Mouseover/CT_UnitFrames.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Author: Dennis Werner Garske (DWG) 3 | License: MIT License 4 | ]] 5 | local _G = _G or getfenv(0) 6 | local Roids = _G.Roids or {} 7 | Roids.mouseoverUnit = Roids.mouseoverUnit or nil; 8 | 9 | local Extension = Roids.RegisterExtension("CT_UnitFrames"); 10 | Extension.RegisterEvent("ADDON_LOADED", "OnLoad"); 11 | 12 | function Extension.SetHook(widget) 13 | local hookedOnEnter = widget:GetScript("OnEnter"); 14 | local hookedOnLeave = widget:GetScript("OnLeave"); 15 | 16 | widget:SetScript("OnEnter", function() 17 | hookedOnEnter(); 18 | Roids.mouseoverUnit = "targettarget"; 19 | end); 20 | 21 | widget:SetScript("OnLeave", function() 22 | hookedOnLeave(); 23 | Roids.mouseoverUnit = nil; 24 | end); 25 | end 26 | 27 | function Extension.OnLoad() 28 | if arg1 ~= "CT_UnitFrames" or not CT_AssistFrame then 29 | return; 30 | end 31 | Roids.Print("CT_UnitFrames module loaded."); 32 | 33 | Extension.SetHook(CT_AssistFrame); 34 | Extension.SetHook(CT_AssistFrameHealthBar); 35 | Extension.SetHook(CT_AssistFrameManaBar); 36 | Extension.SetHook(CT_AssistFrame_Drag); 37 | end 38 | 39 | _G["Roids"] = Roids; -------------------------------------------------------------------------------- /Extensions/Mouseover/FocusFrame.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Author: Dennis Werner Garske (DWG) 3 | License: MIT License 4 | ]] 5 | local _G = _G or getfenv(0) 6 | local Roids = _G.Roids or {} 7 | Roids.mouseoverUnit = Roids.mouseoverUnit or nil; 8 | 9 | local Extension = Roids.RegisterExtension("FocusFrame"); 10 | 11 | function Extension.RegisterMouseoverForFrame(frame) 12 | local onenter = frame:GetScript("OnEnter"); 13 | local onleave = frame:GetScript("OnLeave"); 14 | 15 | frame:SetScript("OnEnter", function() 16 | Roids.mouseoverUnit = "focus"; 17 | if onenter then 18 | onenter(); 19 | end 20 | end); 21 | 22 | frame:SetScript("OnLeave", function() 23 | Roids.mouseoverUnit = nil; 24 | if onleave then 25 | onleave(); 26 | end 27 | end); 28 | end 29 | 30 | function Extension.OnLoad() 31 | if not FocusFrameHealthBar 32 | or not FocusFrameManaBar 33 | or not FocusFrameTextureFrame 34 | or not FocusFrame then 35 | return; 36 | end 37 | 38 | Extension.RegisterMouseoverForFrame(FocusFrameHealthBar); 39 | Extension.RegisterMouseoverForFrame(FocusFrameManaBar); 40 | Extension.RegisterMouseoverForFrame(FocusFrameTextureFrame); 41 | Extension.RegisterMouseoverForFrame(FocusFrame); 42 | end -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: Roid-Macros 2 | pages: 3 | - Home: index.md 4 | - Commands: 5 | - commands.md 6 | - commands/equip.md 7 | - commands/petattack.md 8 | - commands/startattack.md 9 | - commands/stopattack.md 10 | - commands/stopcasting.md 11 | - commands/target.md 12 | - commands/unshift.md 13 | - commands/use.md 14 | - commands/reload.md 15 | - Conditions: 16 | - conditions.md 17 | - conditions/attacks.md 18 | - conditions/buffs.md 19 | - conditions/channeled.md 20 | - conditions/combat.md 21 | - conditions/cooldown.md 22 | - conditions/dead.md 23 | - conditions/equipped.md 24 | - conditions/group.md 25 | - conditions/help_harm.md 26 | - conditions/hp.md 27 | - conditions/isnpc.md 28 | - conditions/isplayer.md 29 | - conditions/mod.md 30 | - conditions/party.md 31 | - conditions/power.md 32 | - conditions/raid.md 33 | - conditions/stance.md 34 | - conditions/stealth.md 35 | - conditions/target.md 36 | - conditions/type.md 37 | - Invoking Macros: macro_invoking.md 38 | - Miscellaneous: 39 | - showtooltip.md 40 | - toggable_abilities_and_channelled_spells.md 41 | - compatibility.md 42 | - About: about.md 43 | -------------------------------------------------------------------------------- /Extensions/Mouseover/ag_UnitFrames.lua: -------------------------------------------------------------------------------- 1 | local _G = _G or getfenv(0) 2 | local Roids = _G.Roids or {} 3 | 4 | Roids.Hooks = Roids.Hooks or {}; 5 | Roids.mouseoverUnit = Roids.mouseoverUnit or nil; 6 | 7 | local Extension = Roids.RegisterExtension("ag_UnitFrames"); 8 | Extension.RegisterEvent("ADDON_LOADED", "OnLoad"); 9 | 10 | function Extension.OnEnter(unit) 11 | Roids.mouseoverUnit = unit; 12 | end 13 | 14 | function Extension.OnLeave() 15 | Roids.mouseoverUnit = nil; 16 | end 17 | 18 | -- Because AddOns are loaded in alphabetical order, this callback will never see the aUF loaded message, had to do a workaround... 19 | function Extension.OnLoad() 20 | if not aUF then 21 | return 22 | end 23 | Roids.Hooks.ag_UnitFrames = { OnEnter = aUF.classes.aUFunit.prototype.OnEnter, OnLeave = aUF.classes.aUFunit.prototype.OnLeave} 24 | aUF.classes.aUFunit.prototype.OnEnter = Roids.aUFOnEnter 25 | aUF.classes.aUFunit.prototype.OnLeave = Roids.aUFOnLeave 26 | Extension.UnregisterEvent("ADDON_LOADED", "Onload") 27 | end 28 | 29 | -- Taken from ag_UnitClass.lua 30 | function Roids:aUFOnEnter() 31 | Extension.OnEnter(self.unit) 32 | self.frame.unit = self.unit 33 | self:UpdateHighlight(true) 34 | UnitFrame_OnEnter() 35 | end 36 | 37 | function Roids:aUFOnLeave() 38 | Extension.OnLeave() 39 | self:UpdateHighlight() 40 | UnitFrame_OnLeave() 41 | end 42 | 43 | 44 | _G["Roids"] = Roids; 45 | -------------------------------------------------------------------------------- /Extensions/Mouseover/NotGrid.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Author: Dennis Werner Garske (DWG) 3 | License: MIT License 4 | ]] 5 | local _G = _G or getfenv(0) 6 | local Roids = _G.Roids or {} 7 | 8 | local CreateFrames = nil; 9 | Roids.mouseoverUnit = Roids.mouseoverUnit or nil; 10 | 11 | local Extension = Roids.RegisterExtension("NotGrid"); 12 | Extension.RegisterEvent("ADDON_LOADED", "OnLoad"); 13 | 14 | function Extension.OnEnter() 15 | Roids.mouseoverUnit = this.unit; 16 | end 17 | 18 | function Extension.OnLeave() 19 | Roids.mouseoverUnit = nil; 20 | end 21 | 22 | function Roids:NotGrid_CreateFrames() 23 | CreateFrames(NotGrid); -- call the original 24 | 25 | -- NotGrid stores all of it's frames in the NotGrid.UnitFrames table. 26 | for k, frame in pairs(NotGrid.UnitFrames) do 27 | local enter = frame:GetScript("OnEnter"); 28 | local leave = frame:GetScript("OnLeave"); 29 | 30 | frame:SetScript("OnEnter", function() 31 | enter(); 32 | Extension.OnEnter(); 33 | end); 34 | 35 | frame:SetScript("OnLeave", function() 36 | leave(); 37 | Extension.OnLeave(); 38 | end); 39 | end 40 | end 41 | 42 | function Extension.OnLoad() 43 | -- NotGrid loads before Roids, so if NotGrid is enabled, then it's global will exist. 44 | if not NotGrid then 45 | return 46 | end 47 | -- Hooking manually as we need a post hook. 48 | CreateFrames = NotGrid.CreateFrames; 49 | NotGrid.CreateFrames = Roids.NotGrid_CreateFrames; 50 | 51 | Extension.UnregisterEvent("ADDON_LOADED", "Onload") 52 | end 53 | 54 | _G["Roids"] = Roids; 55 | -------------------------------------------------------------------------------- /docs/conditions/target.md: -------------------------------------------------------------------------------- 1 | # UnitID 2 | 3 | An identifier that refers to a unit int he game world that can be interacted 4 | with. Available identifiers are: 5 | 6 | * `@player` - The current player (You!) 7 | * `@pet` - The current player's pet 8 | * `@partyN` - The Nth party member excluding the player (N is 1, 2, 3 or 4) 9 | * `@partypetN` - The pet of the Nth party member (N is 1, 2, 3 or 4) 10 | * `@raidN` - The Nth raid member (N is 1, 2, 3, ..., 40) 11 | * `@raidpetN` - The pet of the Nth raid member (N is 1, 2, 3, ..., 40) 12 | * `@target` - The currently targetted unit 13 | * `@mouseover` - The unit which the mouse is currently hovering over (May be 14 | incompatible with some unit frames. Refer to the [Compatibility Notes](/../compatibility.md). 15 | * `@npc` - The NPC with which the player is currently interacting. 16 | 17 | You may append `target` to any of these to refer to that unit's target. You may 18 | even chain them together like `@playertargettargettarget`, but you'll notice an 19 | attendant performance hit if you overdo it. 20 | 21 | ## Examples 22 | 23 | ```lua 24 | /cast [harm @target] Frost Shock; [help @mouseover] Healing Wave 25 | ``` 26 | 27 | You will cast Frost Shock on your current target if it is considered hostile. 28 | If it isn't and your mouseover target is considered friendly, your character 29 | will cast Healing Wave on your mouseover target instead. 30 | 31 | --- 32 | 33 | ```lua 34 | /cast [@mouseover] Flash Heal; [@focus] Flash Heal 35 | ``` 36 | 37 | Casts Flash Heal if you have a mouseover target. Casts Flash Heal on your focus 38 | target if you don't (Refer to the [Compatibility Notes](/../compatibility.md)). 39 | -------------------------------------------------------------------------------- /Console.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Author: Dennis Werner Garske (DWG) 3 | License: MIT License 4 | ]] 5 | local _G = _G or getfenv(0) 6 | local Roids = _G.Roids or {} 7 | 8 | SLASH_PETATTACK1 = "/petattack"; 9 | 10 | SlashCmdList.PETATTACK = function(msg) Roids.DoPetAttack(msg); end 11 | 12 | SLASH_RELOAD1 = "/rl"; 13 | 14 | SlashCmdList.RELOAD = function() ReloadUI(); end 15 | 16 | SLASH_USE1 = "/use"; 17 | 18 | SlashCmdList.USE = Roids.DoUse; 19 | 20 | SLASH_EQUIP1 = "/equip"; 21 | 22 | SlashCmdList.EQUIP = Roids.DoUse; 23 | 24 | SLASH_EQUIPOH1 = "/equipoh"; 25 | 26 | SlashCmdList.EQUIPOH = Roids.DoEquipOffhand; 27 | 28 | SLASH_UNSHIFT1 = "/unshift"; 29 | 30 | SlashCmdList.UNSHIFT = Roids.DoUnshift; 31 | 32 | SLASH_STARTATTACK1 = "/startattack"; 33 | 34 | SlashCmdList.STARTATTACK = function(msg) Roids.DoCast(msg.." !Attack"); end 35 | 36 | SLASH_STOPATTACK1 = "/stopattack"; 37 | 38 | SlashCmdList.STOPATTACK = function(msg) if Roids.CurrentSpell.autoAttack then Roids.DoCast(msg.." Attack"); end end 39 | 40 | SLASH_STOPCASTING1 = "/stopcasting"; 41 | 42 | SlashCmdList.STOPCASTING = SpellStopCasting; 43 | 44 | Roids.Hooks.CAST_SlashCmd = SlashCmdList.CAST; 45 | Roids.CAST_SlashCmd = function(msg) 46 | -- get in there first, i.e do a PreHook 47 | if Roids.DoCast(msg) then 48 | return; 49 | end 50 | -- if there was nothing for us to handle pass it to the original 51 | Roids.Hooks.CAST_SlashCmd(msg); 52 | end 53 | 54 | SlashCmdList.CAST = Roids.CAST_SlashCmd; 55 | 56 | Roids.Hooks.TARGET_SlashCmd = SlashCmdList.TARGET; 57 | Roids.TARGET_SlashCmd = function(msg) 58 | if Roids.DoTarget(msg) then 59 | return; 60 | end 61 | Roids.Hooks.TARGET_SlashCmd(msg); 62 | end 63 | SlashCmdList.TARGET = Roids.TARGET_SlashCmd; -------------------------------------------------------------------------------- /docs/macro_invoking.md: -------------------------------------------------------------------------------- 1 | # Invoking other Macros 2 | 3 | This Addon provides you with the ability to invoke other Macros from within you 4 | own Macros! 5 | 6 | This allows for very interesting things like chaining together very complicated 7 | Macros that each check for certain conditions before they are executed. To 8 | execute another Macro, you have to put the name of the Macro in curly braces 9 | `{` `}` after any chat command that is supported by this Addon. 10 | 11 | ### Example 12 | 13 | Macro 1: `Master` 14 | ```lua 15 | /cast {Blood} 16 | /cast {WW} 17 | /cast {Heroic} 18 | ``` 19 | 20 | Macro 2: `Blood` 21 | ```lua 22 | /cast [mypower>30] Bloodthirst 23 | ``` 24 | 25 | Macro 3: `WW` 26 | ```lua 27 | /cast [mypower>25] Whirlwind 28 | ``` 29 | 30 | Macro 4: `Heroic` 31 | ```lua 32 | /cast [mypower>60 harm] Heroic Strike 33 | ``` 34 | 35 | You can now use Macro 1 `Master` to execute all the other Macros respectively. 36 | 37 | ## Invoking Macros may succeed or fail 38 | 39 | The master Macro that attempts to execute another child Macro also knows 40 | whether the executed Macro has succeeded if you're using conditions in the 41 | child Macro. This allows you to build very complicated recursive constructs! 42 | 43 | ### Example 44 | 45 | Macro 1: `Hawk` 46 | ```lua 47 | /cast {Monkey}; [nomybuff:Aspect_of_the_Hawk] Aspect of the Hawk 48 | ``` 49 | 50 | Macro 2: `Monkey` 51 | ```lua 52 | /cast [nomybuff:Aspect_of_the_Monkey] Aspect of the Monkey 53 | ``` 54 | 55 | When you now use Macro 1 `Hawk`, the macro will call Macro 2 `Monkey` and check 56 | if it succeeded. Macro 2 will only succeed if the player doesn't have the 57 | `Aspect of the Monkey` buff active. If he does, the Macro will fail and the 58 | second part of Macro 1 `Hawk` will be executed! -------------------------------------------------------------------------------- /Extensions/Mouseover/CT_RaidAssist.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Author: Dennis Werner Garske (DWG) 3 | License: MIT License 4 | ]] 5 | local _G = _G or getfenv(0) 6 | local Roids = _G.Roids or {} 7 | Roids.mouseoverUnit = Roids.mouseoverUnit or nil; 8 | 9 | local Extension = Roids.RegisterExtension("CT_RaidAssist"); 10 | Extension.RegisterEvent("ADDON_LOADED", "OnLoad"); 11 | 12 | function Extension.OnEnter() 13 | local tempOptions = CT_RAMenu_Options["temp"]; 14 | if ( SpellIsTargeting() ) then 15 | SetCursor("CAST_CURSOR"); 16 | end 17 | local parent = this.frameParent; 18 | local id = parent.id; 19 | if ( strsub(parent.name, 1, 12) == "CT_RAMTGroup" ) then 20 | local name; 21 | if ( CT_RA_MainTanks[id] ) then 22 | name = CT_RA_MainTanks[id]; 23 | end 24 | for i = 1, GetNumRaidMembers(), 1 do 25 | local memberName = GetRaidRosterInfo(i); 26 | if ( name == memberName ) then 27 | id = i; 28 | break; 29 | end 30 | end 31 | elseif ( strsub(parent.name, 1, 12) == "CT_RAPTGroup" ) then 32 | local name; 33 | if ( CT_RA_PTargets[id] ) then 34 | name = CT_RA_PTargets[id]; 35 | end 36 | for i = 1, GetNumRaidMembers(), 1 do 37 | local memberName = GetRaidRosterInfo(i); 38 | if ( name == memberName ) then 39 | id = i; 40 | break; 41 | end 42 | end 43 | end 44 | Roids.mouseoverUnit = "raid"..id; 45 | end 46 | 47 | function Extension.OnLeave() 48 | Roids.mouseoverUnit = nil; 49 | end 50 | 51 | function Extension.OnLoad() 52 | if arg1 ~= "CT_RaidAssist" then 53 | return; 54 | end 55 | 56 | Extension.Hook("CT_RA_MemberFrame_OnEnter", "OnEnter"); 57 | Extension.HookMethod(_G["GameTooltip"], "Hide", "OnLeave"); 58 | Extension.HookMethod(_G["GameTooltip"], "FadeOut", "OnLeave"); 59 | 60 | end 61 | 62 | _G["Roids"] = Roids; -------------------------------------------------------------------------------- /Utility.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Author: Dennis Werner Garske (DWG) 3 | License: MIT License 4 | ]] 5 | local _G = _G or getfenv(0) 6 | local Roids = _G.Roids or {} -- redundant since we're loading first but peace of mind if another file is added top of chain 7 | 8 | -- Splits the given string into a list of sub-strings 9 | -- str: The string to split 10 | -- seperatorPattern: The seperator between sub-string. May contain patterns 11 | -- returns: A list of sub-strings 12 | function Roids.splitString(str, seperatorPattern) 13 | local tbl = {}; 14 | if not str then 15 | return tbl; 16 | end 17 | local pattern = "(.-)" .. seperatorPattern; 18 | local lastEnd = 1; 19 | local s, e, cap = string.find(str, pattern, 1); 20 | 21 | while s do 22 | if s ~= 1 or cap ~= "" then 23 | table.insert(tbl,cap); 24 | end 25 | lastEnd = e + 1; 26 | s, e, cap = string.find(str, pattern, lastEnd); 27 | end 28 | 29 | if lastEnd <= string.len(str) then 30 | cap = string.sub(str, lastEnd); 31 | table.insert(tbl, cap); 32 | end 33 | 34 | return tbl 35 | end 36 | 37 | -- Prints all the given arguments into WoW's default chat frame 38 | function Roids.Print(...) 39 | if not DEFAULT_CHAT_FRAME:IsVisible() then 40 | FCF_SelectDockFrame(DEFAULT_CHAT_FRAME) 41 | end 42 | local out = "|cffc8c864Roids:|r"; 43 | 44 | for i=1, arg.n, 1 do 45 | out = out..tostring(arg[i]).." "; 46 | end 47 | 48 | DEFAULT_CHAT_FRAME:AddMessage(out) 49 | end 50 | 51 | -- Trims any leading or trailing white space characters from the given string 52 | -- str: The string to trim 53 | -- returns: The trimmed string 54 | function Roids.Trim(str) 55 | if not str then 56 | return nil; 57 | end 58 | return string.gsub(str,"^%s*(.-)%s*$", "%1"); 59 | end 60 | 61 | _G["Roids"] = Roids 62 | -------------------------------------------------------------------------------- /docs/compatibility.md: -------------------------------------------------------------------------------- 1 | # Compatibility Notes 2 | 3 | ## UnitFrames 4 | 5 | Currently, the following UnitFrames have been tested and are compatible with 6 | this AddOn: 7 | 8 | * agUnitFrames 9 | * Blizzard's UnitFrames 10 | * CT_RaidAssist 11 | * CT_UnitFrames 12 | * DiscordUnitFrames 13 | * FocusFrame 14 | * Grid 15 | * LunaUnitFrames 16 | * NotGrid 17 | * PerfectRaid 18 | * pfUI 19 | * sRaidFrames 20 | * UnitFramesImproved_Vanilla 21 | * XPerl 22 | 23 | **Note**: If your AddOn is not on this list, please give it a try anyway! I've 24 | implemented this in a way where it very well might work in your UnitFrames 25 | AddOn as well! And if it doesn't please file an Issue and I'll try to add it asap. 26 | 27 | ## Action Bars 28 | 29 | Currently, the following Action Bars have been tested and are compatible with 30 | this Addon: 31 | 32 | * Blizzard's Action Bars 33 | * Discord Action Bars 34 | 35 | **Note**: If your AddOn is not on this list, please give it a try anyway! I've 36 | implemented this in a way where it very well might work in your Action Bars 37 | AddOn as well! And if it doesn't please file an Issue and I'll try to add it asap. 38 | 39 | ## Supported Addons 40 | 41 | ### ClassicFocus / FocusFrame 42 | 43 | Using one of these two Addons allows you to make use of the `@focus` target 44 | condition! 45 | 46 | ## Known Bugs and work arounds 47 | 48 | ## Gray button fix 49 | 50 | In order to fix the range and cooldown check (gray buttons), you have to write 51 | this line at the top of each macro: 52 | 53 | ```lua 54 | /script if nil then CastSpellByName("SPELLNAME"); end 55 | ``` 56 | 57 | Make sure to replace SPELLNAME with the actual name of your spell. 58 | 59 | ```lua 60 | /script if nil then CastSpellByName("Chain Heal"); end 61 | /cast [@target help mod:alt] Chain Heal; Chain Heal(Rank 1) 62 | ``` 63 | 64 | --- 65 | 66 | **Note:** There is currently no way to make this work for different spells 67 | depending on conditions. 68 | 69 | ```lua 70 | /script if nil then CastSpellByName("Chain Heal"); end 71 | /cast [@target help] Chain Heal; Frost Shock 72 | ``` 73 | 74 | This will only activate the range and cooldown check for Chain Heal and not 75 | check Frost Shock at all! This appears to be a limitation with the API and I 76 | don't see a way of fixing this. Please contact me if you do! 77 | -------------------------------------------------------------------------------- /Extensions/Mouseover/Blizzard.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Author: Fondlez 3 | 4 | This extension adds improved support for mouseover macros in Roid-Macros 5 | for the default Blizzard frames. 6 | ]] 7 | local _G = _G or getfenv(0) 8 | local Roids = _G.Roids or {} 9 | Roids.mouseoverUnit = Roids.mouseoverUnit or nil 10 | 11 | local Extension = Roids.RegisterExtension("Blizzard") 12 | 13 | function Extension.RegisterMouseoverForFrame(frame, unit) 14 | if not frame then return end 15 | 16 | local onenter = frame:GetScript("OnEnter") 17 | local onleave = frame:GetScript("OnLeave") 18 | 19 | frame:SetScript("OnEnter", function() 20 | Roids.mouseoverUnit = unit 21 | if onenter then 22 | onenter() 23 | end 24 | end) 25 | 26 | frame:SetScript("OnLeave", function() 27 | Roids.mouseoverUnit = nil 28 | if onleave then 29 | onleave() 30 | end 31 | end) 32 | end 33 | 34 | do 35 | local frames = { 36 | ["PlayerFrame"] = "player", 37 | ["PetFrame"] = "pet", 38 | ["TargetFrame"] = "target", 39 | ["PartyMemberFrame1"] = "party1", 40 | ["PartyMemberFrame2"] = "party2", 41 | ["PartyMemberFrame3"] = "party3", 42 | ["PartyMemberFrame4"] = "party4", 43 | ["PartyMemberFrame1PetFrame"] = "party1", 44 | ["PartyMemberFrame2PetFrame"] = "party2", 45 | ["PartyMemberFrame3PetFrame"] = "party3", 46 | ["PartyMemberFrame4PetFrame"] = "party4", 47 | } 48 | 49 | local bars = { 50 | "HealthBar", 51 | "ManaBar", 52 | } 53 | 54 | local allFrames = {} 55 | for name, unit in pairs(frames) do 56 | allFrames[name] = unit 57 | for i, bar in ipairs(bars) do 58 | allFrames[name .. bar] = unit 59 | end 60 | end 61 | 62 | -- Inconsisent naming for TargetofTarget required 63 | allFrames["TargetofTargetFrame"] = "targettarget" 64 | allFrames["TargetofTargetHealthBar"] = "targettarget" 65 | allFrames["TargetofTargetManaBar"] = "targettarget" 66 | 67 | function Extension.OnLoad() 68 | local frame 69 | for name, unit in pairs(allFrames) do 70 | frame = _G[name] 71 | 72 | if frame then 73 | Extension.RegisterMouseoverForFrame(frame, unit) 74 | end 75 | end 76 | end 77 | end 78 | -------------------------------------------------------------------------------- /docs/commands/target.md: -------------------------------------------------------------------------------- 1 | # A few words about /target macros 2 | 3 | In theory, you can use every condition, however, a few of them behave a little 4 | different in '/target' macros. Here's a list of them: 5 | 6 | ## Definitions 7 | 8 | A few definitions before we start: 9 | ##### final target 10 | The unit that will be selected after evaluating every condition. E.g. 11 | `/target Ragnaros` - Ragnaros will be the `final target`. 12 | 13 | ##### checked target 14 | The unit against which all conditions will be checked. E.g. 15 | `/target [harm @mouseover] Ragnaros` - Your current mouseover target will be 16 | the `checked target` while `Ragnaros` is still the `final target`. 17 | 18 | ---- 19 | 20 | As stated before, instead of checking the final target, all conditions will 21 | be validated against the checked target. This means that your checked target 22 | may or may not be the same as your final target. This allows you to create more 23 | specialized macros and, on top of that, is more intuitive to use. 24 | 25 | ## Examples 26 | 27 | ```lua 28 | /target [harm @mouseover] Ragnaros; Dotalock 29 | ``` 30 | 31 | This will target Ragnaros, if your mouseover target is hostile to yourself. If 32 | it isn't the player Dotalock will be targeted instead. 33 | 34 | 35 | Additionally, assume you want to target your mouseover target depending on 36 | whether or not some pre-conditions are met. In Vanilla WoW, there is no way to 37 | do something like that. With this AddOn, however, we can do things like this: 38 | 39 | ```lua 40 | /target [harm @target] @targettarget 41 | ``` 42 | 43 | When you use this macro, you will target your target's target, if your current 44 | target is considered hostile towards you. 45 | 46 | ## Known issues 47 | 48 | Assume you're assaulting a capital like Orgrimmar or Stormwind and you have a 49 | macro like the following: 50 | 51 | ```lua 52 | /target [harm @mouseover] @mouseover 53 | ``` 54 | 55 | Now you're trying to use this macro to select one of the city's guards that is 56 | a fair bit away from you. Because of the way the Vanilla client implements 57 | targeting by names, you're not guaranteed to target your mouseover target. This 58 | will always happen when another unit with the same name is closer to you than 59 | the desired unit. There is no way to work around this issue, as the actual 60 | targeting procedure hasn't been implemented in Lua and is therefore out of 61 | reach for AddOn developers. 62 | -------------------------------------------------------------------------------- /Extensions/Mouseover/pfUI.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Author: Dennis Werner Garske (DWG) 3 | License: MIT License 4 | ]] 5 | local _G = _G or getfenv(0) 6 | local Roids = _G.Roids or {} 7 | 8 | Roids.mouseoverUnit = Roids.mouseoverUnit or nil; 9 | 10 | local Extension = Roids.RegisterExtension("pfUI"); 11 | Extension.RegisterEvent("PLAYER_ENTERING_WORLD", "PLAYER_ENTERING_WORLD"); 12 | 13 | function Extension.OnLoad() 14 | end 15 | 16 | function Extension.RegisterPlayerScripts() 17 | local onEnterFunc = pfUI.uf.player:GetScript("OnEnter"); 18 | local onLeaveFunc = pfUI.uf.player:GetScript("OnLeave"); 19 | 20 | pfUI.uf.player:SetScript("OnEnter", function() 21 | Roids.mouseoverUnit = "player"; 22 | if onEnterFunc then 23 | onEnterFunc(); 24 | end 25 | end); 26 | 27 | pfUI.uf.player:SetScript("OnLeave", function() 28 | Roids.mouseoverUnit = nil; 29 | if onLeaveFunc then 30 | onLeaveFunc(); 31 | end 32 | end); 33 | end 34 | 35 | function Extension.RegisterTargetScripts() 36 | local onEnterFunc = pfUI.uf.target:GetScript("OnEnter"); 37 | local onLeaveFunc = pfUI.uf.target:GetScript("OnLeave"); 38 | 39 | pfUI.uf.target:SetScript("OnEnter", function() 40 | Roids.mouseoverUnit = "target"; 41 | if onEnterFunc then 42 | onEnterFunc(); 43 | end 44 | end); 45 | 46 | pfUI.uf.target:SetScript("OnLeave", function() 47 | Roids.mouseoverUnit = nil; 48 | if onLeaveFunc then 49 | onLeaveFunc(); 50 | end 51 | end); 52 | end 53 | 54 | function Extension.RegisterTargetTargetScripts() 55 | local onEnterFunc = pfUI.uf.targettarget:GetScript("OnEnter"); 56 | local onLeaveFunc = pfUI.uf.targettarget:GetScript("OnLeave"); 57 | 58 | pfUI.uf.targettarget:SetScript("OnEnter", function() 59 | Roids.mouseoverUnit = "targettarget"; 60 | if onEnterFunc then 61 | onEnterFunc(); 62 | end 63 | end); 64 | 65 | pfUI.uf.targettarget:SetScript("OnLeave", function() 66 | Roids.mouseoverUnit = nil; 67 | if onLeaveFunc then 68 | onLeaveFunc(); 69 | end 70 | end); 71 | end 72 | 73 | function Extension.PLAYER_ENTERING_WORLD() 74 | if not pfUI or not pfUI.uf then 75 | return; 76 | end 77 | Extension.RegisterPlayerScripts(); 78 | Extension.RegisterTargetScripts(); 79 | Extension.RegisterTargetTargetScripts(); 80 | end 81 | -------------------------------------------------------------------------------- /docs/conditions.md: -------------------------------------------------------------------------------- 1 | # Conditions 2 | 3 | Conditions allow you to fine-tune your macro's behaviour without having to 4 | know any Lua at all! 5 | 6 | --- 7 | 8 | # Notation 9 | 10 | ```lua 11 | /command [condition] parameters 12 | ``` 13 | 14 | Conditions are put after the chat command but before the chat command's 15 | parameters into square brackets. 16 | 17 | --- 18 | 19 | ```lua 20 | /command [condition1 condition2] parameters 21 | ``` 22 | 23 | Conditions can be chained together by seperating them using an empty space. All 24 | conditions must be met before the command is executed. 25 | 26 | --- 27 | 28 | ```lua 29 | /command [condition:parameter] parameters 30 | ``` 31 | 32 | Some conditions may take parameters. These follow after a colon `:` or, in 33 | some cases, after a greater than `>` or less than `<` sign. 34 | 35 | --- 36 | 37 | ```lua 38 | /command [condition:1/2/3] parameters 39 | ``` 40 | 41 | Some conditions may take multiple parameters. These have to be seperated by 42 | slashes `/`. 43 | 44 | # Branches 45 | 46 | When using conditions in your macros, it might be desirable to perform two 47 | different actions that depend on both outcomes of a condition. While you could 48 | in theory achieve this by repeating the inverted condition one line below, 49 | you'll realise that this would lead to making your macros exceedingly bigger. 50 | An example: 51 | 52 | ```lua 53 | /cast [dead] Spell1 54 | /cast [nodead] Spell2 55 | ``` 56 | 57 | Roid-Macros solves this by allowing you to branch off of the first set of 58 | parameters, if the conditions fails, by seperating them with a semicolon `;` at 59 | the end. The same example but now with a branch instead: 60 | 61 | ```lua 62 | /cast [dead] Spell1; Spell2 63 | ``` 64 | 65 | Of course you could also put in more conditons in the different branches! 66 | 67 | ```lua 68 | /cast [condition1] Healing Wave; [condition2] Windfury Totem; [condition3] Healing Wave (Rank 3); Frost Shock 69 | ``` 70 | 71 | Note, that you may use any spell you want within each condition. Also, there 72 | mustn't be a whitespace character after each semicolon. You may, however, use 73 | them to improve readability. 74 | 75 | --- 76 | 77 | # Supported Chat Commands 78 | 79 | This is a list of all Chat Commands that support conditions: 80 | 81 | * /cast 82 | * /target 83 | * [/equip](commands/equip.md) 84 | * [/equipoh](commands/equip.md) 85 | * [/petattack](commands/petattack.md) 86 | * [/unshift](commands/unshift.md) 87 | * [/use](commands/use.md) 88 | 89 | --- 90 | 91 | # Available Conditoins: 92 | * [attacks / noattacks](conditions/attacks.md) 93 | * [(no)buff / (no)mybuff / (no)debuff / (no)mydebuff](conditions/buffs.md) 94 | * [channeled / nochanneled](conditions/channeled.md) 95 | * [combat / nocombat](conditions/combat.md) 96 | * [cooldown / nocooldown](conditions/cooldown.md) 97 | * [dead / nodead](conditions/dead.md) 98 | * [equipped / noquipped / worn / noworn](conditions/equipped.md) 99 | * [group](conditions/group.md) 100 | * [help / harm](conditions/help_harm.md) 101 | * [(my)hp](conditions/hp.md) 102 | * [isnpc](conditions/isnpc.md) 103 | * [isplayer](conditions/isplayer.md) 104 | * [mod](conditions/mod.md) 105 | * [party](conditions/party.md) 106 | * [(my)power / (my)rawpower](conditions/power.md) 107 | * [raid](conditions/raid.md) 108 | * [stance](conditions/stance.md) 109 | * [stealth / nostealth](conditions/stealth.md) 110 | * [type](conditions/type.md) 111 | * [UnitID](conditions/target.md) 112 | -------------------------------------------------------------------------------- /Extensions/Mouseover/Grid.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Author: Dennis Werner Garske (DWG) 3 | License: MIT License 4 | ]] 5 | local _G = _G or getfenv(0) 6 | local Roids = _G.Roids or {} 7 | 8 | Roids.Hooks = Roids.Hooks or {}; 9 | Roids.mouseoverUnit = Roids.mouseoverUnit or nil; 10 | 11 | local Extension = Roids.RegisterExtension("Grid"); 12 | Extension.RegisterEvent("ADDON_LOADED", "OnLoad"); 13 | 14 | function Extension.OnEnter(unit) 15 | Roids.mouseoverUnit = unit; 16 | end 17 | 18 | function Extension.OnLeave() 19 | Roids.mouseoverUnit = nil; 20 | end 21 | 22 | function Extension.OnLoad() 23 | if arg1 ~= "Grid" then 24 | return; 25 | end 26 | 27 | Roids.Hooks.Grid = { CreateFrames = GridFrame.frameClass.prototype.CreateFrames}; 28 | GridFrame.frameClass.prototype.CreateFrames = Roids.GrdCreateFrames; 29 | end 30 | 31 | -- Taken from GridFrame.lua and added OnEnter and OnLeave scripts 32 | function Roids:GrdCreateFrames() 33 | -- create frame 34 | --self.frame = CreateFrame("Button", nil, UIParent) 35 | local f = self.frame 36 | 37 | f:SetScript("OnEnter", function() 38 | Extension.OnEnter(self.unit); 39 | end); 40 | f:SetScript("OnLeave", function() 41 | Extension.OnLeave(); 42 | end); 43 | 44 | -- f:Hide() 45 | f:EnableMouse(true) 46 | f:RegisterForClicks("LeftButtonUp", "RightButtonUp", "MiddleButtonUp", "Button4Up", "Button5Up") 47 | f:SetWidth(GridFrame:GetFrameSize()) 48 | f:SetHeight(GridFrame:GetFrameSize()) 49 | 50 | -- only use SetScript pre-TBC 51 | if Grid.isTBC then 52 | f:SetAttribute("type1", "target") 53 | else 54 | f:SetScript("OnClick", function () GridFrame_OnClick(f, arg1) end) 55 | f:SetScript("OnAttributeChanged", GridFrame_OnAttributeChanged) 56 | end 57 | 58 | -- create border 59 | f:SetBackdrop({ 60 | bgFile = "Interface\\Addons\\Grid\\white16x16", tile = true, tileSize = 16, 61 | edgeFile = "Interface\\Addons\\Grid\\white16x16", edgeSize = 1, 62 | insets = {left = 1, right = 1, top = 1, bottom = 1}, 63 | }) 64 | f:SetBackdropBorderColor(0,0,0,0) 65 | f:SetBackdropColor(0,0,0,1) 66 | 67 | -- create bar BG (which users will think is the real bar, as it is the one that has a shiny color) 68 | -- this is necessary as there's no other way to implement status bars that grow in the other direction than normal 69 | f.BarBG = f:CreateTexture() 70 | f.BarBG:SetTexture("Interface\\Addons\\Grid\\gradient32x32") 71 | f.BarBG:SetPoint("CENTER", f, "CENTER") 72 | f.BarBG:SetWidth(GridFrame:GetFrameSize()-4) 73 | f.BarBG:SetHeight(GridFrame:GetFrameSize()-4) 74 | 75 | -- create bar 76 | f.Bar = CreateFrame("StatusBar", nil, f) 77 | f.Bar:SetStatusBarTexture("Interface\\Addons\\Grid\\gradient32x32") 78 | f.Bar:SetOrientation("VERTICAL") 79 | f.Bar:SetMinMaxValues(0,100) 80 | f.Bar:SetValue(100) 81 | f.Bar:SetStatusBarColor(0,0,0,0.8) 82 | f.Bar:SetPoint("CENTER", f, "CENTER") 83 | f.Bar:SetFrameLevel(4) 84 | f.Bar:SetWidth(GridFrame:GetFrameSize()-4) 85 | f.Bar:SetHeight(GridFrame:GetFrameSize()-4) 86 | 87 | -- create center text 88 | f.Text = f.Bar:CreateFontString(nil, "ARTWORK") 89 | f.Text:SetFontObject(GameFontHighlightSmall) 90 | f.Text:SetFont(STANDARD_TEXT_FONT,8) 91 | f.Text:SetJustifyH("CENTER") 92 | f.Text:SetJustifyV("CENTER") 93 | f.Text:SetPoint("CENTER", f, "CENTER") 94 | 95 | -- create icon 96 | f.Icon = f.Bar:CreateTexture("Icon", "OVERLAY") 97 | f.Icon:SetWidth(16) 98 | f.Icon:SetHeight(16) 99 | f.Icon:SetPoint("CENTER", f, "CENTER") 100 | f.Icon:SetTexCoord(0.05, 0.95, 0.05, 0.95) 101 | f.Icon:SetTexture(1,1,1,0) --"Interface\\Icons\\INV_Misc_Orb_02" 102 | 103 | -- set texture 104 | f:SetNormalTexture(1,1,1,0) 105 | f:SetHighlightTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight") 106 | 107 | self.frame = f 108 | 109 | -- set up click casting 110 | ClickCastFrames = ClickCastFrames or {} 111 | ClickCastFrames[self.frame] = true 112 | end 113 | 114 | _G["Roids"] = Roids; -------------------------------------------------------------------------------- /Extensions/Tooltip/Generic.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Author: Dennis Werner Garske (DWG) 3 | License: MIT License 4 | ]] 5 | local _G = _G or getfenv(0) 6 | local Roids = _G.Roids or {} 7 | 8 | -- Returns information regarding the macro the button is holing. 9 | -- buttonId: The id of the button we're trying to get information from 10 | -- returns: nil if the button doesn't hold a macro. Otherwhise the macro's name, texture path and a list of lines that form the macro's body 11 | function Roids.GetMacroInfo(buttonId) 12 | local macroName = GetActionText(buttonId); 13 | 14 | if not macroName then 15 | return nil; 16 | end 17 | 18 | local name, texture, body = GetMacroInfo(GetMacroIndexByName(macroName)); 19 | 20 | return name, texture, Roids.splitString(body, "\n"); 21 | end 22 | 23 | -- Returns all spells the current player has learned 24 | function Roids.GetLearnedSpells() 25 | local i = 1 26 | local spells = {}; 27 | while true do 28 | local spellName, spellRank = GetSpellName(i, BOOKTYPE_SPELL); 29 | if not spellName then 30 | break; 31 | end 32 | 33 | local list = spells[spellName] or {}; 34 | if not list.spellRank then 35 | list[spellRank] = i; 36 | list.highest = i; 37 | end 38 | 39 | spells[spellName] = list; 40 | 41 | i = i + 1; 42 | end 43 | 44 | return spells; 45 | end 46 | 47 | -- Sanitizes the given name in a uniform way 48 | -- returns: The name without white spaces and in lower case 49 | function Roids.SanitizeSpellName(name) 50 | return string.lower(string.gsub(name,"%s*","")); 51 | end 52 | 53 | -- Returns whether or not the given name is a spell 54 | function Roids.IsSpell(name) 55 | local name = Roids.SanitizeSpellName(name); 56 | local spells = Roids.GetLearnedSpells(); 57 | 58 | for k,v in pairs(spells) do 59 | local knownName = Roids.SanitizeSpellName(v.name.."("..v.rank..")"); 60 | if knownName == name then 61 | return true; 62 | end 63 | end 64 | 65 | return false; 66 | end 67 | 68 | local Extension = Roids.RegisterExtension("Generic_show"); 69 | Extension.RegisterEvent("PLAYER_ENTERING_WORLD", "PLAYER_ENTERING_WORLD"); 70 | Extension.RegisterEvent("SPELLS_CHANGED", "SPELLS_CHANGED"); 71 | 72 | function Extension.OnLoad() 73 | end 74 | 75 | function Roids.ParseSpell(line) 76 | local rankStart, rankEnd = string.find(line, Roids.Localized.SpellRank); 77 | local spellName, spellRank; 78 | 79 | if rankStart then 80 | spellName = Roids.Trim(string.sub(line, 0, rankStart - 1)); 81 | spellRank = Roids.Trim(string.sub(line, rankStart + 1, rankEnd - 1)); 82 | else 83 | spellName = Roids.Trim(line); 84 | end 85 | 86 | local spell = Roids.knownSpells[spellName]; 87 | if not spell then 88 | return false; 89 | end 90 | 91 | local spellSlot = spell[spellRank or "highest"]; 92 | GameTooltip:SetSpell(spellSlot, "player"); 93 | 94 | return true; 95 | end 96 | 97 | function Roids.ParseItem(line) 98 | local bag, slot = Roids.FindItem(Roids.Trim(line)); 99 | 100 | if not bag then 101 | return false; 102 | end 103 | 104 | if bag < 0 then 105 | GameTooltip:SetInventoryItem("player", -bag); 106 | end 107 | 108 | GameTooltip:SetBagItem(bag, slot); 109 | return true; 110 | end 111 | 112 | function Extension.PLAYER_ENTERING_WORLD() 113 | Roids.knownSpells = Roids.GetLearnedSpells(); 114 | 115 | if not Roids.Hooks.GameTooltip_SetAction then 116 | Roids.Hooks.GameTooltip_SetAction = GameTooltip.SetAction; 117 | 118 | GameTooltip.SetAction = function(this, buttonId) 119 | local name, texture, body = Roids.GetMacroInfo(buttonId); 120 | 121 | if not name then 122 | return Roids.Hooks.GameTooltip_SetAction(this, buttonId); 123 | end 124 | 125 | for _,line in pairs(body) do 126 | if string.find(line, "^#showtooltip ") then 127 | local text = string.sub(line, 14); 128 | if Roids.ParseSpell(text) then 129 | return; 130 | end 131 | 132 | if Roids.ParseItem(text) then 133 | return; 134 | end 135 | 136 | Roids.Print("Unknown Tooltip: '"..text.."'"); 137 | end 138 | end 139 | end 140 | end 141 | end 142 | 143 | function Extension.SPELLS_CHANGED() 144 | Roids.knownSpells = Roids.GetLearnedSpells(); 145 | end 146 | -------------------------------------------------------------------------------- /Extensions/Mouseover/PerfectRaid.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Author: Dennis Werner Garske (DWG) 3 | License: MIT License 4 | ]] 5 | local _G = _G or getfenv(0) 6 | local Roids = _G.Roids or {} 7 | 8 | Roids.Hooks = Roids.Hooks or {}; 9 | Roids.mouseoverUnit = Roids.mouseoverUnit or nil; 10 | 11 | local Extension = Roids.RegisterExtension("PerfectRaid"); 12 | Extension.RegisterEvent("ADDON_LOADED", "OnLoad"); 13 | 14 | function Extension.OnEnter(unit) 15 | Roids.mouseoverUnit = unit; 16 | end 17 | 18 | function Extension.OnLeave() 19 | Roids.mouseoverUnit = nil; 20 | end 21 | 22 | function Extension.OnLoad() 23 | if arg1 ~= "PerfectRaid" then 24 | return; 25 | end 26 | 27 | Roids.Hooks.PerfectRaid = { CreateFrame = PerfectRaid.CreateFrame }; 28 | PerfectRaid.CreateFrame = Roids.PerfectRaidCreateFrame; 29 | end 30 | 31 | function Roids.PerfectRaidCreateFrame(self, num) 32 | -- We need to allocate up to num frames 33 | 34 | if self.poolsize >= num then return end 35 | 36 | --[[ 37 | local mem,thr = gcinfo() 38 | self:Msg("Memory Usage Before: %s [%s].", mem, thr) 39 | --]] 40 | local side = self.opt.Align 41 | 42 | local justify,point,relative,offset 43 | 44 | if side == "left" then 45 | justify = "RIGHT" 46 | point = "LEFT" 47 | relative = "RIGHT" 48 | offset = 5 49 | elseif side == "right" then 50 | justify = "LEFT" 51 | point = "RIGHT" 52 | relative = "LEFT" 53 | offset = -5 54 | end 55 | 56 | for i=(self.poolsize + 1),num do 57 | local frame = CreateFrame("Button", nil, PerfectRaidFrame) 58 | frame:EnableMouse(true) 59 | frame.unit = "raid"..i 60 | frame.id = i 61 | frame:SetWidth(225) 62 | frame:SetHeight(13) 63 | frame:SetMovable(true) 64 | frame:RegisterForDrag("LeftButton") 65 | frame:SetScript("OnDragStart", function() self["master"]:StartMoving() end) 66 | frame:SetScript("OnDragStop", function() self["master"]:StopMovingOrSizing() self:SavePosition() end) 67 | frame:RegisterForClicks("LeftButtonUp", "RightButtonUp", "MiddleButtonUp", "Button4Up", "Button5Up") 68 | frame:SetScript("OnClick", self.OnClick) 69 | frame:SetScript("OnEnter", function() 70 | Extension.OnEnter(this.unit); 71 | end); 72 | frame:SetScript("OnLeave", function() 73 | Extension.OnLeave(); 74 | end); 75 | frame:SetParent(self.master) 76 | 77 | local font = frame:CreateFontString(nil, "ARTWORK") 78 | font:SetFontObject(GameFontHighlightSmall) 79 | font:SetText("WW") 80 | font:SetJustifyH("CENTER") 81 | font:SetWidth(font:GetStringWidth()) 82 | font:SetHeight(14) 83 | font:Show() 84 | font:ClearAllPoints() 85 | font:SetPoint(point, frame, relative,0, 0) 86 | -- Add this font string to the frame 87 | frame.Prefix = font 88 | 89 | font = frame:CreateFontString(nil, "ARTWORK") 90 | font:SetFontObject(GameFontHighlightSmall) 91 | font:SetText() 92 | font:SetJustifyH(justify) 93 | font:SetWidth(55) 94 | font:SetHeight(12) 95 | font:Show() 96 | font:ClearAllPoints() 97 | font:SetPoint(point, frame.Prefix, relative, offset, 0) 98 | -- Add this font string to the frame 99 | frame.Name = font 100 | 101 | local bar = CreateFrame("StatusBar", nil, frame) 102 | bar:SetStatusBarTexture("Interface\\TargetingFrame\\UI-StatusBar") 103 | bar:SetMinMaxValues(0,100) 104 | bar:ClearAllPoints() 105 | bar:SetPoint(point, frame.Name, relative, offset, 0) 106 | bar:SetWidth(60) 107 | bar:SetHeight(7) 108 | bar:Show() 109 | -- Add this status bar to the frame 110 | frame.Bar = bar 111 | 112 | font = frame:CreateFontString(nil, "ARTWORK") 113 | font:SetFontObject(GameFontHighlightSmall) 114 | font:SetText("") 115 | font:SetJustifyH(justify) 116 | font:SetWidth(font:GetStringWidth()) 117 | font:SetHeight(12) 118 | font:Show() 119 | font:ClearAllPoints() 120 | font:SetPoint(point, frame.Bar, relative, offset, 0) 121 | -- Add this font string to the frame 122 | frame.Status = font 123 | 124 | -- Lets set the frame in the indexed array 125 | self.frames[i] = frame 126 | self.frames["raid"..i] = frame 127 | self.poolsize = i 128 | end 129 | 130 | mem2,thr2 = gcinfo() 131 | --[[ 132 | self:Msg("Memory Usage After: %s [%s].", mem2, thr2) 133 | self:Msg("Frame creation change: %s [%s].", mem2 - mem, thr2 - thr) 134 | --]] 135 | end 136 | 137 | _G["Roids"] = Roids; -------------------------------------------------------------------------------- /ExtensionsManager.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Author: Dennis Werner Garske (DWG) 3 | License: MIT License 4 | ]] 5 | local _G = _G or getfenv(0) 6 | local Roids = _G.Roids or {} 7 | 8 | -- A list of all registered extensions 9 | Roids.Extensions = Roids.Extensions or {}; 10 | 11 | -- Calls the "OnLoad" function of every extension 12 | function Roids.InitializeExtensions() 13 | for k, v in pairs(Roids.Extensions) do 14 | local func = v["OnLoad"]; 15 | if not func then 16 | Roids.Print("Roids.InitializeExtensions - Couldn't find 'OnLoad' function for extension "..k); 17 | else 18 | func(); 19 | end 20 | end 21 | end 22 | 23 | -- Removes the given hook 24 | -- hook: The hook to remove 25 | function Roids.RemoveHook(hook) 26 | _G[hook.name] = hook.origininal; 27 | end 28 | 29 | -- Removes the given hook from the given object 30 | -- object: The object to remove the hook from 31 | -- hook: The hook to remove 32 | function Roids.RemoveMethodHook(object, hook) 33 | object[hook.name] = hook.origininal; 34 | end 35 | 36 | -- Clears all previously declared hooks 37 | function Roids.ClearHooks() 38 | for k, v in pairs(Roids.Extensions) do 39 | for k2, v2 in pairs(v.internal.memberHooks) do 40 | for k3, v3 in pairs(v2) do 41 | Roids.RemoveMethodHook(k2, v3); 42 | end 43 | end 44 | 45 | for k2, v2 in pairs(v.internal.hooks) do 46 | Roids.RemoveHook(v2); 47 | end 48 | end 49 | end 50 | 51 | -- Creates a new extension with the given name 52 | -- name: the name of the extension 53 | function Roids.RegisterExtension(name) 54 | local extension = { 55 | internal = 56 | { 57 | frame = CreateFrame("FRAME"), 58 | eventHandlers = {}, 59 | hooks = {}, 60 | memberHooks = {}, 61 | }, 62 | }; 63 | 64 | extension.RegisterEvent = function(eventName, callbackName) 65 | Roids.RegisterEvent(name, eventName, callbackName); 66 | end; 67 | 68 | extension.Hook = function(functionName, callbackName, dontCallOriginal) 69 | Roids.RegisterHook(name, functionName, callbackName, dontCallOriginal); 70 | end; 71 | 72 | extension.HookMethod = function(object, functionName, callbackName, dontCallOriginal) 73 | Roids.RegisterMethodHook(name, object, functionName, callbackName, dontCallOriginal); 74 | end; 75 | 76 | 77 | extension.UnregisterEvent = function(eventName, callbackName) 78 | Roids.UnregisterEvent(name, eventName, callbackName); 79 | end; 80 | 81 | extension.internal.OnEvent = function() 82 | local callbackName = extension.internal.eventHandlers[event]; 83 | if callbackName then 84 | extension[callbackName](); 85 | end 86 | end; 87 | 88 | 89 | -- This is a function wrapper that we swap with the function that we want to hook 90 | -- @return Value of Callback() or Origininal() if dontCallOriginal is false 91 | extension.internal.OnHook = function(object, functionName, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) 92 | local hook; 93 | 94 | if object then 95 | hook = extension.internal.memberHooks[object][functionName]; 96 | else 97 | hook = extension.internal.hooks[functionName]; 98 | end 99 | 100 | local retval = hook.callback(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); 101 | if not hook.dontCallOriginal then 102 | retval = hook.origininal(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); 103 | end 104 | return retval 105 | end; 106 | 107 | 108 | extension.internal.frame:SetScript("OnEvent", extension.internal.OnEvent); 109 | 110 | Roids.Extensions[name] = extension; 111 | 112 | return extension; 113 | end 114 | 115 | -- Registers a callback function for a given event name 116 | -- extensionName: The name of the extension trying to register the callback 117 | -- eventName: The event's name we'd like to register a callback for 118 | -- callbackName: The name of the callback that get's called when the event fires 119 | function Roids.RegisterEvent(extensionName, eventName, callbackName) 120 | local extension = Roids.Extensions[extensionName]; 121 | extension.internal.eventHandlers[eventName] = callbackName; 122 | extension.internal.frame:RegisterEvent(eventName); 123 | end 124 | 125 | -- Hooks the given function by it's name 126 | -- extensionName: The name of the extension trying to register the callback 127 | -- functionName: The name of the function that'll be hooked 128 | -- callbackName: The name of the callback that get's called when the hooked function is called 129 | -- dontCallOriginal: Set to true when the original function should not be called 130 | function Roids.RegisterHook(extensionName, functionName, callbackName, dontCallOriginal) 131 | local orig = _G[functionName]; 132 | local extension = Roids.Extensions[extensionName]; 133 | 134 | if not orig then 135 | Roids.Print("Roids.RegisterHook - Invalid function to hook: "..functionName) 136 | end 137 | 138 | if not extension then 139 | Roids.Print("Roids.RegisterHook - Invalid extension: "..extension); 140 | return; 141 | end 142 | 143 | if not extension[callbackName] then 144 | Roids.Print("Roids.RegisterHook - Couldn't find callback: "..callbackName); 145 | return; 146 | end 147 | 148 | 149 | extension.internal.hooks[functionName] = { 150 | origininal = orig, 151 | callback = extension[callbackName], 152 | name = functionName, 153 | dontCallOriginal = dontCallOriginal 154 | }; 155 | 156 | _G[functionName] = function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) 157 | return extension.internal.OnHook(nil, functionName, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); 158 | end; 159 | end 160 | 161 | -- Hooks the given object's function 162 | -- object: The object you want to hook 163 | -- extensionName: The name of the extension trying to register the callback 164 | -- functionName: The name of the function that'll be hooked 165 | -- callbackName: The name of the callback that get's called when the hooked function is called 166 | function Roids.RegisterMethodHook(extensionName, object, functionName, callbackName, dontCallOriginal) 167 | if not object then 168 | Roids.Print("Roids.RegisterMethodHook - The object could not be found!"); 169 | return; 170 | end 171 | 172 | if type(object) ~= "table" then 173 | Roids.Print("Roids.RegisterMethodHook - The object needs to be a table!"); 174 | return; 175 | end 176 | 177 | local orig = object[functionName]; 178 | 179 | if not orig then 180 | Roids.Print("Roids.RegisterMethodHook - The object doesn't have a function named "..functionName); 181 | return; 182 | end 183 | 184 | local extension = Roids.Extensions[extensionName]; 185 | 186 | if not extension then 187 | Roids.Print("Roids.RegisterMethodHook - Invalid extension: "..extension); 188 | return; 189 | end 190 | 191 | if not extension[callbackName] then 192 | Roids.Print("Roids.RegisterMethodHook - Couldn't find callback: "..callbackName); 193 | return; 194 | end 195 | 196 | if not extension.internal.memberHooks[object] then 197 | extension.internal.memberHooks[object] = {}; 198 | end 199 | 200 | extension.internal.memberHooks[object][functionName] = { 201 | origininal = orig, 202 | callback = extension[callbackName], 203 | name = functionName, 204 | dontCallOriginal = dontCallOriginal 205 | }; 206 | 207 | object[functionName] = function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) 208 | return extension.internal.OnHook(object, functionName, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); 209 | end; 210 | end 211 | 212 | function Roids.UnregisterEvent(extensionName, eventName, callbackName) 213 | local extension = Roids.Extensions[extensionName]; 214 | if extension.internal.eventHandlers[eventName] then 215 | extension.internal.eventHandlers[eventName] = nil; 216 | extension.internal.frame:UnregisterEvent(eventName); 217 | end 218 | end 219 | 220 | _G["Roids"] = Roids 221 | -------------------------------------------------------------------------------- /Localization.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Author: Dennis Werner Garske (DWG) 3 | License: MIT License 4 | ]] 5 | local _G = _G or getfenv(0); 6 | local Roids = _G.Roids or {}; 7 | Roids.Locale = GetLocale(); 8 | Roids.Localized = {}; 9 | 10 | if Roids.Locale == "enUS" or Roids.Locale == "enGB" then 11 | Roids.Localized.Shield = "Shield"; 12 | Roids.Localized.Bow = "Bow"; 13 | Roids.Localized.Crossbow = "Crossbow"; 14 | Roids.Localized.Gun = "Gun"; 15 | Roids.Localized.Thrown = "Thrown"; 16 | Roids.Localized.Wand = "Wand"; 17 | Roids.Localized.Sword = "Sword"; 18 | Roids.Localized.Staff = "Staff"; 19 | Roids.Localized.Polearm = "Polearm"; 20 | Roids.Localized.Mace = "Mace"; 21 | Roids.Localized.FistWeapon = "Fist Weapon"; 22 | Roids.Localized.Dagger = "Dagger"; 23 | Roids.Localized.Axe = "Axe"; 24 | Roids.Localized.Attack = "Attack"; 25 | Roids.Localized.AutoShot = "Auto Shot"; 26 | Roids.Localized.Shoot = "Shoot"; 27 | Roids.Localized.SpellRank = "%(Rank %d+%)"; 28 | 29 | Roids.Localized.CreatureTypes = { 30 | ["Beast"] = "Beast", 31 | ["Critter"] = "Critter", 32 | ["Demon"] = "Demon", 33 | ["Dragonkin"] = "Dragonkin", 34 | ["Elemental"] = "Elemental", 35 | ["Giant"] = "Giant", 36 | ["Humanoid"] = "Humanoid", 37 | ["Mechanical"] = "Mechanical", 38 | ["Not specified"] = "Not_Specified", 39 | ["Totem"] = "Totem", 40 | ["Undead"] = "Undead", 41 | }; 42 | elseif Roids.Locale == "deDE" then 43 | Roids.Localized.Shield = "Shield"; 44 | Roids.Localized.Bow = "Bow"; 45 | Roids.Localized.Crossbow = "Crossbow"; 46 | Roids.Localized.Gun = "Gun"; 47 | Roids.Localized.Thrown = "Thrown"; 48 | Roids.Localized.Wand = "Wand"; 49 | Roids.Localized.Sword = "Sword"; 50 | Roids.Localized.Staff = "Staff"; 51 | Roids.Localized.Polearm = "Polearm"; 52 | Roids.Localized.Mace = "Mace"; 53 | Roids.Localized.FistWeapon = "Fist Weapon"; 54 | Roids.Localized.Dagger = "Dagger"; 55 | Roids.Localized.Axe = "Axe"; 56 | Roids.Localized.Attack = "Attack"; 57 | Roids.Localized.AutoShot = "Auto Shot"; 58 | Roids.Localized.Shoot = "Shoot"; 59 | Roids.Localized.SpellRank = "%(Rank %d+%)"; 60 | 61 | Roids.Localized.CreatureTypes = { 62 | ["Wildtier"] = "Beast", 63 | ["Kleintier"] = "Critter", 64 | ["Dämon"] = "Demon", 65 | ["Drachkin"] = "Dragonkin", 66 | ["Elementar"] = "Elemental", 67 | ["Riese"] = "Giant", 68 | ["Humanoid"] = "Humanoid", 69 | ["Mechanisch"] = "Mechanical", 70 | ["Nicht spezifiziert"] = "Not_Specified", 71 | ["Totem"] = "Totem", 72 | ["Untoter"] = "Undead", 73 | }; 74 | elseif Roids.Locale == "frFR" then 75 | Roids.Localized.Shield = "Shield"; 76 | Roids.Localized.Bow = "Bow"; 77 | Roids.Localized.Crossbow = "Crossbow"; 78 | Roids.Localized.Gun = "Gun"; 79 | Roids.Localized.Thrown = "Thrown"; 80 | Roids.Localized.Wand = "Wand"; 81 | Roids.Localized.Sword = "Sword"; 82 | Roids.Localized.Staff = "Staff"; 83 | Roids.Localized.Polearm = "Polearm"; 84 | Roids.Localized.Mace = "Mace"; 85 | Roids.Localized.FistWeapon = "Fist Weapon"; 86 | Roids.Localized.Dagger = "Dagger"; 87 | Roids.Localized.Axe = "Axe"; 88 | Roids.Localized.Attack = "Attack"; 89 | Roids.Localized.AutoShot = "Auto Shot"; 90 | Roids.Localized.Shoot = "Shoot"; 91 | Roids.Localized.SpellRank = "%(Rank %d+%)"; 92 | 93 | Roids.Localized.CreatureTypes = { 94 | ["Bête"] = "Beast", 95 | ["Bestiole"] = "Critter", 96 | ["Démon"] = "Demon", 97 | ["Draconien"] = "Dragonkin", 98 | ["Elémentaire"] = "Elemental", 99 | ["Géant"] = "Giant", 100 | ["Humanoïde"] = "Humanoid", 101 | ["Machine"] = "Mechanical", 102 | ["Non spécifié"] = "Not_Specified", 103 | ["Totem"] = "Totem", 104 | ["Mort-vivant"] = "Undead", 105 | }; 106 | elseif Roids.Locale == "koKR" then 107 | Roids.Localized.Shield = "Shield"; 108 | Roids.Localized.Bow = "Bow"; 109 | Roids.Localized.Crossbow = "Crossbow"; 110 | Roids.Localized.Gun = "Gun"; 111 | Roids.Localized.Thrown = "Thrown"; 112 | Roids.Localized.Wand = "Wand"; 113 | Roids.Localized.Sword = "Sword"; 114 | Roids.Localized.Staff = "Staff"; 115 | Roids.Localized.Polearm = "Polearm"; 116 | Roids.Localized.Mace = "Mace"; 117 | Roids.Localized.FistWeapon = "Fist Weapon"; 118 | Roids.Localized.Dagger = "Dagger"; 119 | Roids.Localized.Axe = "Axe"; 120 | Roids.Localized.Attack = "Attack"; 121 | Roids.Localized.AutoShot = "Auto Shot"; 122 | Roids.Localized.Shoot = "Shoot"; 123 | Roids.Localized.SpellRank = "%(Rank %d+%)"; 124 | 125 | Roids.Localized.CreatureTypes = { 126 | ["야수"] = "Beast", 127 | ["동물"] = "Critter", 128 | ["악마"] = "Demon", 129 | ["용족"] = "Dragonkin", 130 | ["정령"] = "Elemental", 131 | ["거인"] = "Giant", 132 | ["인간형"] = "Humanoid", 133 | ["기계"] = "Mechanical", 134 | ["기타"] = "Not_Specified", 135 | ["토템"] = "Totem", 136 | ["언데드"] = "Undead", 137 | }; 138 | elseif Roids.Locale == "zhCN" then 139 | Roids.Localized.Shield = "Shield"; 140 | Roids.Localized.Bow = "Bow"; 141 | Roids.Localized.Crossbow = "Crossbow"; 142 | Roids.Localized.Gun = "Gun"; 143 | Roids.Localized.Thrown = "Thrown"; 144 | Roids.Localized.Wand = "Wand"; 145 | Roids.Localized.Sword = "Sword"; 146 | Roids.Localized.Staff = "Staff"; 147 | Roids.Localized.Polearm = "Polearm"; 148 | Roids.Localized.Mace = "Mace"; 149 | Roids.Localized.FistWeapon = "Fist Weapon"; 150 | Roids.Localized.Dagger = "Dagger"; 151 | Roids.Localized.Axe = "Axe"; 152 | Roids.Localized.Attack = "Attack"; 153 | Roids.Localized.AutoShot = "Auto Shot"; 154 | Roids.Localized.Shoot = "Shoot"; 155 | Roids.Localized.SpellRank = "%(Rank %d+%)"; 156 | 157 | Roids.Localized.CreatureTypes = { 158 | ["野兽"] = "Beast", 159 | ["小动物"] = "Critter", 160 | ["恶魔"] = "Demon", 161 | ["龙类"] = "Dragonkin", 162 | ["元素生物"] = "Elemental", 163 | ["巨人"] = "Giant", 164 | ["人型生物"] = "Humanoid", 165 | ["机械"] = "Mechanical", 166 | ["未指定"] = "Not_Specified", 167 | ["图腾"] = "Totem", 168 | ["亡灵"] = "Undead", 169 | }; 170 | elseif Roids.Locale == "zhTW" then 171 | Roids.Localized.Shield = "Shield"; 172 | Roids.Localized.Bow = "Bow"; 173 | Roids.Localized.Crossbow = "Crossbow"; 174 | Roids.Localized.Gun = "Gun"; 175 | Roids.Localized.Thrown = "Thrown"; 176 | Roids.Localized.Wand = "Wand"; 177 | Roids.Localized.Sword = "Sword"; 178 | Roids.Localized.Staff = "Staff"; 179 | Roids.Localized.Polearm = "Polearm"; 180 | Roids.Localized.Mace = "Mace"; 181 | Roids.Localized.FistWeapon = "Fist Weapon"; 182 | Roids.Localized.Dagger = "Dagger"; 183 | Roids.Localized.Axe = "Axe"; 184 | Roids.Localized.Attack = "Attack"; 185 | Roids.Localized.AutoShot = "Auto Shot"; 186 | Roids.Localized.Shoot = "Shoot"; 187 | Roids.Localized.SpellRank = "%(Rank %d+%)"; 188 | 189 | Roids.Localized.CreatureTypes = { 190 | ["野獸"] = "Beast", 191 | ["小動物"] = "Critter", 192 | ["惡魔"] = "Demon", 193 | ["龍類"] = "Dragonkin", 194 | ["元素生物"] = "Elemental", 195 | ["巨人"] = "Giant", 196 | ["人型生物"] = "Humanoid", 197 | ["機械"] = "Mechanical", 198 | ["不明"] = "Not_Specified", 199 | ["圖騰"] = "Totem", 200 | ["不死族"] = "Undead", 201 | }; 202 | elseif Roids.Locale == "ruRU" then 203 | Roids.Localized.Shield = "Shield"; 204 | Roids.Localized.Bow = "Bow"; 205 | Roids.Localized.Crossbow = "Crossbow"; 206 | Roids.Localized.Gun = "Gun"; 207 | Roids.Localized.Thrown = "Thrown"; 208 | Roids.Localized.Wand = "Wand"; 209 | Roids.Localized.Sword = "Sword"; 210 | Roids.Localized.Staff = "Staff"; 211 | Roids.Localized.Polearm = "Polearm"; 212 | Roids.Localized.Mace = "Mace"; 213 | Roids.Localized.FistWeapon = "Fist Weapon"; 214 | Roids.Localized.Dagger = "Dagger"; 215 | Roids.Localized.Axe = "Axe"; 216 | Roids.Localized.Attack = "Attack"; 217 | Roids.Localized.AutoShot = "Auto Shot"; 218 | Roids.Localized.Shoot = "Shoot"; 219 | Roids.Localized.SpellRank = "%(Rank %d+%)"; 220 | 221 | Roids.Localized.CreatureTypes = { 222 | ["Животное"] = "Beast", 223 | ["Существо"] = "Critter", 224 | ["Демон"] = "Demon", 225 | ["Дракон"] = "Dragonkin", 226 | ["Элементаль"] = "Elemental", 227 | ["Великан"] = "Giant", 228 | ["Гуманоид"] = "Humanoid", 229 | ["Механизм"] = "Mechanical", 230 | ["Не указано"] = "Not_Specified", 231 | ["Тотем"] = "Totem", 232 | ["Нежить"] = "Undead", 233 | }; 234 | elseif Roids.Locale == "esES" then 235 | Roids.Localized.Shield = "Shield"; 236 | Roids.Localized.Bow = "Bow"; 237 | Roids.Localized.Crossbow = "Crossbow"; 238 | Roids.Localized.Gun = "Gun"; 239 | Roids.Localized.Thrown = "Thrown"; 240 | Roids.Localized.Wand = "Wand"; 241 | Roids.Localized.Sword = "Sword"; 242 | Roids.Localized.Staff = "Staff"; 243 | Roids.Localized.Polearm = "Polearm"; 244 | Roids.Localized.Mace = "Mace"; 245 | Roids.Localized.FistWeapon = "Fist Weapon"; 246 | Roids.Localized.Dagger = "Dagger"; 247 | Roids.Localized.Axe = "Axe"; 248 | Roids.Localized.Attack = "Attack"; 249 | Roids.Localized.AutoShot = "Auto Shot"; 250 | Roids.Localized.Shoot = "Shoot"; 251 | Roids.Localized.SpellRank = "%(Rank %d+%)"; 252 | 253 | Roids.Localized.CreatureTypes = { 254 | ["Bestia"] = "Beast", 255 | ["Alma"] = "Critter", 256 | ["Demonio"] = "Demon", 257 | ["Dragon"] = "Dragonkin", 258 | ["Elemental"] = "Elemental", 259 | ["Gigante"] = "Giant", 260 | ["Humanoide"] = "Humanoid", 261 | ["Mecánico"] = "Mechanical", 262 | ["No especificado"] = "Not_Specified", 263 | ["Tótem"] = "Totem", 264 | ["No-muerto"] = "Undead", 265 | }; 266 | end 267 | 268 | _G["Roids"] = Roids; -------------------------------------------------------------------------------- /Core.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Author: Dennis Werner Garske (DWG) 3 | License: MIT License 4 | ]] 5 | 6 | -- Setup to wrap our stuff in a table so we don't pollute the global environment 7 | local _G = _G or getfenv(0); 8 | local Roids = _G.Roids or {}; 9 | _G.Roids = Roids; 10 | Roids.Hooks = Roids.Hooks or {}; 11 | Roids.mouseoverUnit = Roids.mouseoverUnit or nil; 12 | 13 | Roids.Extensions = Roids.Extensions or {}; 14 | 15 | -- Executes the given Macro's body 16 | -- body: The Macro's body 17 | function Roids.ExecuteMacroBody(body) 18 | local lines = Roids.splitString(body, "\n"); 19 | for k,v in pairs(lines) do 20 | ChatFrameEditBox:SetText(v); 21 | ChatEdit_SendText(ChatFrameEditBox); 22 | end 23 | end 24 | 25 | -- Gets the body of the Macro with the given name 26 | -- name: The name of the Macro 27 | -- returns: The body of the macro 28 | function Roids.GetMacroBody(name) 29 | local macroId = GetMacroIndexByName(name); 30 | if not macroId then 31 | return false; 32 | end 33 | 34 | local _,_, body = GetMacroInfo(macroId); 35 | if not body and SuperMacroFrame ~= nil then 36 | body = GetSuperMacroInfo(name, "body"); 37 | end 38 | 39 | return body; 40 | end 41 | 42 | -- Attempts to execute a macro by the given name 43 | -- name: The name of the macro 44 | -- returns: Whether the macro was executed or not 45 | function Roids.ExecuteMacroByName(name) 46 | local body = Roids.GetMacroBody(name); 47 | if not body then 48 | return false; 49 | end 50 | 51 | Roids.ExecuteMacroBody(body); 52 | return true; 53 | end 54 | 55 | -- Searches for a ':', '>' or '<' in the given word and returns its position 56 | -- word: The word to search in 57 | -- returns: The position of the delimeter or nil and 1 for '>' or 2 for '<' 58 | function Roids.FindDelimeter(word) 59 | local delimeter = string.find(word, ":"); 60 | local which = nil; 61 | 62 | if not delimeter then 63 | delimeter = string.find(word, ">"); 64 | which = 1; 65 | if not delimeter then 66 | delimeter = string.find(word, "<"); 67 | which = 0; 68 | end 69 | end 70 | 71 | if not delimeter then 72 | which = nil; 73 | end 74 | 75 | return delimeter, which; 76 | end 77 | 78 | -- Parses the given message and looks for any conditionals 79 | -- msg: The message to parse 80 | -- returns: A set of conditionals found inside the given string 81 | function Roids.parseMsg(msg) 82 | local modifier = ""; 83 | local modifierEnd = string.find(msg, "]"); 84 | local help = nil; 85 | 86 | -- If we find conditionals trim down the message to everything except the conditionals 87 | if string.sub(msg, 1, 1) == "[" and modifierEnd then 88 | modifier = string.sub(msg, 2, modifierEnd - 1); 89 | msg = string.sub(msg, modifierEnd + 1); 90 | -- No conditionals found. Just return the message as is 91 | elseif string.sub(msg, 1, 1) ~= "!" then 92 | return msg; 93 | end 94 | 95 | local target; 96 | local conditionals = {}; 97 | 98 | msg = Roids.Trim(msg) 99 | 100 | if string.sub(msg, 1, 1) == "!" then 101 | msg = string.sub(msg, 2); 102 | conditionals.checkchanneled = msg; 103 | end 104 | 105 | local pattern = "(@?%w+:?>? tonumber(amount); 230 | end 231 | 232 | -- Checks whether or not the given unit has more or less total power than the given amount 233 | -- unit: The unit we're checking 234 | -- bigger: 1 if the raw power needs to be bigger, 0 if it needs to be less 235 | -- amount: The required amount 236 | -- returns: True or false 237 | function Roids.ValidateRawPower(unit, bigger, amount) 238 | local power = UnitMana(unit); 239 | if bigger == 0 then 240 | return power < tonumber(amount); 241 | end 242 | 243 | return power > tonumber(amount); 244 | end 245 | 246 | -- Checks whether or not the given unit has more or less hp in percent than the given amount 247 | -- unit: The unit we're checking 248 | -- bigger: 1 if the percentage needs to be bigger, 0 if it needs to be lower 249 | -- amount: The required amount 250 | -- returns: True or false 251 | function Roids.ValidateHp(unit, bigger, amount) 252 | local powerPercent = 100 / UnitHealthMax(unit) * UnitHealth(unit); 253 | if bigger == 0 then 254 | return powerPercent < tonumber(amount); 255 | end 256 | 257 | return powerPercent > tonumber(amount); 258 | end 259 | 260 | -- Checks whether the given creatureType is the same as the target's creature type 261 | -- creatureType: The type to check 262 | -- target: The target's unitID 263 | -- returns: True or false 264 | -- remarks: Allows for both localized and unlocalized type names 265 | function Roids.ValidateCreatureType(creatureType, target) 266 | local targetType = UnitCreatureType(target); 267 | local englishType = Roids.Localized.CreatureTypes[targetType]; 268 | return creatureType == targetType or creatureType == englishType; 269 | end 270 | 271 | -- Returns the cooldown of the given spellName or nil if no such spell was found 272 | function Roids.GetSpellCooldownByName(spellName) 273 | local checkFor = function(bookType) 274 | local i = 1 275 | while true do 276 | local name, spellRank = GetSpellName(i, bookType); 277 | 278 | if not name then 279 | break; 280 | end 281 | 282 | if name == spellName then 283 | local _, duration = GetSpellCooldown(i, bookType); 284 | return duration; 285 | end 286 | 287 | i = i + 1 288 | end 289 | return nil; 290 | end 291 | 292 | 293 | local cd = checkFor(BOOKTYPE_PET); 294 | if not cd then cd = checkFor(BOOKTYPE_SPELL); end 295 | 296 | return cd; 297 | end 298 | 299 | -- Returns the cooldown of the given equipped itemName or nil if no such item was found 300 | function Roids.GetInventoryCooldownByName(itemName) 301 | RoidsTooltip:SetOwner(UIParent, "ANCHOR_NONE"); 302 | for i=0, 19 do 303 | RoidsTooltip:ClearLines(); 304 | hasItem = RoidsTooltip:SetInventoryItem("player", i); 305 | 306 | if hasItem then 307 | local lines = RoidsTooltip:NumLines(); 308 | 309 | local label = getglobal("RoidsTooltipTextLeft1"); 310 | 311 | if label:GetText() == itemName then 312 | local _, duration, _ = GetInventoryItemCooldown("player", i); 313 | return duration; 314 | end 315 | end 316 | end 317 | 318 | return nil; 319 | end 320 | 321 | -- Returns the cooldown of the given itemName in the player's bags or nil if no such item was found 322 | function Roids.GetContainerItemCooldownByName(itemName) 323 | RoidsTooltip:SetOwner(WorldFrame, "ANCHOR_NONE"); 324 | 325 | for i = 0, 4 do 326 | for j = 1, GetContainerNumSlots(i) do 327 | RoidsTooltip:ClearLines(); 328 | RoidsTooltip:SetBagItem(i, j); 329 | if RoidsTooltipTextLeft1:GetText() == itemName then 330 | local _, duration, _ = GetContainerItemCooldown(i, j); 331 | return duration; 332 | end 333 | end 334 | end 335 | 336 | return nil; 337 | end 338 | 339 | -- A list of Conditionals and their functions to validate them 340 | Roids.Keywords = { 341 | help = function(conditionals) 342 | return true; 343 | end, 344 | 345 | harm = function(conditionals) 346 | return true; 347 | end, 348 | 349 | stance = function(conditionals) 350 | local inStance = false; 351 | for k,v in pairs(Roids.splitString(conditionals.stance, "/")) do 352 | if Roids.GetCurrentShapeshiftIndex() == tonumber(v) then 353 | inStance = true; 354 | break; 355 | end 356 | end 357 | 358 | if not inStance then 359 | return false; 360 | end 361 | return true; 362 | end, 363 | 364 | mod = function(conditionals) 365 | local modifiersPressed = true; 366 | 367 | for k,v in pairs(Roids.splitString(conditionals.mod, "/")) do 368 | if v == "alt" and not IsAltKeyDown() then 369 | modifiersPressed = false; 370 | break; 371 | elseif v == "ctrl" and not IsControlKeyDown() then 372 | modifiersPressed = false; 373 | break; 374 | elseif v == "shift" and not IsShiftKeyDown() then 375 | modifiersPressed = false; 376 | break; 377 | end 378 | end 379 | 380 | return modifiersPressed; 381 | end, 382 | 383 | target = function(conditionals) 384 | return Roids.IsValidTarget(conditionals.target, conditionals.help); 385 | end, 386 | 387 | combat = function(conditionals) 388 | return UnitAffectingCombat("player"); 389 | end, 390 | 391 | nocombat = function(conditionals) 392 | return not UnitAffectingCombat("player"); 393 | end, 394 | 395 | stealth = function(conditionals) 396 | return Roids.HasBuff("Interface\\Icons\\Ability_Ambush"); 397 | end, 398 | 399 | nostealth = function(conditionals) 400 | return not Roids.HasBuff("Interface\\Icons\\Ability_Ambush"); 401 | end, 402 | 403 | equipped = function(conditionals) 404 | return Roids.HasWeaponEquipped(conditionals.equipped); 405 | end, 406 | 407 | noequipped = function(conditionals) 408 | return not Roids.HasWeaponEquipped(conditionals.equipped); 409 | end, 410 | 411 | worn = equipped, 412 | noworn = noequipped, 413 | 414 | dead = function(conditionals) 415 | return UnitIsDeadOrGhost(conditionals.target); 416 | end, 417 | 418 | nodead = function(conditionals) 419 | return not UnitIsDeadOrGhost(conditionals.target); 420 | end, 421 | 422 | party = function(conditionals) 423 | return Roids.IsTargetInGroupType(conditionals.target, "party"); 424 | end, 425 | 426 | raid = function(conditionals) 427 | return Roids.IsTargetInGroupType(conditionals.target, "raid"); 428 | end, 429 | 430 | group = function(conditionals) 431 | if conditionals.group == "party" then 432 | return GetNumPartyMembers() > 0; 433 | elseif conditionals.group == "raid" then 434 | return GetNumRaidMembers() > 0; 435 | end 436 | return false; 437 | end, 438 | 439 | checkchanneled = function(conditionals) 440 | return Roids.CheckChanneled(conditionals); 441 | end, 442 | 443 | buff = function(conditionals) 444 | return Roids.HasBuffName(conditionals.buff, conditionals.target); 445 | end, 446 | 447 | nobuff = function(conditionals) 448 | return not Roids.HasBuffName(conditionals.nobuff, conditionals.target); 449 | end, 450 | 451 | debuff = function(conditionals) 452 | return Roids.HasDeBuffName(conditionals.debuff, conditionals.target); 453 | end, 454 | 455 | nodebuff = function(conditionals) 456 | return not Roids.HasDeBuffName(conditionals.nodebuff, conditionals.target); 457 | end, 458 | 459 | mybuff = function(conditionals) 460 | return Roids.HasBuffName(conditionals.mybuff, "player"); 461 | end, 462 | 463 | nomybuff = function(conditionals) 464 | return not Roids.HasBuffName(conditionals.nomybuff, "player"); 465 | end, 466 | 467 | mydebuff = function(conditionals) 468 | return Roids.HasDeBuffName(conditionals.mydebuff, "player"); 469 | end, 470 | 471 | nomydebuff = function(conditionals) 472 | return not Roids.HasDeBuffName(conditionals.nomydebuff, "player"); 473 | end, 474 | 475 | power = function(conditionals) 476 | return Roids.ValidatePower(conditionals.target, conditionals.power.bigger, conditionals.power.amount); 477 | end, 478 | 479 | mypower = function(conditionals) 480 | return Roids.ValidatePower("player", conditionals.mypower.bigger, conditionals.mypower.amount); 481 | end, 482 | 483 | rawpower = function(conditionals) 484 | return Roids.ValidateRawPower(conditionals.target, conditionals.rawpower.bigger, conditionals.rawpower.amount); 485 | end, 486 | 487 | myrawpower = function(conditionals) 488 | return Roids.ValidateRawPower("player", conditionals.myrawpower.bigger, conditionals.myrawpower.amount); 489 | end, 490 | 491 | hp = function(conditionals) 492 | return Roids.ValidateHp(conditionals.target, conditionals.hp.bigger, conditionals.hp.amount); 493 | end, 494 | 495 | myhp = function(conditionals) 496 | return Roids.ValidateHp("player", conditionals.myhp.bigger, conditionals.myhp.amount); 497 | end, 498 | 499 | type = function(conditionals) 500 | return Roids.ValidateCreatureType(conditionals.type, conditionals.target); 501 | end, 502 | 503 | cooldown = function(conditionals) 504 | local name = string.gsub(conditionals.cooldown, "_", " "); 505 | local cd = Roids.GetSpellCooldownByName(name); 506 | if not cd then cd = Roids.GetInventoryCooldownByName(name); end 507 | if not cd then cd = Roids.GetContainerItemCooldownByName(name) end 508 | return cd > 0; 509 | end, 510 | 511 | nocooldown = function(conditionals) 512 | local name = string.gsub(conditionals.nocooldown, "_", " "); 513 | local cd = Roids.GetSpellCooldownByName(name); 514 | if not cd then cd = Roids.GetInventoryCooldownByName(name); end 515 | if not cd then cd = Roids.GetContainerItemCooldownByName(name) end 516 | return cd == 0; 517 | end, 518 | 519 | channeled = function(conditionals) 520 | return Roids.CurrentSpell.spellName ~= ""; 521 | end, 522 | 523 | nochanneled = function(conditionals) 524 | return Roids.CurrentSpell.spellName == ""; 525 | end, 526 | 527 | attacks = function(conditionals) 528 | return UnitIsUnit("targettarget", conditionals.attacks); 529 | end, 530 | 531 | noattacks = function(conditionals) 532 | return not UnitIsUnit("targettarget", conditionals.noattacks); 533 | end, 534 | 535 | isplayer = function(conditionals) 536 | return UnitIsPlayer(conditionals.isplayer); 537 | end, 538 | 539 | isnpc = function(conditionals) 540 | return not UnitIsPlayer(conditionals.isnpc); 541 | end, 542 | }; --------------------------------------------------------------------------------