Function within a function

tarrant
Posts: 49
Joined: Thu Apr 15, 2010 10:36 pm

Function within a function

Post by tarrant »

Is it possible to call a function from within another function?
Code: [show] | [select all] lua
function autoBuyAmmo()
	ammoTypetoBuy = ammoTypeCur
	if ammo ~= "" and ammo <= ammoLowerLimit then
		if typetoBuy == "fire" then
			stbfire() end
		if typetoBuy == "earth" then
			stbearth() end
		if typetoBuy == "lightning" then
			stblightning() end
		if typetoBuy == "water" then
			stbwater() end
		if typetoBuy == "air" then
			stbair() end
	end
end
stbfire(), stbearth() etc are all functions i created elsewhere. but i get this error
attempt to call global 'stbfire' (a nil value)

Yetzederixx
Posts: 186
Joined: Sun Nov 14, 2010 5:57 am

Re: Function within a function

Post by Yetzederixx »

Since I'm going to assume that typetoBuy can only be set to one value this is a better way of organizing things since it'll stop once it finds something to do instead of checking all four everytime
Code: [show] | [select all] lua
if typetoBuy == "fire" then
    stbfire()    
elseif typetoBuy == "earth" then
    stbearth()    
elseif typetoBuy == "lightning" then
    stblightning()    
elseif typetoBuy == "water" then
    stbwater()    
elseif typetoBuy == "air" then
    stbair()    
end
Make sure your functions are enabled and your spelling is correct, remeber they are case sensitive. That's about all I got for ya I'm afraid.

Iocun
Posts: 174
Joined: Wed Dec 02, 2009 1:45 am

Re: Function within a function

Post by Iocun »

Some more notes:

First of all, your line: if ammo ~= "" and ammo <= ammoLowerLimit
That contains a contradiction already, although it -will- execute without error if ammoLowerLimit is a number.

ammo ~= "" checks whether ammo is not equal to an empty string. Only strings can ever be empty strings. So this part only makes sense if ammo is indeed a string.

ammo <= ammoLowerLimit checks whether ammo is smaller or equal to ammoLowerLimit. "smaller or equal" only makes sense when we're dealing with numbers, so this part requres ammo to be a number.

A variable can be a number, it can be a string, but it can never be both at the same time, so the line as a whole doesn't make much sense. (Of course, technically, you could set your variable ammo once to a number, and then another time to a string, so this line -could- have some meaning, but in 99% of all cases this would merely be the result of some really sloppy programming.)

Am I right in assuming that you meant for ammo to be a number and simply wanted to check with the first part whether the variable ammo exists at all? If this is the case then don't compare it with the empty string "", but with the term nil. A variable is equal to nil if it doesn't exist/isn't defined. So you could make this line:

if ammo ~= nil and ammo <= ammoLowerLimit

however, you can shorten this simply to:

if ammo and ammo <=ammoLowerLimit

"if ammo" will evaluate to true if ammo is anything but nil or false. This means that if your variable ammo exists, it will pass the test and your next it will be checked if it's smaller than ammoLowerLimit.

One more thing: I don't know what your functions stbfire(), stbearth() etc. do exactly. But am I right in assuming that they do more or less the same things, simply in respect to a different element? If that is so, one would usually only write a single function, and give the element to it as an argument, like:
stb("fire") or stb("earth")
But to help you more there, I'd need to see what your functions do exactly.

As for why your functions fail to fire and you get an error, I can't say more than Yetzederixx about this, sorry. Check that they actually exist and are enabled. If it still doesn't work, please post those functions.

tarrant
Posts: 49
Joined: Thu Apr 15, 2010 10:36 pm

Re: Function within a function

Post by tarrant »

yeah, all of the above assumptions are right. heh. i've shortened the line as adviced.

This is in an alias. ^tbfire (\d+)?$
Code: [show] | [select all] lua
ammoToBuy = ammoUpperLimit - ammo

function stbfire()
	if matches[2] and ammo <= ammoLowerLimit then
		send("\nstbuy " .. matches[2] .. "\n")
	end
	if matches[2] == nil and ammo <= ammoLowerLimit then
		send("\nstbuy " .. ammoToBuy .. "\n") 
	end
end

stbfire()
Basically, when i call the alias tbfire, i want it to buy the number of ammo calculated (ammoToBuy), but if i specify a number, like tbfire 1000, i'll want it to buy 1000 ammo. And i also call this function in a trigger from my first post. Also, how would you write a single function to handle all the different elements? i tried that first, but i couldn't seem to wrap my head around it so i gave up and wrote different functions for each.

