Blog 870: Experiments in Modding UT

Yep, I’m doing it — I’m modding Unreal Tournament. Since the beginning of my festive holiday, I’ve been having a quiet go at implementing that singleplayer roguelikelike monster-hunting adventure I described when lambasting UT2004‘s Invasion game mode.

Yep, Robbie’s idea of “taking a break” from working on his own game is to… mod somebody else’s game. Twenty years too late. Right after it’s been delisted from all online stores and become hard-to-access abandonware.

(Yep, I’m still single.)

Experiments in Modding UT

This is not actually the first time I’ve tried to mod UT — I played around quite a bit with the singleplayer ladder this time last year, with a plan to inject the extra Bonus Pack maps and enemies that were included in the game but not in the tourney itself. So I’d get to play with the stuff that I don’t tend to see very often.

I had some success, but it was slightly too big a deal for my tiny little brain. Unlike most of UT, the singleplayer ladder is very much not designed to be modded. It’s full of hard-coded chunks that mean a “simple” change to the map and bot rosters actually involves recreating the entire ladder menu system. (I’ll tell you about it some other time, when I try to do it again but better.)

Actually even that wasn’t the first first time I’ve ever modded UT. Waaay back, I dabbled a bit with mapping; though I didn’t ever manage anything “real”, I did do a few DM to DOM conversions for my own botmatch amusement. Some early forays into Milkshape 3D also saw me building shonky character models using the BP4 skeletal animation system, which did involve some scripting — but that barely counts because it was a matter of copy-pasting code snippets and being absolutely terrified of them.

But now it’s 20 years later, I’ve got 12 years of being a professional programmer and 9 of actual game development under my belt. There is no longer any fear.

I did not expect Gasbags to be head-shottable… Also in large numbers they’re actually hella tough. Those fireballs pack a PUNCH.

The fun thing about modding UT is that all of the game logic is on show. While the engine itself is compiled away into binaries, the gameplay all comes from high-level UnrealScript — a C-like object-orientated language that also has a heap of fundamental features designed to make game development easier.

Although you can use UnrealEd to browse the UnrealScript classes and do light coding, the best course of action for heavy work is to decompile the lot and work against it in an external IDE. Obviously, because I’m stuck in the past, I fired up WOTgreal, an UnrealScript IDE originally designed for The Wheel of Time but which can work with any UnrealEngine game up to about UT2004.

This ability to pour through all the existing game logic is incredible, because you can scour it for logic you are familiar with from the actual game, that’s similar to what you’re trying to make yourself, and just… copy it. If a piece of logic is good enough for DeathMatchPlus — the actual game we paid money for! — you’re god damn right it’s good enough for me and my little potato mod.

Redeemer? I ‘ardly know ‘er!

My first goal was to make an empty game mode. That is, DeathMatch without bots or other players or anything, but still basically functional. Somewhere you can run around and pick up weapons without any hassle. That seemed like something that shouldn’t be too hard to build as a first step.

UnrealScript is highly object-orientated so my first instinct was to subclass DeathMatchPlus and just override out the bits I didn’t like. However, after some experiments, I was unhappy with how much baggage that actually left me — after all, I’m not making anything remotely arena-like, even if I want to retain some of the structural elements.

Sooooo instead I just copied and pasted the entire DeathMatchPlus script into a new file and started manually shaving off the bits that I didn’t want. Bots? Other players? The ready/not ready split and the start countdown? Respawning on death? Pffft! … there’s basically nothing left of it now, so this was the right choice.

I got it rigged up suspiciously quickly. UnrealScript has some odd foibles, but overall it’s really nice to work with. I should have done this years ago!

You wooden believe how nice it is to work with UnrealScript.

After that, I had to add the monsters for you to hunt. UnrealScript provides easy ways to iterate over all the actors of a given type that exist in the map, so I just walked over every PlayerStart and put a monster at each, exactly as planned.

… That turned out to be a bad idea because there are far more PlayerStarts than the recommended player count of most maps, and many of them are in view of where you enter the level (and indeed on it, giving you an instant telefrag). It’s okay, though, because UnrealScript also offers a way to determine if one actor is visible to another — so I made sure only to spawn monsters in PlayerStarts that cannot be seen from the human’s entry point. Bang, we have an exclusion zone so you don’t get dropped in the middle of the action… though it seems to be a little bit temperamental on some maps, so there’s clearly a bit more refinement needed here.

To get my victory condition, I count the number of monsters that got spawned, and tick that down with each kill. Once they’re all gone, you win the level and get to move onto the next. That was still disturbingly easy to implement.

On the plus side, monsters won’t (can’t?) steal the best power-ups before you grab them.

At this point I discovered that there may, in fact, be a flaw in my original design proposal. One of the primary reasons that I love the original UT over all others is that its maps are small, tight and fast. This is great for an arena shooter, because it means there’s little down time between battles. You’re always coming upon somebody or somebody’s coming upon you.

However, this breaks when you replace a small number of respawning players with a finite number of pre-placed monsters. It doesn’t take particularly many creatures to make most maps feel overcrowded — remember that the original Unreal experience is as much quiet exploration of large and fantastical spaces as it is battling up close with enemies. When the levels are claustrophobic DeathMatch arenas with a monster around every corner, it’s hard to recapture the more varied rhythm of a singleplayer adventure. Either it’s too full of enemies and you’re quickly set upon by a Skaarj war party, or you’re only placing one or two and the level is complete in under a minute (give or take finding the last one).

HyperBlast is great if you’ve accidentally carried some Jump Boots over from a previous level and have to fight outside on the roof. Oops.

That effect was blunted at least a little bit when I factored in a progression system. A simple counter incremented with each victory, and passed along to the next map in its URL (another very handy feature), I use this player “level” to strip weapons that are “too powerful”, so you can’t hoover up Rocket Launchers on your very first mission. Since weapons are naturally arranged in your inventory from the rubbish Impact Hammer at 1 and the best Rocket Launcher at 9, I don’t even need to store my own ranking database — I can hook straight into that pre-existing information. (And, theoretically, if you were to play a mission on a custom map that contained custom weapons, they would “just work”. Mmmmmmm.)

All of this leaves you with the default inventory of the Enforcer and Impact Hammer in your first mission or two, meaning it’s a little tougher to take down even the starter enemies; I can rest easy knowing that a reduced enemy count in early levels no longer means they’re over in seconds. (Mind you, I still made a “ScrubBrute” that fires little Skaarj bolts instead of rockets and has only 100 hit points to ease you in a little more gently than perhaps Unreal itself ever did.)

Of course, with all high-level weapons stripped you run out of ammo quite easily and end up stuck with the Impact Hammer. I think I’ll maybe replace that with the Dispersion Pistol…

All of which brings us to today, where I have a broadly functional implementation of the concept as planned. There are a load of rough edges to work on, I need to flesh out the enemy groups and the balance, but I’m delighted to discover that my original idea is indeed feasible.

Sure, I’ve still got a lot to learn about UnrealScript and the vagaries of UT specifically to get this mod to some kind of completion, but I’m over the starting hump — we have uncovered the technology and we have proof that we can make it work.

What do you mean, I’m supposed to be making a real game?

And you tell me...

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.