Development Progress Report, week 42+43

Skipped a week because I didn’t have time in the window to do the devblog. Let’s see how we’re going.

Cosmetic bugs

A bunch of these had cropped up. Some were accidents, and some were oversights.

I have no idea how long the animated user-prompt has been missing. A long time, I’m guessing. I hadn’t even realised that it wasn’t there.

After I finally did realise that it was absent, it took a while to figure out why. Ultimately, the culprit was this line in the animated image widget renderer:

if (_bitmap->valid() || current_frame == -1)

The idea here is that we’re supposed to bail out if the animation frame is set to -1 or if the texture is invalid. Except this is what it should have looked like:

if (!_bitmap->valid() || current_frame == -1)

Basically, I was bailing out of the render method if the texture was valid, rather than if it wasn’t. Since it always was valid in practice, it didn’t keel over by triggering the other case (rendering with an invalid texture).

So, the prompt is back. Lovely.

The next item was a rare crash in screen-grabs. I try to have the engine take a screen-grab at all of the right times, so that it can be attached to saved games, to help disambiguate them.

The problem lay in maximising/unmaximising the game window. While it is highly unlikely that you’d trigger the maximise/unmaximise at the required rate to trigger the problem (around 5 times per second or more), there was a bit of a race involved.

Maximising/Unmaximising the display window causes multiple asynchronous events to be set off. There’s a notification of the change of state, as well as a notification of the change of size. Somewhere along the way we’re also taking a screen-grab. The problem basically lay with the screen-grab happening while the engine’s idea of the size of the renderer is wrong, because the messages have started to appear out-of-order.

If they did, and if we chanced to try to take a grab between them, and if the new size was smaller than the old size, then we’d crash.

It’s a lot of ifs, but I had a solid-enough repro.

The fact is, I had been really lazy about when and how screen-grabs were taken. Somehow, I’d ended up deciding that hooking them to the prompt-timer was a good idea, which led to two screen-grabs per second, on average. Wasteful.

After some thought, I found some better places in the logic to hook the screen-grabs in. Obviously if you hit the widget or key for quicksave that is a good time to do one. When text output is done or choices appear, those are two more. The last is before the options screen is presented.

This seems to cover all of the bases, so far, unless someone notices that it doesn’t.

The last big one had to do with the new title-screen. Simply put, I’d forgotten that you could tap the key to quickload from that screen, and the main-menu widgets weren’t cleared away in that case. Oops.

Experiments with scripting

I’ve wanted to add in a scripting language over and above Argus’ own script. Something that could be used to fill in for cases where there’s stuff you want to do that the existing story-system doesn’t allow for.

Initially, though, I just wanted to use it for the positioning and sizing of onscreen UI widgets. Positions and sizes of widgets change according to the dimensions of the display area, and while the widgets are customisable in many ways, position and size calculations are hardwired into the engine.

So, I had a go-around with chaiScript, which initially looked perfect for my needs. I could compile it in without any additional library dependencies, run scripts straight out of string variables, and essentially stack all of a script into a single line.

Regrettably, it didn’t work out, due to persistent interpreter contexts.

I’d create the interpreter, provide linkages to internal functions, variables, and data-structures, then fire off a script, and that was fine.

The problem came up when I tried to fire off the script a second time. chaiScript kept the context from the previous run so any declarations (functions or variables) caused it to throw an exception, because they had been declared already (the last time I ran those commands).

I tried a bunch of ways to work around this (like saving the interpreter context beforehand and restoring it after), but nothing worked. All I could do was tear down the interpreter each-time and recreate it for the next run of the script, which turned out to be painfully slow. Ripped it all out.

Probably I will bite the bullet and embed Lua, but not this week. I burned through too much time on embedded scripting for now, already.

Writing

Actually going well. Some of the syntax improvements that went into the story-compiler a few weeks ago have been paying off, and it is much easier to write certain constructs.

One small group of parallel scenes at the beginning of chapter two probably needs me to sit down and draw combinatorial diagrams, though. There’s an absurd number of combinations, and I need to figure out which ones get scenes, and which ones get hand-waved.

Chapter two also marks the point where the narrative migrates from the prologue/chapter one’s moment-by-moment storytelling and starts to migrate to focusing on the highlights of character narratives and events. From a writing perspective, that’s taking a bit of getting used to, and requires a little more consideration about what to show and what to handwave, even within scenes.

Script Actions

As for Argus’ own scripting, it turns out that I couldn’t put a ternary text-substitution expression inside of another. Why? They were evaluated from the outermost to the innermost on an as-needs basis, and this basically messed up the parsing if we stuck one inside another.

A two-line addition allowed me to reverse the evaluation order, making it innermost-to-outermost. Advantages: Any substitution expressions can be cleanly embedded inside any other(s) without confusing the parser. The downside is that we spend a few extra microseconds sometimes evaluating expressions whose results will be discarded by an enclosing expression.

I did get a bunch of work done optimising the parsing, and moving the responsibility of parsing some actions back into the action-classes themselves, which shaves a few more microseconds out elsewhere.

And the rest…

Had some issues with vertical sync not engaging properly on the laptop I use when I’m developing testing from somewhere that isn’t at home. Lots of screen-tearing, but I think that’s fixed now.

Why the laptop doesn’t play any game audio, I’m not sure about. Something to dig into. Maybe SDL isn’t opening up the audio device there properly for some reason. Why now?

0.9.91 has been pushed to itch.io, so if you’re alpha-testing you should get that update automatically. If you’re not getting any audio out of the game, let me know.

Over the course of this week, I’ll be bumping the version up to 0.10.xx and I think I’ll extend the alpha builds to the end of chapter one. That should give you some toothsome stuff to read.