It's time to take a good old roflcopter for a ride and report you from a recent hilarious happening from our beloved Avatar Creations office of fun.

As you may expect from indie game developers, our daily nutrition-intake is largely homogeneous at best, and can be usually expressed with what our friends in Britain would characterize as "beans on toast". To this end, when the game launched, I decided to traverse to the local kitchen appliance store and surprise ourselves with a wonderful sandwich grill, to spice up our otherwise dull circulation of carbohydrates.

The grill has served us wonderfully for a few months, until it's untimely demise when encountering a larger piece of pastry, at which point the structural composition of the object underwent a major realignment:

It was a tragic casualty, but after much grieving, we carried on. Then today, tragedy struck again, as the trusty office toaster, which has served us for the entire duration of the Perpetuum development, has inexplicably caught fire and nearly proceeded to burn through the bottom of the cupboard, only to be carefully unplugged and shoved in the kitchen sink by yours truly in a haphazard but effective manner.

Forensics have later revealed that the culprit was quite possibly the ejection lever lodging in halfway, either due to hardware failure or the toast itself wedging between the rim and the metal framing, which has caused the heater mechanism to switch from "medium well" to "meteor shower", and eventually "thermal ammo AOE attack", cheerfully melting the plastic framing itself in the meantime and looking wistfully towards the wooden cupboard bottom.

So yeah, we're one toaster down, and I'm still hungry. However, on the plus side, rest assured this will not serve as a hindrance on our development schedule.

So finally after lots of wizardry in every imaginable area of expertise we have, we finally offer direct credit card payment in our store.

Yes, we know, it's about time.

So, in keeping up with the tradition of footbulleting via announcing things and not adding them, we only realized today that we never actually enabled the remote corporation storage browsing in the live client, even though it was in the patch notes as a ZOMG MUCHOS IMPORTANTOS feature. D'oh. (That said, in our defense, none of you complained either. No, shut up, you didn't.)

But yeah, sorry about that. The hotfix is out, restarting the client will apply the fix and as an added compensation we also added secondary sorting to datagrids.

Yay, it's 303 today! (You may disregard this if you don't get the reference.)

Anyhow, I thought it's about time to provide some updates about what we've been doing in the past week or two, because we've certainly been busy enough not to say anything so far. As you may remember we posted earlier about what we're planning to add into the game in the coming weeks, with which we've been progressing steadily, but there were also other developments on other fronts, which might be of interest.

Reaching out to another world

The most apparent update we have is that we've been in cooperation with the wonderful people at CodeWeavers to bring Perpetuum to OSX and Linux, and finally we can present you with official Crossover Games support, which will allow you to enjoy the game on those two platforms just as good as under Windows, and you even get a discount if you purchase through that link! We ourselves have been using the game through this method on a MacBook Pro, and it seemed to work flawless as far as we could see. The gist of this essentially means that we'll keep an eye on possible bugs caused by the emulation, while the Crossover developers will continue to pay attention to your reports for the bugs you find seem to be platform specific. Before you ask, we're not excluding the possibility of a future native client for those platforms, but right now the game itself (as a game, not as a piece of software) needs way too much care internally for us to be able to shed any assets or resources on porting, and especially maintaining it afterwards. Right now, we feel really strong about Crossover as a means to deliver our game to a wider audience, so spread the word if you know someone who remained stranded on the OS-fringes until now!

Arrr, treasure!

Moving over to actual game-features, most of the artifact scanning is implemented (save for the usual minor GUI-related swashbuckling) and has proved itself eyebrow-raisingly fun for such a cynic as myself, probably due to the notable simplicity of the mechanic itself. The whole concept boils down to this: You get a normal geo-scanner, you get some artifact scanning ammo, load it, go out to terrain, scan. If there's something cool within range, you get a distance reading. You move around, scan again, you get another reading, with a delta calculation to show you whether you got closer or not. From this point on, it's an entertaining little game of "hotter / colder", which starts out as relatively simple when the distance is still large and any movement toward the general direction is considered as advancing, and gets gradually more and more tricky once you get closer and smack headfirst into either the "It says it must be here SOMEWHERE!"-run-in-circles-scan-like-a-maniac-syndrome, or the unfortunate occurrence that the artifact is likely to be in the middle of a bunch of angry NPCs. Either way, scanning within a given range of the artifact will finally result in the reward to appear - this can be a container with munchies in it, or a trigger to a variety of other things, depending on the type of that artifact. (This is helpfully specified for you along with the distance, just so you don't go cheerfully dowsing for Pandora's box.) There will be additional factors on how efficient you'll be able to geocache yourself to riches, but I'll leave that up to you to discover once the patch is out. The preliminary estimate for this patch is March 9, 2011, but this is still just what we're aiming for and there's still a lot of testing and balancing to do.

Combustion

We've also initiated the process of adding more zones to the game, a considerable task that's gonna take us quite some time to finish, hence it will probably not appear in the next patch yet. We're finished with the basic layout of the maps themselves, we've already placed the terminals and teleports, what remains is the actual level design: flattening the grounds to walkable paths, painting mineral fields, placing NPCs, placing decoration, stuff like that, as well as coming up with absolutely ludicrous new names for everything, the part of the process we admittedly enjoy the most. The plan is to provide six new zones, literally doubling the area available inside the game: three new safe zones (the ones with only a single terminal on them) for general activity, and three unsecured zones (with two outposts each) for unrestrained territory-knuckling. The teleport network has already been laid out, and though I won't go into detail here, we're hoping to provide easy access to each map from most of the current ones.

