Of Mice, Men, and Mod-Friendly Architecture
by [email="email@example.com"]Richard Fine[/email]
One of the best-selling games of all time is Valve Software's Half-Life, released back in 1998. At time of writing, that was 3 years ago - an eternity in gaming industry terms. Much as it was the pinnacle of gaming then (and, in some opinions, still now), shouldn't it have been shoved in a drawer somewhere, having been completed god-knows-how-many times already, and everyone looking for something newer and snappier? So why is it still popular?
In actual fact, if you were to survey how many people owned Half-Life, and actually played the standard game as everyone's favorite crowbar-wielding scientist, you'd find that there aren't many. Sure, people play through the first time, but then they play Counterstrike, Opposing Forces, Day Of Defeat, Boxwar, or Action Half-Life (to name a few). These are, if you hadn't already guessed, modifications - "mods" - for Half-Life.
A technology which has extended the life of a game by 2 or so years must be worth looking into... read on.
Mod Security Levels
OK, so I've persuaded you that might want to support mods in your game. But what exactly is meant by 'support?' To answer this, I'm going to have to discuss something else first - mod security levels.
You could say that any game based on the Quake engine was a 'mod' for Quake. The authors of the mod will have had the full source code for the engine, the license to use it, and will have had to do everything else themselves. However, you could also say that a set of 20 HL maps, with Valve Software's original textures and enemies, is also a mod. Sure, there's a difference, but you get my point (I hope =] ).
So you need to decide how mod-ifiable your game is going to be. Do you want people to be able to completely override your AI or HUD graphics? Remember, of course, that a bad mod for your game is still a mod - and is associated with your game, dragging it through such channels of ill-favor as the mod may travel. So, we get to 'security levels.' How much of your game you want to be fixed in place, forced upon the mod-ers, so you can maintain some semblance of sanity in the games.
You could restrict people to only being able to create their own levels for your game. Using your textures, your models, your game physics, and so on. This might be good, but I'd only recommend it if you've got a fairly large texture library to choose from; otherwise, there are only so many things you can do with concrete and glowing crystals...
You could allow people to add their own textures (most likely in the form of .WAD files) to support their levels. This opens up a whole new world of opportunities; but remember, it's still: fighting aliens in military compounds; fighting aliens in the Australian Outback; fighting aliens in the streets of New York (Provided your game involves fighting aliens, of course).
Models & Skins
You can let people add their own skins - model textures - to your game, or go the full nine yards and let them add their own animated models. This will serve for a lot of purposes - be it new enemies, weapons, and so forth. A notable example which used this technique extensively is Neil Manke's "They Hunger" series for Half-Life (which I may recommend as being one of the best there is) - the original game featured Zombies, and in his mod he added a number of new Zombie models, but the zombies still acted in pretty much the same way - the AI was still the same.
User Interface customization is referring to any menu systems, HUDs, and general non-texture artwork. Things like loading screens, console backdrops, main menu graphics, and so on. You could also allow the mod-er to customize the menus themselves - if perhaps your game includes a single player mode, and the mod is multiplayer-only, they ought to be able to remove the 'Single player game' option from the menu.
This is it, the pinnacle of mod creation. Allowing mod-ers to create their own code that gets loaded in and executed at run-time. Of course, this is also the most risky. Who knows what rogue statements could be present in MaliciousCoder's miscellaneous mod? There is an argument here for the possible use of scripting - but ultimately, if you've got to this point, you do have to go all the way. A script language could never be complete enough to allow mod-ers to do everything they want.
And so, there we have the 'mod security levels,' ranging from 'inane' to 'hardcore.' If you're going to support mods, you must know what security level you're using; because of course, the security level determines where you have to have your code ready to support things...
So, you know what mod security level you're going to use. So, how do you implement it?
The popular - and to my mind, most logical - approach, is to make your game itself a mod. Sort of a 'default' mod - if no mod has been loaded by the player, load the 'yourgame' mod, and play it.
In that way, almost all problems are solved. You simply make your pseudo-mod responsible for all the things you want to be modifiable, and make your game engine take care of the rest. If you wanted to customize only the levels and artwork, then make your pseudo-mod responsible for loading them, and make the game responsible for everything else, the AI, the UI, and so on.
This doesn't necessarily have to be done using code. Half-Life uses a file in the mod's directory called 'liblist.gam' which lists important things like the first map to be loaded, or the name of the mod. There's no code to be seen; the file is simply loaded by the game, put into the appropriate place, and the mod runs seamlessly.
However, if you wanted to support code, that gets a little harder...
Firstly, you need a safe place to store your code. It can't be a standalone app - because the mod needs the game to run. So, the popular approach is to use a DLL (Note that the approach is often the same when the file extension on the code files is something random - they just change it to confuse everyone =] ). And voila! A single file that the game can load, and get pointers to the code within.
This works especially well coupled with a C++ - style vtable - you have some pointers to functions, which can be assigned to point to the DLL, or to point to the game's default functions. The engine can just use the pointers, and not worry about where the code is that it's calling.
It's been a little slapdash, but I think I've covered everything. And if I haven't - well, we're game programmers, the geniuses of the planet - we can find our own solutions! =]
Questions, comments, hate mail, nudie pics (heh heh) - send 'em to [email="firstname.lastname@example.org"]email@example.com[/email]