You are not logged in.

Applications: [GameMaster: OPEN] | [Volunteer Testers: OPEN]


This forum will be permanently shut down on Friday 13.07.2018
Please copy or save all important information from old forum before they will be deactivated
We have moved to new board. https://forum.runesofmagic.gameforge.com/Come join us.

Drake1132

Beginner

Posts: 11

Location: Wait a minute... you mean I'm *not* a figment of your imagination?

  • Send private message

1,421

Friday, March 4th 2011, 9:01pm

Quoted from "Sixpax;395468"

Great idea. Thanks for this suggestion.

I've updated post #1405 with this change and modified the explanation and code example.



So, I've been looking at the new coding methodology that you and Magual have been optimizing, and I just started to wonder...

Why not make the CD(skill) call a pre-qualifier as well, rather than calling it in the MySkill() function? This would, I think, limit the number of times that MySkill() is called, because you would no longer call MySkill() if the skill is on cooldown, you would only call MySkill if the skill is *not* on cooldown (although personally I think that you should consider renaming the CD function to "IsReady" or something, since the logic is reversed... but that discussion has already been held, so I digress).

For example, say you have three skills listed: Skill A, Skill B, and Skill C. Skill A fails its initial pre-qualifiers so MySkill() is not called. Skills B and C both have pre-qualifiers that evaluate to true, but skill B is on cooldown. In such a case, Skill B will currently call the MySkill() function, and when it reached the CD() function check, it would fail, MySkill() would return false, and the class function would move on to check Skill C, which would then be used. But in order to get to that point, DIYCE has to call and fully process MySkill(). If, on the other hand, the CD() check was made as a pre-qualifier, then Skill B would fail the check, MySkill() would *not* be called and processed at all, and the class function would move on to the checks for Skill C just a little bit sooner.

Also, you wouldn't *have* to remove the CD() function call from the MySkill() function, it can be used in class functions as a pre-qualifier anyways, whether it is also used in MySkill() or not, however, if we've already checked CD() as a pre-qualifier, then why call it and process it again in MySkill()?

Admittedly, this would be a *very minor* optimization, and wouldn't likely speed things up very much unless you have a very long skills list, but it could certainly help for people like me who have very long and complex class functions designed to handle almost everything, from healing and buffing, to de-buffing, to combat skills, to pet management, to looting, etc. On modern processors the optimization would probably be measured in 100ths or 1000ths of a second for each MySkill() call that is *not* made, if that, but hey, it all adds up :)

So the usage would then be as follows:

Source code

1
2
3
4
5
6
7
8
9
function WarriorRogue(arg1)
    -- local declarations here

    if (not melee) and CD("Surprise Attack") and MySkill("Surprise Attack", arg1) then return true end
    if (rage >= 25) and CD("Slash") and MySkill("Slash", arg1) then return true end
    if (energy >= 20) and CD("Shadowstab") and MySkill("Shadowstab", arg1) then return true end

    return false