Iocun
Posts: 174
Joined: Wed Dec 02, 2009 1:45 am

Re: Function within a function

Post by Iocun »

tarrant wrote: This is in an alias.
This sums up the reason for your error. Your function stbfire() will only be created when you use the alias tbfire.
So when your function autoBuyAmmo() wants to call stbfire() before you have executed the alias tbfire once, it will produce an error, since the function stbfire() doesn't exist yet.

This is why it's uncommon to define functions in aliases. You usually define functions in script files under the "Scripts" tab. These files/items are run when you connect to your profile, so if you define your functions within those you can be sure they will be defined during runtime. You can (and should) -call- functions from within aliases, of course.

As for combining those functions into a single one:
I'd need to see how exactly they differ, so you should post at least a second one (stbearth or whatever). But my saying that it might be worth to combine them was just a wild guess. It may very well be that your functions work in a way where separate functions are the much better solution.

I'd say the top priority right now is getting it to work. Worrying about "good coding practices", efficiency and style can be postponed a bit, I guess ;)

Yetzederixx
Posts: 186
Joined: Sun Nov 14, 2010 5:57 am

Re: Function within a function

Post by Yetzederixx »

Do you keep track of the number of fire, earth, etc ammo separate?

That code you wrote should work in theory. Remember that in ammoToBuy = ammoUpperLimit - ammo ammuUpperLimit and ammo will need to be set to something or you're going to get errors, most likely you'll enter the alias and nothing will happen as the script crashes.

tarrant
Posts: 49
Joined: Thu Apr 15, 2010 10:36 pm

Re: Function within a function

Post by tarrant »

Ah, can only have 1 type of ammo at once, so don't need to keep track of anything.

Moved alias into a script like so:
Code: [show] | [select all] lua
function stbfire()
	ammoToBuy = ammoUpperLimit - ammo
	if manualammoToBuy == nil and ammo <= ammoLowerLimit then
		echo("\nstbuyfire " .. ammoToBuy .. "\n") 
	end
	if manualammoToBuy and ammo <= ammoLowerLimit then
		echo("\nstbuyfire " .. matches[2] .. "\n")
	end
end
the alias: ^tbfire (\d+)?$
Code: [show] | [select all] lua
manualammoToBuy = tonumber(matches[2])
stbfire()
Another function for another ammo type would be:
Code: [show] | [select all] lua
function stbice()
	ammoToBuy = ammoUpperLimit - ammo
	if manualammoToBuy == nil and ammo <= ammoLowerLimit then
		echo("\nstbuyice " .. ammoToBuy .. "\n") 
	end
	if manualammoToBuy and ammo <= ammoLowerLimit then
		echo("\nstbuyice " .. matches[2] .. "\n")
	end
end
basically everything remains the same except for the function name itself and the stbuy<element>.

Yetzederixx
Posts: 186
Joined: Sun Nov 14, 2010 5:57 am

Re: Function within a function

Post by Yetzederixx »

First make your script
Code: [show] | [select all] lua
function ammoBuy(type, num)
   send("\n" .. type .. " " .. num .. " \n")
end
Now you need alias's, note you could do this manually with a single alias, which I'll discuss at the end.

Alias for fire ammo, mod for rest as necessary
Pattern: ^tbfire\s?(\d*)$
Code: [show] | [select all] lua
local numToBuy = (matches[2] ~= "") and matches[2] or ammoUpperLimit - ammo

-- change stbuyfire in the other alias'
ammoBuy("stbuyfire", numToBuy)
Single Alias for everything, uses the same script
Useage: ammobuy type num
Pattern: ^ammobuy (\w+)\s?(\d*)$
Code: [show] | [select all] lua
local numToBuy = (matches[3] ~= "") and matches[3] or ammoUpperLimit - ammo
ammoBuy("stbuy" .. matches[2], numToBuy)

Yetzederixx
Posts: 186
Joined: Sun Nov 14, 2010 5:57 am

Re: Function within a function

Post by Yetzederixx »

I could make ammobuy a better alias if I knew how to test to make sure something is a number, but I can't get lua_isnumber to work and have other stuff to do this morning, if someone figures it out let me know.

User avatar
Heiko
Site Admin
Posts: 1548
Joined: Wed Mar 11, 2009 6:26 pm

Re: Function within a function

Post by Heiko »

The function tonumber() returns the converted number or nil if a conversion fails.

more information on Lua type checking: http://lua-users.org/wiki/LuaTypeChecking

Post Reply