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.

81

Tuesday, May 13th 2014, 4:31pm

Hey, lots of good input :)

  1. For compatibility I think we should leave the "try" command as is but implement new ones like 'trySkill', 'tryAction' which simplifies writing scripts manually. The multi-argument 'try' command is prolly best for when we get to code generation. There are quite some readebility issues as fdiyce was designed for generated code, extending this with a thin extension layer for scripting should be easy.
  2. I pretty much agree on the naming of Bleeding, we should try to be consistent in naming functions and variables so TargetIsBleeding should be good. The reason I used a separate variable for it is that many classes have multiple bleed skills which gives different debuffs. To make sure we address all and the correct buff I made the 'TargetIsBleeding' which is supposed to be class specific and contains the ID's of each bleed to differentiate. (Like rogue has 3x bleeds)
  3. The Hero and Uni is just my personal thing, I've received many comments and will probably remove from distribution. I like to make diyce re-hero if it runs out in middle of fight so the lines in scripts only renews if your about to run out. I do same with "Briar Shield", when I have put it on I like it to stay on, if I remove it it should stay removed, typically when aoe is not wanted. But - this is still a DIY distribution even though I hope to include workable scripts (as soon as ppl contribute)
  4. The main advantage of FuzzyDIYCE is speed, all variables are cached to minimize the number of client calls done for each attack. They are all done once by demand. Other advantages is gui for control (check in ESC, Interface Settings, FuzzyDIYCE) I haven't done a lot here yet but skeleton is in place. There are also more commands available like the list/reload/help.
  5. The main disadvantage has turned out to be debugability, an error and client tends to die. This is something I'm looking into, we need to have better control over code loading. Currently the '/fdiyce reload' will give nice debug messages on combat script syntax but bugs in other parts like plugins/extension can kill client still.
  6. Upper/lower case, basically 'try' is a command/function while IsTargetBoss is a variable (a usage difference)


This became a long and un-ordered list, I hope I addressed all your input, thx a lot :)
I'll bring this with me into next release.

.frafall

82

Wednesday, May 14th 2014, 7:04am

Been thinking about the bleeding stuff; do I really want to maintain IDs/names of bleed buffs in vars? Doesn't this really belong in the combat script itself, being maintained by the script author...

I think its cleaner to implement TargetHasBuff which accepts a table as argument so we can do it like:

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function RogueScout(...)
       --[[
		Rogue/Scout bleeds
	
		Bleed               : 620313 - 10s (old value 500654?)
		Blind Spot Bleed	: 620297 - 6s 
		Sneak Attack Bleed	: 500726 - 20s
       --]]
       local bleeds = {620313, 620297, 500726}
 
       .
       .
       trySkill("Low Blow", TargetHasBuff(bleed))
       .
       .
end


This might enable ppl writing scripts which test for all buffs in one go which would ruin the caching done in vars:

Source code

1
2
--BAD CODE; DON'T DO IT
trySkill("Wound Attack", TargetHasBuff({620313, 620297, 500726,"Grievous Wound"})

This would cache nicely but probably would never be reused as its specific for one skill so the 'Low Blow' and the 'Wound Attack' buff checks would be executed once each.

It also opens up for interpretation, is it all skills in table given or one skill in table given (and vs. or).
I automatically implied an 'or' in 1st example, 2nd I mixed it up...

.frafall

This post has been edited 4 times, last edit by "frafall" (May 14th 2014, 7:27am)


83

Wednesday, May 14th 2014, 8:53am

Also thinking about timers, for bleeds on r/s we have three different length of bleeds but current a timer is restricted to one fixed time.

Would it be better to somehow enable variable length timers? Any ideas?

Something along the line of:

Source code

1
2
3
4
5
bleed = api.CreateFDTimer("Bleed", 1)  -- argument indicates delta to use in starting new

trySkill("Sneak Attack", (not PlayerInCombat) and PlayerMana >= 20 and IsBehind, bleed(21)) 
trySkill("Blind Spot", PlayerMana >= 20 and IsBehind, bleed(6))
trySkill("Shadowstab", PlayerMana >= 20, bleed(10))


Maybe give a default time in creating the timer so one could use as below as well.

Source code

1
trySkill("Shadowstab", PlayerMana >= 20, bleed)


.frafall

This post has been edited 1 times, last edit by "frafall" (May 14th 2014, 9:17am)


Marvengus

Beginner

Posts: 14

Location: Netherlands

Occupation: Mathematician, Scientist

Mood: Smile

  • Send private message

84

Wednesday, May 14th 2014, 9:10am

Great work :) Thanks!