end
Also, you could, alternatively, set skillname as a local variable and make the function as follows (which would, for me, be easier to read and modify later on because it has fewer places to change a skill name, and everything realted to a particular skill is located just below the skill's name):

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function WarriorRogue(arg1)

    local skillname = nil

    -- other local declarations here


    skillname = "Surpirse Attack"
    if (not melee) and CD(skillname) and MySkill(skillname, arg1) then return true end

    skillname = "Slash"
    if (rage >= 25) and CD(skillname) and MySkill(skillname, arg1) then return true end

    skillname = "Shadowstab"
    if (energy >= 20) and CD(skillname) and MySkill(skillname, arg1) then return true end

    return false
end
In either case, anything that would normally not require a CD() check, such as activating an actionbar slot with a skillname of "Action: <#> (<note>)" could simply leave CD() out of the pre-qualifiers.

Also, it might be worth noting that the pre-qualifier that is most likely to evaluate to false should generally be listed first, because the Lua system will make all the checks until it finds one that is false, and then it will stop and move on. Let's say you have a skill that has, for example, 5 pre-qualifiers: If the first one evaluates to false, then the others will be skipped and the next skill will be checked instead. If, however, the first 4 evaluate to true and the 5th one evaluates to false, then the system will make all 5 checks before moving on to the next skill. This is more an issue of optimizing class function design, rather than optimizing the way that DIYCE works at its core, but it is tangentially relevant to the current discussion. And again, this would be a very minor optimization and would gain very little on modern CPUs, but still *shrugs*.

Just a thought, something to consider.

Drake

Drake1132

Beginner

Posts: 11

Location: Wait a minute... you mean I'm *not* a figment of your imagination?

  • Send private message

1,422

Friday, March 4th 2011, 9:22pm

@sandipandi

It is probably best to create a function called "CustomAction(actionname)" and insert the code for saving your pet into that new function. Following is the way I would personally do it (please note that I have not double checked for spelling and syntax, and I have not tested it to make sure it works, and I also have not made any modifications or improvements to your original class function other than to add the line that will use the new custom code):

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
function CustomAction(actionname) -- this function will be called by the MySkill function *IF* the skillname being processed starts out with "Custom:"
    if (actionname == "Save Pet") then -- adding this line so that you could use the CustomAction function for other custom actions
        -- if (health <= .15) then -- if my health is 15% or less, then do the following... this check could be used inside of your class function instead, and should be, so I'm commenting it out here
            SwapEquipmentItem() -- changes your current equipment set to your other equipment set... this will only prevent equipment damage if your other set is totally *EMPTY*, otherwise your secondary set will take the damage rather than your primary set and you will still need to repair your equipment
            for i=1,3 do -- this loop checks each of three pets, and if the pet is active, it stores it
                if (IsPetSummoned(i) == true) then
                    ReturnPet(i);
                end
            end        
        -- end -- also commenting out the "end" here because it is the closing statement for the health check that I commented out above
    end -- adding this line to close the actionname check made above
end




function ScoutRogueSnipeMA(arg1)
   local Skill = {}
   local i = 0
   local focus = UnitMana("player")
   local friendly = (not UnitCanAttack("player","target"))
   local combat = GetPlayerCombatState()
   local melee = GetActionUsable(8) -- # is your Shadowstab action bar
   local WarnMe50 = ((PctH("player") <= .50) and (PctH("player") >= .26) and (WarningFrame:AddMessage("--- WARNING: Health is UNDER 50%! ---", 255, 255, 0)))


   i=i+1; Skill[i] = { name = "Custom: Save Pet",  use = combat and (PctH("player") <= .15) } -- this is the line that would allow you to use the new code shown above... if I am in a state of combat and my health is 15% or less, then use the "Save Pet" custom action code above.

   i=i+1; Skill[i] = { name = "Action: 55 (HP pot)",  use = (PctH("player") <= .60) }
   i=i+1; Skill[i] = { name = "Action: 56 (HP pot)",  use = (PctH("player") <= .60) }
   i=i+1; Skill[i] = { name = "Action: 57 (HP pot)",  use = (PctH("player") <= .60) }
   i=i+1; Skill[i] = { name = "Action: 58 (HP pot)",  use = (PctH("player") <= .60) }
   i=i+1; Skill[i] = { name = "Action: 59 (HP pot)",  use = (PctH("player") <= .60) } 
   i=i+1; Skill[i] = { name = "Frost Arrow",      use = (not ChkBuff("player","Frost Arrow")) }
   i=i+1; Skill[i] = { name = "Arrow of Essence", use = (not ChkBuff("player","Arrow of Essence")) }
   i=i+1; Skill[i] = { name = "Snipe",            use = ((not friendly) and (not combat))}
   i=i+1; Skill[i] = { name = "Vampire Arrows",   use = ((not friendly) and (focus >= 70)) }
   i=i+1; Skill[i] = { name = "Wind Arrows",      use = ((not friendly) and (focus >= 75)) }
   i=i+1; Skill[i] = { name = "Combo Shot",       use = ((not friendly)  and (focus >= 80)) }
   i=i+1; Skill[i] = { name = "Wrist Attack",      use = ((not friendly) and (melee)) }
   i=i+1; Skill[i] = { name = "Joint Blow",          use = ((not friendly) and (melee)) }
-- i=i+1; Skill[i] = { name = "Autoshot",         use = ((not friendly) and (not ASon)) }
-- i=i+1; Skill[i] = { name = "Shot",             use = (not friendly) }
-- i=i+1; Skill[i] = { name = "Piercing Arrow",   use = (not friendly) }
-- i=i+1; Skill[i] = { name = "Repelling Arrow",  use = ((not friendly) and (mana >= 250)) }
-- i=i+1; Skill[i] = { name = "Disarmament",      use = (((not friendly) and (mana > 150)) and (not string.find(tbuffs,"Disarmament II"))) }
-- i=i+1; Skill[i] = { name = "Disarmament",      use = ((not friendly) and (mana > 150)) }
-- i=i+1; Skill[i] = { name = "Snipe",            use = ((not friendly) and (not combat)) }
-- i=i+1; Skill[i] = { name = "Sapping Arrow",    use = (not friendly) }
-- i=i+1; Skill[i] = { name = "Snipe",            use = (not friendly) }
-- i=i+1; Skill[i] = { name = "Repelling Arrow",  use = ((not friendly) and (mana >= 250)) }
-- i=i+1; Skill[i] = { name = "Disarmament",      use = (((not friendly) and (mana > 150)) and (not string.find(tbuffs,"Disarmament II"))) }
-- i=i+1; Skill[i] = { name = "Disarmament",      use = ((not friendly) and (mana > 150)) }
      
   MyCombat(Skill,arg1)
end
Try that and see how it goes.

Drake

1,423

Friday, March 4th 2011, 11:20pm

Thanks Sixpax, this seems great if I can get it to actually work.

The problem is that I have been using a French client and don't want to use English as all the players I play with as well and I feel more better playing the French game.

At first the addon couln't read the accentuated characters of the French spells. I was using Notepad++ , so I switched the coding to UTF-8 . After that, noting was happening at all when I was trying to run the addon.

Here is what the code looks like:

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
function ScoutRogue(arg1)
   local Skill = {}
   local i = 0
   local focus = UnitMana("player")
   local enemy = UnitCanAttack("player","target")

   i=i+1; Skill[i] = { name = "Flèche de givre",    use = (not ChkBuff("player","Flèche de givre")) }
   i=i+1; Skill[i] = { name = "Flèche sangsues",     use = enemy }
   i=i+1; Skill[i] = { name = "Tir",           use = enemy }
   i=i+1; Skill[i] = { name = "Flèche du vent",    use = (enemy and (focus >= 15)) }

   MyCombat(Skill,arg1)
end


From that code, does someone know what is wrong?

Also, what encoding method to you use in Notepad++?

Drake1132

Beginner

Posts: 11

Location: Wait a minute... you mean I'm *not* a figment of your imagination?

  • Send private message

1,424

Saturday, March 5th 2011, 6:23am

I don't see anything wrong with the code itself. But as for the encoding, because of the Lua engine that RoM uses, the files *must* be encoded as ANSI. If you use UTF-8, then RoM will not properly read and interpret the files, and you'll be lucky if you even get an error.

This may mean that you are not able to use accented text, and that would be very unfortunate, as many/most non-english languages use them at least occasionally, and I'm not sure that DIYCE would work on a French client with English skill names, because the skill names used in DIYCE would not be the same as those used by the client. Maybe someone can figure out a way to make it read and interpret those characters correctly. I'm afraid I don't know anything about localizing addons.

Sorry I can't be more help, but hopefully someone here can be more useful than me.

Drake

1,425

Saturday, March 5th 2011, 4:37pm

Thanks, I switched back to ANSI.
I can't seems to make it work with accentuated characters, so for the spells that has them, I refer to slot number instead. It's not very practicle, but at least it works.

Quoted from "Drake1132;395962"

I'm not sure that DIYCE would work on a French client with English skill names, because the skill names used in DIYCE would not be the same as those used by the client.


I know for sure that you need to use the proper language of spells depending of the language of the client.

nmgara

Trainee

Posts: 114

Location: Azeroth

  • Send private message

1,426

Saturday, March 5th 2011, 6:16pm

Since I haven't seen much for it, here is my basic Warden/Warrior code that I am currently using.

CODE:

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
-- REQUIRES _d303Fix Add-on for os.time() function

g_petBuffBeast = false;
g_petBuffBeastTime = 0;


function WardenWarrior(arg1, aoe, boss)
    local Skill = {};
    local i = 0;
    local pMana = PctM("player");
    local pRage = PctS("player");
    local enemy = UnitCanAttack("player", "target");
    local tDead = UnitIsDeadOrGhost("target");
    local lockedOn = UnitExists("target");

    i = i+1; Skill[i] = { name = "Will Attack",            use = (enemy and (pRage <= .50)) }
    i = i+1; Skill[i] = { name = "Charged Chop",            use = (enemy and ChkBuff("player", "Solidified Will")) }
    i = i+1; Skill[i] = { name = "Beast Chop",             use = (enemy and (pRage >= .20) and ChkBuff("player", "Will of the Beast")) }
    i = i+1; Skill[i] = { name = "Double Chop",             use = (enemy and g_petBuffBeast and (pRage >= .25)) }
    i = i+1; Skill[i] = { name = "Beast Chop",             use = (enemy and (pRage >= .20)) }
    i = i+1; Skill[i] = { name = "Power of the Wood Spirit",    use = enemy }

    MyCombat(Skill, arg1)

    if UnitExists("playerpet") then
        if not g_petBuffBeast and ChkBuff("playerpet","Beast") then
            g_petBuffBeast = true;
            g_petBuffBeastTime = os.time();
        elseif g_petBuffBeast and ((g_petBuffBeastTime+20) <= os.time()) then
            g_petBuffBeast = false;
        end
    end
end
I put the rage check on the Will Attack because I noticed that I'd get a lot of rage build up if I had multiple mobs on me and I'd rather dump the rage than get a possible bonus from Will Attack. I have two Beast Chops because if I have the Will Attack bonus I'd rather use that instead of Double Chop.

Any comments or suggestions are appreciated.

ghostwolf82

Professional

Posts: 859

Location: Kalvans Trunk

Occupation: It's dark in here

  • Send private message

1,427

Saturday, March 5th 2011, 11:38pm

@yannakm - Sixpax was working on translating the code of one of his addons (either partyhealer or the buff one) into spanish. You may want to have a look at that thread to see if you could use info there to get the french to work for you.

@nmgara - If Beast Chop requires that you have the buff "Will of the Beast" on you, then the second Beast Chop will never fire, you can remove it.

nmgara

Trainee

Posts: 114

Location: Azeroth

  • Send private message

1,428

Sunday, March 6th 2011, 4:51am

Quoted from "ghostwolf82;396133"



@nmgara - If Beast Chop requires that you have the buff "Will of the Beast" on you, then the second Beast Chop will never fire, you can remove it.


Will of Beast gives a 50% damage boost to Beast Chop, which is why I'd prefer it to go before Double Chop. You know, now that you mention it, I can probably rework it so there is only one. Just have to get the statements right. I originally wrote this before I got the lvl 45 elite that gives the buffs for Charged Chop or Beast Chop.

1,429

Sunday, March 6th 2011, 5:59am

Hi again!

I need some help adding 3 functions to my existing ScoutPriest macro. I've tried to piece together the Throat Attack part myself, but I must be doing something wrong. The other two, I can't find info on anywhere.

Edit - I fixed Throat Attack. Working fine now!

1: Is there a way to have a skill (say an interrupt or a tanking cooldown) type in a channel. Say, if I'm tanking an instance and DIYCE uses Resolution or my scout interrupts a skill, to say in party "Resolution Used" or "Interrupted X ability", etc?

2: It's hard on big pulls to see if a mob I'm not already targeting is casting something. Is there a way to detect if an enemy in the pack is casting and switch to it and interrupt automatically?

3: A line to check debuffs on my group and cast Purifying Shot (S/P dispel).

4: A line to check if anyone in the group is below 50% mana and then use Mana Arrows on that player.

Here's what I'm using now;

Quoted

function ScoutPriest(arg1)
local Skill = {}
local i = 0
local focus = UnitMana("player")
local friendly = (not UnitCanAttack("player","target"))
local tspell,ttime,telapsed = UnitCastingTime("target")
local a1,a2,a3,a4,a5,ASon = GetActionInfo(9)

i=i+1; Skill = { ['name'] = "Throat Attack", ['use'] = ((not friendly) and (tspell ~= nil) and (ttime >= 1) and ((ttime - telapsed) > 0.5) and (focus >= 15)) }
i=i+1; Skill[i] = { ['name'] = "Vampire Arrows", ['use'] = (not friendly) }
i=i+1; Skill[i] = { ['name'] = "Frost Arrow", ['use'] = (not ChkBuff("player","Frost Arrow")) }
i=i+1; Skill[i] = { ['name'] = "Autoshot", ['use'] = ((not friendly) and (not ASon)) }
i=i+1; Skill[i] = { ['name'] = "Combo Shot", ['use'] = (not friendly) }
i=i+1; Skill[i] = { ['name'] = "Shot", ['use'] = (not friendly) }
i=i+1; Skill[i] = { ['name'] = "Piercing Arrow", ['use'] = (not friendly) }
i=i+1; Skill[i] = { ['name'] = "Wind Arrows", ['use'] = ((not friendly) and (focus >= 15)) }
-- i=i+1; Skill[i] = { ['name'] = "Snipe", ['use'] = (not friendly) }

MyCombat(Skill,arg1)
end
Cheers!

Drake1132

Beginner

Posts: 11

Location: Wait a minute... you mean I'm *not* a figment of your imagination?

  • Send private message

1,430

Sunday, March 6th 2011, 10:10pm

Quoted from "xromkc1;396217"

Hi again!

I need some help adding 3 functions to my existing ScoutPriest macro. I've tried to piece together the Throat Attack part myself, but I must be doing something wrong. The other two, I can't find info on anywhere.

Edit - I fixed Throat Attack. Working fine now!

1: Is there a way to have a skill (say an interrupt or a tanking cooldown) type in a channel. Say, if I'm tanking an instance and DIYCE uses Resolution or my scout interrupts a skill, to say in party "Resolution Used" or "Interrupted X ability", etc?

2: It's hard on big pulls to see if a mob I'm not already targeting is casting something. Is there a way to detect if an enemy in the pack is casting and switch to it and interrupt automatically?

3: A line to check debuffs on my group and cast Purifying Shot (S/P dispel).

4: A line to check if anyone in the group is below 50% mana and then use Mana Arrows on that player.

Here's what I'm using now;

Cheers!




OK, first, for Throat Attack, I personally create another local variable, ttimeremaining, like follows...

Source code

1
2
3
4
local ttimeremaining = 0
if (ttime ~= nil) then
    ttimeremaining = ttime - telapsed
end
This will make it so that *if* the target is using a skill of any sort, then the cast time remaining for that skill is calculated, otherwise the cast time remaining is assumed to be zero. This will allow you to then check against ttimeremaining in the line for Throat Attack rather than doing the math as well as the check both there. Your way should work perfectly well I think, so you probably don't need to change anything if you don't want to, but you might run into an error of trying to perform math on a nil value if the target is not casting anything when the cast time checks are made.

Answers to your other questions follow...

1. Yes, there is a way to do this, but you have to use custom action code to manage it. Essentially you would want the setup to do the following... send the skill to MyCombat using the skill name "Custom: <skillname>" so that MyCombat will call the custom function. Create the custom function: "function CustomAction(actionname)". Inside of that new function, duplicate the CD check and add your additional code for sending a message to chat...

Source code

1
2
3
4
5
6
7
8
if CD(actionname) then
    if talktome then Msg("- "..actionname) end
    if (actionname == ("<skill to check against>" or "<other skill to check against>")) then -- you can add any number of skill/action names to check against here
        <insert code to send message to chat> -- this is probably done with the AddMessage function that is built into the RoM API (see the List of Functions page on theromwiki.com)
    end
    CastSpellByName(actionname) -- cast the spell
    return true
end
With such a setup, you are merely letting people know that you are *attempting* to use the noted action... there is no check in place to see if you successfully use the action or not, and as far as I know there is no way to check.


2. As far as I know, there is no way in the game to detect a particular creature as casting/using a spell/skill when you do not have them targeted, which means that in order to to check all creatures, you would have to cycle through them one at a time. You could theoretically write a function that would cycle through them and make such a check, but I suspect that the process would take longer than would be worthwhile.


3. The biggest issue with this is that there are a large number of "harmful effects" with different effect names that you would need/want to check against, and this can make things a little prohibitive. My suggestion would be to cycle through each party member target and look for a particular debuff *icon* using the UnitDebuff() API. The reason I suggest doing it this way is that many debuffs use the same icon as one another, specifically, most curses use the same curse debuff icon, and most poisons use the same poison debuff icon, etc. Once you have that set up, you make it so that when you find a party member with the icon that you are looking for listed in their debuff list, then you could cast Purifying Shot on that target. You can look through the original DIYCE code for the BuffList() function to get an idea of how to iterate through the entire debuff list of a target.


4. Similar to the debuff and purifying shot check above, you could iterate through each party member, check their Primary and Secondary power types to see if one of them is mana, then if one is, check it's level. If the level is below 50%, then you can cast Mana Arrows on them. Alternatively, if you do not want to cycle through all of your party members automatically, then you could simply use something like the following:

Source code

1
i=i+1; Skill[i] = { ['name'] = "Mana Arrows", ['use'] = friendly  and (((UnitManaType("target") == 1) and (PctM("target") <= 0.5)) or  ((UnitSkillType("target") == 1) and (PctS("target") <= 0.5)))  }

Both 3 and 4 would require you to write your own custom code, and then make DIYCE call that custom code.

You could also check out Sixpax's other addons, PartyBuffer and PartyHealer for help with cycling through party members.

Hope that helps,
Drake

1,431

Monday, March 7th 2011, 12:51pm

Quoted from "yannakm;396023"

Thanks, I switched back to ANSI.
I can't seems to make it work with accentuated characters, so for the spells that has them, I refer to slot number instead. It's not very practicle, but at least it works.



I know for sure that you need to use the proper language of spells depending of the language of the client.


ANSI is the proper file format, but you'll need the (decimal) UTF-8 character encoding on the accentuated characters.

If you look at the first post in this thread, near the bottom I have a link to a post by someone explaining how to handle German characters, so all you need to do is find the chart with UTF-8 encoding for the French characters you use.

1,432

Monday, March 7th 2011, 1:18pm

Quoted from "Drake1132;396337"

Source code

1
        <insert code to send message to chat> -- this is probably done with the AddMessage function that is built into the RoM API (see the List of Functions page on theromwiki.com)
With such a setup, you are merely letting people know that you are *attempting* to use the noted action... there is no check in place to see if you successfully use the action or not, and as far as I know there is no way to check.


Here's the command to send a party message:

Source code

1
SendChatMessage("This is my message", "PARTY")

Quoted from "Drake1132;396337"

2. As far as I know, there is no way in the game to detect a particular creature as casting/using a spell/skill when you do not have them targeted, which means that in order to to check all creatures, you would have to cycle through them one at a time. You could theoretically write a function that would cycle through them and make such a check, but I suspect that the process would take longer than would be worthwhile.


You can actually check the casting of a particular unit without targeting them, but for mob's you'd probably have to assign all the ones you want to consider to a focus slot first. Once you do that, you can do something like:

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
local tspell,ttime,telapsed

for j = 1,12 do
    if (not UnitExists("focus"..j)) then
        break
    end

    tspell, ttime, telapsed = UnitCastingTime("focus"..j)
    if (tspell ~= nil) and (ttime >= 1) and ((ttime - telapsed) >= 0.5) and CD("Throat Attack") then
        TargetUnit("focus"..j)
        CastSpellByName("Throat Attack")
        return true
    end
end

Quoted from "Drake1132;396337"

3. The biggest issue with this is that there are a large number of "harmful effects" with different effect names that you would need/want to check against, and this can make things a little prohibitive. My suggestion would be to cycle through each party member target and look for a particular debuff *icon* using the UnitDebuff() API. The reason I suggest doing it this way is that many debuffs use the same icon as one another, specifically, most curses use the same curse debuff icon, and most poisons use the same poison debuff icon, etc. Once you have that set up, you make it so that when you find a party member with the icon that you are looking for listed in their debuff list, then you could cast Purifying Shot on that target. You can look through the original DIYCE code for the BuffList() function to get an idea of how to iterate through the entire debuff list of a target.


As it turns out, there is a debuff type you can check to see if it is removable. For Purifying Shot (which removes harmful effects), the type is 10. Here's the function (modified to be generic) from my PartyHealer addon that checks to see if the unit passed to it has a dispellable debuff:

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
local function UnitIsSick(thisunit, matchType)
    local cnt = 1
    local debuff,_2,_3,_4,debuffType = UnitDebuff(thisunit, cnt)

    while debuff ~= nil do
        if (matchType == debuffType) then
            return true
        end

        cnt = cnt + 1
        debuff,_2,_3,_4,debuffType = UnitDebuff(thisunit, cnt)
    end

    return false
end
So you can add that to your .lua file and then use it like so:

Source code

1
2
3
4
5
6
7
8
9
if CD("Purifying Shot") then
    for j = 1,GetNumPartyMembers()-1 do
         if UnitIsSick("party"..j, 10) then
            TargetUnit("party"..j)
            CastSpellByName("Purifying Shot")
            return true
        end
    end
end

1,433

Thursday, March 10th 2011, 11:39pm

Trying to use a function from long ago to check buff times, so I have a buff button that recasts buffs if they are within 2 minutes of ending. Here is what I am using from the earlier posts:

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function ChkBuffTime(tgt,buffname)
   local cnt = 1
   local buffcmd = UnitBuff

   if UnitCanAttack("player",tgt) then
      buffcmd = UnitDebuff
   end
   local buff = buffcmd(tgt,cnt)

   while buff ~= nil do
      if buff == buffname then
         return GetPlayerBuffLeftTime(cnt-1)
      end
      cnt = cnt + 1
      buff = buffcmd(tgt,cnt)
   end
   return 0
end

function MyBuffs()
    local mybuffs = { "Grace of Life", "Amplified Attack", "Magic Barrier", "Battle Monk Stance", "Soul Bond" }
    for i,buffname in pairs(mybuffs) do
	Msg("Checking "..buffname)
	Msg("Checking "..i)
        if (ChkBuffTime("player",buffname) <= 120) then
            Msg("Casting "..buffname)
            CastSpellByName(buffname)
            return
        end
    end
end


It appears to work fine at first, but the time check is not working properly or something, even if a buff gets under 2 minutes, it never recasts it, and when the first buff gets down below 2 minutes, it will continually try to cast Grace of Life, regardless of what the first buff is.

I have been playing around with it for hours and haven't made much progress.....adding some debugging messages I seem to be able to get it to return the proper time check (each buff reads out the duration it has left), but it still attempts to cast the wrong buff for some reason.

Any help? Thanks.

ghostwolf82

Professional

Posts: 859

Location: Kalvans Trunk

Occupation: It's dark in here

  • Send private message

1,434

Friday, March 11th 2011, 5:47am

Just at first glance, try changing this

for i,buffname in pairs(mybuffs) do

to this

for i,buffname ipairs(mybuffs) do

1,435

Friday, March 11th 2011, 3:57pm

Nope, it said mybuffs was a nil value, I also tried "for i,buffname in pairs(mybuffs) do" (note the addition of "in", unlikie what you said to change it to), and it "worked", but it constantly recasted Grace of Life, even when all other buffs were missing.

1,436

Saturday, March 12th 2011, 2:04pm

Quoted from "Sixpax;396450"

if CD("Purifying Shot") then
for j = 1,GetNumPartyMembers()-1 do
if UnitIsSick("party"..j, 10) then
TargetUnit("party"..j)
CastSpellByName("Purifying Shot")
return true
end
end



Quoted from "Drake1132;396337"


Source code

1
2
3
4
5
6
7
8
if CD(actionname) then
    if talktome then Msg("- "..actionname) end
    if (actionname == ("<skill to check against>" or "<other skill to check against>")) then -- you can add any number of skill/action names to check against here
        <insert code to send message to chat> -- this is probably done with the AddMessage function that is built into the RoM API (see the List of Functions page on theromwiki.com)
    end
    CastSpellByName(actionname) -- cast the spell
    return true
end
With such a setup, you are merely letting people know that you are *attempting* to use the noted action... there is no check in place to see if you successfully use the action or not, and as far as I know there is no way to check.


So, is there some way to combine these two into one function? Even if there is no way to tell if a skill was successful, using DIYCE to activate Mana Arrows, Purifying Shot, etc only when someone is at a set amount of mana, or only when they have an appropriate debuff, would cast the ability at an appropriate time and then alert the party that it was used?

Also, I've tried following Drake's advice to use the PartyHealer .lua as a reference, but I can't find the right lines to check party mana bars for casting Mana Arrows. I'm no good with all this stuff, just trying to piece it together from other peoples scripts :P Bit of (more) help please!

Here's what I have so far. It's hard to tell if the decurse and interrupt scripts are working correctly, I'm going to go run a couple MA's and see if it's dispelling and interrupting properly. If these are working, all that's left is getting Mana Arrows to cast properly and I think I'm done :D

Edit -

One more thing I've thought of. Someone posted somewhere (can't find it, now!) a line that distinguishes between a standard mob and a boss level mob, so you can add skill lines that will only be used if it's a boss. Could you post an example so I could edit in a couple of those. I notice it's a waste of time casting BlindStab on my K/R on bosses, for example, because they're immune.

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
function ScoutPriestB(arg1)
   local Skill = {}
   local i = 0
   local focus = UnitMana("player")
   local friendly = (not UnitCanAttack("player","target"))
   local tspell,ttime,telapsed = UnitCastingTime("target")
   local a1,a2,a3,a4,a5,ASon = GetActionInfo(9)
   local function UnitIsSick(thisunit, matchType)
       local cnt = 1
       local debuff,_2,_3,_4,debuffType = UnitDebuff(thisunit, cnt)

       while debuff ~= nil do
       if (matchType == debuffType) then
            return true
       end

       cnt = cnt + 1
       debuff,_2,_3,_4,debuffType = UnitDebuff(thisunit, cnt)
       end

    return false
