Fanfiction – Loopholes

I decided that this story is so different from the usual Zero no Tsukaima/Familiar of Zero fare that it deserves a full review of its own.

Loopholes by DschingisKhan

The basic plot is that Louise summons Tabitha from across the field (after she summons Sylphid, though that’s not really emphasized much) instead of Saito from another world.

Naturally, this throws the canon dynamic completely out the window even before Kirche invites herself into the group and it’s the feel and focus that makes this story so noteworthy. It focuses a lot on the characters’ thoughts and emotions.

For example, when the tone swings light, like the the time Kirche grabs the suspicious cloaked figure coming to Louise’s room, only to discover she’s just molested the princess, the overall dynamic actually feels like what I might come up with if I were to try to take the feel I enjoyed in harem romantic comedy anime like Ai Yori Aoshi and then stir in a liberal dose of what I’ve seen in shoujo manga. A lot more focus on their thoughts and feelings and minimal tacky fanservice-y stuff aside from Kirche occasionally being too Kirche. With no male protagonist, there’s instead hints at a possible future intent to blur the line between friendship and romantic interest between multiple female characters.

When the tone swings more serious, we get to see Kirche showing her more serious, more competent side… and her emotional baggage. Not for too long at a time, of course. Kirche wouldn’t be Kirche otherwise.

With her familiar being female, a fellow noble and mage, and not someone who irritates her, Louise has little provocation to act her canonical tsundere self and, combined with the amount of focus spent on seeing things from her perspective, I actually spent the first couple of chapters double-checking that she was sufficiently in-character because it’s such a departure from the norm.

That said, It does feel like there’s room for improvement in the writing style at the beginning. There were parts that felt like they were missing something they needed to connect. Given other evidence, like the short length of the early chapters and one of the examples I was able to put my finger on, I think it’s that the writing style was too brief and didn’t have enough flow.

On a couple of occasions when I’d stayed up late reading, I found the process grinding to a halt. I’d slipped into skim-reading, and the style made it too easy to miss an important detail which completely changed the mental picture for the following few pages.

For example, in chapter 6, in the “under ordinary circumstances” sequence, I somehow missed the fact that Tabitha had whistled for Sylphid and taken Louise airborne and didn’t realize something didn’t match up until a whole screenful of text later, at which point my befuddled mind had to read backwards up the page to figure out what I missed. It’s very rare that I run into something where the implications of such a major change don’t flow into the prose after, providing a supporting cue that I was about to skim over something very consequential to the mental imagery.

I’m still not sure about the later chapters to be honest. It’s just such an alien feeling to see Louise knuckling down and being that reliably serious and competent.

That aside, once it gets over its teething problems, it’s a very pleasing read and I like how it takes proper advantage of the opportunity to address canon events differently. For example, with Tabitha managing to get Fouquet/Mathilda’s story out of her, recognizing a kindred soul, and insisting that she come back with them so they can try to help her… which then flows into a very significant divergence from how canon events unfold.

Overall, it’s definitely worth a read and I’ll give it a tentative 4.5 out of 5 despite its flaws. Given how significant a divergence from canon and shift in tone it makes so close to the end of the chapters which have been written, I don’t yet have enough information on the author’s strengths and weaknesses to guess whether it’ll maintain that rating going forward.

Posted in Fanfiction | Leave a comment

Platformer Design Trends: Then and Now

I started playing Celeste a couple of days ago and, while I was playing it, I started tallying up some of the ways that the average modern platformer, retro-styled or not, differs from its counterparts in the 80s and 90s.

This isn’t an exhaustive list… just what came to mind while I was playing or while I was writing this.

Retired Arcade Mechanics

These are the archaic mechanics which are so overtly unhelpful that I can’t think of a single modern platformer in my collection that gets them wrong.

No Time Limit

In the early days of home platformers, they were still drawing a lot of influence from arcade machines, where the goal was to maximize the number of quarters machines took in per hour.

In that environment, a time limit makes sense to set an upper bound on how much time a player can spend on a single payment without also paying in skill. (Of course, earning more time with skill was allowed because it motivates player engagement.)

In home games, that rationale is absent, and you want to encourage the player to recognize and enjoy all the effort you put into building the game, so modern games usually solve this problem by tracking how long you take but not imposing a limit… which is even more useful to competitive players who actually care about the time taken.

A notable exception is Sonic The Hedgehog for Sega Genesis, which feels ahead of its time in this respect, but not far enough. It has a timer that ticks up, allowing you to easily note down your completion time for each stage, but, when it hits 10 minutes, you unexpectedly die with a “TIME OVER” message. (Granted, you should never even discover that time limit exists unless you’re exhaustively exploring the level… but why have it in the first place?)

As someone who enjoys platformers with an exploration component to their mechanics, like Super Mario World, I say good riddance to arbitrary time limits in games. (I’ll touch on time limits that are integral to the mechanics later.)

No Life Counter

It’s pretty obvious that lives were a means to milk more quarters out of players which then got adapted to home consoles as a way to artificially lengthen the game.

Yes, they increase the challenge, but it’s very frustrating to lose large amounts of progress and be forced to replay earlier areas to practice later ones.

(After ruining Warcraft 2 for myself when I was a little kid by cheating too liberally, I decided that “infinite lives” is the only cheat code I’ll use when playing older games… a rule I still follow.)

Having a limited number of lives also penalizes player experimentation, which is never a good thing because it makes them less likely to discover less obvious game content or mechanics.

No Score Counter