Not sure what you mean with the caching (I know what it means in software) since with each run of the method the (de)buffs may have changed. So, such information needs to be refreshed each time I guess?

Ignoring that, I like the approach with explicit (de)buff names and id's more than having this hidden inside the FD code. Reason is that it gives script developer better control and understanding about what they are doing. I think that for this project, we're trying to balance on a fine line between providing flexibility and ease of use... but isn't that always when developing "developer tools". :)

Another question I forgot to ask: In previous DIYCE combat scripts, we were building two skills arrays, and then the DIYCE core code iterated that list to find the first which could and should be used. Having a list of try statements, visually looks similar, but it suggests that after we have done the first try, we always do the 2nd, then the 3rd, etc. But I guess what really happens is that we try the 1st, and only if that fails, we try the second... But that is not so obvious from the code. Suppose that a try statement succeeds (so the skill/action gets exectuted), then what part of the rest of the combat method gets executed? Everything except the try calls? For example in the following snippet from the RogueScout script:

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
    -- Maintain Hero, Speed pots, HP pots and stuff
    try("action", hero, PlayerHasBuff("Hero Magic Medicine") and PlayerHasBuff("Hero Magic Medicine").time <= 5)
    try("action", uni, PlayerHasBuff("Touch of the Unicorn") and PlayerHasBuff("Touch of the Unicorn").time <= 5)
	
    -- We have a target?
    if GotTarget and not TargetIsDead then
        api.CreateFDTimer("Bleed",  9.0)
		
        try("skill", Skills["Premeditation"].entry, (not PlayerInCombat) and IsTargetType("boss") and PlayerMana >= 50)
        try("skill", Skills["Informer"].entry, (IsTargetType("boss") or IsTargetType("elite")) and not PlayerHasBuff("Informer"))

        -- deleted
    end


Suppose the code decides to drink a hero pot, I assume it does not even try the unicorn, so the 2nd try should be ignored. But in that same situation... do we even enter the If-blocK, and does the timer get created? If so, then again, I guess the 3rd and 4th try are ignored?

(I have never used timers, so have no input on them.)
Marvengo R/S/K (90/90/65)
Marvengus M/D/Wd (85/80/68 )
Playing on Isilitir (EU)
Guild Traumfaenger

85

Wednesday, May 14th 2014, 9:51am

.. see Peryl's answer below :)

This post has been edited 1 times, last edit by "frafall" (May 14th 2014, 6:47pm)


Marvengus

Beginner

Posts: 14

Location: Netherlands

Occupation: Mathematician, Scientist

Mood: Smile

  • Send private message

86

Wednesday, May 14th 2014, 10:34am

Not sure if I understand this correctly... Aren't you afraid that if a combat script stops after the first successful try command, that it becomes non-intuitive for programmers? I saw FuzzyDIYCE combat scripts with targeting logic at the end. Would this targeting logic not be triggered if an earlier try succeeds?

Perhaps I need to understand whether the general DIYCE flow remains intact. My current DIYCE script does this (which does not deviate from the code I copied the first time):
  1. collect variables about player, target, health, etc.
  2. build skills lists
  3. call MyCombat to let the DIYCE core select and execute a single skill
  4. retarget if I have no target or target is dead, where I ensure skipping pets and lvl 1 mobs.
