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.

641

Thursday, June 10th 2010, 8:00pm

Quoted from "mrmarc0001;287028"

Ah, that's unfortunate indeed. Perhaps something that can be added in the next version of DIYCE? :D


It's possible, but it wouldn't be very eloquent since (I believe) there has to be a delay between the weapon swapping and the skill executiong... so you'd have the engine swap weapons on one pass, then *hopefully* execute the skill you need (i.e. Shadowstab) on the next pass, and finally swap weapons back on the third pass. That gets into the whole issue of trying to make the engine work in a particular sequence. There are problems with doing that... for instance, what do you do when step #2 isn't ready when its supposed to fire?

Quoted from "mrmarc0001;287028"

Regarding BuffTimeLeft(), is there a reason to use the "Action" definition instead of the skillname, or is it interchangeable?


Feel free to use either. I used "Action" because that's what was in the code of the person I was responding to.

mrmarc0001

Beginner

Posts: 3

Location: SF Bay Area

Occupation: Web Producer @ UCSF

  • Send private message

642

Thursday, June 10th 2010, 8:42pm

Quoted from "Sixpax;287092"

It's possible, but it wouldn't be very eloquent since...There are problems... for instance, what do you do when step #2 isn't ready when its supposed to fire?


I suppose the user would just have to make sure the appropriate conditions are being checked before each action is fired, but I see what you're getting at. Perhaps this is one of those things that should be left to custom Lua scripting, similar to the BuffTimeLeft() function, that can be tied into DIYCE but not necessarily be a part of DIYCE core (although, I will add that BuffTimeLeft() might make a good addition to core in the next version ;))

In fact, I personally feel there should be limitations to what DIYCE can do, mainly for performance reasons.

Quoted

Feel free to use either. I used "Action" because that's what was in the code of the person I was responding to.


Just wanted to double check since I didn't want to have bad information on my guide regarding that example.

643

Thursday, June 10th 2010, 9:06pm

Quoted from "mrmarc0001;287122"

(although, I will add that BuffTimeLeft() might make a good addition to core in the next version ;))


I have that on the list of things I'm putting together for the next release. Adding functions like that isn't a problem because it just gives the user more utility rather than having to change the design of the engine itself. If they don't use the function, it doesn't affect them at all.

Quoted from "mrmarc0001;287122"

In fact, I personally feel there should be limitations to what DIYCE can do, mainly for performance reasons.


I couldn't agree more. I attempted to add the ability to cast on a specified unit, rather than the target. I eventually gave up because although it was doable, the code became very complex and would have hindered performance since I didn't want to add that functionality without checking to see if the unit was able to be cast on (otherwise your custom function would get stuck on that skill). That meant having to target the specified unit and checking GetActionUsable(), then resetting the target back after the check. Imagine doing that for 10 different skills... each time you hit the macro. :eek:

hangman04

Savage Warrior

Posts: 113

Location: Romania

Mood: Smile

  • Send private message

644

Thursday, June 10th 2010, 9:30pm

I made a simple macro:
/cast Slash
/wait 0.75
/cast Power of the Wind Spirit
/wait 0.75
/cast Tactical Attack

but there are some problems like if slash misses i want to skip TA, or it is not enough rage and only performs PoWS
also i want the combo to not start if it not enough rage.
also if its not too much :D is there a way to make the combo button like a rage skill button, i mean to be red when is not enough rage and normal when there is a specific amount of rage.

regarding the macro this is how i would like it to be:
sub combo()
{
if playerskill >=25 cast slash
cast power of the wind spirit
if targeteffect = bleed cast tactical attack
}

The last condition could be problematic since the target could have other player bleed effect and i don't know if my TA does 2x dmg on any bleed effect or just my own (maybe others can tell me), or if it's different from other bleed effects (rogues and scouts have too, if i remember correctly).

Ty for your help!
I copied from my topic, lazy guy :D
K, so...

function WarriorWarden(arg1)
local Skill = {}
local i = 0
local mana = UnitMana("player")
local rage = UnitSkill("player")
local friendly = (not UnitCanAttack("player", "target"))
local tbuffs = BuffList("target")