This is another mechanic which developed in the arcades and was already pretty useless and ignored by the time Super Mario World incorporated one. If you don’t have a high score list in a public place, there’s no reason to have a score counter.

For modern platformers, the mechanic that replaced this is some blend of public achievements and public leaderboards.

(In the interest of fairness, I will say that neither of those are my thing because I prefer to play only what I can archive to re-experience later, and the online social aspect of gaming isn’t as reproduceable as inviting some friends over for local multiplayer. If a game doesn’t offer offline achievements, I don’t bother collecting them.)

Less Simplistic Mechanical Changes

Tighter Controls and Agility-Oriented Gameplay

If you go back to play a platformer game from the 1980s or 1990s, they tend to feel a little stiff and sluggish until you get used to them.

Whether because they don’t have multiple movement speeds, like Super Castlevania IV, or because their long acceleration curves make the character feel heavy (slow to start and slow to stop) like NES and SNES Mario games. Even the best ones usually do this.

I’ve noticed that, ever since the Nintendo 64 introduced the analog stick and Super Mario 64 incorporated the wall-jumping mechanic originally found in games like Ninja Gaiden, the popularity of agility-oriented gameplay has skyrocketed among developers.

Now, keep in mind that agility-oriented gameplay doesn’t require analog controls. Guacamelee! has so many moves that the pause menu has a reference chart and it still only has the digital stop/go movement you’d expect on a platform without analog sticks.

Hollow Knight takes it even further by giving you perfect air control (no horizontal movement inertia in any circumstances I could identify) but the game is tuned so that I didn’t even notice the character has no movement physics beyond basic gravity until I was writing this post. (The level design never makes you want to precision-platform at a speed less than the run you’re stuck at, the lack of a deceleration curve keeps the character from feeling slippery, and character and camera animation are used to keep the instant response to control inputs from feeling cheap and lazy.)

Don’t get me wrong, I’m not saying every platformer should be about agility, but, all else about a game’s input response being equal, an agile character certainly helps to reinforce the sense that, if you fail, it’s because of genuine challenge, not bad controls.

Even with its ledge-hanging and double-jump mechanics, Odallus: The Dark Call makes a good example of this principle. While it keeps the restricted color palette, limited animation, and limited attack mechanics of NES action platformers, the character responds instantly to all inputs, and the way the camera follows him has a distinctly modern polish to it.

I should also make it clear that responsiveness doesn’t imply fancy movement mechanics and vice-versa. Dustforce is an example of a game which annoys me because, for something with so many agility-based mechanics (double-jumping, wall-jumping, wall-running, dashing, etc.), the controls are sluggish by design (I e-mailed the developers) to enable the kinds of fancy animation dynamics they wanted.

Reduced Death Penalty

You’re gonna die. Failure is part of learning and, in 80s and 90s platformers, you couldn’t get this more wrong than the “one life, no continues” games James Rolfe has done send-ups of in The Angry Video Game Nerd… but even without that, most games still made dying a pretty punishing experience.

Whether it’s giving you a limited number of continues or making you sit through an annoyingly long Game Over cutscene in Castlevania: Symphony of the Night, the implication was “players need to be Skinner Box‘d into not dying”.

That said, given how long it took for PC games to recognize that the mantra of “save early, save often” was just code for “make the player implement checkpointing manually without a solid reason”, I won’t hold it against them too much.

Modern games, on the other hand, vary widely in how frequently they checkpoint you. (I found Celeste’s checkpoints to be mildly annoying at times, such as the moment during the fight with your alter ego where you have to get through three or four screens of precision platforming before it’ll checkpoint.)

Super Meat Boy is probably the purest example of the direction platformers have moved in this respect. Not only is there no life counter, and frequent checkpointing (in the form of small levels), the game goes out of its way to optimize for a death-heavy play style. From the beginning of your death animation to when you can start moving after respawning is less than two seconds, and, after you finish the level, it shows a simultaneous replay of all your attempts, making your deaths more worthy of a smile than a groan.

For larger levels, true checkpointing becomes more important and Shovel Knight does a beautiful job of this by providing an in-universe way for the player to dial in on their preferred difficulty in fine detail: By breaking checkpoints to get more loot. In fact, I want to say a little more about this…

Difficulty Selection

Traditionally, if a game wanted to have multiple difficulty levels, you’d choose from a difficulty selector beforehand. This has two problems: First, you don’t know how your estimation of your skill compares to the developers until you try it and, second, you can’t change your mind without restarting.

Some older games, like Double Dragon II add insult to injury on this front by not telling you that the true ending is only available on the hardest difficulty until you’ve struggled all the way through a lower difficulty level.

Modern design instead favours a more organic approach to difficulty, where the player can fine-tune the challenge as they play, and the game mechanic incrementally encourages the player to take on greater challenges.

The crudest, simplest way to accomplish this is replacing a difficulty selector with some form of system for skipping levels that you’re struggling with, but I’d argue that it’s better for difficulty to be additive instead of subtractive (optional extra challenges) and to not break the immersion the way a “skip” option does.

I especially don’t like how Nintendo does this in recent Mario games with its Assist Blocks, where, if you fail a level too many times, it shoves the offer of a cheat code in your face. Sure, offer a “skip” mechanic, but don’t shove it in our faces when we’re trying to “git gud”. Instead, do something like Goblins Quest 3 where there’s help if you go looking for it, but it’s just an always-present toolbar option like any other.