Marvengo R/S/K (90/90/65)
Marvengus M/D/Wd (85/80/68 )
Playing on Isilitir (EU)
Guild Traumfaenger

Peryl

Intermediate

  • "Peryl" started this thread

Posts: 313

Location: Elsewhere

  • Send private message

87

Wednesday, May 14th 2014, 12:09pm

The skippable commands are try and perform.

By skipable, I mean a flag is checked internally prior to actually calling the code that executes the command to see if a previous try statement actually did its thing. If this is the case, then the command is not actually executed, otherwise it will.

The perform statement doesn't set the flag, but does check it. This gives the abilty to have sub-function scripts that only execute when previous try statements have failed.

For example, lets say you have a script that checks if you need to use buff pots (lets say it is called PotUp), one for self-healing (SelfHeal) and one that does your skill rotation (DoRotation). You could then have your main FD script be something like:

Source code

1
2
3
perform SelfHeal
perform PotUp
perform DoRotation

and it will act as if the whole thing was one DIYCE skill list.


There is a (almost) one to one relationship between the old skill list entries and the try command. That was the point. Instead of building a list of skills to try to use, I setup the try command to do it directly. No need to pre-build a list and it makes a logical relationship between the script's code order and execution of the skill list.


As to the data caching, it does refresh on each execution of the FD script, but within a single execution pass, it only really reads it once. Look at many of the older DIYCE scripts folk have posted and you will see many examples of them calling functions to retrieve the same info that obviously will not have changed. By caching the result the first time, we can just return the cached result instead of actually calling the game functions. That is what the cached variables are doing.

Further, old DIYCE scripts had a tendency to have a boat-load of variables defined at the start in order to try to manually cache some info. Unfortunately, this means that data and function that might never have a use on a given script pass will be read. The caching system aleviates this by only reading it the first time it is used (just-in-time) behind the scenes so there is no need for the massive list of variables at the start of the script.

Edit:
Forgot to mention. Having cached vars like this introduces one complexity (though it also exists in the older DIYCE code). In some conditions, you will need to force the caching system to refresh its cached data. Re-targeting is an example of this. Since you changed targets, all cached variables that contain information about the target will need to be refreshed. This is why the invalidate command exists. It gives you the ability to force a cached variable to refresh its data.
2013... The year from hell....

This post has been edited 1 times, last edit by "Peryl" (May 14th 2014, 12:20pm)


Marvengus

Beginner

Posts: 14

Location: Netherlands

Occupation: Mathematician, Scientist

Mood: Smile

  • Send private message

88

Wednesday, May 14th 2014, 2:58pm

Nice! :)

For optimal speed, then, it would be great if in the following snippet,

Source code

1
2
        try("skill", Skills["Premeditation"].entry, (not PlayerInCombat) and IsTargetType("boss") and PlayerMana >= 50)
        try("skill", Skills["Informer"].entry, (IsTargetType("boss") or IsTargetType("elite")) and not PlayerHasBuff("Informer"))


if the first try executed the premed, then the arguments in the second line would not be evaluated. Just like in many programming languages, if you write (A and B) and A is false, then B does not get evaluated anymore. I don't know lua well enough, but I'm afraid that, since the skip logic is inside the try method, in the second line we always evaluate the possibly expensive (IsTargetType("boss") or IsTargetType("elite")) and not PlayerHasBuff("Informer"). Is that correct? I realize that old DIYCE had the same "issue".

If try would return a boolean that indicates whether it has executed the skill/action, then we could create constructs like

Source code

1
2
3
        if not try("skill", Skills["Premeditation"].entry, (not PlayerInCombat) and IsTargetType("boss") and PlayerMana >= 50)
        then if not try("skill", Skills["Informer"].entry, (IsTargetType("boss") or IsTargetType("elite")) and not PlayerHasBuff("Informer"))
        then if not ...


