The gentle layered failure of Spyro the Dragon

I love it when a game feels like it’s rooting for you.

Over this ten day weekend that comprises the holidays, I’ve been playing the remake¹ of Spyro the Dragon. So I want to talk about the way the game handles failure gently and in a way that tries to give you a leg up to success.

I need to give you a bit of a sense of the structure of the game to discuss the topic, so here we go. As a platformer of its time, it has “lives².” Spyro has a starting number of lives, like Mario does; when he runs out of lives, the game is “over” in some sense (we’ll get to that). The world in which the game takes place consists of a number of hubs, which are themselves game levels, from which Spyro can reach other levels via magic portals; additional hubs can be reached by accomplishing certain in-game goals. The current state of the game is saved every time Spyro enters or leaves a level, or when he rescues a dragon. The game state consists of what collectibles he has collected (gems that are either distributed loose, in chests of different kinds, or dropped by defeated enemies), which dragons have been rescued, and a smattering of other small details. Collectibles, once gained, are gained forever³. That’s the rough outline, and I’ll fill in more as we go as I discuss the various ways the game makes you feel like it wants you to succeed.

So, the first way it wants you to succeed is to make it harder to lose a life. Spyro is accompanied by a dragonfly named Sparx, he flits alongside him as he has his adventures. Sparx acts effectively as a renewable shield; Sparx will take three hits for Spyro before he disappears, and then Spyro will be unguarded and further damage will end this particular life of Spyro’s. It is as if Spyro has four hit points, which can be depleted one-by-one by environmental hazards or walking into enemies or being hit by their attacks. The three hit points belonging to Sparx can be regained by finding non-threatening ambient critters (sheep and rabbits and that sort of thing). All of this is fairly standard mechanical stuff going back to Mario and probably before; Mario eats mushroom to get big, Mario can now take two hits before he dies, if he takes one he can eat another mushroom to regain it.

One way it differs from Mario’s 2D games is that these ambient creatures are both fairly plentiful and more importantly, they respawn a little time after Spyro has gotten Sparx to consume them. So although good level design tends to place these critters after significant challenges for Spyro and the player, it’s almost always possible to go back and find some before you engage in these challenges. The game is happy to have you be at your best before you take on its challenges. So that’s one layer of encouragement to the player, to protect these lives.

Above, I mentioned how rescuing dragons saves the game state; it’s also true that returning to a place where Spyro has rescued a dragon will save the state again; typically we call this a checkpoint. The game state that is maintained while Spyro still has lives includes which enemies are alive or dead in the level he is currently in, but as noted above, collectibles such as gems are collected once and forever. If Spyro loses a life, therefore, any enemies he has encountered since the last save point are restored — this is done to maintain a level of challenge to the actual moment-to-moment play4.

Since gems dropped by enemies are collected once and forever, the game then goes further to give the player another benefit from defeating them a second time. On any subsequent defeat, an enemy will drop an orb which, when Spyro grabs it, will fill up a meter that grants an extra life once filled. It’s as if the game is saying, “Oh, I see you had trouble with this section, perhaps this will make it up to you.” Enemies similarly respawn whenever Spyro re-enters a level, and since the hubs are themselves levels, enemies will be recreated whenever one returns to them, giving Spyro an additional chance to earn these orbs and thus earn extra lives. There are also items in the levels which grant a whole extra life at one go.

Finally, on “game over,” the game can be continued and Spyro will be returned to the hub nearest to his final death — since enemies are restored when levels are entered, the enemies in the hub will be restored. On continuing the game with five new lives, then, the player is subtly encouraged to go ahead and add another life or two before continuing with whatever challenge ended his prior game.

I love these sorts of layered failure states, which is why I went into all of this so pedantically. It just feels like a pat on the back from the designer, a sort of “hey, you got this” cheer and a little boon to help you finish the game. It allows you to fail with a sort of forward momentum at each stage.

Sadly, none of these carry over into the final level5, which requires a nimbleness of the player which hasn’t really been strictly required up to that point, except occasionally. That final boss requires real agility and doesn’t contain any enemies that allow you to start building up new lives. If I were a player who had leaned heavily on the fail forward mechanics of the rest of the game, I’d be frustrated. Endings are hard.

Just thought I’d document all of that to help explain to myself why playing these games again feels like seeping in a warm bath.