Shovel Knight does this sort of thing much better with its “break checkpoints for extra money” mechanic. Not only does it give you fine-grained control over what’s easy and what’s hard, it’s also very organic, it gives you an incentive to challenge yourself, and it ensures the devs can’t be tempted to make the easy mode patronizingly easy because the easy mode is the default everyone will see.

A more common approach is what you see in games like Celeste, Super Meat Boy, VVVVVV, and New Super Mario Bros. where you have a system of collectables and possibly hidden challenge levels which aren’t required to beat the game. (Be very careful about requiring players to get all of a level’s collectables in a single run, though… it can easily lead in the same direction as the “no checkpoints, limited lives” paradigm of 80s games because the underlying problem is the same. “I have to do all that over again because of one tiny little mistake!?”)

Personally, I prefer the Shovel Knight approach because the collectable-based approaches tend to leave you feeling that you haven’t beaten the game without “getting the true ending” while the Shovel Knight approach is more of a “play at your own difficulty level” mechanic.

I read that the Switch Palaces in Super Mario World were meant to be this, but they still have that flaw that, once you’ve lowered the difficulty level, you have to start a new game to raise it again.

Skippable Cutscenes

A lot of old games force you to just mash buttons to rush through cutscenes, while modern games generally provide a “skip cutscene” option somewhere.

Why did it take until the 80s generation grew up and became game developers to recognize that we don’t want to sit through stuff we’ve already seen?

Sadly, this is still a change in progress since modern developers generally don’t get that we also don’t want to sit through the on-startup logos.

(In the worst cases of this, it makes me want to install the game in a virtual machine that has suitably good 3D guest drivers and “suspend to disk” the whole virtual machine instead of quitting the game.)

Going Above and Beyond In The Name Of Fun

This is probably the least obvious difference. In fact, it’s one I had to be told in Game Maker’s Toolkit’s video, Why Does Celeste Feel So Good to Play?.

In short, a modern game knows when to cheat in your favour.

In an NES or SNES game, if you press Jump a split second too late when walking off a ledge, you’ll fall. This is technically accurate and fair, but it feels needlessly frustrating when the core purpose of a game is entertainment.

In Celeste, by contrast, you can still initiate a jump for a few frames after you leave a ledge. This is referred to as coyote time by game developers. It’s one of several ways the game goes out of its way to fudge reality to match expectations, and is akin to how the Parthenon‘s architecture isn’t actually made of straight lines [2] but, instead, of curves that compensate for the effects of optical illusions.

An example that’s easier for the player to notice, but still welcome, is erring on the side of small hitboxes. “Nobody ever complained that their character’s hitbox was too small”.

This sort of “deceiving the player to improve their enjoyment” is common in game design, an important part of tuning the play experience, and it makes perfect sense that 30-40 years of progress would have turned up more ways to do it.

It also applies to stuff that is mechanically the same, but looks different. For example, it feels much better to be killed by something in-universe, like the pursuing monster in Castlevania: Rondo of Blood and its remake, and to retain the ability to move the camera normally, than to have a traditional self-scrolling level where you can be crushed between the edge of the screen and an on-screen object. Speaking of which…

Keep the Player In Control

The biggest thing that Trine got right about storytelling was overlaying character dialogue on top the beginning of the levels. The biggest thing it got wrong was aborting the pre-level narration when you start the level.

Whether it’s cutscenes, forced or otherwise, or a self-scrolling camera in an old-school self-scrolling level, players don’t like having their illusion of control broken. As Rebecca Heineman said in an interview I watched, “I don’t want to watch a movie. I want to play a game.”

The more you can keep the player in control, the more satisfying it will be. Tight controls, playing narration or dialogue over active gameplay instead of using cutscenes, using in-level hazards instead of scrolling cameras, simplifying the traditional SCUMM UI’s unnecessarily diverse choices for actions in Monkey Island 3… anything that breaks down that sense that the player has had control arbitrarily taken away from them is good.

The remake of Castlevania: Rondo of Blood (Castlevania: The Dracula X Chronicles) is actually a step backward in that respect because they pause the gameplay and move the camera to make the arrival of the pursuing monster more “cinematic” before returning control to you so you can run away from it. (Luckily, you can unlock the original version of the game so you can experience it as it was meant to be.)

Automapping and Objectives

Look at a classic game, like Metroid …or even Super Metroid and you quickly realize that, if you haven’t been playing it for a while, you’ve probably forgotten what you need to do next. Good interface design isn’t just about having an automapper in a non-linear platformer, but about minimizing the drudgework of keeping track of player progress.

I won’t say much about games from the 80s and 90s, since, so often, they didn’t even have the system resources for an automapper, let alone a proper objective tracker. Instead, I’ll focus on what is still being learned today.

Celeste is actually a game that could use some improvement on this front. It may be linear between levels, and it does get you used to the idea that moving from one scene to another could trap you in the new scene, but the levels feel a little Metroid-like at times, with it being unclear which branch will take you to a collectable and which branch will take past a one-way boundary and then to the end of the level.

That said, for a full open-world or Metroidvania game, the problem is usually insufficient mapping or objective-tracking support. Take, for example, the freeware Treasure Adventure Game. I put it down for too long and now I’m reluctant to pick it up again, because I have no idea how much wandering around I’ll need to do in order to get back on track.

A much better example would be Aquaria. Yes, it distinguishes discovered regions and visited segments of them in the automapper and marks permanent points of interest, like Super Metroid, but it also allows you to put pushpins on the automap in two different colors and type a description into each pin. I’m surprised this isn’t standard in every Metroidvania. It’s not perfect, lacking auto-filling of quest markers, but I’m not sure I’ve seen a perfect automapper yet.

