Scripting thoughts
So last night I had a bit of a look at how a javascript thing might work for the game engine. It tempered some of my enthusiasm but I also need to adjust my expectations. Security is a pain, and JavaScript itself turns out a bit ugly, although i can probably do something about that. Strangely the script engine doesn't let you implement new functions for the script? That's probably the weirdest thing about it; you can add objects but not top-level functions. The fact the javascript engine keeps variables around between invocations also makes things a bit more interesting, and not all in a good way.
I had a look at how I might implement a simple existing item: absinthe (it's not a drink i'm a fan of btw so the choice is arbitrary).
The existing item is defined over multiple separate files: the item descriptor and one for each script - 3 total files for absinthe.
Object
Obvious is to implement it as a full object with methods. The object name would match the script name, and all objects could be loaded at once into the script engine.
var absinthe = { onUse: function(thing) { thing.emote('wails: oh, my head!'); if (thing.getInte() > 10) thing.incrInte(-1); thing.remove('absinthe'); }, onDrop: function(thing) { thing.order("get absinthe"); thing.remove('absinthe'); } };
Drawback here is the scaffolding required. It's almost to the point that you may as well just use Java directly. I will probably do that too.
If the script engine were a proper execution container then things could be very interesting - the state could live inside it too, but I don't want to go down that path.
Script fragments
This is similar to the existing system, separate standalone scripts define each action. They are referenced via names in the objects.
absinthe_use:
thing.emote('wails: oh, my head!'); if (thing.getInte() > 10) thing.incrInte(-1); thing.remove('absinthe');
absinthe_drop:
thing.order("get absinthe"); thing.remove('absinthe');
It has similar drawbacks and advantages to the existing system - lots of little files to manage, separated logic, but also isolation and simplicity. It does allow for pre-compiled scripts though.
Script of functions
Here the script just defines top-level functions. It makes it a bit easier for the user to develop as they don't need to include all the scaffolding.
var onUse =function(thing) { thing.emote('wails: oh, my head!'); if (thing.getInte() > 10) thing.incrInte(-1); thing.remove('absinthe'); }; var onDrop = function(thing) { thing.order("get absinthe"); thing.remove('absinthe'); };
This approach has the drawback that the script must be parsed and executed separately, and must be parsed and executed every time.
Scripted actions
A compromise between the first two is to have a single script but also pass the script action to the script and let it decide what to do. e.g. use a switch statement. i.e. lets one put all behaviour in one file, but 'simplifies' the scaffolding.
switch (action) { case 'use': thing.emote('wails: oh, my head!'); if (thing.getInte() > 10) thing.incrInte(-1); thing.remove('absinthe'); break; case 'drop': thing.order("get absinthe"); thing.remove('absinthe'); break; }
Problem is that it doesn't really simplify the scaffolding, although it allows for precompiled scripts.
Thoughts
One problem is i'm thinking about the scripting system from the wrong viewpoint - more of a library of potentially compiled functions rather than thinking of it as scripts. I need to shift my thinking because they really should just be scripts, and not self-contained applications. If I support Java classes to define behaviour as well then efficiency of the scripting language itself isn't of a primary concern.
The fact that Java can't directly define functions sucks a bit - for example the "thing." prefix to every call. But I guess i can hide that with some simple global functions I inject on my own which hide the details for the main target object.
At this point i'm leaning toward the second option - i.e. much the same as the existing system. But I will look at some techniques for simplifying their configuration such as convention-based lookup rather than needing a pile of settings for each object. A convention-based mechanism would let me support multiple mechanisms without needing to change the file formats.
I might need to let this stew a bit for the moment, and whilst that is coalescing have a look at the multi-map/layer stuff which will be more fun to hack on too.