i=i+1; Skill = { name = "Enraged", use = (rage <= 25) }
i=i+1; Skill[i] = { name = "Slash", use = ((not friendly) and (rage >= 25)) }
i=i+1; Skill[i] = { name = "Power of the Wind Spirit", use = (not friendly) and (mana >= 130) }
i=i+1; Skill[i] = { name = "Tactical Attack", use = ((not friendly) and (rage >= 15) and string.find(tbuffs, "Bleed")) }

MyCombat(Skill,arg1)
end

mrmarc0001

Beginner

Posts: 3

Location: SF Bay Area

Occupation: Web Producer @ UCSF

  • Send private message

645

Thursday, June 10th 2010, 9:40pm

Quoted from "hangman04;287174"

I made a simple macro...I copied from my topic, lazy guy :D K, so...


I don't get it. The problems you stated were problems with the original macro. What are you asking regarding your DIYCE function?

Quoted from "Sixpax;287149"

I have that on the list of things I'm putting together for the next release. Adding functions like that isn't a problem because it just gives the user more utility rather than having to change the design of the engine itself. If they don't use the function, it doesn't affect them at all.


Sweet. (Watch for PM later)

Quoted from "Sixpax;287149"

I couldn't agree more.


As our functions grow in size and number, what's to be looked out for as far as performance goes? Is it DIYCE's size or the custom function's size/complexity that will have greater impact on performance?

I never noticed until recently, but when using my DIYCE function, I can't throw a Fireball right after Flame as fast as I "normally" could. The difference is maybe 1/3-1/2 of a second, but it's noticeable when compared to manually firing the two spells. Now that I think about it, I should test it out using a simple DIYCE function compared to my actual one.

Know of any debugging tools that could probably be used in-game (or side-by-side) to monitor performance, perhaps?

mrmarc0001

Beginner

Posts: 3

Location: SF Bay Area

Occupation: Web Producer @ UCSF

  • Send private message

646

Thursday, June 10th 2010, 11:17pm

Quoted from "Sixpax;286830"

I'm not sure this will work, so you'll have to test it...


I'm dying to have this ready (if it works) before I get home, so here's a more practical example for mage cc. Could someone test and post results? Much appreciated. :)

You can ignore the commented lines. They're for something a bit more complex I want to add to this if it indeed does work. The part in question, of course, is the chat message portion.

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
function MageSF(arg1,arg2)  
  local Skill = {}
  local i = 0
  
  local enemy = UnitCanAttack("player", "target")
  local combat = GetPlayerCombatState()
  
  local pBuffs = BuffList("player")
  local tBuffs = BuffList("target")
  
  local isCharged = string.find(pBuffs, "Charged")
  local isChargedSF = string.find(pBuffs, "Static Field Charge")
  
  --local stunList = ""
  --local tSpell,tTime,tElapsed = UnitCastingTime("target")
  local pSpell,pTime,pElapsed = UnitCastingTime("player")
  
  local inParty = UnitInParty("player");
  --local inRaid = UnitInRaid("player");
  
  if (enemy) then
    i=i+1; Skill[i] = { name = "Static Field", use = (isChargedSF and (not isCharged)) }
    i=i+1; Skill[i] = { name = "Electric Compression", use = (isCharged and (not isChargedSF)) }
    i=i+1; Skill[i] = { name = "Lightning", use = (isCharged) }
    i=i+1; Skill[i] = { name = "Plasma Arrow", use = ((not isCharged) and (not isChargedSF)) }
  end
  
  MyCombat(Skill,arg1)
  
  if (pSpell == "Static Field") then
    if inParty then
      SendChatMessage("Stuffing " .. UnitName("target") .. " Stay clear.", "PARTY")
    else
      SendChatMessage("Stuffing " .. UnitName("target") .. " Stay clear.","SAY")
    end
  end
end

647

Friday, June 11th 2010, 3:28am

Quoted from "mrmarc0001;287180"

As our functions grow in size and number, what's to be looked out for as far as performance goes? Is it DIYCE's size or the custom function's size/complexity that will have greater impact on performance?