Hollow Knight approaches this from the opposite direction, with an automapper that does automatically fill in quest markers, but doesn’t let you type a description into your arbitrary markers, gives you a limited number of them, and you have to buy them.

…but hey, progress is progress, right?

Narrative and Diversity

Now we get to the part that’s about what story is being told, instead of how it’s told.

First, I want to remind readers that I’m not saying all games need to have these aspects… just that the market had a dearth of them back in the glory days of 2D consoles.

Like with the Bechdel Test, these are about the market meeting the diverse demands of the customer base, not mandatory changes for individual games. (Because a lot of people don’t realize that. The Bechdel Test isn’t about any specific movie but about “If 50% of customers are women, it stands to reason that about 50% of movies should easily pass this test.”)

So, with that said, what’s happened in the last 30-40 years?

Well, in early platformers, there was an overwhelming preponderance of “man being the hero” plaformers, whether it was Mario rescuing Princess Peach, Bill and Lance saving humanity from Red Falcon in Contra, or less iconic things in the same vein like the adaptations of countless action movies.

That still happens. For example, Super Meat Boy is an over-the-top caricatured love letter to those days with its gratuitous gore, gratuitous difficulty, and a gratuitously “rescue your kidnapped girlfriend” plot. (Seriously, you’re up against a fetus in a mecha suit dressed like Professor Fate from The Great Race (and countless stereotypical “girl on traintracks” moustache-twirling villains) and he ties her back up and spirits her away again at the end of every level.) It’s one of my favourite modern platformers, but I wouldn’t want every game to be Super Meat Boy, just as I wouldn’t want every book on my bookshelf to be sci-fi, no matter how much I enjoy it.

So, with that said…

Rich Storytelling

It’s true that gameplay is the most important thing in any game, and storytelling is optional. Just look at a puzzle game I’ve sunk countless hours into, like the Hexcells trilogy. However, people will always experiment with any new medium as a way to tell stories, and, if you’re trying to tell stories, you might as well give it your all.

Whether for technical reasons or not, old games tended to have little narrative in the game, relying on varying amounts of narrative in the manual and your imagination to find the story if you cared. (Wasteland being an extreme example of the former. It’s an RPG, the original story-heavy genre, but the game keeps referring you to the manual because the text couldn’t fit on the disk. Modern re-releases resolve this inconvenience and fold the text into the game itself.)

Modern games, on the other hand, tend to go too far in the opposite direction, being so obsessed with telling a story that it detracts from the gameplay experience. I’ve lost count of the number of games I’ve played where I was watching a cutscene or paging through dialogue windows and all I could think is “Yeah, yeah. The game hasn’t even started yet. Just let me play!”

I mentioned Trine before, because I love how it manages to demonstrate one way to resolve this conflict. If pressing the start button after loading a level finishes didn’t cancel out of the narration, it’d be perfect.

Reduced Gender Stereotyping

I’m not stupid enough to try to argue that gender stereotyping has been banished from games, but this difference should be pretty obvious.

In the 80s, it was just taken for granted that non-puzzle games were primarily about manly men doing manly things, rescuing damsels and so on, and you were a lot more likely to see artwork inspired by the “bikini-plate barbarian” aesthetic meant to draw men to fantasy novel covers.

There’s nothing wrong with a game about a hero and, if a guy wants to look at some scantily-clad ladies, more power to him… but the market seems to have grown a bit more taste since then on the “scantily clad women” front, and I don’t think Super Princess Peach would have felt as cringe-y if it came out back in the 80s instead of in 2005.

(It’s a Mario platformer where the player’s secondary abilities are emotion-based, with Peach crying on plants to grow them and so on. If you remember the hullabaloo about Metroid: Other M, Super Princess Peach just reinforces what a skewed perspective on women Japanese game designers have.)

Not Every Conflict Is About Heroic Intent Or Proving Yourself to Someone Else

Maybe it’s because fighting games had so much prominence in arcades, but it feels like, once arcade narratives grew beyond Missile Command and Defender, every game had something to do with either racing, rescuing a damsel (eg. Double Dragon), proving your might (eg. Mortal Kombat), or some other heroic or manly activity.

If the gameplay is good, I’ll play it, but if you look at modern platformers, they seem to have bifurcated into two groups:

  • Games which intentionally keep the story minimal or nonexistent, like You Have To Win The Game or Towerfall: Ascension.
  • Games which embrace the storytelling and are made by people who’ve grown tired of the old clichés.

Celeste is one example of the latter, being a story of a girl named Madeline who’s decided that climbing Celeste mountain will help her to work through her psychological issues, but another great example would be Thomas Was Alone… a puzzle platformer about several pieces of data in a computer which really made me feel for them.

Outside of the technical aspects, I’d argue that this “we’ve grown tired of telling the same story over and over again” element is the biggest change from the 1980s. (Probably due mostly to how much technological progress has reduced the barrier to entry, allowing individuals to show the industry that demand exists for a wider range of stories.)

Female Leads

Outside of Samus Aran from Metroid, who you didn’t know was female until you beat the game, “let’s get some hot chicks in skintight outfits jumping around” characters like Cammy White from Street Fighter, and Ms. Pac-Man, how often can you remember 80s games having female leads?

Granted, the stereotypes of the period were against women playing video games, so you can’t just say “Bechdel Test”, but go a level deeper and the problem is pretty obvious. We’re all human, with fundamentally the same psychology, so, if that social pressure is omitted, the same “50% of the customers, 50% of the media” relation still applies… I’m just glad we’re finally seeing that kind of equality coming to pass.