end


-- DECURSE
if CD("Purifying Shot") then
    for j = 1,GetNumPartyMembers()-1 do
         if UnitIsSick("party"..j, 10) then
            TargetUnit("party"..j)
            CastSpellByName("Purifying Shot")
            return true
        end
    end
end


-- SKILLS
   i=i+1; Skill[i] = { ['name'] = "Neck Strike",  ['use'] = ((not friendly) and (tspell ~= nil) and (ttime >= 1) and ((ttime - telapsed) > 0.5) and (focus >= 15)) }
   i=i+1; Skill[i] = { ['name'] = "Vampire Arrows", ['use'] = (not friendly) }
   i=i+1; Skill[i] = { ['name'] = "Frost Arrow",    ['use'] = (not ChkBuff("player","Frost Arrow")) }
   i=i+1; Skill[i] = { ['name'] = "Autoshot",       ['use'] = ((not friendly) and (not ASon)) }
   i=i+1; Skill[i] = { ['name'] = "Combo Shot",     ['use'] = (not friendly) }
   i=i+1; Skill[i] = { ['name'] = "Shot",           ['use'] = (not friendly) }
   i=i+1; Skill[i] = { ['name'] = "Piercing Arrow", ['use'] = (not friendly) }
   i=i+1; Skill[i] = { ['name'] = "Wind Arrows",    ['use'] = ((not friendly) and (focus >= 15)) }
