Global functions?

Talk about creating Grimrock 1 levels and mods here. Warning: forum contains spoilers!
Post Reply
daverd
Posts: 2
Joined: Mon Jun 13, 2016 11:00 pm

Global functions?

Post by daverd »

Googling for this is turning up nothing so it seems impossible, but I'll ask anyway because this is such basic functionality that I refuse to believe that.

Is it possible to define a global function in one of the lua files in my mod? I just want to create a reusable code snippet so I don't have a lot of redundant code in my scripts.

I don't want to put it in a script entity in the world because I don't want to have to remember physically where it's located. I just want to be able to have something like the following:

Code: Select all

foo = function() print("it works!") end
and then be able to call foo() from my entity scripts.

The above doesn't work, obviously.
User avatar
Isaac
Posts: 3189
Joined: Fri Mar 02, 2012 10:02 pm

Re: Global functions?

Post by Isaac »

AFAIK, LoG [1&2] scripting does not allow for globals in user scripts; (I'd love to be shown otherwise ;) ).

About the closest you can do (that I know of), is make a library script and [if calling it by object/component/function is really not an option for you... define the library as a variable in every script you plan to use it in; which is rather wasteful I think... but it works.

*Quick [not well tested] example:
SpoilerShow
library script_entity ( lib.script )

Code: Select all

lib = {
		["qprint"] = function(data) print(string.upper(data)) end,
		["b"] = function() print("@", "library function 2") end,
		["c"] = function() print("@", "library function 3") end,
		["d"] = function() print("@", "library function 4") end,
		["e"] = function() print("@", "library function 5") end,
		["g"] = function() print("@", "library function 6") end,
		["h"] = function() print("@", "library function 7") end,
		["i"] = function() print("@", "library function 8") end,
		["j"] = function() print("@", "library function 9") end,
		["k"] = function() print("@", "library function 10") end,
}
use of lib.script

Code: Select all

lib = lib.script.lib
	
function torchTrigger(caller)
		lib.qprint("it works!")
end
	
torchTrigger()
minmay
Posts: 2790
Joined: Mon Sep 23, 2013 2:24 am

Re: Global functions?

Post by minmay »

Grimrock does not allow you to access or modify _G. Modifying the global namespace is impossible. but you don't need to know where a script entity is located to use functions in it. You can just type

Code: Select all

script_entity_1.function()
in Grimrock 1, or

Code: Select all

script_entity_1.script.function()
in Grimrock 2.
(replacing "script_entity_1" with the id of the script entity)

You can also freely set fields in Grimrock 2's global tables like Config and GameMode, so

Code: Select all

Config.foo = function() print("it works!") end
works, and then you can call Config.foo(). But the global tables are not serialized, so make sure that anything you add to them is added by your init files and not from a script entity. Of course, using the global tables for this purpose is even worse practice than defining global functions.
Last edited by minmay on Tue Jun 14, 2016 4:38 am, edited 1 time in total.
Grimrock 1 dungeon
Grimrock 2 resources
I no longer answer scripting questions in private messages. Please ask in a forum topic or this Discord server.
User avatar
Isaac
Posts: 3189
Joined: Fri Mar 02, 2012 10:02 pm

Re: Global functions?

Post by Isaac »

minmay wrote:You can also freely set fields in the global tables like Config and GameMode, so

Code: Select all

Config.foo = function() print("it works!") end
works, and then you can call Config.foo(). But the global tables are not serialized, so make sure that anything you add to them is added by your init files and not from a script entity. Of course, using the global tables for this purpose is even worse practice than defining global functions.
That's pretty cool. 8-)

So this seems a place to put a few choice utility functions; (like a pronoun utility for use in all hudPrinted dialog). Is there a reason not to fill that table with a large number of (often used) functions?

**Funny issue though... It would seem that functions in the Config table are [above?] some of the 'global' functions; like hudPrint() [which is nil when called].

***This might prove useful for defining items using dynamic property values. IE. using a custom function [variable] to return the value for an item property during the definition of it; where [afaik] one usually cannot. But by using Config this way, it can work in a definition:
uiName = Config.uiName(), ~uiName gets assigned the return value; instead of the function id (were you to try to use one).
minmay
Posts: 2790
Joined: Mon Sep 23, 2013 2:24 am

Re: Global functions?

Post by minmay »

Isaac wrote:
minmay wrote:You can also freely set fields in the global tables like Config and GameMode, so

Code: Select all

Config.foo = function() print("it works!") end
works, and then you can call Config.foo(). But the global tables are not serialized, so make sure that anything you add to them is added by your init files and not from a script entity. Of course, using the global tables for this purpose is even worse practice than defining global functions.
That's pretty cool. 8-)

So this seems a place to put a few choice utility functions; (like a pronoun utility for use in all hudPrinted dialog). Is there a reason not to fill that table with a large number of (often used) functions?
The potential problems with it are
1. it's bad programming practice
2. not serialized in savegames, so you must be careful to define them again when the game is reloaded
3. the tables are persistent until the game is exited. You can save and load, you can even go back to the main menu and into another dungeon, and the table will keep all your extra stuff in it. So if you change one of the default keys in a table (like changing GameMode.advanceTime() to do something specific to your dungeon) you could break other dungeons if the player switches away from your dungeon without exiting the game.
Isaac wrote:**Funny issue though... It would seem that functions in the Config table are [above?] some of the 'global' functions; like hudPrint() [which is nil when called].
It's not clear what you are saying here. Do you mean that Config is present in the init file namespace and hudPrint() isn't? That is correct, but you shouldn't think of it as "above".
Isaac wrote:***This might prove useful for defining items using dynamic property values. IE. using a custom function [variable] to return the value for an item property during the definition of it; where [afaik] one usually cannot. But by using Config this way, it can work in a definition:
uiName = Config.uiName(), ~uiName gets assigned the return value; instead of the function id (were you to try to use one).
You don't need to use this hack for that. Init files have a shared namespace that you can freely modify. There is no advantage to what you describe over doing this in an init file:

Code: Select all

function getUiName()
-- whatever
end

Code: Select all

uiName = getUiName(),
Grimrock 1 dungeon
Grimrock 2 resources
I no longer answer scripting questions in private messages. Please ask in a forum topic or this Discord server.
User avatar
Isaac
Posts: 3189
Joined: Fri Mar 02, 2012 10:02 pm

Re: Global functions?

Post by Isaac »

minmay wrote:Do you mean that Config is present in the init file namespace and hudPrint() isn't? That is correct, but you shouldn't think of it as "above".
In this case I was thinking that hudPrint was not a built in function; and/or not "visible" to the function placed in the Config table.
minmay wrote:You don't need to use this hack for that. Init files have a shared namespace that you can freely modify. There is no advantage to what you describe over doing this in an init file:

Code: Select all

function getUiName()
-- whatever
end

Code: Select all

uiName = getUiName(),
uiName wasn't specifically meant (but that's what I tested)... I remember once trying to [re]define all weapon items with conditional values to some of their properties, and not being able to; as using =function() to return a value would assign the id of the function instead of the intended return value ~~except for some built in functions.

I'm pretty sure that that was with LoG1. I know that in LoG2, many [most?] property values can be changed with existing setter functions; but not all of them IRRC.
minmay
Posts: 2790
Joined: Mon Sep 23, 2013 2:24 am

Re: Global functions?

Post by minmay »

Isaac wrote:I remember once trying to [re]define all weapon items with conditional values to some of their properties, and not being able to; as using =function() to return a value would assign the id of the function instead of the intended return value ~~except for some built in functions.
The only reason you weren't able to is that you misunderstand the syntax of Lua. This assignment:

Code: Select all

asdf = function() return 1 end,
assigns the memory address of the function itself to asdf. It does not call the function. If you want to assign the return value of the function, you need to do this:

Code: Select all

asdf = (function() return 1 end)()
Grimrock 1 dungeon
Grimrock 2 resources
I no longer answer scripting questions in private messages. Please ask in a forum topic or this Discord server.
User avatar
Isaac
Posts: 3189
Joined: Fri Mar 02, 2012 10:02 pm

Re: Global functions?

Post by Isaac »

minmay wrote:
Isaac wrote:I remember once trying to [re]define all weapon items with conditional values to some of their properties, and not being able to; as using =function() to return a value would assign the id of the function instead of the intended return value ~~except for some built in functions.
The only reason you weren't able to is that you misunderstand the syntax of Lua. This assignment:

Code: Select all

asdf = function() return 1 end,
assigns the memory address of the function itself to asdf. It does not call the function. If you want to assign the return value of the function, you need to do this:

Code: Select all

asdf = (function() return 1 end)()
Cool (and useful!)

*I'm sure I have read that about parentheses somewhere before (and forgot); but I certainly didn't know that then...
It works in the test item I just tried. Thanks for explaining it.
Post Reply