Game Design, Programming and running a one-man games business…

Coding for the sake of elegance

I’m working on campaign stuff for a future (long way off) GSB expansion pack.

Right now, when the player clicks the battle screen to show the missions, there is an extra “campaigns” tab, and when that screen is initialised, the game currently loads in all the campaign data, including data for all the encounters within each campaign.

That doesn’t take very long tbh, it’s fairly negligible, even in debug mode.

Yet I am determined to fix it. I can just load the campaign name, and only bother loading further data if that campaign gets selected, and the player goes to the next screen. Otherwise, I’m wasting time.

Back in the days of the ZX81, that sort of delay would be very long, slow and totally unacceptable. It would be hugely wasted processing to load any data you didn’t really need, regardless of how much effort it took or complexity was involevd to avoid it. These days, it really doesn’t matter so much. We have more than 1k of RAM, we have more than a million times as much.

And yet it still bugs me. The code is inelegant, and I must fix it. Like most games programmers > 30 years old, I’ll never shake that desire to code ‘close to the metal’ and get as much performance as I can, even in fairly unimportant scenarios like this. Maybe it’s a good thing? Maybe thats why GSB surprises people sometimes in how well it runs on crappy old PC’s :D.

Collosal space battles (in fuschia)

Aren’t TV and movie space battles a bit tame?

Take the battle of Waterloo. It contained approx 140,000 soldiers. The battle of Kursk was 900,000 Germans vs 1,300,000 Russians, complete with 3,600 tanks and 20,000 guns. This was a big battle between two countries in a world war, fought over 50 years ago, when the world population was smaller.

Imagine a modern day non-nuclear war between China and Russia on one side, and everyone else on the other side. Now picture it as a purely naval battle. How many people would be involved? Lets say conservatively that each side only fielded 2 million troops (a trivial subset of fit, able potential combatants). Lets look at a big US battleship : The USS Massachusetts has approx 2,000 crew involved. Lets assume only 10% of our navy serve on these big ships (200,000 men) so thats 1,000 battleships, in an all out naval war. (remember we are talking a war for survival, not the relative peacetime deployments of today).

That’s a large fight between two earth-bound nations.

But lets assume a planet with less water-coverage than earth, and slightly larger, so it has double our population. Thats a factor of two. Now fast forward another two generations time wise and assume a doubling of that population again. Thats x4. Now assume that they are all on the same side (x6) and that they form part of a federation of 20 such worlds (still an incredibly small speck in an average size galaxy). Thats 120 x 1,000 battleships.

What I’m getting at, is when the Rebel Alliance attacked the death star, they seemed to do it with the sort of navy you would use to maybe lay siege to Malta, or at best, to attack Dieppe. Hardly a clash of galactic powers.  Assume 20% of your 240,000,000 are in fighters and thats suddenly 12,000,000 fighters, or a million twelve man squadrons. Imagine how long “all wings report in” would take… Imagine how quickly you run out of colors?

“Peach-tinted fuschia leader standing by”, “Oaky pastel rose leader standing by…”

So I guess that issue, and the whole problem of ILM filming a million plastic model flybys in 1983 doesn’t help.

I know what you are thinking, Even Gratuitous Space Battles isn’t really gratuitous enough is it? Maybe for the sequel…

Lets talk about patch 28

Ok, so patch 28 for gratuitous space battles is out, bringing the game to version 1.28. Hurrah. Lets take a looky at the two big new things (in addition to the major crash bug that was somehow still in the game, and is hopefully now hunted down and killed).

CUSTOM CHALLENGES

This is a big deal. If you go to the challenges screen, there is a new ‘custom challenge’ map, which opens up a whole new screen showing stuff to fiddle with to basically create your own map, from existing backdrops, plus settings for pilot limits, budget, and the supply limits or spatial anomalies present. You want a battle with a 10,00CR budget, 4 pilots, no shields and no missile modules? You got it kiddo!