--   i=i+1; Skill[i] = { ['name'] = "Snipe",          ['use'] = (not friendly) }

   MyCombat(Skill,arg1)
end

ghostwolf82

Professional

Posts: 859

Location: Kalvans Trunk

Occupation: It's dark in here

  • Send private message

1,437

Tuesday, March 15th 2011, 10:46am

To determine if a mob is a boss, elite, or normal, ad this to your locals section

Source code

1
2
    local boss = UnitSex("target") > 2
    local elite = UnitSex("target") == 2
Then call the variable into your skills sections like any other variable.

Ok, So I am having some thoughts, and am now messing with a scout, and wondering if anyone ever figured out a way to make arrows with a rune war bow?

If not, there is a way it may well work, but so far I am unable to figure out how to "use" an inventory slot, or how to call UseAction on something that is grayed out. I get no errors from my trials, which is why I am unable to figure out why it doesn't make arrows. When you place the bow on an action bar slot, it immediately goes gray, even though you can still slick it to use it to make arrows. Either using the action bar slot, or directly using the equipment slot will make arrows. Anyone know the api call to make either of these solutions work?

1,438

Tuesday, March 15th 2011, 2:08pm

Quoted from "ghostwolf82;398912"

Ok, So I am having some thoughts, and am now messing with a scout, and wondering if anyone ever figured out a way to make arrows with a rune war bow?


