It's late and I don't feel like sleeping quite yet, so I figured I'd type out a few major/serious ideas I've been considering for the scripting system.
1) Functions should be as flexible as possible, accepting a minimum of arguments, while using optional parameters to greatly extend their capabilities. This is to minimize the learning curve, without cutting off functionality.
2) The scripting environment should be safe and never crash the executable. This is probably an ideal that can't really be realized; however it does have two main applications:
- Release builds should be able to recover from any unexpected failures without throwing up any errors. A ship dying would be considered an unexpected failure; the scripting designer not providing required arguments to a function or making gross syntax errors would not, because there's virtually no test the script without running into them. (For larger scripts and systems of scripts this may not be the case)
- Debug builds, on the other hand, should be able to recover but should not err away from telling the user what is wrong, as long as it's obvious that something _is_ wrong. If it's iffy as to whether or not there would be a practical purpose of doing something unusual (Writing an empty string, perhaps) then the system may spit something out in the debug spew, but overall will fail silently and let the user figure it out.
3) The system should attempt to take into account future expansion of the codebase.
4) Although sticking with the fs2_open codebase's way of doing things does provide a lot of compatibility, and would help make scripting a sort of stepping stone to coding, the most important thing should be whether it meets with the above guidelines for ease of use; as it's worthless if the only people who can understand what's going on with it are qualified to actually code features into fs2_open!1. Simplified function return values
Kind of simple, really. Most functions in Lua have at least two main return types, if not 3. All functions return Nil if the arguments are satisfied; of course, they also throw up an error in this case, but within the scripting environment, the only evidence is that the functions returned a nil value. In addition, many functions and variables that are either members of an object, or take an object as a (critical) argument will return nil if the object is invalid. (eg the ship is destroyed)
The problem comes with 2a. If a ship is killed and a modder does something irresponsible like:
ship = mn.Ships['Beta 4']
if ship.HitpointsLeft < 40 then
--Play a warning sound that a mission critical objective is about to die.
then at the point that Beta 4 is killed, Lua will crash because it's trying to use "<" on a nil value. If, on the other hand, the function returned an arbitrary value instead of nil (If we know that Beta 4 doesn't exist, we can reasonably assume that it does not, in fact, have any hitpoints at all) such as 0, then the code would continue to execute and there would be some oddities, but altogether there's a good chance that it would survive.
On the other hand, I've heard it said that it's handy to be able to check for the nil values to see whether a handle is valid or not. Since I've provided the isValid() function on all handles for just such a reason, I'm skeptical of that...but it is still a valid reason nonetheless, and it's a pain in the ass to change _all_ the return values for functions at once. Though if I did that, I would probably create some kind of special function for future use that would let you view the error, and replace the return values with that.2. Greater focus on OOP
It's the difference between
--Set a drawing color
gr.setColor(255, 255, 0)
--Get mouse coords
x = io.getMouseX()
--Set a drawing color
gr.CurrentColor = ba.createColor(255, 255, 0)
--Get mouse coords
x = io.CurrentMouse.X
The latter is more OO-friendly, and uses variable names rather than specialized function names which would be (in theory) easier to remember. But in a sense, it makes less sense to create a new color and set the current color to it, than to simply call a setColor() function. I could do it on a case-by-case basis, but then you have to remember which case applies when. This may be grounds for reconsidering the object creation method, since in theory I could provide color(), vector(), and orientation() functions that would simplify things somewhat. It makes sense to create ships and such from within the mission library - since the objects in Lua are handles to items that are basically contained within the mission library, in a theoretical sense anyway, but basic types...I'm not so sure. Although that would make it a case-by-case basis.
--Set a drawing color3. Error handling system
gr.CurrentColor = color(255, 255, 0)
I've thought it'd be nice to have a better error handling system for Lua, so you could specify a warning/error level and see as many errors as you wanted - from critical, script-go-boom ones, to noncritical autocorrected ones.4. Console
Given the fad of having consoles in-game, with new games like Half-life 2, and even as far back as the original Half-Life, I've thought about expanding teh debug console to possibly run in release mode, or at least switch it over to interface with the lua interpreter rather than the existing system. There's a certain irony because the way the current Lua implementation is done is inspired, heavily, from the debug console code - but it's rarely used. Whether or not it would support branching and conditionals and all that might require more work than I really want to do at this point in time, but I can still see a lot of uses for being able to arbitrarily type code in and execute functions from scripting at will, with arbitrary arguments.
Of course I don't know how widely used the debug console is, and if I did swap it for a Lua version, I wouldn't support the old system. I'd add a debug library for debug functions, but supporting two different systems at the same time seems pointlessly redundant and an opportunity for confusion and bugs.
With a more widely-used debug console, I would also have an excuse to add an LuaConsolePrint() function or something, for noncritical errors or what-have-you, and have an interface for setting the errorlevel.
Anyway, I feel like I'm forgetting something, but numbers one and two I've been see-sawing back and forth on. Mostly I hate to make such a critical change to the language again, but I feel like it makes more sense in the long run.