How to Screw Up

It all started so simply. I was playtesting and realized that I had to spend an undue amount of time wandering around trying to run into other actors. This, I realized, is absurd: storytelling isn’t about trying to find other people, it’s about interacting with them. So I decided to eliminate the easter egg hunt and make meeting other actors a direct process. An actor should be able to specify up front “I want to meet actor X” and have it happen immediately.

It seemed simple enough. All I had to do was insure that actors go directly to their interlocutor’s home. But that raised a new problem: what happens if two actors try to go to the same location? Does one actor sit outside, waiting for the first to finish his business? That struck me as too artificial. I needed something better. After much fiddling around, I settled on a radical solution: dethread the engine. From the very beginning of this effort, twenty years ago, I had decided that actors should be able to operate independently of each other, without taking turns. This required me to build a threading system that permits actors to pursue their goals simultaneously. A complex tracking system was required to prevent collisions. In some ways, my system is analogous to a multi-threaded operating system, although much simpler. But now I had to collapse it down to a single thread without completely destroying it. 

This proved to be more difficult than I had anticipated. The trick lay in the “Unconcious” actor trait. If I set all the actors to be unconscious, then I could wake up just one actor, allow that one actor to pursue his goal, waking up any other actor he bumps into, and then, when the actors part, I put them both to sleep again, and wake up the next actor in the sequence.

This raised a small problem immediately: there is nothing in Sappho that allows the scripts to access the actor sequence number. As far as Sappho is concerned, actors are defined by their names. Sappho has no way of knowing who is Actor #1 and who is Actor #2. This would usually have presented a nasty obstacle, but I have long since abandoned any pretense of keeping the operator set clean and neat. I quickly wrote up a short Java method for the interpreter called “NextActor” that accepts one actor as its input and returns the next actor in the numerical sequence. 

But I immediately ran into another problem: exactly when do actors wake up and when are they put to sleep? And when is the next actor aroused? I decided to kill two birds with one stone and use the Goodbye verb to handle everything. When Goodbye is executed, it automatically returns both Subject and DirObject to their home stages and puts them both to sleep, and awakens the next actor. All in one big operation.

Alas, that didn’t work out. The next actor, upon awakening, had nothing on his schedule and so did nothing. Nobody did anything and the storyworld timed out. I needed a way to wake an actor AND get him to decide on a course of action. 

Sounds easy, doesn’t it? Just have the next actor react to the Goodbye event with the only option being to select a new interlocutor. That didn’t work, either: actors cannot react to events that they don’t witness. So the action still died out and the storyworld still timed out.

The next step forward came with the clever idea to let Fate handle the problem. Fate, after all, witnesses every event, so Fate can react to every event, and Fate can execute a secret verb that applies only to the next actor, giving that next actor something to react to. 

But while implementing this I encountered a new problem: the various actor trait values were changing. That’s not supposed to happen! This first appeared when, for no apparent reason, actors refused to wake up when told to wake up. After much mucking around, I figured out the problem: when the engine runs, it is supposed to reset all actor trait values to their original settings upon completion of a run. However, in my efforts to disentangle the engine from the Internet interface, I had inadvertently disabled the process that saves and restores the actor traits. So I had to write my own save and restore routines. 

So I implemented the scheme with Fate waking up the next actor, and after getting it working discovered that I could have simply set the Audience of the goodbye verb to include everybody everywhere. That would have solved the problem, too. But I decided to stick with what I’ve got. 

Next problem: An actor, after wakening, must have something to do. I added a Role plus Option for an actor to go to another actor’s location, and that solved the problem — mostly. It correctly handled everybody, generating lots of conversations, right up through Skordokott — but for some reason it halted before Gaustusu. Oops, I realized that I made the classic mistake of using the wrong terminating index. {blush}. That’s what I get for slapping code together. I made the opposite mistake at the other end. With that fixed, the damn thing ran correctly. 

Now all I have to do is make the conversations interesting. At last I have left the damn technical problems behind me and am moving back to getting the storyworld working!