Aside from just being fair, the average man and the average woman do get socialized differently.

Look at Knytt Stories, where it feels much more obvious to have an atmospheric, Hobbit-like approach to the “Save the World”-style plot of the first episode without the cultural baggage of a male hero. I think this is what Hayao Miyazaki is getting at when he tries to explain why he prefers female leads in his movies. Especially in Japan, there’s a lot less cultural baggage about what a female hero’s motivations should be.

Let’s go a step further. Look at Ittle Dew. A charming, tongue-in-cheek game that I just can’t see being made in the 80s or early 90s, because part of the humour and charm comes from the type of tomboyishness the heroine manages to exude. (An organic sense of being female, yet expressing that same facet of humanity that makes little boys “act gross”.)

In the end, I think proper progress in storytelling is intrinsically tied to society relaxing, so storytellers feel comfortable telling all the stories.

Posted in Web Wandering & Opinion | Leave a comment

Automated Testing for Open Watcom C/C++ and DOS

One of the hobby projects I’ve been poking at again is written for DOS using Open Watcom C/C++ (v2 fork), and, being as averse to drudgework (and spoiled by modern tooling) as I am, I wanted some automated testing… so I wound up doing another blog-worthy survey of the field.

Unit Testing

Funny enough, there are actually several easy-to-use unit test frameworks that will build perfectly well with Open Watcom C/C++ v1.9 inside DOSBox… and that is the first test. There’s no point testing anything further if it’s not compatible in the first place.

TL;DR: greatest is the greatest.

greatest (ISC License) (My Recommendation)

This is probably the best bang for your buck if you want a simple test harness for your DOS projects. Just drop greatest.h into your project, add a few GREATEST_MAIN_* macro invocations to your test .c file, and start using RUN_TEST or RUN_SUITE and ASSERT_* macros.

#include "greatest.h"

TEST test_func(/* arguments */) {
    ASSERTm("Test string must not be empty", strlen(some_arg));
	
    /* ... */
    ASSERT(foo);
    ASSERT_EQ(bar, other_arg);
	
    /* ... */
    ASSERT_STR_EQ(baz, some_arg);
    PASS();
}

GREATEST_MAIN_DEFS();

int main(int argc, char **argv) {
    GREATEST_MAIN_BEGIN();

    RUN_TESTp(test_func, /* args */);
    greatest_set_test_suffix("other_args");
    RUN_TESTp(test_func, /* other args */);
    /* ... */

    GREATEST_MAIN_END();
}
screenshot

It’s also surprisingly featureful for something so simple:

  • It claims to work with any C89 compiler, does no dynamic allocation, and I had no problem building and running a real-mode executable from it inside DOSBox.
  • It supports passing a userdata argument to a test function with RUN_TEST1, so you can define your test once and then feed it various different inputs.
  • If you’ve got a compiler which supports the requisite C99 feature, you can use RUN_TESTp to invoke a test function with an arbitrary number of arguments (And I did use RUN_TESTp in my real-mode test .exe)
  • It provides SET_SETUP and SET_TEARDOWN macros which accept userdata arguments.
  • It’ll handle --help for you, but can also be invoked as a library for integration into a larger executable.
  • It’ll give you the familiar “one period per successful test, but verbose output for failing tests” output by default but there are also contrib scripts for colourizing the output or converting to TAP format.
  • It supports filtering which tests get run and listing registered tests from the command line.
  • It supports macros to randomly shuffle the order of tests or test suites to reveal hidden data dependencies.

For something that works with Open Watcom C/C++ v1.9, the experience is surprisingly reminiscent of Python’s standard library unittest module.

While it lacks some “check this and show the values if they fail” assertions I would have preferred, such as greater/less than comparisons (ironic for a library named “greater”), there’s a PR which would add them that you can grab instead and the author is considering them for the next version.

The only wart I noticed is how the assertion macros interact with helper functions. (The assertion macros work by returning enum values, so helper functions which use them have to have a return type of enum greatest_test_res and you have to wrap calls to them in CALL() to conditionally propagate the return.) That said, that’s a minor problem and I am a fan of making good use of return values to avoid hidden control flow and unnecessary side-effects.

All in all, a very nice little harness to choose for retro-C projects… or for any C projects that don’t need something fancier, really.

Unity (MIT License)

This is the next step up the complexity ladder but it’s primarily designed for embedded development, so its features are more poorly aligned for desktop development.

  • It’s split into three files (two headers and a .c file)
  • It doesn’t handle argument parsing (No --help, no test filtering)
  • The introductory documentation has a lot of “Here’s how to do this with microcontrollers and your favourite non-Watcom build system” content that can get you side-tracked if you’re not careful.
  • Because it’s designed to make microcontrollers first-class citizens, it’s got a lot of ASSERT macros which are just more specialized versions of what greatest offers. (eg. TEST_ASSERT_EQUAL_HEX8)
  • It expects you to have one setup and teardown function per file, rather than providing a macro to register them with arguments to pass in, so you may have more code duplication.
  • I couldn’t find any evidence that it provides an equivalent to greater’s RUN_TESTp for calling a template function with varying arguments.
  • The assertion macros are more verbose. (TEST_ASSERT_TRUE_MESSAGE instead of TEST_ASSERTm)
  • Its default configuration depends on more of the standard library, so I had to remove some of my compiler flags intended for size optimization to get it to build.

Going from greatest to this reminds me of going from POSIX to Java or Windows APIs.