I never noticed until recently, but when using my DIYCE function, I can't throw a Fireball right after Flame as fast as I "normally" could. The difference is maybe 1/3-1/2 of a second, but it's noticeable when compared to manually firing the two spells. Now that I think about it, I should test it out using a simple DIYCE function compared to my actual one.

Know of any debugging tools that could probably be used in-game (or side-by-side) to monitor performance, perhaps?



Primarily I would think
1)Size and complexity of the MyCombat() function
2)Size and complexity of (especially the number of secondary function calls within) the custom function.

#2 is what each user mostly has control of, and ideally you'd want to put as few use[] lines as possible in, using separate functions for situational uses like CC where possible rather than using parameter controls (var2). Just my off the cuff analysis though, ymmv. Basically the parser runs through every line of your custom script at each execution, so the shorter it is and the fewer function calls within it the better your performance. You can also tweak them by putting the most commonly false factor of the conditional statement first, since LUA will short circuit conditionals.

As for MyCombat() I expect Six will make every effort to keep it clean and efficient since it pretty much drives everything, and he's very good at this. The number of helper functions included (pctHP() et al) shouldn't matter as they're only executed when called from the custom script and MyCombat().

mrmarc0001

Beginner

Posts: 3

Location: SF Bay Area

Occupation: Web Producer @ UCSF

  • Send private message

648

Friday, June 11th 2010, 10:39am

Quoted from "delve;287374"

...LUA will short circuit conditionals.

What do you mean by this?

=======

So, my CC function from Post #646, based off of Sixpax's code in Post #639, does indeed work. The catch is that the macro seems to need to be called again while casting that spell (i.e. won't work for anything insta-cast).

649

Friday, June 11th 2010, 12:41pm

Short circuit evaluation of conditionals refers to the scheme of only evaluating the second expression if necessary. So if the first exression of an AND is false then the whole thing must be false and LUA stops evaluating the expression. The same effect occurs if the first expression in an OR is true.

The more often your conditional short circuits the more efficient it will be so putting lightweight expressions that will cause a short circuit most often will help to some degree.

650

Friday, June 11th 2010, 3:16pm

Quoted from "hangman04;287174"

K, so...

function WarriorWarden(arg1)
local Skill = {}
local i = 0
local mana = UnitMana("player")
local rage = UnitSkill("player")
local friendly = (not UnitCanAttack("player", "target"))
local tbuffs = BuffList("target")

i=i+1; Skill = { name = "Enraged", use = (rage <= 25) }
i=i+1; Skill[i] = { name = "Slash", use = ((not friendly) and (rage >= 25)) }
i=i+1; Skill[i] = { name = "Power of the Wind Spirit", use = (not friendly) and (mana >= 130) }
i=i+1; Skill[i] = { name = "Tactical Attack", use = ((not friendly) and (rage >= 15) and string.find(tbuffs, "Bleed")) }

MyCombat(Skill,arg1)
end


One noticeable problem with your code is you have the mana and rage definitions backwards. I know it sounds wrong, but UnitMana is actually your Warrior's rage and UnitSkill is your Warden's mana when you're playing Warrior/Warden. It confuses everyone because of the function names, but UnitMana is the energy/rage/focus/mana pool of your primary class and UnitSkill is that of your secondary class.

Next problem, since the engine processes things by priority and not in a sequence, you'll want to put Tactical Attack before Slash. Otherwise it will only execute Slash because the conditions for it will be met before TA.

Lastly, I believe the Warden skill is Power of the Wood Spirit, not Wind Spirit. Or am I missing something?

So give this one a try:

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function WarriorWarden(arg1)
    local Skill = {}
    local i = 0
    local rage = UnitMana("player")
    local mana = UnitSkill("player")
    local friendly = (not UnitCanAttack("player", "target"))
    local tbuffs = BuffList("target")

    i=i+1; Skill[i] = { name = "Enraged", use = (rage <= 25) }
    i=i+1; Skill[i] = { name = "Tactical Attack", use = ((not friendly) and (rage >= 15) and string.find(tbuffs, "Bleed")) }
    i=i+1; Skill[i] = { name = "Slash", use = ((not friendly) and (rage >= 25)) }
    i=i+1; Skill[i] = { name = "Power of the Wood Spirit", use = ((not friendly) and (mana >= 130)) }

    MyCombat(Skill,arg1)