Visually less attractive, but could this gain a lot of speed?
Marvengo R/S/K (90/90/65)
Marvengus M/D/Wd (85/80/68 )
Playing on Isilitir (EU)
Guild Traumfaenger

89

Wednesday, May 14th 2014, 8:31pm

Hey Peryl, I'v got a thing u perhaps can help me out with.

I have made a IsTargetPlayer variable, this calls the IsTargetType.

Source code

1
vars.IsTargetPlayer = function () return vars.IsTargetType("player") end


Interesting thing, this returns true/nil, not true/false.


I have tried to insert debug messages, the value of "return _CachedVars[k].value" in Vars metatable is true/false, but when I receive the value its true/nil.

I have bashed my head for an hour, must have overlooked something, somewhere... :dash:

.frafall

Peryl

Intermediate

  • "Peryl" started this thread

Posts: 313

Location: Elsewhere

  • Send private message

90

Thursday, May 15th 2014, 12:24am

@frafall
In Lua, nil is considered false for logic operations (and with if statements) so from a Lua logic stand point, this is correct. The reason it returns nil is that the code that handles that function effectively falls through and returns nothing (or nil).

If the nil is annoying for some reason, you can always double negate the result which will always convert the nils to false and non-nil, non-boolean values to true. Boolean value will remain untouched.

So convert the return value to:

Source code

1
return not not vars.IsTargetType("player")

Will do the trick.

EDIT
Just realized. IsTargetType is a templated cached variable (the only one implemented, though other might have followed). It acts in a special way and the code is written with this in mind.

Because it is supposed to be a "variable" and have the data caching on it, I didn't want to either write a second caching system just for it, nor remove the data caching altogether. But as you need to give it a parameter (the type of target your are looking for) it also acts a bit like a function. Soooo... I cheated a bit and used an obscure little feature of Lua function calls. If providing a single parameter to a function that happens to be a table, you do not need to actually use the parenthesis for the paremeter list.

When you look at the code for the IsTargetType variable, you will see that the internal function actually resides inside IsTargetType.func and it expects a table. This is checked for internally and does nothing (i.e. returns nil) if the argument isn't a table.

Try changing the code to

Source code

1
return vars.IsTargetType( {"player"} )
or you can use

Source code

1
return vars.IsTargetType{"player"}
note the use of braces instead of parenthesis here.

This is how this var is used in FuzzyScript BTW. With braces instead of parentheses.



@Marvengus
Lua already does short-cut evaluation of logic operators, so the and/or logic operators will work as you describe (see my Logic operator guide in the Add-on Dev sub-forum for details on the ins and outs on this stuff and some of the tricks that can be done with them). Edit Apprently, those old guides got moved to the archive section, but at least they are still around.

As to evaluating logic operators in a function parameter list, Yes, that would indeed happen. Though since the evaluation happens at run-time, it wouldn't evaluate parts that get skipped via short-cut evaluation.

Edit
The try command (actually any skipable command) returns a true, false or nil. They have the following meanings
  • true The try command succeeded in executing the action.
  • false The try command did not trigger this action.
  • nil Command skipped because a previous try command was triggered.

Skippable commands already abort before executing meaning that if-else constructs as you propose are not required which was in fact the reason for creating skipable commands in the first place. It all gets handled internally so you don't have to clutter your code with what amounts to pointless if-else statements.


Having said all this...

Note that I consider the following a hack and should only ever be used if trying to squeeze the most speed out of a script.

To enforce non-evaluation of the condition of a try command, we can fake out the Lua interpreter by specifically or-ing the condition with the variable that is used to check if a skill has been triggered.

Using your first try command we could do

Source code

1
try("skill", Skills["Premeditation"].entry, fdvars.Triggered or ((not PlayerInCombat) and IsTargetType("boss") and PlayerMana >= 50) )


Make sure the following exists at the start of your script file:

Source code

1
2
local fd = FuzzyDIYCE
local fdvars = fd.FDVars
2013... The year from hell....

