Newsletter
Join the mailing list below for occasional development updates.Stay Up to Date
Links
-
Recent Posts
Recent Comments
- Anonymous on Hacking, the InterfaceCY-PHR sounds like such a troll of a bot, and it probably be very annoying (in a good way) as well as dangerous
- Kyzrati on Hacking, the InterfaceGood point, and a good reminder from this now-ancient article :) Obviously never took that direction in the regular game, but yep ...
- y0un65t3r on Hacking, the InterfaceSome of these unused hacking risks would make epic CY-PHR mechanics!
- Kyzrati on Adventures in Map Zooming, Part 2: Engine-level ArchitectureUm, yeah, complete overhaul so not something that would ever happen for that reason alone (unnecessary now), although just as impo...
- Kyzrati on A Simple Approach to Player-Designed RobotsYeah it's turned out quite well! (and we've been having a lot of fun with these things even outside the game, as you can see...
- Kyzrati on Fog of WarYeah it's a pretty old post at this point, and I remember that was a fun article but they must've changed their link structure, or...
Archives
- ►2024 (7)
- ►2023 (16)
- ►2022 (8)
- ►2021 (14)
- ►2020 (12)
- ►2019 (21)
- ►2018 (14)
- ►2017 (15)
- ►2016 (19)
- ►2015 (27)
- ►2014 (49)
- ►2013 (22)
Categories
- Annual Review (10)
- Art (12)
- Cogmind Beta Overhaul (6)
- Design (72)
- Dev Series: 7DRL Postmortem (4)
- Dev Series: Fonts (4)
- Dev Series: Full UI Upscaling (5)
- Dev Series: Map Zooming (5)
- Dev Series: Procedural Maps (7)
- Dev Series: Sound Effects (6)
- Dev Series: Story in Roguelikes (3)
- Dev Series: Ultimate Morgue File (4)
- Game Overview (3)
- Gamedev (14)
- GUI (24)
- Internal (6)
- Marketing (5)
- Mechanics (31)
- Meta (7)
- Post-Mortem (5)
- Release (4)
- Uncategorized (8)
- This blog is now for long-form topical articles. For most game updates and other news see the regular forum announcements!
Full UI Upscaling, Part 5: Completion and Demos
They’re alive! Last month I shared a sizeable collection of interface mockups summarizing my vision for a playable Cogmind interface that could fit within a 45-row terminal. Those mockups are now a reality, fully implemented more or less as described, and in the time since I’ve even gone further down that path and implemented the so-called “Phase 4” UI with its greater number of modal windows.
Although I already demonstrated much of the first new modal UI layout in an earlier forum announcement, I figure I could review those features here in order to provide closure to this series, plus cover some related dev topics as well as the second modal layout.
“Semi-modal” 45-Row UI Layout
Although players are free to continue using the full 60-row layout originally designed for Cogmind, anyone who does not mind sacrificing some convenience in exchange for greater cell size can use 33% larger tiles and text by switching to a 45-row layout. In other words, anyone using size 18 fonts (the majority of players), would instead be using size 24 under the new layout.
One of the biggest compromises in this mode is the smaller map view, but it’s still reasonably large (at least 50×35), large enough to at least see out the extent of normal sight and attack ranges, and for information beyond that all the QoL recently developed for map zooming comes in handy, even when not zoomed.
Here is a sample screenshot of the 1080p 45-row terminal layout in the early game, before the inventory even switches to its modal form:
Inventory/Parts
The other compromise is interacting with a modal inventory for much of a run, but I’ve also put a lot of work into designing QoL features to make it as seamless as possible.
Easy access to information and feedback is important, so of course the INVENTORY access button directly reports its current usage and capacity, pieces of info which would normally be found at the top of the inventory window itself.
One of the most important forms of inventory interaction for mouse users, drag-dropping, is also preserved by automatically opening the inventory while dragging a part, then automatically closing it again after release, in case you want to put the item in your inventory.
In fact, quite a few operations will automatically toggle the inventory like that wherever it makes sense--the part management keyboard interface (‘p’), the ‘d’rop shortcut, part swapping, item tagging…
Of course the regular old swap menu also works just fine, even when the inventory is modal, meaning opening the inventory is often not even necessary.
One of the most controversial aspects of the 45-row interface is likely how it treats part type headers. As I wrote about during the mockup descriptions, we can save space, and delay inventory modality, by temporarily removing the headers themselves from the parts list. That was going to be an optional feature disabled by default, but for now I’ve instead decided to have it do that automatically, and be opt-out instead.
The headers are only replaced by the sidebar method for as long as the inventory conversion to modal form is delayed (so about two evolutions in the mid-game), after which they’re restored to normal again since there’s plenty of room.
Secondary Windows
As per the mockups, many of Cogmind’s secondary windows that were originally designed for at least 50 rows had to be squished down to 45, including machine hacking, the status window, and item/robot info.
The most obviously different of the group is item info, which saved enough lines by moving its art off to the side.
The other biggest new feature which took a while to build and finalize but will likely be seen by almost no one (:P) is the [M]ore button as applied to robot resistances. Such a button was already added to Beta 13 to support the occasional longer item/effect descriptions, but was given new purpose for the very rare possibility that a robot might have too many total lines in its info window, in which case one way to cut it down to size is to put excess resistances in a popup window.
The world map view was yet another one of the secondary windows originally designed for a height of 50, but fortunately removing some of its interior padding was enough to shrink that to 45. At the same time, I also took this opportunity to do something else that I’ve wanted to do for years: speed it up! Although I first designed the map in 2016 with this fun vision of a map animating the route you took to get to your current location, while not too problematic in Cogmind’s early years, the continued addition of new areas and potential for lengthier routes could make it a bit of a slot to view the full map in the late game, so I’ve rebuilt it to appear in its entirety almost instantly :D
This world map change will benefit everyone, regardless of UI layout. In fact a number of tweaks and fixes made throughout the layout development project have carried over to the regular interface as well.
Game Menu
A good half of the work involved in creating a 45-row version of the interface involved adjustments to the game menu and its various subwindows. It was a lot. The content was, after all, mostly designed to fit within the map area, which had presumed minimum dimensions of 50×50. At least we didn’t have to worry about the width (whew--very glad Cogmind was designed for 4:3), but again with the height…
Pages with a 50-row layout now needed 35-row layouts as well.
Overall the biggest impacts were to the Advanced commands page, which had always been pushing up against the limit to begin with, and all the records interfaces.
The problem with the Achievements/Gallery/Lore records, and actually much of the “game menu” in all, was spaghetti code. Most of Cogmind is fairly well organized code, but not the game menu and its pages--it’s all in just two files to which I kept adding and adding and adding and sharing variables and it’s just messy all around. I used this opportunity to clean it up a bit, especially the records code which share a lot of the same functionality anyway but instead of using common functions there was just copy-pasted code everywhere.
Design-wise, at least the records weren’t trying to fit into the map view area, and they turned out fairly well, if slightly cramped compared to before.
Amidst the refactoring, in another of those “I should do this while I’m here” moments that benefits all layouts, I finally darkened the background when a modal popup is active in the game menu. Doing so always made sense, of course, but it wasn’t vital and it never felt worth dedicating the time before.
After building this new UI layout, last week I streamed the first run to make use of it, explaining all the major features as we went…
“Modal” 45-Row UI Layout
The first 45-row layout I developed is essentially “semi-modal,” because all windows are visible as usual until only later when just the inventory is hidden as necessary. The true modal interface hides multiple windows, and does it immediately from the start, but in doing so allows for a map view which is almost as large as what Cogmind was designed for (50×50).
All three options are available in a new setting at the top of the Options menu.
How do we reclaim our missing map height? By making the top-side consoles all but disappear, of course! The info displayed up there does not warrant constant attention anyway, consisting of transient logging info and some menus for accessing control of allies and intel. Anything that might be of potential importance can be displayed temporarily, and any menus can be called up as needed. The result is a much taller map view: 50×44.
The top row buttons serve more or less the same functions, such as toggling the message log to its full height, or switching the center console mode, though in this case the toggle must also open the Allies/Intel windows to make them visible and interactive when necessary.
The Extended Log and Combat Log modes simply determine what the space below is used for when messages are being displayed.
You might recognize the temporary message log style from POLYBOT-7, which is where I ripped it from :)
The automated full-detail combat log messages (the ones that even in the 60-row layout could appear over the map as combat plays out) are hidden by default in 45-row layouts, even if the detail level is set to Full, since given the narrower map view they can easily obscure nearby action.
There is a new config option to force it anyway, for those so inclined, but as usual, as long as it’s currently your turn, in combat log mode you can always scroll the combat log backward to review the details of recent combat. (However, in the Modal 45-row layout there is currently no way for the mouse to initiate this scroll--it’s keyboard-only…)
I’ll be streaming a run in this layout as well, once the build is ready…
Extra Credit
With playtesting having only just begun, I’m sure these layouts could use some more polish here and there, but they seem in a really good place already. Looking further ahead, there’s also the chance that other related features might be added as well, things I’ve held off on so far in the interest of actually releasing this to players and getting back to the content expansion I was working on before.
Tutorial
One such feature I was on the fence about throughout layout planning, and to a lesser extent throughout all of Cogmind development, is a more intrusive vector for tutorial info. I much prefer to maintain Cogmind’s theme of immersion as best possible, and that has always meant avoiding an in-your-face type tutorial with dedicated popups or some similar effect. A sound cue and flashy log messages, that’s it.
In particular this Modal 45-row interface has me more worried about teaching new players, especially if it’s to be a default layout, because log messages automatically disappear after a little while. Yes the log can be opened in full to view them as normal, but players would need to be proactive about it. A log-based tutorial was already easy enough to miss bits of before, and people did :P
To somewhat address that issue I doubled the duration of specifically tutorial messages in the Modal layout, so they remain visible longer even as other messages disappear.
Another problem which had me again thinking about alternatives is the handful of tutorial messages that appear when the log area is not visible at all in the modal layout, such as while hacking! (since in that case the machine hacking interface now extends all the way to the top of the screen) One might suggest putting these immersion-breaking messages right in the hacking interface itself, but if we’re going to go that far we may as well take the dedicated popup route :/
I’m letting this topic simmer for now, and ultimately the decision would be affected by whatever our default layout ends up being.
Screenshot Mode
Although not particular to modal layouts, and a feature I’ve been considering for years, the need for some form of “screenshot mode” clearly becomes more acute with the introduction of new UI layouts.
One of the original principles of Cogmind UI design was the desire to have all or almost all important information necessary for decision-making visible at all times on the main interface--stats, parts and their condition, inventory and item states, the map, the log, basically everything.
I like that by extension this means a single screenshot could be a comprehensive or at least very good indicator of a run’s overall state, either as a record or something to share with others. For that reason I’ve often considered facilitating a way to include one’s entire inventory contents in a single screenshot, since some builds might possess about 10~15 items that aren’t currently visible in the screenshot (some people have taken to sharing Cogmind’s stat dumps to provide that info, and more, in lieu of a screenshot, but screenshots tend to be easier to digest overall; other folks have literally stitched together their own screenshots to include a complete inventory…).
And now depending on one’s UI layout we might have not only zero inventory items visible in a screenshot, but also even a missing message log and list of allies etc. In that light, I guess the chance that I finally add such a feature will only grow going forward… I’ll be keeping an eye on the sharing scene among frequent players using these layouts.
I don’t have any mockups of “screenshot mode” for you now, but the idea is simply that some of the map area could be used to display the additional info.
A New Default
When the next Cogmind version releases, new and old players alike will be faced with a new UI layout. But which one?
The setting can be changed in the Options menu, but it needs a default, and even returning players who have a config file will be initialized to that layout. This will at least be a good way to get everyone to realize the new layout options exist (if they somehow miss the repeated news :P).
I really like the original layout (obviously), specifically designed to immerse with maximum information, at the cost of cell size perhaps requiring a large display. That might work for a relatively specific target audience, but Cogmind has many more players these days, players who come from a variety of backgrounds and with different setups, and they’d like to enjoy the gameplay, too, so some accommodation is necessary. One of the other layouts then, with larger fonts from the get to…
My original assumption was that the default would be the middle option--partially modal with most windows and info still visible, just the significantly larger text (yay for most people on laptops) and smaller map view (but still large enough). Leaning even more heavily in a modal direction for new players loses some of the overall atmosphere, plus hiding information can be bad. However, that may not be the case with what gets immediately hidden in Cogmind--the top-side windows aren’t essential for new players, and necessary messages are still shown and accessible… so maybe hiding windows is okay in order to let everyone see even more of the map at once? The message log being permanently visible doesn’t seem to imply that everyone will read it anyway--plenty of people miss important messages :P
The modal inventory has the largest impact on gameplay, and it doesn’t even take effect until part way through the game, at which point there is supporting QoL, and applies to both 45-row layouts anyway, so that doesn’t work in favor of either.
Results on a default: Inconclusive xD
This is the end of our multi-part series about building Cogmind’s fully upscaled semi-modal interface layout:
- History and Theory
- Holy Mockups
- Dynamic Terminal Swapping
- Simpler Lightweight Fonts
- Completion and Demos
Adventures in Map Zooming, Part 5: QoL
Map zooming again! Although I finished off the final bits of the core map zooming feature, that series went quiet when I turned my attention to planning and preparation for the upscaled UI, essentially due to my belief that once the latter is implemented, map zooming wouldn’t be as necessary in the first place.
But it would still no doubt be used by some, and more urgently I also realized that it wouldn’t make sense to put out map zoom test builds without including the additional QoL required to make a zoomed view actually playable in a normal sense. Although I rightly assumed few current players are very interested in zooming, some of them might at least test it out, and for proper feedback the QoL needs to be in place, otherwise any feedback will essentially amount to “needs QoL” :P
Good QoL is a make or break part of map zooming, where the real magic happens, and I love me some QoL design, so let’s see what we can do to facilitate zoomed play!
First of all, not exactly surprising or amazing, but one piece of the puzzle did suddenly fall into place here: scroll wheel zoom toggling. Back in the polishing stage I covered the reasoning for using methods other than the scroll wheel to zoom, but when putting together the QoL features I realized that zooming in and out might often be done in conjunction with map panning, which among several other methods can be accomplished by holding Shift and moving the mouse. Well if you’re panning with the Shift key held, using the mouse wheel wouldn’t do anything since that’s not a command yet (Shift-Wheel), so we can conveniently assign it to zooming!
That’s low-hanging fruit, though. We’re going to need much more powerful QoL…
Relative Centering
A common theme throughout map zooming QoL development is enabling the player to get information about, and react to, things that are outside the current map view. As explained in my article on the history and theory behind Cogmind’s interface and plans for other layouts, in a roguelike it’s crucial to have easy access to knowledge that affects near-term decision-making, and by shrinking the map view to increase the size of its content we’re giving up a lot of that easy access!
We need to find ways to retain it where possible, or at least create alternatives.
One of the most direct ways to accomplish this is to offset the player’s position from the center of the map. Normally Cogmind is shown at the center of the view, allowing the player to see equally in all directions, but technically we can assume that what’s most important while exploring the world is what’s in front of the player in whatever general direction they’d like to focus on. Thus one new optional feature is the ability to manually set a new relative centerpoint.
The above recording shows how setting such a point is accompanied by a fading cardinal crosshair animation akin to the drone centering/following animation, but here is grey instead of green. This keeps our visual theming consistent for the idea of interface-controlled “centering.” While a manual centerpoint is set, you can also see the intermittent flash of the current centerpoint, which is optional and can be adjusted or disabled. Restoring the default centering is as simple as setting your current position as the centerpoint.
How do you set that point, anyway? Oh no, it’s time to go… back to the engine! (are you counting? this is the fifth time :P)
I decided for this feature we are finally, after ten years, going to have RMB detection based on releasing the button. Cogmind has always responded to mouse down events for input, which I prefer since it’s that much more responsive, but the difference isn’t huge, and by forgoing that approach we gain access to a new realm of mouse input: holding the button for a different effect!
Now this alone doesn’t require any extra engine work, it’s just a different event we could always detect, but if you’re going to have input based on holding a key you probably need to know how long it’s been held, and for that we’re going to need more engine functionality. Paging the REX testing environment!
RMB has always been one of the other methods for panning the map in Cogmind, by just right-clicking on some location outside FOV, but now if you hold down the button for a bit longer (the default is 350ms, but it’s adjustable) it will not only pan the map over there but also set it as the new relative centerpoint, as seen in the demo.
As far as implementation goes, although a little more difficult to implement, it made more sense to cause the centering effect to occur immediately after a set time had passed, rather than simply waiting for the player to depress the mouse button after a minimum amount of time, because otherwise the player has to guess whether they’ve held down the mouse long enough to count for one input over another.
Dynamic Centering
Pure keyboard users need access to this recentering concept as well, though unlike with a mouse where it’s fairly quick to select a new forward point to center around, this isn’t so convenient to do via keyboard… We need an automated alternative!
By default whenever zoomed in keyboard mode, simple regular movement will automatically attempt to adjust the map view so that a more useful or pertinent area is visible at all times. Exactly how to achieve this is a big question, however :)
I’m sure no single algorithm will be perfect for everyone, but I experimented with five different possibilities before settling on a default. Most of these are included with the game as optional alternatives, and can also be completely disabled or further adjusted by specifying a maximum distance out to which they’re allowed to offset the view. Many of them feel quite strange at first, but with some actual play experience I got more and more used to the default as a helpful feature.
The behavior I actually chose for the default was a combination of the last two, gradually shifting the centerpoint with each move, and using a second pass to try to ensure that FOV edges are visible where it’s possible to shift the view without obscuring already-visible FOV cells. This is a pretty effective way to solve the corner problem, or whenever a large batch of new cells becomes visible, for example on passing through a door, or terrain destruction. It can also even keep the FOV shifted backwards if the current direction of movement doesn’t yet really contain much to see.
As with the mouse, keyboard users can also manually designate a relative centerpoint. This is done with the ‘s’ key in examine mode with the cursor over your desired target cell. Assigning a manual centerpoint deactivates the automation feature until designating Cogmind’s own position to reset it, at which point the automated system will again take over. This feature is also useful for quickly recentering the map to reset the automated system, by simply pressing ‘x’ to enter examine mode followed by an immediate ‘s’.
While playtesting keyboard mode, zoomed in for almost the entirety of play, I started to rather like the combination of default autocentering sprinkled with occasional setting of a manual offset for certain situations!
Notice that while in keyboard mode, the centerpoint highlight is not shown--that’s a mouse-only thing because it is automatic, and also at times quite near Cogmind’s own position.
Internally, the automated centering feature is implemented by simply adjusting the same offset variable used for manual centering, just doing it on the fly. So they’re the same mechanism. Automating this behavior during mouse-based play doesn’t really work because you have to be able to click on locations, including most importantly your next move destination, but that’s hard to pull off when everything is shifting around in a semi-unpredictable manner.
And even for keyboard mode, the automation behavior is only applied while the map is zoomed in, but it’s always being calculated and updated while not zoomed, so that zooming in again can continue to take the latest navigation information into account.
Of course I added new contextual tutorial content for these features, including Cogmind’s first tutorial messages that will eventually repeat themselves if you haven’t actually tried a given feature yet, because these are quite important :)
Offscreen Object Info
So far we have ways to try to keep important objects in view, but once you’re zoomed in on only a quarter of the normal map area it’s literally impossible to always see everything you might need to see in every situation. We need new indicators for important objects outside the current map view, especially those which are still within FOV (and probably even attack range!).
While manually panning the map or designating a centerpoint to keep an eye on a particular direction is useful, and temporarily zooming out to get a general idea of the surroundings is another option, to save time there are a variety of new markers that can appear at the edges of the map view to denote objects in that direction. You’ll see markers for offscreen hostiles, non-hostiles (both neutral and friendly), new items, and sensor data. Each marker category uses its own unique background color, and in the case of sensor data is also darker and blinks in and out to reflect the fact that it is not a directly visible object like the others. Items are only marked until automatically labeled for the first time after entering view.
We’ve seen such map edge markers before, for map intel (for example known interactive machine locations) and also Cogmind or drones currently out of view. The latter appear a couple rows away from the map edge, so there aren’t any issues with overlap, though intel would technically be able to overlap these markers, also being up against the view edge. I’ve updated those to not only reposition to avoid any offscreen object markers, but they also avoid covering visible robots currently at the edge.
Similarly, the new offscreen object markers will also avoid covering visible robots.
Offscreen Object Responses
Indicators are great, but not quite enough. After all, what do you generally want to do when a new threat comes into view? A quick visual check! What exactly are they, what’s their status, do they have company, what’s the surrounding environment like… These can be important questions to answer before making your next decision, and by default Cogmind already pauses for a moment in these situations in order to let the player have a moment to take it in (and avoid accidentally wasting valuable turns), so why not also use that opportunity to automatically shift the view over to spot the threat?
This feature is optional, but active by default.
Notice that the shift leaves one space of padding to the edge rather than putting the hostile right at the edge, which is harder to see and there may also be other markers present, plus it’s nice to know a little of what’s around the target.
There are also a couple other important threats that don’t involve direct sighting of enemies, but that most players would probably find worth automatically shifting to see for better situational awareness.
We can use this shifting behavior for more than just enemies, too!
Other Features
As part of this update I even added a completely new type of indicator, one that can come in handy even when not zoomed in. Sometimes those pesky Operators spot you and immediately zip out of FOV, much less out of view, on their way to their Terminal. At least there’s a log message reflecting that fact, though it may not be obvious where they were at the time. Now it will be.
Although available even while not zoomed, a new <HOSTILES> button that appears above the map while there are hostiles within Cogmind’s FOV was added primarily to facilitate play while zoomed in, offering another way to know and confirm that there are hostiles in line of sight, even if not currently in view. The button reports the total enemy count, and can be pressed to focus on and highlight the largest concentration of enemies. Pressing it again restores the centerpoint to its original area, or in some cases if there are other enemies not visible in the first highlight area it may be able to determine that and focus there instead.
I also have notes on even more QoL ideas for map zooming, as well as ways to further extend these new features, but this seems quite good enough for now and we’ll have to see how more playtesting pans out.
Shortly before the first testing build went out I did my own playtest run, trying out both mouse and keyboard play while zoomed… it went well!
We’ve arrived at the end of our five-part adventure through the process of putting all this together:
Full UI Upscaling, Part 4: Simpler Lightweight Fonts
So we’ve developed the theories, we’ve got mockups, we’ve got the necessary architecture… surely it’s time to start building the new UI layout, yeah? Not so fast!
It’s true we could start now, but on the horizon I could already see the increasing usefulness of another supporting feature, and decided it was a good opportunity to finally automate Cogmind’s font scaling.
Cogmind has always included many fonts available at many different sizes, all of these stored as bitmaps for pixel-perfect crispness. Each requires its own image file, and in the past I have always manually upscaled them to ensure availability at the appropriate higher resolutions, which means even more files.
Well with the advent of map zooming, which itself needs 2x upscale versions of all fonts within each set, and this whole UI upscale project, which unlocks an average 33% font size increase for everyone, we’re going to need quite a few more upscaled bitmap font files and going forward it doesn’t really make much sense to keep doing this manually.
REX, Again Again
Okay if anyone’s keeping count this will be the fourth time I’ve revisited the engine for a major update since starting map zoom and UI scaling work xD
Hi, REX.
I thought this would be a quick project, but it actually took several days to finally finish this feature because I ended up rewriting a lot of the engine’s font handling code, encountering a few challenging (hair-ripping) bugs along the way. The original system had made a lot of assumptions which would no longer hold true, and I wanted more features on top of the autoscaling as well, like only generating upscaled fonts once they’re actually needed (yay for faster startup), and having all font sets reusing the same source file share a single reference image in memory rather than having multiple copies of the same bitmap. Individually nothing too complex, just a lot of changes necessary to the original architecture to make these features possible.
Once again back in the good old REX testing environment, I set to testing two new syntax options for the font set configuration file:
- “NewFontName [SourceFontName*2]” would create an entire new font set by upscaling an existing one, in this case by a factor of 2. (A font “set” means a collection of text, tiles, zoomed text and so forth, all categorized under a single name and selected as an option by the user.)
- “<source_image_name*3>” is a sample of syntax usable in any single field for a bitmap font source image, instead taking another image and upscaling it by the specified factor.
This same format is used by anything else built on the engine, so both Cogmind and REXPaint can benefit from this, the latter of which I hope to also release a new version before long!
Cogmind Applications
Cogmind’s last public release, Beta 12, includes a total of 118 bitmaps font images, and that was before all the map zooming and Beta 13 work, so without this autoscaling feature that number would balloon significantly.
As of writing, Beta 13 has currently dropped that file count to 80, this despite the zooming, nine brand new font types, and supporting even more large options derived from smaller ones.
I had to spend a while going back through all those files to confirm which were original files and which were upscaled--in most cases there were records, but I had to be sure, and did find a few outliers to which I made further manual modifications to their upscaled versions, or sourced from multiple different sets. Those required special treatment, but otherwise it was really nice to cut down on the clutter.
As of the current Beta 13 prerelease, the current max font size included with Cogmind is 48, needed for 5K displays, but with the new upscaled UI the max needed for that resolution will be 64! Definitely about time to get automated scaling…
New font sizes aside, this also saves time when new tiles are added and need to be inserted throughout the images, since tiles themselves are also part of the font bitmaps. Tiles aren’t added very often, but a new batch is indeed being released gradually over the next several versions.
Since I was working with fonts anyway, I also took advantage of this opportunity to add brand new options! In classic terminal roguelike style, some people like to switch their display font after a while in order to freshen up the whole experience, so in addition to others who simply want more options from which to select their favorite for readability or stylistic preferences, that’s another good reason to make sure there is a good variety of styles available.
The main two new typefaces are Tamsyn and Cherry, available at several sizes.
While I was at it, I also made other font-related improvements, like having Cogmind’s options menu list fonts from largest to smallest to be able to more easily adjust style via the menu without changing map size. The original approach based purely on how they’re listed in the config file didn’t make sense, and I’m not sure why I left it that way for so long.
Pixel Corruption
Shortly after releasing a build with autoscaled fonts to patrons, a wild bug appeared! Apparently some people were seeing artifacts on the display…
At first we weren’t sure what it was, since it was only affecting a few people, and recent SDL DLL optimizations aimed at improving rendering speed had also been introduced as well. But bugs aren’t all that elusive if they only affect some people and a discernible, repeatable pattern emerges, which happens to be the case here. That these artifacts only appeared for players using very high resolutions suggested it might be an issue with font scaling, since all of the high-resolution fonts are upscales.
So I set up a bunch of tests to confirm, and eventually found that some large fonts ended up with these artifacts when scaled, and in all cases had a scaling multiplier of at least 3. How weird!
Anyway it’s now even more clear this has gotta be something with the scaling process, right, for which I had actually just plugged in SDL_gfx, a common companion library for doing this sort of thing. Cue stepping through its zoomSurface() function, specifically zoomSurfaceRGBA(), and while comparing how it handled a 2x vs a 3x scale operation, I noticed that there seems to be… a bug in the library?
I’m kinda surprised since this library has been in relatively wide use for over two decades, and even continues to be used alongside subsequent SDL versions, but that code remains the same. Maybe most people tend to use it with smoothing/antialiasing turned on (I had it off because I want crisp), or are using less tightly packed tilesets (or even separate files for their images), all of which may help conceal such an issue from discovery? Or maybe there’s something else at play.
I replaced that whole optimized method with my own brute force scaling solution and *poof* the problem indeed disappeared. It’s only rarely called anyway--as mentioned before fonts are only scaled when they’re first needed, not before or ever again afterward, so we don’t need to worry about performance. (And anyone who actually does need to worry about performance should probably avoid doing this in software mode in the first place :P --that’s probably where all the other potential bug finders went off to…)
This is the fourth in a multi-part series about building Cogmind’s fully upscaled semi-modal interface layout:
- History and Theory
- Holy Mockups
- Dynamic Terminal Swapping
- Simpler Lightweight Fonts
- Completion and Demos
Full UI Upscaling, Part 3: Dynamic Terminal Swapping
I was really happy to have come up with workable concept for a modal inventory, as well as producing a mass of mockups with proven solutions for all the potential hurdles on the road to dropping 15 rows from Cogmind’s interface. Or so I thought.
Suddenly at the end of that process, a review of remaining UI systems revealed an unexpected show-stopper: ending animations.
Cogmind has a lot of different endings (currently nine, with more to come), and all of them feature full-screen ASCII animations. While some of these are flexible enough to fit dynamically within any terminal dimensions, a good many were designed to assume a height of 60 rows. The only way to fit those into 45 rows would be a complete redesign…
I put a lot of time into the existing animations, and they make good use of their space, so one would hope there must be another way…
Terminal Swapping
What if… the terminal was still 60 rows during ending animations?
After all, there’s no strong need for the endings to be limited to only 45 rows--you’re essentially watching these animations for the overall visual effect rather than needing to interpret every little detail for gameplay purposes. As described at the beginning of this series, the reason for shrinking the base terminal dimensions is to enable larger fonts across the board, but the intent there is to facilitate reading and interpreting details, which we don’t need in this case.
So the theory is we use a 45-row terminal for normal play, but once we need to do an ending animation simply switch over to a 60-row terminal to display that, then switch back when done.
This reminds me of games that switch to a different display mode specifically for cut scenes, especially common (and noticeable) in early video games, and then later it became a big deal when those sorts of things could be done “in engine,” which is the norm nowadays. Cogmind has always been consistent about its display, but in this case I could ideally continue to make use of all the work that’s already gone into the animations.
Now come the important questions: Is the engine architecture capable of such a feature, and what other roadblocks might be in the way?
Technically the idea immediately showed some promise based on the fact that Cogmind already uses what I call “terminal swapping,” but only between frames and behind the scenes, specifically for special screenshotting purposes.
The main usage is for map output, or creating a composite PNG containing the entire current known map. This is useful for sharing interesting layouts with other players, or asking for advice about where to explore.
I also used it to produce an image marking the launch of Cogmind’s achievements, for which I wanted the background to be a matrix of many achievement icons.
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, like I did not too long ago with the quads and octs powering the map zooming system.
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.
It took about a day to implement terminal swapping and work out all the kinks.
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 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 zoom text 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 in the massive scoresheet data, 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 ;)
This is the third in a multi-part series about building Cogmind’s fully upscaled semi-modal interface layout:
- History and Theory
- Holy Mockups
- Dynamic Terminal Swapping
- Simpler Lightweight Fonts
- Completion and Demos