Here's my solution, at the top of my DIYCE function. I don't yet have a replacement bow, so I don't have to do any equipment swapping yet. The time thing makes sure the addon waits at least 2 seconds after making the arrow before trying again, otherwise if you spam your DIYCE button quickly it can queue up several stacks before they register as being in your bag.

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
arrowTime = 0
function DoDIYCE(tableFunction, ammoName)
    if ammoName ~= nil then
		if GetCountInBagByName(ammoName) > 0 then
			UseItemByName(ammoName)
			return true
		end
		if GetInventoryItemDurable("player", 9) == 0 
				and GetTime() - arrowTime > 2 then 
			UseEquipmentItem(10)
			arrowTime = GetTime()
			return true
		end
	end

ghostwolf82

Professional

Posts: 859

Location: Kalvans Trunk

Occupation: It's dark in here

  • Send private message

1,439

Tuesday, March 15th 2011, 8:05pm

Quoted from "Xemnosyst;398970"


Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
arrowTime = 0
function DoDIYCE(tableFunction, ammoName)
    if ammoName ~= nil then
        if GetCountInBagByName(ammoName) > 0 then
            UseItemByName(ammoName)
            return true
        end
        if GetInventoryItemDurable("player", 9) == 0 
                and GetTime() - arrowTime > 2 then 
            UseEquipmentItem(10)
            arrowTime = GetTime()
            return true
        end
    end