This post has been edited 3 times, last edit by "Peryl" (May 15th 2014, 4:54am)


91

Thursday, May 15th 2014, 6:42am

@Peryl

My 1st thought was to try out the 'not not' conversion which didn't make any differences.

I''ve been fooled by the curlies a couple of times (bad eyesight) so I ended up modifying IsTargetType to accept a single 'non-table' argument as well and in the same go enabled it to check for multiple target types in a go. To be sure I tested out curlies before modifying as well.

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
vars.IsTargetType = {
    -- types are "player","boss","elite","hard","mob","self","npc","pet","other"
    func = function (arglist)
		local arglist = type(arglist) == "table" and arglist or {arglist}
		local trgttype
		local desiredtype = arglist[1]

		if not UnitExists("target") then
			return false
		end

		for k, desiredtype in pairs(arglist) do
			if desiredtype == "player" then
				trgttype = UnitIsPlayer("target")
			elseif desiredtype == "hard" then
				trgttype = UnitSex("target") >= 2
			elseif desiredtype == "boss" then
				trgttype = UnitSex("target") > 2
			elseif desiredtype == "elite" then
				trgttype = UnitSex("target") == 2
			elseif desiredtype == "mob" then
				trgttype = UnitCanAttack("player", "target")  and not UnitIsPlayer("target")
			elseif desiredtype == "self" then
				trgttype = UnitIsUnit("target", "player")
			elseif desiredtype == "npc" then
				trgttype = not UnitCanAttack("player", "target") and not UnitIsPlayer("target")
			elseif desiredtype == "pet" then
				trgttype = not not UnitMaster("target") -- The double not converts non boolean values to boolean
			end

			if trgttype then return true end
		end
		return false
    end,

    args = {
        { names = {"player", "boss", "elite", "hard", "npc", "mob", "self", "pet"} },
    },
}


As lua accepts nil as false value this isn't a big problem but I got damn curios on how a return false got converted to a return nil. I tried making a test case outside FD to replicate the issue but was unable to replicate.