end

651

Friday, June 11th 2010, 3:23pm

Quoted from "mrmarc0001;287481"

So, my CC function from Post #646, based off of Sixpax's code in Post #639, does indeed work. The catch is that the macro seems to need to be called again while casting that spell (i.e. won't work for anything insta-cast).


Actually it should work on the same call as the spell is being cast, but you either need to update "pSpell" after the MyCombat() call, or just use UnitCastingTime().

For instance:

Source code

1
2
3
4
5
6
7
if (UnitCastingTime("player") == "Static Field") then
    if inParty then
       SendChatMessage("Stuffing " .. UnitName("target") .. " Stay clear.", "PARTY")
    else
       SendChatMessage("Stuffing " .. UnitName("target") .. " Stay clear.", "SAY")
    end
end

652

Friday, June 11th 2010, 3:36pm

Quoted from "mrmarc0001;287180"

I never noticed until recently, but when using my DIYCE function, I can't throw a Fireball right after Flame as fast as I "normally" could. The difference is maybe 1/3-1/2 of a second, but it's noticeable when compared to manually firing the two spells. Now that I think about it, I should test it out using a simple DIYCE function compared to my actual one.

Know of any debugging tools that could probably be used in-game (or side-by-side) to monitor performance, perhaps?


There's a bug in the RoM code that allows you to occasionally use a skill while the GCD is active. I suspect this is why you're noticing the difference... since my engine is checking the cooldown of each skill before using it, it will never be able to take advantage of this bug.

653

Friday, June 11th 2010, 4:10pm

Quoted from "delve;287374"

Primarily I would think
1)Size and complexity of the MyCombat() function
2)Size and complexity of (especially the number of secondary function calls within) the custom function.

#2 is what each user mostly has control of, and ideally you'd want to put as few use[] lines as possible in, using separate functions for situational uses like CC where possible rather than using parameter controls (var2). Just my off the cuff analysis though, ymmv. Basically the parser runs through every line of your custom script at each execution, so the shorter it is and the fewer function calls within it the better your performance. You can also tweak them by putting the most commonly false factor of the conditional statement first, since LUA will short circuit conditionals.

As for MyCombat() I expect Six will make every effort to keep it clean and efficient since it pretty much drives everything, and he's very good at this. The number of helper functions included (pctHP() et al) shouldn't matter as they're only executed when called from the custom script and MyCombat().


I have the MyCombat() function streamlined fairly well. By the time it gets called, all of the "use" definitions have already been evaluated (all that occurs within your custom function). So I have it first check to see if "use" is true before even attempting to dissect the Skill/Action and execute it. If you look at the code, obviously "Action" definitions are doing a lot more checks than using Skill names, so it will help to use Skill names as much as possible. The only time I would suggest using "Action" definitions is for items (potions) and if it's absolutely necessary to do a range check.

For your custom function, not only should you take delve's advise and try to "short circuit" the conditions as efficiently as possible, but you also want to avoid running external functions unnecessarily. This is why I created the BuffList function which allows you to capture all the buffs/debuffs in a string and then use string.find() operations to check for a buff rather than calling ChkBuff several times within your function. The same goes for using PctH (just call it once at the top of your function).

There are other methods for streamlining your custom function that we haven't even discussed yet. For instance, you don't have to build the Skill table for every skill you want to use, but instead you can check conditions for which skills to include before building the table.

