I had a revelation the other day. There is something that has eluded me for a very long time, which is how to cleanly script a "scene" in a map. For example, lets assume we need a sequence of "events" to happen when the player's character sprite walks onto a certain trigger zone inside a cave map.
Now technically we can do this all right now, but it would be a mess and is not a feasible approach for the long-term. For...I'd say the last two years this problem has been on the back of my mind and I never came up with a good solution thinking about it idly. Last week, I directly approached this problem for the first time. I came up with a solution that frankly seems almost too good to be true. Its simple, flexible, and does everything we'll need. Before I explain how it works, let me give a little background.
Obviously to do all of these things, we'll need to do it inside the map script (in Lua). We can't hard code all of our maps in C++ for obvious reasons. The way we've been doing our scripting up until now is to enable C++ to call Lua functions. But we can't call a single Lua function to do all of the things I listed in that example scene above, because we require a lot of game loops to occur so that the player can see and experience all of these events playing out in real time (instead of just seeing the end result of all these actions being done). If we called the same Lua function over and over every loop, we'd have to keep track of where we are in the function, and also make sure that we don't do "too much" in a single function call that would produce a lag in the game or advance the progress of events too far.
The technology I created to resolve this problem is called the event system. At its core are two classes: MapEvent and EventSupervisor. MapEvent is an abstract class that contains two pure virtual functions: Start and Update. When an event begins, its Start function is called only once. The event's Update function is called every game loop until it returns a true value, indicating that the event is finished. MapEvent objects contain a vector of event "links". Each link consists of an event ID, a start/finish boolean, and an interger time value. What these three pieces of data allow us to do is to spawn child events any time after the parent event starts or finishes. So using these links, from a single starting event we can produce a cascading of further events, complete with accurate timing. Take a look at the image below, showing a directed acyclic graph of events. Any line with a +#s by it indicates that we wait that number of seconds before starting that event. If an event is located below its parent, the event starts after its parent. If instead it is located to the side of the parent, it starts when the parent starts.

The EventSupervisor class simply manages all of these events. It contains a mapping of all registered events, updates active events, and analyzes event links and starts the child events at the specified time. Recall that the MapEvent class is abstract. To create an event purely in Lua, we can either create a Lua class that derives from it, or use a C++ derived class called ScriptedEvent which does nothing more than call two Lua functions in its Start and Update methods. We can also define a number of "common" events in C++, such as moving a sprite to a destination on the map. This makes it easy to re-use and share these events throughout maps without requiring that each map file re-define their function.
This design is simple, flexible, and elegant. Honestly, I'm surprised at myself that I came up with such a great solution. The system is so powerful that I'm considering using the event system in place of some of our other constructs, namely sprite actions and dialogue actions. Sprite actions are what controls the NPCs on the map, telling them to walk from A to B, etc. Dialogue actions are nothing more than a Lua function that may optionally be called after each line of dialogue, or after a dialogue option is selected. Replacing these systems with events would allow them to take advantage of all of the offerings of events (namely linking and timing).
Truly, I think this is a major breakthrough for the map code. It will allow us to make the maps come to life in our next release. I'm really excited to start using this system in the game. There are still some questions about its implementation that remain to be answered, like event chain looping, simultaneous execution of the same event, etc., but I'm not worried about those cases just yet. Instead of trying to predict what we'll need in the future, we'll work with what we need to do in the present.
So for the past four years, our team philosophy on programming has been to spread everyone out across the entire code base. Person A works on the graphics engine, B works on the battle code, C the editor, D the shopping menu, etc. There were a couple reasons why we did things this way. First, in those days we didn't have a firm foundation of code yet and so many parts of the code depending on so many other parts being functional that we had to spread ourselves thin. We also wanted to avoid conflicts of working on the same code and clobbering each others commits (this was a much greater concern back when our versioning system was CVS, before we upgraded to SVN). There were some downsides to this model though, particularly that there wasn't someone around to bounce ideas off of all the time and having to take on a large area of the code by yourself was pretty intimidating.
Our programming team has talked this over a bit in the last few months, and we've decided to try something new to help us decrease our development time and to increase our motivation, enjoyment, and quality of code. The change is a two part one.
#1. Work on the engine as little as possible
#2. As a team, work together on one area of the code at a time and completing it before moving forward
Now the reason why that first bullet about the engine is there is because we've already spent a ton of our time over the last several years working on the engine instead of working on the game (a major reason why our demo releases to date have been so small). There is still lots of work in the engine that remains to be done for sure, but it is currently stable enough that we don't really need to spend more time on it right now. We need to add some more advanced features for the next release we are working on, but that's about it.
The second point is entirely contradictory to our earlier programming philosophy of spreading everyone out and assigning them to a specific portion of the game code. Now we are bringing everyone together to work on a specific component and dividing the work amongst ourselves. When I say "everyone" I really mean the programmers who make up the core workers of the team (usually all staff), and not the contributors that pop in and help out from time to time. Its hard to assign contributors something important in an urgent area of code, because they typically don't make half the progress that a standard staff programmer would (although there are exceptions). To start, our team has decided to work on the map code together, getting all of the features for the next release in place. This includes things like save points, environmental sounds, better AI, etc.
I really hope this new approach works well for us. What we need more than anything I feel is the motivation from seeing immediate progress and the reinforcement of working with others closely. I know from experience that when this team is motivated and gets the ball rolling, we can do some pretty amazing things in a short period of time. Its still being approached as an experiment though, so we'll have to wait and see what happens.