I inserted print debugs into the FD_CachedVars to verify, it verified that the return value was false. I used LuaExplorer to grab the vars table (api.GetCachedVarTable()) and check it out, the cached value was 'false' but when returned it came out as 'nil'.

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
fd.Vars = setmetatable({}, {
    __index = function (t, k)
        if _CachedVars[k] then
            if _CachedVars[k].template then
                return _CachedVars[k]   -- this is a templated var, so just return the entry
            elseif _CachedVars[k].cache ~= CacheNum then
                -- Data currently in cache is out of date, so update it
                _CachedVars[k].value = _CachedVars[k].func()
                _CachedVars[k].cache = CacheNum
            end
            -- Send cached result back
            api.FDMsg("DEBUG: "..tostring(_CachedVars[k].value))
            return _CachedVars[k].value
        end
    end,


Then I tried converting the return value to a string in the vars function before returning which turned out to be ok, it returned the string "false". Removing the conversion (tostring) it returned nil again instead of false.

.frafall

92

Friday, May 16th 2014, 2:54pm

Next version

I've ended up with the following for next version:
  1. Renamed the original PlayerMana/PlayerSecMana variants to RawPlayerMana/RawPlayerSecMana and added 'links' to these with the class dependent names PlayerEnergy, PlayerMana, PlayerFocus, PlayerRage (and PlayerManaPct).
  2. Removed the Bleeding variable and rather made TargetHasBuff accept a table as argument
  3. Changed the timers to be variable length (while maintaining the original interface)
  4. In the examples I have added the fdvars.Triggered trick to make sure we distribute 'optimal' combat script (at least technical)


This results in a typical combat script looking like:

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
local fd     = FuzzyDIYCE
local fdvars = fd.FDVars
local api    = fd.API

-- Set the environment for the scripts to run in
api.SetDefaultScriptApartment()

--[[
	Rogue/Scout bleeds
	------------------
	
	Bleed               : 620313 - 10s (old value 500654?)
	Blind Spot Bleed	: 620297 - 6s 
	Sneak Attack Bleed	: 500726 - 20s
--]]
local bleeds = {620313, 620297, 500726}
local dangerous = {"boss", "elite"}

function RogueScout(...)
	local skip = fdvars.Triggered

	-- Silence target skills
	trySkill("Throat Attack", skip or SilenceThis)

	-- Survival	
	trySkill("Evasion", skip or PlayerInCombat and PlayerHealthPct < .5)

	-- We have a target?
    if GotTarget and IsEnemy and not TargetIsDead then
		local BleedTimer = api.CreateFDTimer("Bleed", 0, 0.5)
		
		trySkill("Premeditation", skip or ((not PlayerInCombat) and IsTargetBoss and PlayerEnergy >= 50))
		trySkill("Informer",      skip or (IsTargetType(dangerous) and not PlayerHasBuff("Informer")))
		
		trySkill("Sneak Attack",  skip or ((not PlayerInCombat) and IsTargetType(dangerous) and PlayerEnergy >= 20 and IsBehind), BleedTimer(21))
		trySkill("Shadow Step",   skip or (IsTargetBoss and PlayerEnergy >= 50 and not IsBehind))
		trySkill("Blind Spot",    skip or (PlayerEnergy >= 20 and IsBehind), BleedTimer(6))
		
		trySkill("Shadowstab",    skip or PlayerEnergy >= 20, BleedTimer(10))
		trySkill("Wound Attack",  skip or (TargetHasBuff(bleeds) and TargetHasBuff("Grievous Wound")))
		trySkill("Low Blow",      skip or TargetHasBuff(bleeds))
		
		trySkill("Shot", not skip)	
    end

    if (TargetIsDead or not GotTarget) and (IsSiege or ShiftHeld) then
        target("select", "next", "enemy")
    end
end


Any comments?

.frafall

Marvengus

Beginner

Posts: 14

Location: Netherlands

Occupation: Mathematician, Scientist

Mood: Smile

  • Send private message

93

Friday, May 16th 2014, 4:04pm

Wow you work fast :) ... and thanks for incorporating many of the given suggestions :)
I think this is a great step forward.

A few notes:

The argument list to the combat function is now empty (function RogueScout(...)) or does ... mean that I can add my own arguments? In my current DIYCE script, I'm passing in the standard healthpot,manapot, and foodslot parameters, but also a mode, that I give values like "sw", "ranged", "melee", "strongboss", which I use to (not) select certain skills. E.g. cannot drink Phirius Pots in Siege Wars, but HP very frequently is very low :o Also, my Mage script with mode=melee uses Discharge and Purge without a target, etc.

I like how the skip variable should improve speed, but it hurts the readability / intuitiveness of the code. On the other hand, I can't think of a better solution yet. So, at least, developers have a choice.

In my current R/S script, I do not use timers, but I use the following trick to manage bleeds and Wound-Attack. Not claiming that this is better than the timers, but somehow the timers make my brain short-circuit :) As you see, I calculate a variable "wantWoundAttack" which is true if the required bleeds are present and wound-attack is out of cool down. This requires access to the CD function. Could I still do this in FD? (Or can you convince me that I should not want this, and the timer solution is superior? :) )

Source code

1
2
3
4
5
6
7
8
9
10
11
12
if enemy then
  wantWoundAttack = (tbuffs[620314] and tbuffs[500654] and CD("Wound Attack") )
  -- if true, and we don't have energy for WA, then do not waste energy on LB or SS, but use filler skill to regen energy
			
  Skill2 = {
    -- many deleted lines
    -- MAIN ROTATION
    { name = "Wound Attack", use = ( (pctEB1 >= .35) and wantWoundAttack )},                                              -- I, CD 0:06 
    { name = "Low Blow", use = ( (pctEB1 >= .25) and (not wantWoundAttack) and tbuffs[500654] ) },               -- causes 10 sec Grievous Wound
    { name = "Shadowstab",	use = ( (pctEB1 >= .20) and (not wantWoundAttack) and (not tbuffs[500654]) ) },   -- causes 10 sec Bleed
    -- many deleted lines
  }
