Well, well, well.. Been a while, hasn't it? About four month to be exact. Sorry! To be fair, I mostly was not slacking off, you can look
at the git history!
I have, I think, finished the story for day 3, which means the release should be coming very soon (upd: it's out). There is also some optional content that
hopefully isn't too hard to find. Many things have happened, especially code-wise, next follow some interesting techincal highlights.
To implement a certain feature for the walking part of the game, there was a need to draw things over the shader-processed stuff the rest
of the game has (that is, the darkness and the lights). For this, I have implemented a "layer" system, of which there is only one now (not
counting the unnamed default layer). The overlay
layer ensures that the object is drawn after everything else is drawn and without the
room's shaders, which are now specified per-room and can have all kinds of parameters, there can even be multiple shaders! So anyway, the
overlayed objects are drawn afterwards so they're not affected by shaders, and they still have the usual z
level logic which allows to put
them on top of each other on the overlay layer.
For some sprite related things, I have discovered (thanks to my dayjob, actually) the concept of slices in aseprite. Slices are basically
rectangles on the picture that are saved in its json metadata file. I used this feature for that very same thing mentioned before. I mapped
out two areas for putting text into them and then in code made text conform to these areas. Hopefully since the code is quite generic I will
be able to use them for something else, too.
The code structure changed quite a bit, since there was need for dynamic entity instantiation. So, now it's easy to make new entities and
the code that existed before takes advantage of the entity creation functions too. Overlall, the code moved quite a bit into modules.
The callback system was reworked a lot and I used that same concept in other places too: that is, callbacks now specify the module and the
name of the function they want to call, instead of some hard-coded name. This makes things a lot easier to separate and is very good for
modding.
This same concept was used for custom story lines: the lines which are too rarely used to have them built into the parser. These lines
basically specify "it's a custom line, here's the module and the class, and here's the data to pass to it", and the parser does so. When
implementing custom lines I came up with an idea to mark places where line names are referenced in their data with YAML type tags. Many
people don't know they even exist but there were very useful in my case, since custom lines aren't directly processed by the parser it had
no way to know which things to parse if the custom line wanted to jump somewhere in a different file. So when using a custom line if one
wants to reference a line in it, it has to be written as !line-name name/goes/here
. This makes the parser aware that this is indeed a line
and it can pre-load the file and validate all the things at startup. Very useful and a lot better than what I initially did, which was just
loading lines from lua at runtime. Needless to say, it didn't work very well and it didn't scale. An example custom line looks like this:
1:
custom:
class: { module: "terminal.select_line", class: "SelectLine" }
data:
- condition: |-
return TerminalModule.state_variables.know_about_stuff
next: !line-name know-about-stuff
- next: !line-name dont-know
The few custom lines implemented and used currently are:
-
SelectLine
, which selects from a set of possible ways to branch from some conditions and has a default condition to select if nothing
matches. Sort of like switch~/~case
-
SaveLine
and ReturnLine
, these work together. The first one saves its "returnto" property and then jumps to "next". Afterwards, when
one wants to go back, ReturnLine
is used by specifying next_was
to the value that was used in SaveLine
and after loading the return
line name from it it jump back to that line. Effectively, that means one can have, for example, a dialogue which can be started from
anywhere with a SaveLine
and then after it's finished execution is returned back to where the dialogue was called from, even though it
doesn't not exactly where that happened. I used this to implement dialogues that will, most likely, be available throughout several points
in the story.
Another custom line that exists is a special one-off menu, which I will not be discussing here because it's kind of spoiler-y, but it's not
that interesting anyway.
The tags for the walking system objects were reworked a bit: now they created components automatically based on their name. Before, the tags
where dispatched from hard-coded values to components created beforehand. In this context, a tag is a component (in ECS terms) which doesn't
have any actual data but it used to mark an entity as something special.
A new puzzle was implemented for day 3's walking section, hopefully it's not too hard, since this time it's actually somewhat of a puzzle
and I thing it can't really be just brute forced. It requires just a tiny bit of thinking, so to speak.
A testing system was implemented, for both C++ and lua's ECS. As of this moment, the coverage says about 50% but that's not really true.
Not much is tested but the foundation is there. I have also moved back from moonscript to lua, because one can't really count coverage from
moonscript, as no coverage tool exists for it. The only thing where moonscript still exists are the tests, because it's a lot more
convenient to use there.
A full-blown templating engine was introduced in the terminal part, so answers could be easily changed depending on certain choices the
player makes. Day 3 uses this functionality heavily, I hope it creates more choice for the player to enjoy, making this whole thing more of
a game.
The walking mode also has received a debug menu, like the one used in terminal mode. For now it just shows state variables for the walking
mode, but hopefully I'll add more useful features to it. Showing the whole ECS world structure would be cool to have.
Interaction system for the walking mode was changed a bit too, now interactables can overlap and if they do, the player will have a choice
of which one they want to use: first pressing E to show the list and then the number of the thing they want to use.
A character parameter of font size was added, as it is used in the special custom menu line mentioned before. This menu has a header that
writes text that's bigger than usual.
For the past month or so I didn't actually have to touch the code most of the time, as most of it was already written I just had to write
the rest of the story. I tell you, it wasn't easy!
I also implemented an accurate way of counting words in the story, currently it shows 11789
!
The past few weeks have been hard for me, due to an uneasy situtation in my country. I wasn't really able to concenrate on anything. After a
bit I did actually start doing things again, even though the uneasy situation is far from over. Nevertheless, I think I can work on things
now, so that's good.
The environment images sadly are still not really available. I didn't draw new ones, as it takes me a lot of time. I'm hardly an artist,
and drawing even such small pictures takes a long time. I recenly tried to ask a certain person who in the past said I may commision
him some art for the game when I'm ready for it, but it turned out after he published his game he left the industry as it was too much for
him. That means, of course, I couldn't commision art from him. The search continues (though I'm not exactly trying really hard).
I also received a PinePhone recently. Let me tell you, it's not a good "phone" in the traditional sense as the software is very rough, young
and made by the community, but it's a full-fledged computer, whic is great. It's so easy to cross-compile for: you just compile it with the
usual desktop compiler for AArch64 and copy it to the phone, and that's it. Everything works. I spent the last few days tinkering with it
before actually coming back to finish the story :)
Update from 06.09.2020: After writing this post I stumbled upon an interesting bug that took me a bit to solve, so I thought I'd write about
it here too. When OutputLine
is skipped too fast, the next line would be created too soon, before script_after
is executed,
that is, right after the interaction is processed (and scripts are executed afterwards in another function, which draws the lines).
So, now the OutputLine
explicitly says to wait until its script is executed before proceeding. This problem didn't seem
to concern the other lines because they have more requirements than just "all text is output".
I have also implemented a way to scale a window down and up to half/double the size for smaller and bigger screens. It's not ideal,
but it allows people to play even if their screen has a very small or high resolution.
I think that's most of the things.. Hopefully we shall meet again soon. And thank you for reading my blog post :)