You can save out these custom scenarios or load them in, (if you save them out, that lets you name them, otherwise they default to ‘custom map’. Clicking the deploy button takes you to the normal setup screen for arranging your own fleet, and from there you issue a challenge as before. I hope people really investigate this as an option for the game, because it gives a lot more creative control to the player. If you thing fighter rockets are overpowered, you can issue a challenge where there aren’t any, and see what other methods people use to beat you. if you like a certain map but wished it had a ‘must have engines’ requirement, you can do that too. And if I add in extra anomalies or scenario options, they will all end up in this editor too.

MESSAGING

The game now maintains an on-line ‘inbox’ for everyone, and auto-sends you a message when your challenges are beaten or played, or when someone sends you a challenge. It also gives you the option of sending post-challenge feedback to the issuer. This means less wondering how the hell they beat you invincible fleet, and more reading the gloating from your nemesis, which is of course, all in the spirit of GSB.

1.28 took a lot of under-the-hood fiddling, but I think these two things were missing from the game, and needed putting in. I wasn’t sure the challenge stuff would be as popular as I wanted it to be, but it has proved to be very popular, so it’s been l33t to go back and add this stuff to an existing game. The game will auto-update if you have registered it on-line, but I’ll be getting updated patches to the distributors like steam and impulse and the others right away.

Scenario Editor

I’m a big fan of modding and game editors. people love to tweak a game they way they want it, and I support that 100%. So with this in mind, here is a work-in-progress screenshot of the custom scenario editor.

The idea is that there is a new way to launch a challenge (maybe from the challenges window), rather than selecting an existing singelplayer mission. That new button takes you to this screen which lets you tweak everything. Once done, you can then click deploy, and arrange your fleet like any other mission, then issue that as a challenge to anyone else. You can only use backgrounds that already exist in the game, but everything else is tweakable.  The only big chunk not done yet is changing the deployment zones. I may end up adding that later and using defaults for now. My UI coding is sadly slow and inefficient :(

Together with in-game messaging, this is the second big feature that will be in the next patch (alongside many bug fixes) which will be 1.28

Fixing a single GSB bug

Step 1:
Where is the game crashing? it crashes here:
void GUI_TitleBar::SetTitle(std::string str)
on an assert
GASSERT(Width > 0);
Width is clearly not set right when we set the title. Cue lots of hunting through every window that uses that code to check that they never set their title when they are yet to set their width. No luck.

Step 2:
Sudden realisation that the window width is a red herring, it’s the titlebar width itself that isn’t set. Sudden discovery that a function in the dialog class is virtual, but the function it supposedly implements is not. Possible confusion? certainly sloppy and needs fixing, but I can’t fix it *now* because I need to know *exactly* what causes this, rather than changing stuff and hoping I found it.

Step 3:
Realisation that the negative width may be an infinite high width wrapping round, which implies width has never been set. Maybe this is why I never see the crash in debug? A check shows that window widths are always set to zero, but that would still trigger it…

Step 4:
Reading up on related bugs suggests something to do with the race changing, combined with the ship editor. Decide to test in release mode deploying, then changing race then going to design mode. W00T! It crashes, although release mode debugging is far from trivial. It looks like a null pointer though, meaning it should reproduce in debug

Step 5:
Reproduced it in debug, which normally means home and dry. A module type pointer is set to 0xcdcdcdcd. This means uninitialised, and this seems to be the case. I’m assuming it is null without setting it to NULL. If it had been set to NULL, then a module would have been selected.

Step 6:
Temptation to fix an obivous unintialised pointer error here, but that would be BAD. The task is to really understand the bug before fixing it. For example, why does this not *always* crash when launching ship design? Lets test… It seems to always crash for me in ship design. That cannot be right…Aha, it’s handily crashing in some code inside the STL library, but only in debug build. A quick check of the shipped release build shows I can’t now replicate the bug there. Even stranger. Could I possibly have shipped a debug executable in a patch, this explaining why not everyone has the issue? No, the file size difference is 3MB.

Step 7:
Tests shows that the same exe does not crash taking the same steps if outside the IDE. The IDE is clearly setting those debug values and trapping an error. Is this actually related to the titlebar error crash and change race crash everyone has? If the module pointer is invalid, all hell could theoretically break loose. Getting tempted now to just fix the obvious errors, at least to see what happens next.

Step 8:
There is just no way that this pointer is correctly set to null. Unless it’s null by happy co-incidence, the game should crash whenever the ship builder is viewed. (if null, the game assigns it a valid value). Adding an assert for this, which still triggers in my release builds. It doesn’t trigger. How the hell is that pointer being set to NULL?

Step 9:
I suspect I am being lucky in release build with this. The pointer is uninitialised and being set to NULL most of the time as a side effect of something else, but this is not guaranteed, hence the randomness of the crash. It’s clear this pointer should be initialised, so I’ll just do that, and move onto new stuff.