Learning Lua; Need a Paradigm

So I’ve started learning Lua with the intention of replacing ASL with a language other people might be able to use. Now that Lua is a standard package with Free Pascal it’s a natural choice for a scripting language, and it’s been no problem to set up and use… by itself, at least. My big problem is trying to figure out how to incorporate it into GearHead.

I can see two obvious ways to do this. First, I could do things the way I already do them and attach individual Lua scripts to every gear that needs them. When the time comes to trigger a script then the scripts for that gear will be sent to the stack and the proper function invoked. One problem I can see with this is that function declarations from previous gears might be hanging around in the Lua environment; suppose I want to process a “START” trigger, and the current gear doesn’t have a “START” script but the gear which came before it did. Wouldn’t this execute the previous gear’s START function a second time, since it hasn’t been overwritten?

An alternate way to do things would be to make each script-holding gear a Lua object and access their scripts as methods. In this case, how do I deal with having parallel representations of each gear? When a gear is created/disposed of I’d have to create/dispose the parallel Lua object, which seems like a pain in the arse… though, I guess, no more a pain in the arse than creating/disposing of attached attributes.

Whichever way the scripting is done, there’s one more very big problem which I need to address: How to merge scripts together. GH’s plot creator takes multiple component scripts and combines them into a single script. The general rule is that for any given trigger the newly added effect happens first, then the previous effects are called. ASL was designed with this in mind but I have no idea how to do it with a language such as Lua.

Any ideas?

5 Responses to “Learning Lua; Need a Paradigm”

  1. getter77 Says:

    Likely not the kind of suggestion you are looking for, as that would require knowing things, but in the general sense of “How to make use of Lua when doing things”—perhaps ToME 4 would be a good case study as pretty well the entire game is constructed in it? I’d like to think clues would be there for the imparting…

    http://tome.te4.org/

  2. Joseph Hewitt Says:

    ToME is pretty much entirely written in Lua, which I think makes it a poor model for what I want to do here.

  3. Anne Says:

    I haven’t used Lua at all, so this is not necessarily relevant advice. But my experience with python has been that it’s so much nicer to write things in python than C that I’d implement the game in it, with any compiled code set up as objects the python code calls into. Given that you already have a functioning game in Pascal and are just looking to add some scripting, though, this may not be the way to go.

    Which functions from the core will the Lua code need to be able to access? Basic things like creating gears and modifying them, I suppose, and maybe some of the higher-level stuff (finding the total weight of an inventory)? It seems like you will probably want to make at least some of the functions in GearHead callable from Lua.

    For functions associated with gears, I’d be inclined to view the gears as objects, in the sense of data plus some functions that act on that data. So each gear (or really, each kind of gear) would have a table of Lua functions that know how to manipulate it. Since all Lua code that gets run lives inside functions, most variables and functions that get created live inside the namespace of that function (Lua has lexical scoping). So only if programmers go out of their way to manipulate global objects will they be able to shoot themselves (each other?) in the foot. So you might call a trigger function as, say, Gear:drop(location). This also gives a way for someone writing Lua to specify where the function should live – I mean, if you want to add a script that specifies how Gears should be dropped, you just define the function Gear:drop in some file or other.

    As for combining functions, if I understand your question, it’s a little like the problem of “callbacks” in GUI programming – I’ve created a dialog box, and I want to have my function called when the mouse pointer leaves the window. The usual solution seems to be to have a list of places you can attach functions – window exit, mouse click, et cetera – which each store a list of callbacks that get called in order. Sometimes the callbacks can return True or False to indicate whether to keep going down the list, or whether they can be removed from the list after this time. Plus one generally has functions to add callbacks to the list or remove them. If the callbacks need to know about each other (“is this the last callback? if so I’ll print a newline, otherwise not”), things become more complicated…

  4. Joseph Hewitt Says:

    “it’s so much nicer to write things in python than C that I’d implement the game in it”
    Yes, that’s becoming quickly apparent. Most of the examples I can find have a minimal framework in C or Pascal and everything else coded in Lua. Once I get the basic scripting working I can start exporting more and more functionality to the Lua part; kind of like the “Roguelike of Theseus”.

    Your idea to treat gears as objects is really good. That would open up a whole lot of possibilities.

    Thanks.

  5. Anne Says:

    I think one reason applications tend to be written mostly on the scripting side is, apart from the coding convenience issues, that otherwise you end up with two “worlds”: things with representations in the compiled language, and things with representations in the scripting language. Any communication between the two worlds is code to be written, so if there are large parts in each world, there’s lots of boring adapter code. If everything lives in the scripting world, with just a few speed-critical operations that go “under the hood” and are written in the compiled language, then at least you’re not writing much adapter code. And what adapter code there is is fairly simple, since it’s just an interface to a single “thing”, e.g., the map and its graphical representation. I’ve seen a few applications that go the other way, usually because they’re using Tcl, that is, where everything lives in the compiled world and there’s just sort of a command interface. It quickly becomes frustrating to do anything in the scripting language because you can’t really manipulate objects except in the very limited ways the designers thought you might want to. (The example I’m thinking of is the X-ray spectroscopy tool “xspec”, FWIW.)

    Gears as objects is actually a design I used while working on a game that would use GH graphics; it was implemented in pure python, though I never got the graphics up to a comfortable speed, so that would have probably been moved to compiled code. But I eventually set it aside in hopes of sooner or later writing my thesis.

    The nice thing about gears-as-objects was that I could make good use of inheritance – a few methods worked for all gears, others were specific to gears that represented physical objects, a few more were specific to gears you could carry. An inheritance hierarchy made good sense for sharing code appropriately. I suspect your existing Pascal code can be viewed in this light, in fact, and if so, it makes sense to export it as such to the Lua world.

    My own attempt overused metaprogramming – I tried to set up a system where all objects automatically knew (for example) how to save themselves to disk and load themselves back in. This turned out to be really clunky and made every new object require a whole lot of arcane boilerplate to function.

Leave a Reply