On the plus side, it does have some advantages:

  • It comes with a lot of documentation, including a printable cheat sheet for the assert macros.
  • If you don’t mind the lack of “develop DOS software on DOS” purity, it includes some ruby scripts to generate test boilerplate for you.
  • It has a few “automatically pretty-print on failure” assertions that greater is missing, like array and bitfield equality tests.

…but still no less/greater than pretty-print macros!

Once you ignore the flood of details in the introduction that are irrelevant to DOS retro-hobby development, it becomes pretty clear that writing a Unity test suite is almost identical to writing a greatest test suite.

Drop the three Unity files somewhere your compiler can find them, tweak your makefile to also build and link unity.c, and then write a little test program:

#include "unity.h"

void setUp(void) {}     /* Required or it'll fail to link */
void tearDown(void) {}  /* Required or it'll fail to link */

void test_a(void) {
    TEST_ASSERT_TRUE_MESSAGE(strlen(some_arg), "Test string must not be empty");
	
    /* ... */
    TEST_ASSERT_TRUE(foo);
    TEST_ASSERT_EQUAL_UINT(bar, other_arg);
	
    /* ... */
    TEST_ASSERT_EQUAL_STRING(baz, some_arg);
}

int main(void) {
    UNITY_BEGIN();

    RUN_TEST(test_a);
    /* ... */

    return UNITY_END();
}
screenshot

Final verdict: It’s certainly nicer than JTN002 – MinUnit (Heck, I could write something better than that) and it’s probably the best choice for testing embedded C, but it’s not for DOS retro-computing.

Minctest (Zlib License)

For the most part, this is unarguably a worse choice than the previous two options, having fewer assertion types than either, less supporting documentation, no support for parameterized tests, and no helper for command-line options… but it does do two things which I think are valuable:

  • It shows pass/fail counts for individual assertions within a test case.
  • It lets you easily and obviously set custom display names for tests.

Again, it’s a fairly simple API. One minctest.h file to include, and then you write tests like this:

#include "minctest.h"

void test_a() {
    lok(1 == 1);

    /* ... */
    lsequal("foo", "foo");

    /* ... */
    lequal(2, 2);
    lfequal(3.0, 3.0);
}

int main(int argc, char *argv[]) {
    lrun("Test A", test_a);

    /* ... */
    lresults();
    return lfails != 0;
}

In the end, it’s not something I’d use for anything when greatest and Unity exist, but it’s a good data point for test suite UI design.

Others…

CuTest (zlib/libpng License)

CuTest (zlib/libpng License) does pass my initial triage question of “Does this cross-build from the Linux version of Open Watcom C/C++ 1.9 and run as a real-mode EXE under DOSBox?” …but that’s it.

First, it’s the only option that worked, but failed with a Stack Overflow error until I raised Open Watcom’s notoriously small default stack size with the OPTION STACK linker directive.

Second, and most damningly, the documentation and distribution archive front-load too much complexity… especially when, from what I can tell, it still produces a worse overall experience than greatest.

For that reason, I only ran the example provided in cutest-1.5.zip and this is what it looks like in DOSBox:

I checked µnit, µTest, utest.h, FCTX, and siu’s MinUnit but they all failed the “Will the distributed source build for real-mode DOS with Open Watcom 1.9 without patching?” test.

I also checked Labrat, CUnit, Check, Embedded Unit, and cmocka, but they were even more complex than CuTest to get going, so I didn’t even bother checking whether they would compile.

(It also doesn’t help that some of these rejected options are under the Unlicense, which multiple parties have criticized, and which doesn’t reliably account for “when in doubt, protect the rightsholder from their own ignorance” provisions in jurisdictions like Germany the way CC0 would. See this review of the CC0 for details.)

Functional Testing

Concept

Functional testing for a DOS program is complicated, because there is so little abstraction from the underlying platform. In fact, I think that, in the general case, it’s only worth the trouble if you run the test driver outside the DOS system under test.

This means one of two things:

  1. Run the program under test in an emulator, with the functional test harness running on the host operating system.
  2. Run the program under test on real hardware, with the functional test harness running on another machine.

To support both cases, and to avoid the needless complexity and potential for mistakes that would come from using a TSR, the solution I’ve chosen is to instrument the program to be tested with a simple serial console. Then, the same mechanism can work with real DOS machines (just use a null modem cable and, if your development machine is modern, a USB-Serial adapter) or with any DOS emulator that provides a means to connect an emulated serial port to the host system.

The serial console needn’t be complicated. Just log messages which the test harness can assert for correctness, and add a means to substitute input that would usually be provided by the user.

For additional testing, I’ll probably implement some kind of way to have the stub prompt the harness to continue, so it can deterministically capture screenshots and compare them to expected results.

(This can be done with real hardware using a VGA capture device, but it’s much easier with an emulator because you don’t need to do a fuzzy comparison to account for VGA being an analog standard. Emulator screenshots are pixel-perfect aside from the whole “pixel aspect ratio” thing.)

With DOSBox, it’s also easy for the test harness to assert for the presence, absence, and/or contents of on-disk files without having to mount or otherwise interact with an emulator’s disk images.

Research

The emulators which look to be capable of bidirectional COM port redirection to the host OS include DOSBox, QEMU, VirtualBox, and Bochs.

PCjs has some kind of serial console support but I haven’t had time to figure out whether it can be exposed to a separate process in the way I need.

I haven’t been in a hurry to investigate DOSEMU compatibility, since it’s more like Wine for DOS programs than a full-blown emulator and, aside from being especially thorough in my compatibility testing, I don’t see testing in it gaining anything if I’m already testing with DOSBox.

