|
06-10-2012, 08:38 AM
|
The Undefeated
|
|
Join Date: Jun 2012
Posts: 7
|
|
Read out the EffectList
Hi, I'm new to this Forum and LUA programming, so sorry if I've done any stupid mistake
Ok, I'm pretty f***** up and I have no more ideas.
I took Jackdaws LowWarn and tried to modify it, so it will show when you get the Effects that Saruman applies to you in Orthanc.
(Because I didn't knew how the Effects are named I took charge for testing)
So this is what I did (used Disease as example, to make it less confusing):
EffectList = Turbine.Gameplay.EffectList
AddCallback(EffectList,"EffectAdded", function(sender, args) DiseaseWindow:SetOpacity(Disease()) end)
AddCallback(EffectList,"EffectRemoved", function(sender, args) DiseaseWindow:SetOpacity(Disease()) end)
--These are the Callbacks, I think they aren't the problem, it's the Disease function
function Disease()
if (EffectList:Contains(charge)) then -- This is line 30
Disease = 0.5
else
Disease = 0
end
end
The plugin starts without problems, but when I use charge the game prints an errormessage:
...the Rings Online\Plugins\Kunter\EffectWarn\Main.lua:30: Invaild member function call.
What have I done wrong?
Greeting
Kunter
Last edited by Kunter : 06-10-2012 at 08:40 AM.
|
06-10-2012, 09:13 AM
|
|
The Undying
|
|
Join Date: Feb 2009
Location: Lancaster, England
Posts: 249
|
|
The contains function interests me - I didn't know it existed!
__________________
************************************************** ************************************************** **
"Our ideals may never be realised, But they indicate what we are trying to do." Dick Tahta
|
06-10-2012, 09:49 AM
|
The Undefeated
|
|
Join Date: Jun 2012
Posts: 7
|
|
Oh the Master himself
Found it in the Isengard-Documentation...
I thought this would bei a good command.
|
06-10-2012, 10:02 AM
|
The Undying
|
|
Join Date: Sep 2010
Posts: 51
|
|
I'm not sure how familiar with object oriented programming you are, so I'll start my explanation from there.
In object oriented programming, there's two major things - Classes and Instances. Classes are templates or instructions on how to build something. So a Window class might contain all of the information to display some sort of window. Instances are actual individual objects of a particular class - so there might be multiple Window instances, and each represents a different window on your display.
Turbine.Gameplay.EffectList is a class. So you've just tried to ask the template if it has the charge effect - and it has no idea which actor's EffectList you want, because the class itself isn't associated with any particular actor.
What you probably want is the LocalPlayer's EffectList, so you should probably say:
EffectList = Turbine.Gameplay.LocalPlayer:GetInstance():GetEffe cts();
The second thing is (and it probably hasn't caused you problems, but I suspect it will) "charge" never gets defined. So your EffectList:Contains(charge) is asking if the EffectList contains a nil value (undefined variables are always nil) - which will always be false. The list only contains actual Effects.
You've got two options - one, scan the EffectList (see :GetCount() and :Get(index)), or two use args.Effect and args.Index to keep track of which effect is being added or removed. I'd do the first one - it's clunkier to handle, and once you've got that working, think about using the args.Effect and args.Index arguments.
|
06-10-2012, 11:03 AM
|
|
The Undying
|
|
Join Date: Oct 2010
Posts: 346
|
|
Quote:
Originally Posted by Kunter
function Disease()
if (EffectList:Contains(charge)) then -- This is line 30
Disease = 0.5
else
Disease = 0
end
end
|
In addition to what the authors above noted, you have a number of problems in the Disease function. First, you are using the same name for a function and a variable within that function (I suspect you have a VB background and are trying to assign the return value). Unfortunately in Lua what will happen with your code is the first time the function gets called, it gets reassigned to a numeric value and will become invalid as a function the next time you try to call it.
Consider the code:
Code:
import "Turbine"
function Disease()
Disease = 0.5
end
Turbine.Shell.WriteLine("Type before call:"..type(Disease));
local tmpVal=Disease();
Turbine.Shell.WriteLine("tmpVal:"..tostring(tmpVal));
Turbine.Shell.WriteLine("Type after call:"..type(Disease));
The above code demonstrates the two problems with your function, first the output:
Code:
Type before call:function
tmpVal:nil
Type after call:number
shows that "Disease" is indeed changed from a function to a number after it is called. Second, the value returned by Disease() is "nil". This is because you must explicitly use the "return" statement to return a value.
The below code demonstrates using a local value for the return value, initializing it to the default and explicitly returning it. Note that you should always create variables with the narrowest possible scope, so the return value is scoped as local to the function to avoid conflict with any other variable with the same name.
Code:
-- assumes that "EffectList" is properly assigned an instance of an EffectList and that "charge" is properly defined
function Disease()
local retVal=0;
if (EffectList:Contains(charge)) then -- This is line 30
retVal = 0.5;
end
return retVal;
end
|
06-10-2012, 11:27 AM
|
The Undefeated
|
|
Join Date: Jun 2012
Posts: 7
|
|
Quote:
Originally Posted by Garan
In addition to what the authors above noted, you have a number of problems in the Disease function. First, you are using the same name for a function and a variable within that function (I suspect you have a VB background and are trying to assign the return value). Unfortunately in Lua what will happen with your code is the first time the function gets called, it gets reassigned to a numeric value and will become invalid as a function the next time you try to call it.
Consider the code:
Code:
import "Turbine"
function Disease()
Disease = 0.5
end
Turbine.Shell.WriteLine("Type before call:"..type(Disease));
local tmpVal=Disease();
Turbine.Shell.WriteLine("tmpVal:"..tostring(tmpVal));
Turbine.Shell.WriteLine("Type after call:"..type(Disease));
The above code demonstrates the two problems with your function, first the output:
Code:
Type before call:function
tmpVal:nil
Type after call:number
shows that "Disease" is indeed changed from a function to a number after it is called. Second, the value returned by Disease() is "nil". This is because you must explicitly use the "return" statement to return a value.
The below code demonstrates using a local value for the return value, initializing it to the default and explicitly returning it. Note that you should always create variables with the narrowest possible scope, so the return value is scoped as local to the function to avoid conflict with any other variable with the same name.
Code:
-- assumes that "EffectList" is properly assigned an instance of an EffectList and that "charge" is properly defined
function Disease()
local retVal=0;
if (EffectList:Contains(charge)) then -- This is line 30
retVal = 0.5;
end
return retVal;
end
|
Ok, I get the return thing, but how to define "charge"?
I mean it's the name of the buff the plugin should look for, whats wrong about this?
Ok, just a try concerning moebius post:
What about this line:
if (EffectList:Get(EffectList:GetCount()) == "charge") then
The Get function needs the Index of the effect, cause it's the last added effect I use Get count (schould return a number/index of last added effect).
EffectList:Get returns an effect, but how can I get the name of the effect, so I can compare it to the strin "charge"?
if (EffectList:Get(EffectList:GetCount()):GetName() == "charge") then
Last edited by Kunter : 06-10-2012 at 11:45 AM.
|
06-10-2012, 12:30 PM
|
The Undying
|
|
Join Date: Sep 2010
Posts: 51
|
|
for loops. for loops are your friend.
You'll want something like...
for i = 1, EffectList:GetCount(), 1 do
if EffectList:Get(i):GetName() == "Charge" then
dostuff();
break;
end
end
Actually, what you might want to start with is:
for i = 1, EffectList:GetCount(), 1 do
Turbine.Shell.WriteLine(EffectList:Get(i):GetName( ));
end
...so you can check the names of all of the effects. It probably is called "Charge", but you never know.
And remember that string comparisons with == are case sensitive, so you'll want to get the case right.
Edit: Lua Reference manual is also your friend. Feel free to keep asking questions, but there's a good chance I'll be looking up the answer in the reference manual.
Last edited by moebius92 : 06-10-2012 at 12:48 PM.
|
06-10-2012, 12:56 PM
|
The Undefeated
|
|
Join Date: Jun 2012
Posts: 7
|
|
Code:
function Disease()
var = 0;
for i = 1, EffectList:GetCount(), 1 do
Turbine.Shell.WriteLine(EffectList:Get(i):GetName( ));
if (EffectList:Get(i):GetName( ) == "Charge") then
var = 0.5;
end
end
return var;
end
YEEEAAAAHHHH, it works^^
Many Thanks!
Now I have to find the debuffs names...
Last edited by Kunter : 06-10-2012 at 01:03 PM.
|
06-10-2012, 02:18 PM
|
|
The Undying
|
|
Join Date: Oct 2010
Posts: 346
|
|
Quote:
Originally Posted by Kunter
Code:
function Disease()
var = 0;
for i = 1, EffectList:GetCount(), 1 do
Turbine.Shell.WriteLine(EffectList:Get(i):GetName( ));
if (EffectList:Get(i):GetName( ) == "Charge") then
var = 0.5;
end
end
return var;
end
YEEEAAAAHHHH, it works^^
Many Thanks!
Now I have to find the debuffs names...
|
Two things, first, you are still failing to assign a local scope to your variables and while that won't necessarily cause an issue here, it WILL eventually trip you up somewhere. Especially with commonly used variables like "i". Consider a loop using "i" which calls a function which internally also has a loop using a variable "i" - both "i" variables are one and the same (same scope) so the function will destroy the value in the outer loop causing lots and lots of havoc. By declaring them as local you will get different instances of the variable and eliminate any potential conflict.
Second is more a matter of efficiency. As moebius showed in his example, when using a loop and looking for a specific condition, it is beneficial to use a break statement to exit the loop once the condition has been met if such a condition should only be true for one iteration or if only the first occurence is relevant (if more than one match can occur and all matches must be processed then a break statement is not useful). This can significantly increase the efficiency of your code, since on average you can cut the iterations in half or if you can reasonably expect your match to be at the end of the iteration, perform the iteration in reverse and get even better efficiency.
|
06-10-2012, 02:56 PM
|
The Undying
|
|
Join Date: Sep 2010
Posts: 51
|
|
Actually, the loop variable of a for loop always has a scope that is local to the for loop itself. So I think Kunter's okay in this case.
As for finding debuff names - look up Turbine.Gameplay.Effect - specifically GetCategory. And then look up Turbine.Gameplay.EffectCategory. You ought to be able to cobble something together to look for specific types of debuffs.
Edit: Mind you, var should be local. Heck, I'd probably skip naming it, and just return 0.5 from inside the if statement, and then have a second return at the end of the function.
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -5. The time now is 02:44 AM.
|
|