• 1 Vote(s) - 5 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Rotation Framework
#1
Hey guys,

I recently ported my rotation framework to Lua to see if I could do it. It was pretty challenging getting all the functional aspects right, since I am used to strongly typed languages where functions and their parameters are also types.

Either way, I want to share the framework with you guys, because I believe it'll make it much easier for the average joe to write a rotation and still have them be extensive and powerful. 

The attached files are a rogue rotation that can be used as a base for your fightclasses (inspired by Logitech's rogue, not fully tested).


Guide

Put rotation_framework.lua into your scripts folder, then add the following code to your coremenu.lua under Core Files.
Code:
-- Rotation Framework
include("scripts\\rotation_framework.lua")



The framework can execute a rotation. Each rotation consists of several steps. Each step contains the following parameters:

Quote:action - a RotationAction requiring methods Range():float and Execute():bool
priority - float, sorting order, lowest to highest
predicate - a function taking RotationAction and WoWUnit as targets, returning bool
targetFinder - a function returning a WoWUnit (can be friendly) to execute action upon - this function takes a function(WoWUnit unit):bool as an argument
force - a boolean indicating whether this can interrupt the currently casting spell
rangeCheck - a boolean indicating whether we need to check the range for this action

The interesting parameters for most rotations are the actions, which can either be created through RotationFrameWork:CreateSpell(name, [rank = optional]) or RotationFrameWork:CreateRawAction(function, range). Each step in the rotation is checked for validity and skipped automatically, if it cannot be casted/used/out of range/not in LoS, etc. The first step that can be executed stops the rotation. Each new spell you want to be casted requires another execution of the rotation. 

Each step is also evalulated against a predicate that you can define and supplies its own targeting logic. By default, this will be the target the bot selects for you. You can, however, supply another function like RotationFramework.FindPlayer (returns the player itself) or create your own function to find a target (e.g. for blind, polymorph, sap, etc).

The predicate is the most interesting part. The action itself, as well as the previously evaluated target are parsed as parameters here (s, t => spell, target). You have access to both and need to return a bool value to determine whether this action can be executed. You do NOT need to check for LoS, mana etc here, the framework will automatically check if you can cast the spell or not. 

Example code
Code:
local Me = GetLocalPlayer();
local RF = RotationFramework;

local rotation = {
    RF:CreateStep(RF:CreateSpell("Throw"), 1, function(s, t) return SchakaRogue.needsRangePull and t:GetHealthPercentage() == 100 and t:GetDistance() > 8 end),
    RF:CreateStep(RF:CreateSpell("Shoot Crossbow"), 1, function(s, t) return SchakaRogue.needsRangePull and t:GetHealthPercentage() == 100 and t:GetDistance() > 8 end),
    RF:CreateStep(RF:CreateSpell("Shoot Bow"), 1, function(s, t) return SchakaRogue.needsRangePull and t:GetHealthPercentage() == 100 and t:GetDistance() > 8 end),
    RF:CreateStep(RF:CreateSpell("Shoot Gun"), 1, function(s, t) return SchakaRogue.needsRangePull and t:GetHealthPercentage() == 100 and t:GetDistance() > 8 end),
    RF:CreateStep(RF:CreateSpell("Stealth"), 2, function(s, t) return not IsInCombat() and t:GetDistance() <= 25 end, RF.FindPlayer),
    RF:CreateStep(RF:CreateSpell("Preparation"), 3, function(s, t) return IsSpellOnCD("Evasion") and RF:GetNumberAttackingMe(10) >= 2 end, RF.FindPlayer),
    RF:CreateStep(RF:CreateSpell("Adrenaline Rush"), 4, function(s, t) return IsSpellOnCD("Evasion") and not Me:HasBuff("Evasion") and RF:GetNumberAttackingMe(10) >= 2 end, RF.FindPlayer),
    RF:CreateStep(RF:CreateSpell("Blade Flurry"), 5, function(s, t) return RF:GetNumberAttackingMe(10) >= 2 end, RF.FindPlayer),
    RF:CreateStep(RF:CreateSpell("Evasion"), 6, function(s, t) return RF:GetNumberAttackingMe(10) >= 2 end, RF.FindPlayer),
    RF:CreateStep(RF:CreateSpell("Ripose"), 7, function(s, t) return true end),
    RF:CreateStep(RF:CreateSpell("Kick"), 8, function(s, t) return t:GetMana() > 0 and t:IsCasting() end),
    RF:CreateStep(RF:CreateSpell("Hemorrhage"), 9, function(s, t) return Me:GetComboPoints() < 5 and Me:GetEnergy() >= 50 end),
    RF:CreateStep(RF:CreateSpell("Sinister Strike"), 10, function(s, t) return Me:GetComboPoints() < 5 and Me:GetEnergy() >= 50 and not HasSpell("Hemorrhage") end),
    RF:CreateStep(RF:CreateSpell("Slice and Dice"), 11, function(s, t) return Me:GetComboPoints() >= 3 and not Me:HasBuff("Slice and Dice") and (t:GetHealthPercentage() > 65 or (t:GetHealthPercentage() < 15 and Me:GetHealthPercentage() > 70 or RF:GetNumberAttackingMe() >= 2)) end),
    RF:CreateStep(RF:CreateSpell("Eviscerate"), 12, function(s, t) return (Me:GetComboPoints() > 4 and not t:HasDebuff("Cheap Shot")) or Me:GetComboPoints() >= 3 and t:GetHealthPercentage() <= 20 end),
    RF:CreateStep(RF:CreateSpell("Slice and Dice"), 13, function(s, t) return t:GetHealthPercentage() > 50 and not Me:HasBuff("Slice and Dice") and Me:GetComboPoints() >= 2 and (RF:HasMainHandEnchant() or RF:HasOffhandEnchant() or Me:HasBuff("Blade Flurry")) end),
};

RF:RunRotation(rotation);


Attached Files
.lua   rotation_framework.lua (Size: 11.02 KB / Downloads: 122)
.lua   schaka_rogue.lua (Size: 8.22 KB / Downloads: 132)
  Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)