Here's an example... let's say you play a Priest/Mage. You can separate your friendly healing skills from your damage skills and only build whichever ones you need for whatever mode you're in before calling MyCombat().

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
function PriestMage(arg1)
    local Skill = {}
    local i = 0
    local health
    local friendly = (not UnitCanAttack("player","target"))
    local combat = GetPlayerCombatState()
    local pbuffs = BuffList("player")
    local tbuffs = BuffList("target")

    if (not combat) then
        i=i+1; Skill[i] = { name = "Blessed Spring Water",  use = (not string.find(pbuffs, "Blessed Spring Water")) }
        i=i+1; Skill[i] = { name = "Magic Barrier",         use = (not string.find(pbuffs, "Magic Barrier")) }
    end
    
    if friendly then
        health = PctH("target")
        
        i=i+1; Skill[i] = { name = "Regenerate",        use = ((health <= .95) and (not string.find(tbuffs, "Regenerate"))) }
        i=i+1; Skill[i] = { name = "Heal",              use = (health <= .5) }
        i=i+1; Skill[i] = { name = "Urgent Heal",       use = (health <= .75) }
        i=i+1; Skill[i] = { name = "Amplified Attack",  use = (not string.find(tbuffs, "Amplified Attack")) }
        i=i+1; Skill[i] = { name = "Grace of Life",     use = (not string.find(tbuffs, "Grace of Life")) }
        i=i+1; Skill[i] = { name = "Angel's Blessing",  use = (not string.find(tbuffs, "Angel's Blessing")) }
    else
        health = PctH("player")

        i=i+1; Skill[i] = { name = "Regenerate",  use = ((health <= .95) and (not string.find(pbuffs, "Regenerate"))) }
        i=i+1; Skill[i] = { name = "Heal",        use = (health <= .5) }
        i=i+1; Skill[i] = { name = "Urgent Heal", use = (health <= .75) }
        i=i+1; Skill[i] = { name = "Bone Chill",  use = (not string.find(tbuffs, "Bone Chill")) }
        i=i+1; Skill[i] = { name = "Fireball",    use = true }
        i=i+1; Skill[i] = { name = "Rising Tide", use = true }
    end
    
    MyCombat(Skill, arg1)
end
So instead of building a Skill table with all 11 of those skills in it each time, I'm only building it with the required Skills for the situation.

mrmarc0001

Beginner

Posts: 3

Location: SF Bay Area

Occupation: Web Producer @ UCSF

  • Send private message

654

Friday, June 11th 2010, 7:40pm

Quoted from "Sixpax;287538"

Actually it should work on the same call as the spell is being cast, but you either need to update "pSpell" after the MyCombat() call, or just use UnitCastingTime().


Ah yes, I should have known that. That's what I get for not getting to this script til 1AM. LOL

Quoted from "Sixpax;287546"

There's a bug in the RoM code that allows you to occasionally use a skill while the GCD is active. I suspect this is why you're noticing the difference... since my engine is checking the cooldown of each skill before using it, it will never be able to take advantage of this bug.


Neat bug. Oddly enough, it seems thats why I can [sometimes] double pot (using DIYCE) before the pot-CD kicks in. Bug of bug??

============

Quoted from "delve;287505"

The more often your conditional short circuits the more efficient it will be


Quoted from "Sixpax;287563"

I have the MyCombat() function streamlined fairly well...You can separate your friendly healing skills from your damage skills and only build whichever ones you need for whatever mode you're in before calling MyCombat()...So instead of building a Skill table with all 11 of those skills in it each time, I'm only building it with the required Skills for the situation.


That basically answers the question I was going to pose after delve's last response. Now I'm glad I've been doing this for portions of my function.

Thanks, guys!

hangman04

Savage Warrior

Posts: 113

Location: Romania

Mood: Smile

  • Send private message

655

Friday, June 11th 2010, 8:04pm

Quoted from "mrmarc0001;287180"

I don't get it. The problems you stated were problems with the original macro. What are you asking regarding your DIYCE function?


sorry mrmarc the post was an answer to Sixpax from another topic :)

Quoted from "Sixpax;287534"

