One of the more involved aspects of the Argus story engine is how characters learn and express information about each-other. Some of that knowledge is just used for conditional narrative, but the most important part (currently) is how characters address each-other.
Names, titles, nationality, differing levels of formality, age, gender, and more, all get churned through sets of constructs provided by the story, which ultimately result in some form of address. That’s what I call the reference model. It’s updated as characters learn new information about each-other, and gaps in the knowledge-structure are filled in with assumptions, where no direct knowledge exists.
And annoyingly, way down in scene 360, one of the characters seemed suddenly unable to create a valid form of address for the character she was speaking to.
What was it? Had I broken the assumption engine or the reference model calculations? I didn’t think so. I hadn’t worked on that part of the code recently, and everyone else seemed to be capable of producing valid forms of address.
Was some data missing? Was actor 19 missing some key piece of information about actor 14 that prevented her from being able to properly assemble a form of address for him? Or was it the recent reduction in formality levels during their conversation? I automated some runs through, and checked the spammy debug logs, and everything seemed to be as it should.
Finally, after a protracted debugging session, I found it. As it turns out, there are two possible precursors to this scene. Either scene 250 or scene 260 take place earlier, and in both of those scenes, actor 19 is supposed to meet actor 14 (and others). Only, actor 19 hasn’t been fully written through those scenes, so there’s just some placeholders. In one scene, she’d learned the appropriate information, and in the other scene, she had not.
If we reached scene 360 by way of scene 250, everything was fine. If we got there by way of scene 260 instead, she never found out who he was, and ended up drawing a blank on how to address him in conversation.
Silly of me.
I did, however, find some useful places where I could optimise. Unplayable, minor characters were still receiving a lot of narrative (with its associated background generation work) that they really didn’t need to. They’re not being operated by a human user, and won’t ever be, so sending them massaged narrative text was kind of redundant, especially since I was throwing that text away just a few steps later.
Fixed. Actors are properly flagged for that now, and a lot of machine-work on text is headed off early for minor characters (just as it already was for temporary characters).
All to the good, really.
I did wind up with an odd regression, however. For the last week or so, I’ve largely been running the engine in an automated testing mode, where it runs to completion with minimal interaction from me. Then I crawl through logs to check what happened and what narratives were generated for various characters in the story. A debug mode gives me control over all of the character-choices, so I can direct the narrative whichever way I need to for testing.
Running it live today, though, surprised me a little. Illustrations weren’t appearing.
Or rather they were, but only when an illustration changed. Then the one that was changed from appeared instead of the one it should change to. That felt really familiar, so I dragged the window partially offscreen, and dragged it back.
The freshly exposed portion contained the correct image, while the rest did not.
Right. Been there before, early on. The last time it was a failure to properly invalidate the image area of the window used to display illustrations, so when we got a paint message, it wasn’t included in the area to update.
It smelled like the same thing this time, only I couldn’t think of a good reason for it to happen. I checked my observer patterns, to make sure the engine was handing redraw requests back to the interface, and that was fine. The interface was correctly invalidating regions of the window. All good.
But not good enough.
I traced out the code-paths to make sure everything triggered when it should, and apparently it did (though Window update logic is a bit tricky, since the system calls back with Paint messages out of your normal flow of processing).
Ironically, scrolling backwards and forwards through the story log updated everything just fine. I looked at the logic of the scrollback functions, and they did indeed maintain some fine-grained control over how portions of the screen were updated.
And then I realised that one piece that also should do that actually didn’t. It absolutely should have, but I’d never put that one line of code in. Where the interface layer communicates with the core engine.
Apparently, way back in the original prototype code, I’d gotten illustration updates working largely by accident, and sometime in the last week or so while I was cleaning and optimising, I undid that accident.
One-line fix, which is nice. It’s right at the point where we’re pulling new data for the illustration image widget, so it makes sense to flag it for repainting on the spot.
Problem solved. Two problems, really, counting the knowledge issue above.
I can’t help thinking that I could have spent the whole time more profitably on some other aspects of the project, though.