end

Ok, how am I to call this within my function?

I want to include the ability to create arrows into my main diyce function due to the fact I often forget to make new ones when I log in. Here is the code I use for arrows right now, and the line with the custom action isn't working

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    --Ammo Check and Equip
    if (ammo == false) then
        local HaveAmmo = false
        local arrows = ""
        for i=1,60 do
            local x,y,name = GetBagItemInfo(i)
            if ((string.find(name, " Thorn")) or (string.find(name, " Arrow"))) then
                HaveAmmo = true
                arrows = name
            end
        end
        if (HaveAmmo == true) then
            i=i+1; Skill[i] = { name = "Item: "..arrows,    use = (not ammo) } --Equip arrows if have           
        elseif ((g_cnt%100) == 0) then
                i=i+1; Skill[i] = { name = "Action: 16 (Rune War Bow)",     use = true }
            --DEFAULT_CHAT_FRAME:AddMessage"I need to get Arrows!"
        end
        g_cnt = g_cnt + 1
    end

1,440

Tuesday, March 15th 2011, 9:51pm

Quoted from "ghostwolf82;399132"

Ok, how am I to call this within my function?


Ah - sorry my code is not meant to be a stand-alone function. That's the top of my main function, which I named "DoDIYCE". So paste the top line ("arrowTime = 0") above your current function, then replace your current arrow code with:

Source code

1
2
3
4
5
6
7
8
9
10
    if GetCountInBagByName("<ammo name here>") > 0 then
        UseItemByName("<ammo name here>")
        return true
    end
    if GetInventoryItemDurable("player", 9) == 0 
            and GetTime() - arrowTime > 2 then 
        UseEquipmentItem(10)
        arrowTime = GetTime()
        return true
    end