Some minor additional bits that have been done: We've changed the datafile handling so the local settings (keyboard, sound, window positions) will be saved separately from the large datablob, so deleting that will never cause your settings to be lost again. (Whoo-hoo!), we also added a free-look button so you can rotate the camera around the robot even when it is moving, we've made tabstrips squishy so now you won't have the problem of channels not fitting on the chat window, and last but not least we're in the final stages of adding direct credit card payment to our store. (About time, really.)

So that's about it for now, and we'll update you with details as soon as we have time to take a larger breath.

I took the liberty to hijack the blog from BoyC to start a little skunk-work series of tech-articles about the stuff that goes on behind the curtains in Perpetuum. There's some fairly unusual ideas and solutions we came up with over the years and I hope they're as interesting to you as they were for us to invent / implement. (Or well, potentially more interesting, and without the malnutrition / hangover / sleep deprivation.)

So, maps.

The main principle

What is the task at hand, what are the conditions we can work under?

  • We need to have a map in the game where players can see the main navigation points. The goal is the map to look as good as possible within the given circumstances, since players will be staring at it for prolonged periods, and we don't want them to stuff their own eyes into the recycling facility 5 minutes into the first transport mission.
  • We do not have expendable artists who can spend time on painting maps manually, but more importantly, unlike other games, the map here needs to be as accurate as possible, for strategic reasons.
  • The terrain is a height-map - we can safely assume the client has access to this data, but this data has the possibility to change fairly often. (Think terraforming, either by players or by level design.)
  • Not really a mission-statement as such, but resolution-independence is a plus.

Summed up, we need a fairly non-linear data flow coming from a 2D dataset, and ending up in a good looking texture. In other words, procedural textures. Luckily, we're fairly comfortable with that. (*wink* *wink* 64k *cough*)

The steps

Let's look at our starting dataset first:

This is the actual terrain height-map, a 2048x2048 2D dataset of 16-bit height values. The reason it looks so dark is because this is a linear mapping of the 0..65535 range to the 32 bit colors available on your screen. Given that we don't really have to care about the peaks so much, since robots can rarely pass those, we can re-map the range of interest between two completely arbitrary values following "This Looks Good Enough"-principle, ideally somewhere around the water level for the low value, and the highest walkable point on the map for the high value.

This already looks a lot more usable. Sure, the mountain peaks become a big white spot, but we don't have to concern ourselves with those because they're rare, usually uninteresting for the player, not to mention the strange yodeling sound they emit.

It's time to add color. Cartographers generally follow a principle where they assign certain colors to certain heights, which works perfect for us, because we can use a look-up table internally to do so. This look-up table, in our case (and ideally), is a simple 256 pixel wide bitmap, painted by a graphics artist:

So if we use this to color up our altitude levels, we get this:

This almost looks good enough and no-one would blame us if we'd stop here (no, you wouldn't, shut up), but we knew we could do something more interesting given the data at hand a little maths. The image already has a nice faux-natural quality to it, but it needs contrast, the same way maps often have a little lighting / shading on them.

Adding contrast

At this point, the idea was to take the altitudes, more specifically the altitude-differences (or slopes), and turn them into shading. For this, what we've done is an implementation of what generally bitmap-manipulation software call as "Emboss", and basically means taking surrounding pixels, and calculating a normal vector out of them. Many of you might wonder if it means we're calculating a normal map, and in one sense yes, but the trick here is that the direction of the light can be fixed, because why not, it's Good Enough, and that allows us to speed up the calculations simply by assuming that the light always comes straight from the left.

For less technical minded: This practically could mean that we start walking (figuratively speaking) from left to right on every row of pixels, and if the next pixel is a point higher, we get a bright point, if it's lower, we get a dark point. (If you're indeed a code-savvy person, please refrain from gnawing out your own cerebrum at this stage because of this rather sloppy explanation, I was trying to make a point here.)

If we take this normal value and map it (with a bit of magic number wizardry) to the grayscale color range of 0..255 (0 meaning the next pixel was lower, 255 meaning higher, 128 meaning it was the same level), we get this:

Not the prettiest of pictures, but it's a vital component towards what we want: contrast.

So we have a colorful picture with no contrast, and we have essentially a bump map with no colors - how do we blend the two without calculating lighting on every pixel?

Simple: Prepared lookup-tables. We know we have 256 levels of color, and we know we have 256 levels of contrast, so we can pre-calculate a 256x256 pixel lookup table with all the possible combinations and utilize that to render the final image:

This lookup-table is ostensibly the above gradient, with the top half fading to black and the bottom half fading to white. Between that, in the very center, is our original gradient.

All it remains now is to run the following little lookup, matching our color and contrast:

for every pixel {
  tx = get_remapped_altitude() // 0..255
  ty = get_contrast() // also 0..255
  final_color = shaded_gradient_lut(tx,ty)
}

And here's our final image:

The difference is subtle, but definitely visible when the maps are zoomed up close - which is what will happen in most cases.

The advantages of this method are manifold: it's fairly fast (it's entirely fixed point arithmetics), it's resolution-independent, it looks Good Enough, and most importantly, it's responsive to the level of immediacy, i.e. every change done on the map can be rapidly re-rendered on the map as well. (This also goes for the passable terrain calculations, but that's a whole new story.)

That concludes our first visit to the forsaken wretched nadirs of the Perpetuum codebase. I'm not sure what to write about next time, but I suppose a quick look at the "number of changes per line of code" graph will quickly indicate where the "interesting" bits in our code are.