Full UI Upscaling, Part 3: Dynamic Terminal Swapping

Grid Sage Games | Cogmind |

Experience sci-fi tactical combat and exploration in a procedural world that marries traditional roguelikes with an engaging modern interface like no other! Build yourself using components found or salvaged from other robots - power sources, propulsion units, utilities and weapons can then be attached for power sources, propulsion units zipping past enemies before they even have time to react, sword wielding assassin/hackers and stealthy assassin/hacker roles can even be achieved! Your situation could quickly shift as components become lost or rebuilt using enemy remains as you discover who exactly you are as the Cogmind! Explore a living and breathing world filled with robots!

  • View media
Post news Report RSS Full UI Upscaling, Part 3: Dynamic Terminal Swapping

An exercise in making Cogmind's 60-row ending animations compatible with a 45-row terminal layout.

As I thought back on it, it seemed I'd successfully created an effective conceptualization for a modal inventory and produced mockups with solutions for every obstacle on my journey to dropping 15 rows out of Cogmind's interface - or so I thought.

At the conclusion of that process, however, an audit of remaining user interface systems exposed an unexpected roadblock: ending animations.

Cogmind provides nine unique endings (with more planned) all featuring full-screen ASCII animations, some flexible enough to adapt dynamically within any terminal dimensions while some were specifically created assuming 60 rows for height; for those seeking 45 rows as their terminal height requirement...

I invested considerable effort into making current animations as they make great use of space; yet they seem incomplete... One would hope there must be another solution...

What Are My Terminal Swapping Options Ideally Sought After? (B.I) W hy not conduct terminal swapping animations at this stage? (A.)

Once again, endings don't need to be limited to 45 rows; after all, we are mostly watching these animations for aesthetic rather than gameplay purposes. At the outset of this series I noted how shrinking base terminal dimensions is used as an excuse for providing larger font sizes across-the-board; this may make reading and understanding details simpler for some but less so in others; therefore we no longer require this facility in this instance.

So the basic idea is that for normal gameplay we would utilize a 45-row terminal; then when needing an ending animation simply switch over to the 60-row terminal to display that, and switch back when done.

It reminds me of early video game cut scenes where different display modes would switch on solely during these sequences; later these kinds of things became much simpler once done "in engine", becoming the norm today. Cogmind has always maintained its consistent display; here however, I could take advantage of all my hard work in animating everything so far.

Now comes the tricky part - are engine architecture capable of supporting such features, and are there any additional obstacles standing in its way?

Technically, this concept immediately showed promise based on how Cogmind already uses "terminal swapping," although only between frames and behind the scenes for screenshotting purposes.

Main uses are for map output or creating a composite PNG of all of the known maps in play, useful for sharing interesting layouts with fellow players or getting advice about where to explore next.

Both of these use cases required generating an image larger than the screen, so a normal screenshot wouldn't do.

Already armed with a built-in way to take a "screenshot" of the terminal contents (bypassing the screen itself entirely), if we build a larger terminal than the screen we can just as easily run the "screenshot" process on that to produce an even larger image.

With just a small bit of isolated code it's pretty easy to temporarily replace the engine's terminal with one of a different desired size, write to that, generate the image, then restore the original terminal as if nothing happened. We're not actually rendering to the screen itself so resolution doesn't matter, we don't need to change the video mode, none of this is ever displayed, nor does any outside interaction occur.

This was a promising starting point, at least providing a theoretical approach for our ending animation management.

REX, Again

The above initial examples of basic terminal swapping are pretty much entirely Cogmind-side. As it's happening between frames for the sole purpose of creating an image using the normal system, the engine doesn't need to know or care about what's going on. All that was needed was a simple function allowing the root terminal to be swapped out for another one.

Taking the next step and swapping the terminal with a new one that would exist for a longer duration, and even involve some level of player interaction, would be a much more complicated process, meaning it's once again time to revisit the engine to expand its core capabilities

Also once again, as an engine feature it makes more sense to head back to the simpler engine testing environment to build and debug it, rather than using Cogmind itself.

I was pleased, and surprised, to find that terminal swapping of an extended nature really wasn't an incredibly complex operation with many repercussions. As far as the engine was concerned, it only required changing a handful of core variables, although beyond that I had to resolve some cursor-related issues, like crashiness related to its screen position and hover data, and the software cursor dirty rect status.

The first successful root swap in REX, temporarily replacing the standard 80x60 demo terminal with a 120x90 terminal, while switching the font size from 6x12 to 4x8, so the window size remains consistent. This behavior simulates what would be required to run Cogmind's animations using a smaller font while maintaining the same resolution.

The next stage in building this feature would be to import it into Cogmind while changing as few variables as possible. It doesn't have to be specifically for endings, and we don't even need to start by actually changing the terminal dimensions--simply swapping from the default 60-row terminal to another 60-row terminal and back would be sufficient to weed out any issues with regard input or other basic functionality. One step closer to a real use case scenario. That went fine as well!

When and Where

Having passed a simpler test, it was time for the real thing, but exactly where is the best opportunity for a swap to take place? Swapping is a pretty significant cutoff, after all, forming a clear barrier between what is before and after, and there shouldn't really be much talking between the two sides, at least not on an interface level.

As stated at the beginning, the goal here was to allow animated endings to use 60 rows instead of 45. Given the simplicity of terminal swapping at the engine level, it seems easy enough...

As so many things are, up close it no longer looked so easy.

I originally imagined just having the animation segment of the ending in a different terminal, and tried that for a bit, but the endings (there are so many xD) are a relatively complex collection of classes and processes since they mix and match different components, and it was really hard to untangle what needed to be untangled. Even before considering swapping needs, it turns out that in many cases the process involves multiple windows in varying states of visibility and overlap. While swapping right before an animation would be possible, it would likely be pretty tough to both implement and debug.

Then a new idea popped up: How about instead of focusing so tightly on the animations we move one level higher and handle the entire game over process in its own separate terminal interface? This would include the standard game over screen (losses as well), stats, and restart menu etc. This is a much cleaner break, far easier to pull off without worrying about any serious complications.

The aftermath of the first [mostly] successful root swap in Cogmind, having gone through an ending and starting a new run. Some of you will recognize what's going on there... Clearly some bugginess to be resolved, but it didn't crash and we're back in action for a new run :D

The only drawback is that said stats screen would then be in the 60-row terminal interface using the original font size. In other words, back to the smaller font. Still, this might be fine since it's 1) just text, 2) not a lot of text, 3) only in that one spot, although if we wanted to we could perhaps use the new font size to display it. Doing so would require reducing the number of listed stats in order to fit in the available space, at least if trying to keep the vertical design. They're only a tiny subset of those found, anyway, but I don't like the idea of further slimming down the already short representative list, so it's either accept a smaller font size for that particular screen, or eventually go as far as a more significant redesign that makes more use of horizontal space. I tried a few mockups but didn't like any of them, so nothing will probably change with that at first.

While working on this whole terminal swapping business I also happened to discover that if you manage to close the game window during an ending animation (including the loss animation), it would not overlay the separate program close animation that I added some versions back. This is not an uncommon occurrence, inadvertently uncovering obscure bugs in old, or in some cases very old, parts of the source that were simply never encountered or noticed before. Always a good opportunity to stay alert and fix things

One final note: For an article about new tech to support ending animations, there is a curious absence of samples demonstrating the primary use case, but I figured I'd leave those out

Post a comment

Your comment will be anonymous unless you join the community. Or sign in with your social account: