Way back in December, we had just implemented a bunch of the character logic for going through the world and doing things using our Finite State Machine model and utility functions. What we discovered was that writing the code for the FSMs themselves was, to put it frankly, a huge pain. Additionally, non-C++ programming members of the development team could not easily add new items and new behaviours to items (mines, buildings, trees, and the like.) Micah J Best, at the end of December, decided that we should use scripting to wrap some of the complexity and hide it from the end user, while simultaneously letting our development team create new objects and FSMs without requiring a programmer to go thrashing about in the codebase. I said, “Fine. Show me a proof of concept and then we’ll talk.”

Fundamentally, Gaslamp’s programming team operates based on spite. If somebody says “oh, well, we’ll never get that done in time”, or “oh, well, it’s too impractical”, somebody usually says “no, it well isn’t” and will jump to the bait. (I did this recently with a pipe system test.) Saying “Well, show me a proof of concept and we’ll talk” is equivalent to putting a red cape in front of a bull.

Over the holidays, Micah found himself stuck in Quebec. With nothing but inlaws, a language barrier, two laptops (one of which was destroyed by a cat), a turkey stuffed with poutine, and spite, he put together the first build of what is our new scripting system. It does, indeed, encapsulate all our programming decisions and is fairly powerful and flexible. We took apart all the character code we wrote in December, ported it to the new scripting system, and have now started using it to implement new things in game. It’s very powerful and, after some back-and-forth, I’m quite happy with how it’s turned out. We’re still fixing bugs and fine tuning how it all comes together, but let’s see how it all works…Our system is built on top of Lua, the happy interpreted language you may know from World of Warcraft and, if you’re a sysadmin, nmap. Each object type has a .go file, containing a name, a list of its variables, and a number of messages that it receives. Objects in Clockwork Empires (more properly, objects in our engine) communicate with each other in a given game frame by message-passing; this is the same framework that we use to communicate with the renderer, and between the renderer and the gameplay and networking layer. One advantage of this approach is that it’s very, very threadsafe; no object can get out of its sandbox except by messages, and we control the messages. This makes it possible to do some… interesting optimizations. For those of you familiar with early game creation toolkits, this is the same programming idea as the languages exposed in Tim Sweeney’s ZZT game, and later on in Greg Jansen’s Megazeux.

Whenever an object gets a message type that it knows how to handle, it runs the corresponding Lua script. For instance, here’s the chunk of code for a mineshaft that, if you click on its interactive menu object and select “Mine”, registers a new mining job:

receive InteractiveMessage( string messagereceived ) << print ("Message Received: " .. messagereceived ); if messagereceived == "Mine" then send( "gameCitizenRequestBlackboard", "gameObjectNewJobByNameMessage", SELF, "Mine" ) end >>

The mineshaft gets a message from the renderer saying “Hey, you just were selected and told to perform mining!” It then sends a message to the jobs request blackboard (the object responsible for managing all player jobs in the game) telling it to create a new job, “Mine”, from the jobs list with itself as the originating object. Jobs are still stored in XML, as are item definitions, character information, text strings, and the like.

Each message has a type. Message types can either be defined in C++, or on the fly in Lua scripts.

FSMs, for characters and Other Entities, are separate Lua files. Each FSM runs on a character, and cycles through a list of states. At each stage of execution, the FSM can remain in the same state or advance to a different state depending on where it is in its execution. For instance, here is the “pick up an item” FSM:

pickup_item = { ["start"] = function(state, tag) print("pickup_item") -- FIXME: if I have a currently picked up item, I should drop it. if state.curPickedUpItem ~= nullHandle then FSM:abort( "Hands full." ) return; end -- As far as we are concerned on the game side, the transition is instantaneous. We remove the item from the grid, -- we put it in the character's inventory, and we let this elapse some number of ticks. resultROH = query( tag.target, "ROHQueryRequest" ) name = query( tag.target, "HandModelQueryRequest" ) state.curPickedUpItem = tag.target -- de-register from spatial dictionary send("gameSpatialDictionary", "gridRemoveObject", tag.target ); -- Start the animation send( "rendOdinCharacterClassHandler", "odinRendererCharacterPickupItemMessage", state.renderHandle, resultROH[ 1 ], name[ 1 ] ) state.animationTickCount = 0 return "animating" end, ["animating"] = function(state, tag) state.animationTickCount = state.animationTickCount + 1 if state.animationTickCount == state:getNumPickupTicks() then return "final" else return end end, ["final"] = function(state, tag) print("Done") return end, ["abort"] = function(state, tag) print("Aborting") return end }

The query() function actually sends a message to other objects involved in code execution (in this case, the object being picked up), and halts program execution until it returns. We support this, internally, using Lua’s coroutine functionality.

There will also be a third type of Lua file, for “special events”, which will be responsible for governing Interesting Discoveries.

Unlike in Dredmor, where scripting using our XML system causes hideous silent failures, both our XML and our Lua code will scream at you, furiously, if anything is broken or incorrect. Modal dialog boxes will appear as soon as your Lua script breaks, and won’t let you advance the game until you have acknowledged all the Lua code that broke in this rendering frame. “Hot Loading” and resumption is Coming Soon, as well as some sort of a wrapper for Lua’s debugging functionality.

To cool the heels of the invariable cries of joy from the modders: we have not decided how much scripting, if any, we will end up exposing to the mod API and, if so, when we expose it. There’s a pretty good case to be made for doing a launch of the game without modding and turning it on later, like we did with Dredmor; amongst other things, this will ensure that we get the core game right and resolve any post-release issues (which hopefully we will have none of this time, knock-on-wood) before we start letting other people modify it.

In other news, Chris Whitman, Terrain Wizard, has finished rewriting the rendering code for our terrain. Our new terrain implementation doesn’t use a standard heightfield; instead, it uses an algorithm called Marching Cubes (thankfully now patent-free) in order to generate terrain from a scalar field. With this rewrite comes support for improved texture blending with Interesting Edges, and also the ability to raise and lower terrain. Support for terrain modification is necessary in a game like CE to ensure sufficient buildable space; additionally, we can use it (at our discretion) for things like Impact Craters from the Space Fungus Meteor.

Biome selection is now in as well, although the biome generators themselves are only filler right now. Here you can see a “grass and plains” biome with a giant cliff for whatever reason featuring smooth texture transitions, a swamp biome with various swampy things in it, and whatever the heck is going on in that desert place with the obelisk and jolly little campsite.

So, yeah, humming away here quite happily. Now, back to work! I’ve got overseers to fix!