The team is getting features in like a well oiled machine. The new research screen just totally rocks. Kudos to Mudflap and Mormegil for getting that stuff humming. BoogieBack and the Elf Girl (doncha just love these handles) made good progress for getting the new star base system in and the new freighters in.
Our newest team member, Jesse (no cool handle yet), has started on the ship battles. We want the ship battles to be really impressive and we want ships to show damage. Ever see Star Trek II/III where the Enterprise has phaser burns and such? We want that kind of stuff.
The big debate this week is something that's kind of an on-going thing. I've been writing games now for 12 years. That's games on store shelves. I'm not a great programmer as I've mentioned many times before. But my coding style does lend itself to easy debugging and easy readability. I.e. I can go back and look at my code from 4 months ago and know what I was doing and in a pinch, put it through the debugger with all the important stuff just a click or two away in a debugger watch.
But I wouldn't program an application the same way as I program a game. Most of our business is creating applications. And when it comes to applications, robust coding techniques take the lead. A well designed application still needs readable code, but the odds of going in and tossing out features or algorithms in a typical application on a regular basis are not as high as they are in gaming.
In a strategy game, debugging becomes critical because debugging isn't about finding bugs. Debugging is about fine-tuning game-play. The last couple months of development usually mean, for me, spending 90% of that time in the debugger tweaking playability. And that means having structures and objects and classes that lend themselves to being easy to view in the debugger. To me, CString is the devil. STL is a pain. I don't like iterators. Which means I really don't like container classes. I understand the need for those things. I just find them a pain to deal with when I'm debugging.
The last few months of Galactic Civilizations II will mostly be about tweaking the AI. Why did the AI build this kind of ship? What did the AI put together a fleet with those kinds of ships in them? Why did the AI not build a particular structure on that particular planet? Where in the heck is that AI ship giong? Why are players running out of money? Why does the morale on a planet fall so low after a certain point is reached? Why did the AI not build a certain type of star base in a certain sector? Why did the computer player declare war on the human player when he did? Why didn't the AI recognize the threat posted by the human player? Why did the AI offer help to that player despite being morally opposite of him? Why did the AI choose to build that ship on that particular planet? How did the AI see my starship when it was over here in the corner? Why did the AI put their spending ratios and spend rate at that level? Why did the AI send their freighter there? How much money per turn is a particular trade route established between AI player 1 and AI player 2 costing? How many shield modules does that particular AI ship have on it? How much time is it taking the AI to research a typical technology when on Average intelligence? How much difference is there between different AI intelligence levels?
The questions go on and on. And those questions create many subsequent questions. The answer isn't to put a bunch of debug print statements in the code, that would take forever. The answer, as a practical matter, is to try to make it such that you can always look at a particular ship, computer player, planet, colony, improvement, whatever and with a few clicks be able to see the numerical value of it. And moreover, to be able to code it in such a way that it doesn't take long.
That means things like Arrays and pointers. Not special array types, but good old fashioned pClassStarShip pShipsInFleet[MAX_NUM_SHIPS_IN_FLEET]; type stuff. This is the kind of thing that drives seasoned developers crazy because it's so prone to causing bugs later on. One slip-up in a for loop or something and suddenly you're getting unexplained crashes that can take weeks to debug.
The way I've tended to deal with that is to break down my stuff into lots of small functions. So things that could potentially introduce some overrun don't happen. I also don't allocate memory on the fly. In 12 years of game development, none of my code has ever used a Malloc. And I've only recently (mainly because I'm had to adapt to other people's code) had to create instances of things on the fly and destroy them when I was done. My code has traditionally only created new things at the start of a game and deleted them at the end of a game. A single function for creating the stuff and another to wipe it out. Everything else is created (and stays) so I'm not messing with memory leaks, memory overrruns, etc.
And those people who have played our games know that they're traditionally quite solid. I don't need a standard template library or a CString or other "stability via compiler" type stuff. My way isn't better as any general rule. But I believe it is better for game development on a game with limited scope (I wouldn't recommend this method for a development team of 20 people, it still requires pretty disciplined coding).
So that was our debate this week. Things are going well though. Beta 3 is going to rock.