Either way, DOSBox should do well for quick and dirty testing, akin to testing a Windows program under Wine, and QEMU or VirtualBox should work for testing real DOS on fake hardware, but testing how software interacts with quirky hardware is another story.

Unfortunately, I’m still looking for a way to make this work with the emulators most suitable for that. PCem and its derivatives, 86Box and VARCem, are currently the state of the art in trying to accurately reproduce vintage hardware via emulation, but none of them have serial port pass-through support.

  • PCem’s developer has stated a lack of time to implement serial port pass-through but is willing to accept patches. It supports emulating an NE2000 network adaptor, but the only TSR I’ve yet found for redirecting COM ports over a network socket is paid proprietary software. (Though this TSR may be something I can MacGyver into doing the job. If I can, I’ll have to contact the author to ask for clarification on the license though.)
  • 86Box was forked before the frontend was rewritten to be cross-platform, the developers are still soliciting an experienced contributor to port over PCem’s new SDL+wxWidgets frontend, and I don’t know if it was forked before or after the NE2000 support landed.
  • VARCem doesn’t offer non-Windows binaries and it was apparently forked from 86Box, so all the same caveats probably apply.

Finding any information on whether serial support has been added to 86Box or VARCem since the fork is complicated by how PCem-lineage emulators provide dummy/unconnected serial and parallel ports to emulated OSes to ensure that the observed behaviour of the hardware for a selected system is 100% accurate.

So far, my best hope for testing handling of hardware quirks is that a half-functional test harness could be rigged up by running 86Box inside Wine (assuming it works in Wine), using its LPT-to-file support and inotify to handle sending data from the program under test to the harness (assuming 86Box doesn’t force block-wise buffering on it), and using XTestFakeKeyEvent to send control inputs from the harness to the program under test. (Obviously, this would only work on X11-based desktops capable of using Wine to run x86-based Windows applications.)

Whatever I come up with, if it’s easy enough to generalize, I hope to release it as a reusable test framework once I’ve got something useful.

Posted in Retrocomputing | Leave a comment

Retrocomputing Category Announcement

While working on an upcoming post (a run-down of C unit test frameworks that are easy to use under Open Watcom C/C++), I realized that I’m getting enough of these retrocomputing resource posts that mentioning them from each other is no longer a viable option.

…so, I decided to go back and add a new subcategory. If you are interested in my lists of retrocomputing resources, give the “Retrocomputing” category link at the bottom of the post a click.

Posted in Retrocomputing | Leave a comment

A Major QtExceptHook Update

For anyone who uses QtExceptHook, my port of the old gtkexcepthook.py script to PyQt5, I have an announcement I think you’ll appreciate… I just made a major update.

If you don’t use QtExceptHook, it’s a single Python file you can drop into your PyQt5 projects so that uncaught exceptions will appear as a user-friendly dialog box which harvests both the traceback and all the local variables at each level of the call stack. It also has your choice of a “copy to clipboard” button or a “report bug” button which invokes a traceback-sending callback of your choice.

…so, what features did I add?

  • In exchange for bumping the minimum Python version to 3.5, it now relies on the Python standard library’s TracebackException to generate the traceback and variable dumps, removing all the most opaque code I inherited and massively reducing the surface area for bugs that might not show up under basic testing.
  • It’s now fully documented in Sphinx-dialect ReStructuredText, in case you want to expose it in your API documentation. (Though it does assume you’ll be using the sphinx-autodoc-typehints and sphinx-qt-documentation extensions.)
  • The dialog is now resizable and the traceback preview now scrolls horizontally instead of wrapping.
  • I did a major refactoring of the Qt-specific parts of the script to make them simpler and more readable.
  • The example SMTP bug-reporting code now has error handling.
  • Qt’s QCommandLineParser is now used to provide a --report-button option so you can run the demo code both with and without a bug-reporting callback without having to edit the file.
  • The file is now TODO-free.

Enjoy. 🙂

Posted in Geek Stuff | Leave a comment

Making a 2-button Trackball Useful on Modern Linux

I was the kind of nerdy kid who read computer catalogues for fun before his tenth birthday, and one of the nerdy things I always wanted was a Logitech Trackman Marble… an early optical trackball with a distinctive patterned ball for the sensor to detect. (So distinctive that they still use it on the modern ones.)

Well, I got one in a box of nerdy hand-me-downs, but it’s the one I was eyeing as a kid, with two buttons and no scroll wheel… that won’t do.

Here’s a little script, adapted from someone else who had a similar problem with a Kensington trackball, which adds the following features:

  • Adjust pointer acceleration so use with a three-monitor spread isn’t an exercise in frustration
  • Press and hold the left button for 300ms without moving the ball to produce a right-button press (This seems to work perfectly well to allow me to do both left- and right-button dragging)
  • The physical right button is remapped as the middle button for clicking purposes.
  • Press and hold the physical right button to use the trackball as a scroll wheel
  • Adjust sensitivity of emulated scroll wheel to be usable for things like tab-switching without physical detents.
  • Enable both vertical and horizontal scrolling on the emulated scroll wheel.
  • Work around the cheap chinese USB-PS/2 adapter using the same name for both keyboard and mouse devices so it’s still possible to reference the pointer device by name. (To find the name of yours, run xinput in a terminal.)

It’s not perfect, since you can’t middle-click drag, and I still need to get some ScratchX to fix some scratches on the ball itself that cause an occasional hitch in its motion, but, aside from that, it’s surprisingly comfortable to use.

