Development Progress Report, week 35

Progress was slower this week. Stuff got in the way, as stuff often does.

Let’s see what got done anyway.

Customisable user-interface widgets

After a huge migration of the user-interface code back in March, a lot of messy widget-creation got turned into a big table that handles the creation of the user-interface.

It looks like this:

std::vector<Layout> masterlayout
{

 {"background",Layout::IMAGE,{},"",ARGUS_CMD_NONE,L"",L"show,fullsize"},
 {"locationimage",Layout::IMAGE,{},"",ARGUS_CMD_NONE,L"",L"show"},
 { "portraitgroup",Layout::GROUP,{},"",ARGUS_CMD_NONE,L"",L"" },
 {"portrait",Layout::IMAGE,{},"portraitgroup",ARGUS_CMD_NONE,L"",L"hide"},
 {"portraitframe",Layout::IMAGE,{},"portraitgroup",ARGUS_CMD_NONE,L"",L"hide,image:faceframe"},
 { "dimmer",Layout::RECTANGLE,{},"",ARGUS_CMD_NONE,L"",L"fullsize,hide" },
 { "flasher",Layout::FADER,{},"",ARGUS_CMD_NONE,L"",L"fullsize,hide" },
 { "debug",Layout::RECTANGLE,{0,0,0,-99},"",ARGUS_CMD_NONE,L"",L"sysfont,hide" },
 { "narrativegroup",Layout::GROUP,{},"",ARGUS_CMD_NONE,L"",L"" },
 { "narrativebox-shadow",Layout::TBOX,{},"narrativegroup",ARGUS_CMD_NONE,L"",L"radius:20,backgroundcolour:black/200" },
 {"narrativebox",Layout::TBOX,{},"narrativegroup",ARGUS_CMD_NONE,L"",L"radius:20,backgroundcolour:beige/200"},
 { "speakergroup",Layout::GROUP,{},"",ARGUS_CMD_NONE,L"",L"" },
 {"speakerbox",Layout::IMAGE,{},"speakergroup",ARGUS_CMD_NONE,L"",L"image:paperscrap"},
...

It’s a huge improvement to the old way of doing things, and easy to find and adjust specific widgets, when I’m messing with the code.

I could take that a step further, though, and I did.

By delaying the point where UI widgets are initially created until after the story has loaded, I was able to allow the story-file to override widget definitions in this table.

@modalboxshadow|RECT|3,3,400,150|modalgroup|0||backgroundcolour:black/127,bordercolour:black/127
@modalbox|RECT|0,0,400,150|modalgroup|0||backgroundcolour:silver
@modalyes|TEXT|1,117,199,32|modalgroup|48|YES|sysfont,backgroundcolour:silver,mousedbg:green,mousedborder:green
@modalno|TEXT|200,117,199,32|modalgroup|49|NO|sysfont,backgroundcolour:silver,mousedbg:red,mousedborder:red
@modaltext1|TEXT|1,1,398,32|modalgroup|0|Are you sure?|sysfont,backgroundcolour:silver
@modaltext2|TEXT|1,33,398,32|modalgroup|0|Because reasons.|sysfont,backgroundcolour:silver

The actual syntax of doing that isn’t anything to write home about, but it works. Also, compiling the story is a whole lot faster than compiling the code, so it makes it easier for me to make experimental changes to the UI.

A caveat, though, is that a lot of the widgets have their size and position calculated dynamically based on the available display-size, so those can’t be overridden for many widgets. Yet.

I could probably embed Python or something into the engine and allow the author to specify their own positioning/sizing code, but that’s not a right-now thing. Honestly, having some sort of thing like that would make other things easier. That makes it a future-probable item.

Knowledge

I went back and revisited knowledge-representation. A single knowledge structure (of the exclusion logic sort) holds a whole assortment of things: Basic facts about characters (ages, names, nationalities, interests, and more), opinions, relationships, character-flags, knowledge about other characters, global event-flags, inference rules, and all sorts.

The engine-logic is constantly looking things up in there, but as I get more into the swing of things, I discovered some disparities in the way I was representing certain forms of information (with simple character flags, in many cases), and the way I needed to actually use that information.

So, I went back to review how knowledge was represented.

The specific questions that needed answering at various points in the narrative were:

  • Do you know X?
  • How do you know about X?
  • Who do do you know who you know also knows about X?

Initially, it didn’t look like that would fit into my model, and then I realised that it actually was a fairly good fit.

The hard part was actually expressing these relationships concisely in English for the author to use.

I’m still working on that, but setting the information is done. Building from last week’s work on the story-compiler, I was able to add a new instruction that builds as many knowledge-insertions as required to produce the desired effect (between one and a couple dozen, in practice, judging from how it has worked out in practice in my tests).

So, we can represent certain knowledge items as transferable, whether you acquired the information by being present or by being told, and an awareness of who else knows what you know.

Trust me, that’s going to come in handy.

Syntax

The last part was more work on last-week’s role-aliases, and general syntax.

I’ve managed to simplify the syntax for when a character speaks, shaving four whole bytes off, every time someone does it. The new, simpler syntax is more obvious to the eye, when you’re looking at a lot of story-source, and – since the compiler just straight-up converts it to the syntax the engine understands anyway – there’s no need to modify the Argus engine to understand the new syntax.

It did require a whole lot of work disambiguating the shorthand versions of the narrative/speaking syntax, though. They’re the two most commonly use action statements, and now neither of them bears any distinguishing prefixes. Plus, adding role-aliases as targets/enactors further increased the complexity of disambiguating the two types of statement.

But done.

All in all, I probably didn’t get more than ten hours done this week, but it was definitely worth it.