¹I was surprised to discover it’s a remake, actually. I had assumed it was a remaster of some kind though I realize how difficult that would likely be and it’s not something we see too often from PS1 to PS4. (back)
²”Lives” mechanics are a holdover from the arcade era, where they were used to force a “game over/put in another quarter” loop. As of the PS2 era, I remember talking with Nathan Martz about how the mechanic was almost certainly going to die off. I’m sure it hasn’t, entirely, but it’s no longer a staple and indeed when Insomniac released its first PS2 platformer, Ratchet and Clank, they had abandoned it. (back)
³To be fully pedantic about this, collectibles once gained could be lost if the game were turned off before another save, but as long as the game is running, a collected gem is Spyro’s forever. (back)
4As a collection-based platformer, returning to empty levels just to search for remaining collectibles might be more tedious without combat distractions; mileage will vary for and individual player’s tastes. (back)
5Sadly, these mechanics do not apply at all to a certain class of level, in which Spyro must fly through a timed obstacle course; however, it might be possible to complete the game without engaging with these levels at all. I didn’t do the math, but I generally skipped them in favor of returning to them after I had defeated the final boss, so I think that’s the case. I did come back to them later, for the cheevos. 🙂 (back)

How One Line in a Text File Changed Jedi Starfighter

There’s a bug in Jedi Starfighter. It was caused by one line of data, and although we considered the bug pretty significant, and although we knew about it before we shipped, we didn’t fix it. This is the story of that bug.

In the original Starfighter, the damage done by laser blasts was a bit of data that was specific to each ship type (more or less), defined with a single line of our data definition language¹. Laser fire was defined by four floating point values as I recall: a minimum amount of damage, a maximum amount of damage, the distance before which the maximum was applied (i.e. shots closer than this distance did the maximum damage), and a distance beyond which the minimum was applied. In between, we interpolated between the two. This was meant to be a quiet inducement to the player to engage in dogfighting — close-up fights were more exciting, showed off the ships to better effect, and also better to reflect the feel of Star Wars space combat.

One source of the bug was this: because it was perfectly mathematically valid to have the maximum damage actually be lower than the minimum damage, the idiot programmer² who coded it up didn’t think to have the game warn if that were the case. Sure, it didn’t make any sense for a laser to do more damage the further it went, but it wasn’t harmful for that to happen, and anyway, this is Star Wars, who knows what kind of space lasers they might develop.

In Jedi Starfighter, the data for the player ship³ was tweaked so that this happened, which dramatically improved the ability for players to destroy ships from long range with just their lasers, using the camera zoom. Lasers became more powerful the further they traveled, up to some maximum amount. Effectively, what was meant to be a game about close-quarters combat became about at-edge-of-visual-range combat. We went from a game we thought was about handguns and knives to a game about sniping, metaphorically speaking.

No one involved in this bug was acting improperly. The implementation was general enough to allow for as wide a number of behaviors as possible. The person who made the change did so based on personal taste. When we played the levels, we all tended to shoot things from long range anyway, and when you play these things every day you might mistake sudden changes in the data as simply being much better at the game (because you play it all the time). At some point, the vision of JSF as continuing in the legacy of Starfighter and having that close-quarters feel was not reinforced enough, but we were a short project and most folks had worked on the first. Reiterating that design goal may have seemed unnecessary, or may have simply slipped through the cracks with the other pillars we were pursuing: Force Powers, improved performance, some other stuff.

Now, as I said, we discovered the bug before ship and didn’t fix it. That was the right call then, though it might not be today, hard to say. We discovered the bug once we were either in beta or very close to it. At this point, hundreds of QA hours had been put into the game already, and the game had been balanced around the fact of how the weapons worked, whether we liked that or not, whether it led to the gameplay we liked or not. For business reasons, the game absolutely could not slip, and so… we just left it. It was too risky to change. Balancing all those numbers is so often just a house of cards, and the amount of damage the player’s weapons does are one of the ones at the bottom of the pile. You can’t just pull it out and hope the whole thing will stand.

We had other options, but they weren’t good ones. We could have put the lasers back to where they were on Starfighter, and done a round of tests, but that might have simply ended up burning a test cycle to learn that wasn’t practical, and lost that time forever. As close as we were to ship, and with real bugs that had to be fixed for cert and what-not, that was simply too costly. Today, we might have patched it after more time could have been spent with it. At the time, the best decision we had available to us was to leave it as it was. We couldn’t afford the risk of other options.

So I feel for the folks who missed a typo in some data file on Aliens: Colonial Marines. I’ve been there.

 

¹I hesitate to even call it a language. It had no control flow statements in the original Starfighter and I don’t think even any variable support, both of which were added in minimal ways for JSF but which aren’t really germane. I just like to digress.

²I feel comfortable calling this programmer an idiot because it was a long time ago and also I was that idiot.

³OK, technically, there are several player ships and so this bug was replicated in several places, but essentially a single line each time. <waves hands in air>