So give this one a try:

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function WarriorWarden(arg1)
    local Skill = {}
    local i = 0
    local rage = UnitMana("player")
    local mana = UnitSkill("player")
    local friendly = (not UnitCanAttack("player", "target"))
    local tbuffs = BuffList("target")

    i=i+1; Skill[i] = { name = "Enraged", use = (rage <= 25) }
    i=i+1; Skill[i] = { name = "Tactical Attack", use = ((not friendly) and (rage >= 15) and string.find(tbuffs, "Bleed")) }
    i=i+1; Skill[i] = { name = "Slash", use = ((not friendly) and (rage >= 25)) }
    i=i+1; Skill[i] = { name = "Power of the Wood Spirit", use = ((not friendly) and (mana >= 130)) }

    MyCombat(Skill,arg1)
end


so practically the script runs all skills in that order from 1 to n, and the rule would be that conditional skills (like TA) should be on top on the list as soon as their condition is valid they will be casted.
now ill ask noob question since i didnt read all pages.how does it work:
install add on-> macros ->copy paste script and it works as a macro?

and how or when does the script end? when targed is dead or i exit combat?

mrmarc0001

Beginner

Posts: 3

Location: SF Bay Area

Occupation: Web Producer @ UCSF

  • Send private message

656

Friday, June 11th 2010, 8:40pm

Quoted from "hangman04;287821"

so practically the script runs all skills in that order...how or when does the script end? when targed is dead or i exit combat?


You're calling a custom function. The script starts and ends with the first skill performed by the function. You continue to call the function to perform each skill based on the conditions set forth in your function. It doesn't work like a macro script that performs skills one after the other.

Quoted from "hangman04;287821"

now ill ask noob question since i didnt read all pages.how does it work:


Read the first post or my work-in-progress guide. See my sig for link to my site (don't want to publish the URL just yet). I'm surprised you're even trying to use this without reading up on how it even works.

mrmarc0001

Beginner

Posts: 3

Location: SF Bay Area

Occupation: Web Producer @ UCSF

  • Send private message

657

Friday, June 11th 2010, 8:44pm

Quoted from "Sixpax;287563"

I have the MyCombat() function streamlined fairly well. By the time it gets called, all of the "use" definitions have already been evaluated...So I have it first check to see if "use" is true before even attempting to dissect the Skill/Action and execute it.


The more I think about, the more I want to really make my function efficient. Now, I understand that DIYCE will see if a skill is usable on its own (check cooldown, skillusable, etc), so is doing something like

Source code

1
i=i+1; Skill[i] = { name = "Static Field", use = (isChargedSF and (not isCharged)) }

just slowing things down since it's checking the conditions in the "use" definitions before it even gets to the skill, or is this in fact better because it skips that skill altogether when false? I understand that in some cases you need/want to have those conditions there, of course.

hangman04

Savage Warrior

Posts: 113

Location: Romania

Mood: Smile

  • Send private message

658

Friday, June 11th 2010, 9:37pm

Quoted from "mrmarc0001;287840"

You're calling a custom function. The script starts and ends with the first skill performed by the function. You continue to call the function to perform each skill based on the conditions set forth in your function. It doesn't work like a macro script that performs skills one after the other.

So in order to get a "combo" i have to spam the macro button, right? and depending how well made is the list of priorities i might get smth good.

mrmarc0001

Beginner

Posts: 3

Location: SF Bay Area

Occupation: Web Producer @ UCSF

  • Send private message

659

Friday, June 11th 2010, 9:49pm

Quoted from "hangman04;287875"

So in order to get a "combo" i have to spam the macro button, right? and depending how well made is the list of priorities i might get smth good.


Correct. If you set it up right, you can even have it be a "do-it-all" macro. Mine takes care of potions, buffs, debuffs, and attacks, including special conditions for when I require "maximum damage" and group pulls (AoE). I can basically play with one hand (macro set to mouse button) and have a beer with the other, LOL.

hangman04

Savage Warrior

Posts: 113

Location: Romania

Mood: Smile

  • Send private message

660

Friday, June 11th 2010, 9:57pm

very nice then its a trial and fail process finding the right combination, anyway as wr/wd its easier for me to create a nice combination. just have to add 2 skills open flank + probing attack.
i still don;t know if the script makes difference if there are other bleed effects, i mean other classes', cause that may use my TA whit only 1xdmg not 2x.