Marvengo R/S/K (90/90/65)
Marvengus M/D/Wd (85/80/68 )
Playing on Isilitir (EU)
Guild Traumfaenger

94

Friday, May 16th 2014, 9:45pm

Well the CD uses additional client commands so makes code slower (very slightly), also you cant be sure if you have a bleed going or not, if there is other rogues in party u might be leaching bleeds from them since your only checking targetbuffs.

.frafall

P.S. The skill variable I used will ofc not work, you have to use the full fdvars.Triggered in each statement as its modified internally in the try statement which will ofc not be reflected in the skill variable...my bad

95

Sunday, May 18th 2014, 9:49am

For the argument list to the combat functions:

When you do a "/fdiyce Attack mele 10 15" all the arguments given on command line will be given to the combat script as arguments, ie in this example the "function MageRogue(mode, slot1, slot2)" will contain the values given above. Command line is made so that u can give any number of arguments, if you are unsure about the number you get you can use the normal Lua variable number of arguments syntax to check like "function MageRogue(mode, ...)" and do a "n = select("#",...)" or use the "arg" table.

.frafall

Marvengus

Beginner

Posts: 14

Location: Netherlands

Occupation: Mathematician, Scientist

Mood: Smile

  • Send private message

96

Friday, May 23rd 2014, 10:42am

Hi,

I have now the following files in my scripts folder:
  • all the scripts that came with the distribution
  • RogueScout-Original.lua which is a copy of the original RogueScout.lua that came with the distribution
  • RogueScout.lua which is my personal RogueScout script

Now, what happens when I install a next version of FD? Will that overwrite my personal RogueScout.lua? That wouldn't be good of course :) Of course, I should backup my own code before installing new/updated add-ons, but some day, someone is going to forget this...

I very much like how /fdiyce Attack automatically selects a script based on the class combo, but therefore I have to put my logic inside RogueScout.lua.

If this issue indeed exists, we could name the example combat scripts in the distribution e.g. PrimarySecondary_example.lua. Alternatively, RegisterPlugin could be adjusted to create explicit mappings like this:

Source code

1
2
3
4
5
local function InitPlugin()
    api.FDLoad("Rogue", "Mage", PLUGIN_PATH..PLUGIN_FOLDER.."RogueMage.lua")
    api.FDLoad("Rogue", "Scout", PLUGIN_PATH..PLUGIN_FOLDER.."RogueScout.lua")
    -- etc
end


Final alternative is that I name my script RogueScout_personal.lua and use /fdiyce RogueScout_personal, but that defeats the purpose of the /fdiyce Attack feature.

Thinking about this more... players with many characters at different levels may want this anyway.. They may have an endgame R/S and also some low level R/S for dailies.. and these will need different scripts... Well, they can resort to /fdiyce scriptname :)
Marvengo R/S/K (90/90/65)
Marvengus M/D/Wd (85/80/68 )
Playing on Isilitir (EU)
Guild Traumfaenger

97

Friday, May 23rd 2014, 11:19am

Ye, I see that naming might be a problem.

  • Modifying the FDLoad is not going to happen I guess, its a generic script loader for plugins. BUT, I might extend/make new to facilitate if nessesary
  • I really want this to work out-of-the-box
  • The current Attack plugin will use PrimarySecondary class names, to avoid this you will need to call script directly


So whats the goal? Is it to make a generic system for the experienced script writer or to have something working directly out of the box.

I have to check out the Curse script installing, I don't know if it removes the whole old directory or just overwrites? I.E. if you have a file or directory in there with a unique name will it be kept or removed?