I’m not sure how much I’ll actually use it, but it’s nice to have it useful. Enjoy. 🙂

Posted in Geek Stuff | Leave a comment

Fanfiction – A Prince’s Duty

…and, in case you’re not into Naruto, here’s another one I had waiting in the wings:

A Prince’s Duty by BonusPoints

For all that Ranma ½ has a gender-transformative curse as such a central element of its narrative, there aren’t enough Ranma ½ fics that both attempt to focus on how it affects the characters psychologically and succeed at doing it.

Even worse, it’s almost impossible to find any stories that give Prince Herb of the Musk significant character focus, psychological or otherwise, since he’s from the half of the manga that never got adapted into the anime… this is one such fic. Not only that, it’s a story where Herb is a main character, the story starts out being told from his perspective, and it leans about as far toward “character piece” as you can go.

It goes into lots of satisfying detail on Herb’s motivations and thought processes. Just as important, it gives him opportunities to show that, when not being pissed off by Ranma, he’s as skilled in diplomatic discourse and as interested in acquiring politically important information as is appropriate for someone of his station, and it makes good use of the opportunity to use that princely objectivity to get a second perspective on Ranma’s canon situation. That is what a character piece should be… especially when you understand your characters and your readers well enough to use a line like this.

Herb was finding actively revealing her curse to be something too embarrassing to so much as attempt. She would leave that for Ranma to figure out.

It also has an interesting thread that never had time to play out in full before the story ended, but still helps to grease the wheels and make things interesting. Upon encountering Ranma at the Nekohanten, Lime jumps to the mistaken conclusion that Herb has secretly always been a girl and that “he” came to Japan to pursue Ranma as someone who can be a wife in public and a husband in private. Mint tries to correct him, but gets convinced instead, and Herb mistakes their innocent loyalty to him for a proper understanding of the situation.

It also doesn’t skimp on giving some character to anyone who gets a scene from their perspective. For example:

Ryoga’s idea of conversation seemed to consist mainly of bringing up random subjects, then looking around with a flushed face, before repeating the process over again. Mint flinched at the raw ineptitude the bandanna-clad youth was exhibiting. It reminded him of the very first time he had seen a woman. ‘What’s his excuse,’ the Musk warrior wondered.

That said, within the scope of what did get written, I think it’s reasonably obvious that the intent was to build up to a Ranma-Herb pairing built around only Herb’s female form being close enough to human to be able to have children with other humans. I’m not sure how I feel about that. I’m not specifically against such a pairing, but even something this well-written does flirt with feeling contrived in how it keeps the misunderstanding about Herb’s true gender going. (Even if it does make for a very elegant way for Ranma to unknowingly reveal the solution to Herb’s problem in chapter 7.)

Despite all that, what I found most noteworthy on re-reading it was actually one of the least memorable things… It’s one of those rare stories that truly knows how to use flashbacks and time cuts properly, bouncing back and forth without making me reluctant to follow. Usually, flashbacks prompt at least a bit of resistance, because they pull me away from what they’ve primed me to care about next… but, in this case, the story is staying close enough to canon , and we already have a solid understanding of how canon unfolds, and the writing carefully steers the reader to care about the character development in a way that doesn’t tie it to the events too strongly. As a result, carefully jumping back and forth in time can make the revelation of Herb’s character feel more consistent.

In fact, until Akane accidentally locks Ranma’s curse rather than Herb doing it on purpose, and makes Herb pause to think about what he was about to do, it’s believable that this could have been showing a different perspective on canon events. (A scene which is then repeated from Ranma’s perspective without it feeling boring or repetitive… like I said, this is how you do character writing.) For how brief it is, I think this moment is the most important to the plot, because, when set in a narrative which will build on it rather than quashing it, it’s one of those little “for want of a nail” moments. In this case, “for want of a nail, a bad first impression was lost and a spark of sympathy gained. For want of a bad first impression and a lack of sympathy, a prince’s hostility and lack of introspection was lost. For want of hostility and a lack of introspection, conversations were prompted. All for want of a horseshoe nail.”

I also find it amusing to see a scene where, when Ranma is puzzled at Herb neither wanting to kill nor woo him, and Herb points out that Ranma isn’t the catch he thinks he is, Ranma retreats to insults when his ego is threatened. Why? Because, it’s the first time I can remember seeing a scene where you have a male character nursing a bruised ego… in a way that strongly reminds me of how tsundere female characters react to emotional threats. (And then Lime interrupts, giving Herb a chance to realize the value in learning to not let himself be goaded by that, thus continuing a pattern of keeping things from degenerating without it feeling artificial, contrived, or forced.)

Back when I first discovered it just shy of a decade ago, I felt that it was the epitome of everything I wanted in such a fic, and it’s a real shame it’ll never be finished, but at least we got half a novel worth of text out of it. I do worry that how it was handling Herb and Ranma was steering into some grade-A tightrope-walking, but it didn’t jump the shark within what actually got written, so I’m giving it a 4.9 out of 5 for the too-convenient-for-the-author ways in which the miscommunication about Herb’s true gender persisted.

I just wish that it had stayed on the more psychological feel it had in chapters 1 through 5. I know characters like Ryoga had to come in eventually, and chapters 6 and 7 were when the other shoe dropped… but a guy can dream.

P.S. The amount of care and caution it spends on the interactions between Ranma and Herb reminds me of another unfinished fic that I really need to re-read and review at some point: Kunoification by Ozzallos.

Posted in Fanfiction | Leave a comment