One trick though, if you make your own FuzzyDIYCE/userscripts directory, it's named alphabetically after scripts so its loaded after the FuzzyDIYCE/scripts directory, copy the RegisterPlugin and .toc (and edit it) into userscripts then you have your own, non-touchable files (at least by me, not sure about Curse upgrader). I will test this and give you feedback.

Hmm I could supply the skeleton userscripts in a .zip file in distribution then ppl who want could install manually (once).

Update:
I've tested the userscripts solution which works nicely BUT I still suspect the directory will be removed on Curse upgrade so please keep a backup, I do by holding it in svn.

Update:
Yes, Curse removes all directories during an upgrade, I'm googling like XXX but can't seem to find any way of keeping it.

.frafall

This post has been edited 3 times, last edit by "frafall" (May 23rd 2014, 12:33pm)


98

Friday, May 23rd 2014, 11:58am

Well from my perspective, even if we insist to provide scripts in FD for all/most/most usable classes, they shouldn't be well optimized... Simply every user should have basic knowledge how FD works. There was similar discussion about provided scripts in old DIYCE and generally many players complained, that someone can be top DPSer on his class and do not know anything about it nor about DIYCE. Provided scripts should be IMO just to show how to write your own script and how this addon works.

Of course we can say that even providing DIYCE is same, as providing class scripts, but there is one small difference, to make something similar you have to know something about lua coding and this is not a game issue. To write optimal script you have to know something about your class and this is a game issue.

From my perspective many players simply do not even bother to acquire knowledge about their class nor DIYCE/FD and it usually goes like this: a:"write me a FD script", b:"but i do not know anything about your class, I play different char", b:"yeah right simply tell you do not want to help me" - or something similar....

This post has been edited 1 times, last edit by "pietroasp" (May 23rd 2014, 12:03pm)


Marvengus

Beginner

Posts: 14

Location: Netherlands

Occupation: Mathematician, Scientist

Mood: Smile

  • Send private message

99

Friday, May 23rd 2014, 12:30pm

Yes, although I love DIYCE, and am now heavily falling in love with FD, I am doubting the distribution of ready-to-use scripts. I believe that writing a combat script helps you to understand your class-combo better: by writing the script, you become a better player. (Not claiming that only script developers can be good players! :) ) But, by just using scripts that you don't understand, well...

It's also a personal choice: I rather build a good character myself, than buying a great character from another player. For me, the creative process is a huge part of the fun of the game.

Personally, I see FD as a development toolkit. My feedback in this thread has always been on making it easy to write the script code, but still requiring the script developer to understand the game very well (refer to the discussion on bleed debuffs). I think frafall is on the same page?

That being said, people learn from examples, and it was great to develop my own R/S script from a simple working example delivered with FD. Maybe we should target for "it works out of the box, but with really simplified scripts". Perhaps the trick with a user directory that, if present, overrides the provided scripts directory would work fine? I'll await frafall's investigation results on the curse installer, before making up my mind about what I think is the best delivery mechanism.
Marvengo R/S/K (90/90/65)
Marvengus M/D/Wd (85/80/68 )
Playing on Isilitir (EU)
Guild Traumfaenger

100

Friday, May 23rd 2014, 12:43pm

I tend to agree with you both, I do not aim to present top dps scripts as I'm totally unable to, also a good script reflects
personal playing style which is totally incomprehensive to others, ex. like my hero/uni renewal code.

So, distribution should contain an ok basis script which can help ppl on their way.

But, the big question is how not to overwrite user written scripts, I like the userscripts idea (and it works) but it seems
it will be overwritten by curse upgrader.

By making sure the userscripts are loaded after the scripts, which we do due to alphabetically loading, any duplicate
function names will be overwritten with the userscripts version.

The only way I can think of to keep the userscripts is to move it down one or more levels, like to Interface/userscripts.
Again, it would have to be created manually and since its outside of the Addons space the plugin machanisms wont
automatically work to load the scripts, I would have to look into writing something specifically to load this.

.frafall