2008/08/30

AoC: The Good

I've been playing Age of Conan for the better part of three months now; most of you probably already know that. Some of you have probably already heard my rantings on such but in an effort for closure, I'm writing them up here. For the haters out there, yes, I got to 80, and yes, I did a fair share of PvP, but no, I didn't raid. As always, YMMV.

Overlooking Conarch Village

This write-up ended up being way more gigantically huge than I expected, so I'm breaking it up into parts. Stay tuned for the next exciting installment!

The Storytelling
LotRO, for everything I disliked about it, had some pretty good storytelling for the storyline quests at least (the rest of the quests were...uninspired). The storyline quests in that game featured some well-narrated voice overs and some truly epic-feeling instances that were woven in pretty well with the Middle Earth stories we all know and love. Time has robbed me of specific examples, but you generally spent a lot of time clearing the way for the Fellowship or blocking the way of the unrelenting evildoers. I never saw the end of the game (too boring, sorry), but the storyline was the one shining gem amidst a fairly mediocre and redundant game, IMO.

Age of Conan seems to take this the next step--it pushes all the normal MMO mechanics we, um, "know and love" and weaves them into a story with all of the epic trappings befitting the Conan license. There's a great evil (check), it threatens all of existance (check), there needs to be a hero to deal with it (check), and that hero is you! (check) Ok, so we've got the basics covered; it doesn't really deviate at all from any epic fantasy plot. (cue writers)

So why can you res when you die? They go to great pains to explain this! It's worked into the story! I know, nuts, isn't it? If you're such a badass, why are you getting worked by low level thugs? They explain that too! Inside the fictional framework they've put in place, it even makes sense in a fantasy-plot-logic kind of way. That's a ballsy move. They could have left all of that unsaid like every other MMO I've played to date, but they didn't. The only glaring hole they left that I noticed is that everyone's a hero but, ya know, they did so well with the rest of it that I'll spot 'em that one.

The storyline quests were, in fact, the one part of the game that I really looked forward to. I was sad that post noobalicious island, there's only a handful of them and they're spaced pretty far apart.

The Voiceovers
I'm a sucker for voice overs; I don't know why. For the vast majority of games to date, they're awful. Some of my favorite games, in fact, have crappy voice overs (Spellforce was all over the map, the sequel was not much better, and many of Vanguard's voice overs were downright cringeworthy). It doesn't take much to come up with a list of games with crappy voice overs (don't even get me started on CivRev or EQ2) but coming up with the opposite list is way harder. Among the tops, IMO, are Mechwarrior IV: Mercenaries, Supreme Commander + expansion, and now, Age of Conan.

The entirety of the dialog is voiced over for the intro island (1-20). All of the storyline quests are voiced over. While some of them are mediocre, some of them are quite excellent. In particular, Rhiderch, your spiritual guide through most of the early parts past the intro, is quite well played, in addition to Turoch, Laranga, and Cassilda in the intro. In fact, Rhiderch has a set of dialog after you finish the last part of the quest at 80 for no other reason than story. The kicker? This game is not made where English is a first language! I'd love to know how the other language versions of the voiceovers are.

The Combat System
Admittedly, the combo system isn't what I was expecting, but that's their fault for picking terminology from a different genre. You basically get three swings to start with (left, middle, right) and add two more at a later level (lower left, lower right). To go with that, there's a set of shields on your opponent signifying where their defense is. Hitting a heavily shielded direction means you do a heck of a lot less damage so you're rewarded for hitting places where your opponent's defense isn't. To that end, there's no auto-attack. None. Every strike your character does is more or less because you hit a button to create that action.

A combo is just a starter with a string of attacks in a given sequence that, when uninterrupted, yields a multi-part hit at the end usually doing high damage and looking really cool. These start low (one move) and end very high (four moves). It's sometimes tricky landing a combo on a moving target especially when it's a four move job but it's not impossible. I'd expected a more freeform thing where you stick moves together and they speed up or slow down or have other bonuses/penalties but that's just my fighting game background shining through, I guess.

The thing I like most about the combat system in AoC is that you can't phone it in. You have to be aware and awake and mashing away at the right buttons at the right time. If you're not, you're probably not going to survive anything more than the most trivial of encounters. It's even more important when grouping since no character has even footing with any of the epic level mobs (elites from WoW).

The Art
Old Tarantia
The game looks really good. If you've got enough machine to do so, crank everything up as far as you can for the love of pixels. The environments are excellent. The character models are excellent. The weapon models are excellent. Normally I don't care terribly much about such things but this game looks really good. Just look at the screenshots.

2008/08/08

Wheels

Seemingly forever ago, I was at the beginning of what would be my last winter in Illinois. My modus transportatus at the time was a 1987 Oldsmobile Cutlass Ciera which we regarded not-so-fondly as the "Gutless" because it had trouble moving its 2900lb bulk even with a 2.8L V6 when it wasn't stalling in the middle of the road. At this point in the not so distant past, I had already had the transmission rebuilt twice and it was in pretty bad need of some intensive care. I was not prepared to provide this care (Damnit Jim, I'm an engineer, not a mechanic!) so it was time to replace it.

This is what I got:
It looks just like it did when I drove it home the first time.

This is the Saturn SL1, 2002 model. It was the last of its kind having been replaced by the not-critically-acclaimed Saturn Ion. As you may remember from my previous not-so-award-winning post on Fragmentation, it's mostly made of plastic. Thus, it weighs in at a comparatively svelte 2350lbs and is reasonably powered by a 1.9L 100hp inline 4. If that doesn't sound like a lot of power, it's because it isn't; but it was plenty enough to kick the crap out of the dying Gutless. It gets on average, 35mpg in city and 40mpg or more on the highway if there aren't a lot of hills (i.e., not PA). Yes, that's right, I get more than 40mpg on the highway most of the time (highest clocked in at 44mpg or so on a straight shot through Ohio).

After purchasing the vehicle, I ended up leaving the state for Virginia soon thereafter only to move to Wisconsin in a couple years, and now Maryland a couple years after that. You wouldn't believe the pain in locating and then transferring my title. It's been through a lot in the roughly 6 years I've owned it and still is in pretty good working order. It's a great car, even if a bit low on power, and it's hard to beat the gas mileage. But as much as I love my SL1, it was time for something new and hot.

Imagine my surprise when Saturn not only came through with a very sporty vehicle that I wouldn't have to haggle for, but also came through with one of the top vehicles in its class! I present to you, my brand new Saturn Sky Redline, 2009:
It looks just like it did when I brought it home for the first time...last Tuesday.

The Redline comes equipped with a 2.0L 260hp turbocharged inline 4 and has a curb weight of about 2900lbs. No amount of my picture taking can adequately capture its knuckle biting beauty. It is also not slow. No, sir, it is not. And if you compare it to just about any other vehicle in its class, it comes out ahead either in looks, power, or power/price ratio. Seriously. Go compare for yourself if you don't believe me. I'll wait.

I don't think I've ever owned a nicer thing. I even learned to drive stick so that certain people (you know who you are!) wouldn't mock me for buying a slushbox. For a guy who's spent more time driving 10+ year old rust buckets than otherwise, it's a pretty big change of pace and a heck of a lot of fun.

2008/07/10

Safety Tip #948

When one desires a piece of pie, avoid the urge to eat the pie in place (in the tin) even if you live alone.

That is all.

2008/05/21

Fragmentation And You!

In the continuing series of posts about Stuff They Never Tell You About Game Development, I'm going to rant a bit about fragmentation, why it's evil, and how you can stop its nefariousness.

Fragmentation is basically where you've got a something that's X big but all the wee tiny bits where you can place your something are too small even though your something would totally fit if the space weren't partitioned so badly. Consider me trying to park in Fell's Point (this is near the water in Baltimore for those wondering):

This happens ALL the time.

If you try to park on the street in Fell's Point, you will rapidly learn that there are no lines on the street. This means that people with giant SUVs getting less than 10 mpg highway have NO IDEA where to park their environment destroyingly inefficient vehicles. I drive a tiny Saturn which is mostly made of plastic. It does not ever fit in the spaces left. If only (heaven forbid) I could rearrange these parking challenged bozos' vehicles, I would have plenty of room!

Like you've never had this thought before.

This, friends, is fragmentation at its ugliest. It also happens in your computer's memory (among other places).

Backing Stores and Virtual Memory and Consoles, Oh My!
Memory fragmentation is basically like the two images above: you've got X amount free but it's all broken up into tiny bits that you can't really use. It's a Bad Thing (TM). Occasionally you need to allocate something big and contiguous like an image or something and those tiny bits just aren't going to cut it even though it would totally fit if you could add up all the tiny bits. This requires another chunk of memory to be grabbed from the free store to satisfy your request.

For a normal modern OS, this usually isn't a big deal because we have a) a backing store like a hard drive, and b) a good virtual memory system that can page things in and out if you get near the end of physical RAM a la your undergraduate OS course. The worst that usually happens is the program is a little more chuggy (or a lot more chuggy, depending on your system) and you get fragged more often because your framerate dips and you just can't dodge that guy's rail anymore (bastard).

On a console or embedded device (like the iPhone) it's a whole lot more catastrophic. We may or may not have a backing store. We may or may not even have a basic virtual memory system. It probably doesn't use the backing store that we may or may not have to page RAM even if it has the hardware to do so. So we may or may not be screwed when trying to allocate a giant piece of memory for the screen grab of your most recent death because railboy is totally hacking. By "screwed" here I mean "crash" because that's usually what such devices do. And, sadly, in this situation, we're usually screwed.

How It Be Happenin'
Consider the following horribly-contrived-yet-so-close-to-actual-production-code-I've-seen-recently-that-it-makes-me-shiver-just-typing-it example:


vector StuffToLoad;
StuffToLoad.push_back( "some_prefs.xml" );
StuffToLoad.push_back( "a_texture.dds" );
StuffToLoad.push_back( "this_is_temp.dds" );
StuffToLoad.push_back( "big_honkin_asset.stuff" );
StuffToLoad.push_back( "another_asset.stuff" );
for ( uint ii=0; ii<stufftoload.size(); i++ )
{
LoadAsset( StuffToLoad[ii] );
}



The basic idea is that it's trying to load a bunch of stuff. During the loading of those assets, it really needs the "this_is_temp.dds" texture prior to loading "big_honking_asset.stuff" but then gets rid of both of it and the prefs XML file. Those of you who have dealt with this issue are probably headpalming right now (just play along). For this exercise, we'll assume that LoadAsset allocates exactly once per asset. and UnloadAsset properly deallocates that one allocation. So how swiss-cheeseified does this snippet make your memory?

Seems simple enough?

That's the big blocks, certainly. What about the rest of it? The bad news is that depending on your particular compiler and the version of the Standard C++ Library you're using (otherwise known as the STL), it might be much, much worse. At the very least, the vector is going to allocate at least once but more likely two or three times. Each string pushed into the vector is probably going to allocate once for the string. If LoadAsset's prototype looks like this:


BOOL LoadAsset( string AssetToLoad );


it probably allocates once per function call for the pass by value (hooray for copy constructors!) as well. So by the time you get to allocating the one chunk for your optimzed LoadAsset, you've probably blown two tiny temporary allocations on strings! Load and unload a bunch of assets and you're nickling and diming your memory to screwedness!

Closer!

For people not used to thinking about this kind of optimization, this often comes as a complete shock. This kind of thing usually requires someone (typically me), to go through piles of code to root these things out of them because memory is prodigiously perforated and the game crashes if you play it a lot. This is both tedious and error prone and a better solution is to not write it like this in the first place.

This is one way fragmentation happens and it's really, really painful to deal with after the fact. Such issues tend to not manifest themselves until the very end of the game which tends to only get played near the end of the project which is where disasters tend to collect leading to some very, very long work weeks. Don't ask how I know this. To make matters worse, it only takes one dood to sprinkle such gems throughout a significant portion of your codebase.

If You Were Looking For an Easy Fix, You Will Be Disappointed
WIthout going into a lot of gory details about How To Write A Memory Manager in C++, I'm going to have to gloss over some details (besides, that's for a different post). The basic gist of how to deal with fragmentation is to have a decent idea of how your program's memory is going to be used and be uber-careful with anything that might allocate.

For the example above, we know that both string and vector are going to allocate at least some memory. We can provide an allocator to it or remove them completely since, at least in this example, we don't actually need most of what they do and our list is hardcoded anyway. We can further make this better by having a temporary heap that we know is going to be churning a bunch and pass that into the LoadAsset function so our two temporary assets don't fragment the main heap either. At that point, we can optimize the heap function for the temp heap to prevent fragmentation since we're going to hammer it (and believe me, once you have such a heap, you will hammer it). Here's a somewhat less fragmenty version:


struct AssetLoadInfo
{
const char *mAssetName;
uint mHeapIndex;
};
AssetLoadInfo *c_StuffToLoad[] =
{
{ "some_prefs.xml", c_tempHeap },
{ "a_texture.dds", c_defaultHeap },
{ "this_is_temp.dds", c_tempHeap },
{ "big_honkin_asset.stuff", c_defaultHeap },
{ "another_asset.stuff", c_defaultHeap },
{ NULL, 0 }
};

BOOL LoadAsset( const AssetLoadInfo &rfAssetInfo );
BOOL UnloadAsset( const char *AssetName );
for ( uint ii=0; NULL != c_StuffToLoad[ii].mAssetName; ii++ )
{
LoadAsset( c_StuffToLoad[ii] );
}
UnloadAsset( "some_prefs.xml" );
UnloadAsset( "this_is_temp.jpg" );


We aren't talking rocket science here, but it does require programmers to carefully consider what they're doing. C++ makes it stupifyingly easy to make a mess of things and you just don't want to get yourself backed into a corner with fragmentation when your game is being released on a console. People don't like it when their games crash (believe me on this one).

There's WAY more to it than just small optimizations like the one above. Having a proper memory strategy, making sure that you have a proper memory budget, and making your own memory allocation devices are all super important in memory limited situations and can save you an awful lot of painful debugging. See you next time for the next installment of "Stuff They Never Tell You About Game Development"!

2008/05/09

MIND THE GAP!

Ever been on one of those projects where someone (usually the leadership) thinks it's going way better than it actually is? If you've spent a reasonable amount of time in software, you probably have. Here, then, is my sole addition to the software engineering lexicon. Feel free to use this whenever appropriate.

    The distance between the actual doneness of a project and the perception of doneness is hereby defined as the Reality Gap.


So, assuming you had some magical way to determine precisely how far along on a project (or task, or whatever) you are, the distance between there and where you think you are is the Reality Gap. If the Reality Gap is large, then, well, your team may be tremendously optimistic or, sadly, in denial. Welcome to deathmarch.

I mention this for no reason whatsoever. None.

2008/05/08

Switch?

Over the last, I dunno, few years or so, I've been trying to justify buying a Mac. in fact, it's been long enough that this post has been in my drafts list for the better part of a year and a half. Let's face it, I'm a die hard PC guy and a gamer and Macs just don't stack up in many of the ways I care about.

A brief historical interlude: way back in the day when OSX was first introduced, I remember having talks with one Jeff Kopmanis who at the time was the IT guy at the AI lab where I worked. I trust his opinion and he was Mac optimistic. Fast forward to my near-Chicago days and I had a bunch of friends who were also Mac optimistic, notably one Andy Carra whom you might recall is at least partially responsible for my tastes in laptops.

Around the time I was first writing up this post I was tooling around on AnandTech where I tend to go for hardware news when I want such things and I found this article and this article. Ever since there's been a BEER, I've been toying with the idea of porting it to the mac because, well, I know nothing about programming for the mac and goshdarnit, that's something I'd like to know. I'm told by people in the indie biz that the mac has a pretty captive audience who are just dying to have some games to play on their spiffy machines.

I now give you:
  • Exhibit A: the unbelievably slick design of these lovely slices of awesome
  • Exhibit B: the iPhone which I will own soon (very soon), and
  • Exhibit C: the iPhone SDK which will let me program for the thing

    So yeah. I have a problem with technology; I'm an addict. I have no problem with this. I now own an iMac.

    Oh man.
  • 2008/04/08

    My Fridge

    Sign #5,731 that you've been crunching too much:
    BEHOLD! My Fridge:
    This isn't a staged shot.
    Click to embiggen.

    2008/02/21

    Oh Man...

    I probably shouldn't have done it but I did anyway. In fact, I'd talked myself out of it for a few months but really, I didn't stand a chance. Behold!

    5000+ pieces of awesome

    2008/01/01

    Happy New Year

    I hope y'all had a good holiday and didn't have too many hangovers. Me? I ate entirely too much and spent way too much time in airports.

    I don't have any big release this year, not that GWA was a big release or anything, and I didn't even really do that much work over break aside from the work I get paid for. That's mostly due to a high level of burnout and the fact that at my parents' place in AZ, I don't have a quiet place to do work.

    In keeping with my (now) two year tradition, I'm not posting New Year's Resolutions here. To this statement, I'll make one concession today. The one not-quite-resolution is doing more work at home and releasing more stuff here. I'd like to write more technical stuff and release more code, even if it's not in game form.

    2007/12/10

    True Story

    Last night I had some time so I fired up Spellforce 2: Shadow Wars. I didn't buy it because there's a half nekkid dark elf on the box, (though I might have bought this one because of the box art). I think I'm about halfway through given the mix of races, the explored vs. unexplored portions of the map, and comparisons with the original (they both follow the same general plot and buildup lines).

    Without getting into a lot of detail about the game or the setup, the two characters in question here are Bors, the fighter dood, and the hunter Mordecay who at this point is fairly new in the party. On my way back through a zone to take care of some side-quests I found a named baddie and proceded to open a can on it. It dropped a pretty good two handed sword. This was the resulting voice-over banter (as best as I can remember; I was kind of drunk):

    Mordecay: "Hunter weapon."
    Bors: "No it isn't!"
    Mordecay: "Roll?"
    Bors: "Bah!"

    That's far too awesome.

    2007/12/09

    Two Book Recommendations

    Since we've been crunching, I haven't had a lot of time to do a whole lot of development at home. So instead, I've been trying to catch up on my reading. As in the title, there are not one, but two books that I'm prepared to recommend to y'all.

    The first one is by one Gerald Weinberg
    Becoming A Technical Leader. He's the author of such classics as PL-1 Programming: A Manual of Style and
    The Psychology of Computer Programming. (The former may not have aged quite as well as the latter for those keeping score.)

    It's quite a good text; the kind that really makes you think if you're willing to.

    The second is a bunch of stuff that I'd already read, handily polished up and put into dead tree form: Managing Humans by one Michael Lopp of Rands in Repose fame whose link you can also find over there on the right. Rands is the sort of manager I wish I had at my first three jobs but didn't (seriously). Ever wonder if you and your boss are speaking a different language? It's because you are and Rands will tell you all about it. It's good stuff and should be required reading for anyone who manages technical people.

    2007/12/02

    Mind the Rubble

    The good thing about ridiculously long compile times is that you get time to do stuff like update your blog's template.

    Carry on.

    2007/11/21

    Full of Fail

    They say you shouldn't blog angry. You can add that to the long list of seemingly good advice that I don't heed.

    So I've been in crunch for the last couple months which in general makes me crankier than normal. At some point in the last week or so I picked up the Supreme Commander expansion. You also might recall that I like Supreme Commander. It is, after all, being the spiritual succesor of one of my all-time favoritest games.

    I verily took said expansion, installed it, ran it, patched it (multiple times) and for my $39.99 at that hive of scum and villainy otherwise known as Best Buy, I got this:

    FULL OF FAIL

    That's it. No indication of what's wrong in any kind of end-user-meaningful way. No clear recourse as to how to fix the issue whatsoever. Smashing. I'm going to guess that this has something to do with SecureROM. Ya know what? If my reward for buying the game is not being able to play it then maybe I shouldn't be buying your games! There's probably a workaround but the days of me having to fiddle around with that kind of shit should be way over. It isn't 1997 anymore.

    Guys, I know software is hard, but would it be too much to let me play the game I just bought?

    2007/11/20

    Oh man...

    Crap. Double crap.

    So sad; I just bought one of these so I can't justify it (even to myself). But they're soooo coooool!

    Stupid technology addiction.

    2007/11/10

    What You Should Know About Load Times

    (cleverly abbreviated as WYSKALT)

    If I have time to get pissed off and say "I can't help but notice that I'm not playing your game RIGHT NOW," then it means your load times suck and I'm probably wondering why I bought your game in the first place.

    This seems bad!

    Loading your game off media isn't rocket science. I'm going to assume that we're loading off some kind of disc with a 'c' media like in a console game rather than your hard drive like on your PC of choice. However, anything applied to optimize load times on disc-with-a-c will also optimize disk-as-in-hard-drive as well. I'm not going to cover everything with load times in this post, but this is the absolute bare minimum of stuff you need to know but I couldn't fit it in quite as catchy an acronym. There's lots more stuff that will make load times even better which I might rant about at a later date.

    So at any rate, here we go.

    Opening Files Sucks
    Most times we don't notice this. Occasionally you run into something where you need to load N files which are kinda small but where N is something gigantic (like 1000). Then you notice--even if you have an uber fast machine. On this generation of console, N is usually on the order of thousands for a given level load for those who might be curious.

    Fixing this is uber-easy: pack all your files into one giant uber-file so you only ever need to have one or at most a small number of file handles open. We often know of these as zips, wads, paks, pigs, etc. (The one I use for BEER is "keg". Clever, no?)

    This makes load times suck less which is the goal. Sadly, they still suck.

    Loading Non-Sequential Data Sucks
    So now you've got your data all archived and it's time to load it. Surprise! It still takes a long time because you're constantly seeking around in your uber file. I can hear you smug Win32 people scoffing--but remember that your file mapping eats virtual address space and I know that since you're still using WinXP that you only get two gigs of VM. Ha!

    This is pretty easy conceptually: stick all the data in your archive in order. The bad news is that depending on your particular data set and load time trickery, this might be really hard in practice. Chances are good that it leans toward the really hard side because you might only load some subset of your data and probably don't have a fixed order for it. If you can make your loading respect a fixed order then the problem moves pretty quickly to the easy side again.

    I've found that in most cases the best we can hope for is that some subset can be made to lean toward "most" for fixed sequentiality. Sometimes you can change the loading code to do nicer things; sometimes you can't for <fill in the blank> reason that fits your situation. In either case you need to generate a sequence list for some set of your data then stick all the data in your archive in that order as best you can. Neither of these are particularly difficult assuming you have source code and enough time to do stuff and an archive builder that doesn't totally blow chunks.

    Why does this work? Once file open issues are dealt with, seek time tends to be the dominant factor in unruly data sets. On discs-with-a-c, each seek is going to weigh in at roughly between 50 and 150 milliseconds depending on your particular hardware. So, if you're loading 10MB of data but seeking 100 times, your load bandwidth for that data can be no better than 1MB/s in the best case (assuming a flat 100ms/seek which is normal). If you try to load a gig of data with that bandwidth, then, well, I'll not be alone in returning your game.

    So: if you can significantly reduce the number of seeks your game needs to do, you can significantly reduce the load time of your game. I've seen particularly poorly loading data sets extend the load time of a 100MB data set more than five minutes. For those in the audience reaching for calculators, that's a bandwidth of less than 1MB/3seconds. Glacial.

    But Our Game Is On the Hard Drive!
    Don't care. These will still make your loads better. Your seeks are still on the order of 8ms and your bandwidth isn't free. Wait till your users start fragmenting the crap out out their drives. Galactic Civilizations is a reasonably fun game but its load times are absolutely brutal. Why? Tons of tiny files none of which seem to be in easy-to-load formats just sittin' there on the disk. Lots of games are like this for the PC and it's a damned shame.

    Oh! You did that for your modders, did you? Guess what; you can still put most of your stuff in order in archive. You can even give modders your packing tools so their stuff loads fast too! Sure, you have to design for it but you're already designing extra stuff in for modders, right?

    Odds, Ends, and Disclaimers
    As mentioned atop, this is the bare minimum you need to know about load times. There are lots of other things you can optimize to make your loads suck less but I'll save that for another rant.

    This has been a public service announcement paid for in part by the "Your Game Loads Too Slowly" foundation of Maryland and made possible by viewers like you!

    2007/11/03

    Script-fu

    Not terribly long ago, I was a self-proclaimed scripting hater. "Oh sure," I said, "You can do some neat stuff in script-land with your not-real languages and your dynamic types. But wow, my C++ can do all of that and uber-more!" Yeah. So it's time to fess up and admit that I might have, ever so slightly, been somewhat mistaken on some 'a that.

    I've had this completely irrational thing for Ruby for, oh, about a year now which mostly manifested itself as not doing Ruby. This (irrational thing for Ruby) is mostly the fault of the blogosphere, notably one Steve Yegge who, despite often being somewhat long winded with a propensity for ten cent words and compilers, is also quite often terribly amusing and a lot of the time spot on. He's got loads of stuff trumpeting the awesome that is Ruby. So I bought a book and read some online tutorials and then got a new job and moved cross country and got tied up in godawful amounts of stuff that's not ruby and wow is that a pretty laptop I should totally get one of those while not doing Ruby.

    I used to know perl in much the same way that most people who knew (past tense) perl once did. That is to say, I have absolutely no ability to do perl now because a) it's very obtuse, b) it looks like line noise, and c) it's so unbelievably obtuse that sane human beings flee in terror when confronted with it. Have I mentioned its obtusitude?* Some have described Ruby as "perl with the suck removed" and as I mentioned before, I have a thing for Ruby.

    <yet another entry for the worst segue ever category>

    I'm now in charge of making load times not suck on my current project. I'd built a couple tools to build giant archive files and to parse in-game spew to do various things that are reasonable and useful toward that goal. I'd built them in C++. This in and of itself is not odd since by and large, I'm a C++ programmer. What I did notice is how godawful difficult seemingly simple things are in C++. This also is not odd since by and large, I'd been noticing that on and off for the last, say, decade. So moving from "hey, I think I can fix our load times" to "holy sweet moby jebus, I have to fix our load times!" I decided that I needed better tools.

    Enter Ruby, stage left.

    So I used it in a real "have to get this crap working right now kind of situation...and it was good.

    So now I gotta take back some of the mean things I said about scripting languages and the people who promote them. Uncle already. I may have been a bit hasty with all of that. Ruby has made the otherwise unbelievably daunting data mangling tasks I've got slightly less unbelievably daunting because now at my very fingertips I have the power to mangle data like never before! Data the world around, tremble before my gemstone inspired might!

    I'll save some gory details and horribly contrived examples from Teh Real World(TM) for a later date. So, if you're like me and only really ever looked at your primary statically-typed language for solving all manner of problems, you might go and pick up a scripting language just cause. It might save you some unbelievably daunting.

    *obtusitude is not a real word. I made that up, honest.

    2007/11/01

    HL2

    One of the (many) things I missed out on during my two year long stint in WoW is Half Life 2. Despite being told how uber-awesome it is, I never got it since at the time I didn't have enough machine to really play it. So beta for the Orange Box rolls around and my co-workers are playing TF2 and I hop on the bandwagon...just in time for them to lose interest (bastards). TF2 is plenty of fun on its own but it also gave me a chance to catch up on otherwise missed gaming (brilliant move by the Valve guys).

    I wasn't prepared. Half Life 2 rocked my socks. There are definitely things about it that I didn't like but overall I thought it was an excellent game. Add to that the two free-to-me episodes 1 and 2 and it ended up being even more excellent. I missed the whole "better than sliced bread" launch so I had to judge it on its own merits and I still think it's by far the best single player game I've played in the better part of two years.

    If you missed this one, aren't totally put off by jumping puzzles, and enjoy a good action FPS, I highly recommend it. Can't wait for Ep3.

    2007/10/04

    Random or Not?

    Here's a not-quite-hypothetical problem: you have a fixed size graph and want to arrange N points on that graph in a random manner. You could use such a thing for lots of different stuff not limited to distributing player positions on a map, etc.

    So how do you do it? Feel free to code along at home.

    Totally random.
    First try: completely random. We'll just use our good friend rand() with some "proper" seed to choose X and Y values and mod them into the map space. Smashing. If you do that, it looks something like those on the left.

    I saw the results and wondered where my bug was cause that sure as crap doesn't look random. Hint: there was no bug.

    Small influence circles.
    Hokay. Welp, I don't want those points to be within N distance of one another where N is something I can calculate easily because, er, I want it to run fast (not because I'm lazy--no not that at all).

    Closer...

    If you were looking for a point, you may have just found it: when I say random in this particular context, really mean evenly distributed rather than really random. In fact, truly random is not what I want at all.

    Final results.
    On the left here are my final results after a mess of hacky heuristics. It's not the prettiest code but it seems to give good results on every map I've generated and it has a calculable upper bound on computation time. As a final step not shown here, I jitter each position inside the grid line so even points that are on the same row or column on the grid appear a little less regular (left as an exercise for the reader).

    Now, I freely admit that I'm one to run off and code something because a) I figure I might learn something, b) I need the practice, and c) I reall like coding. Try as I might I was unable to find a better solution than the hackery I came up with. Apparently my google-fu is not as righteous as I thought. I'm pretty convinced that there's some crazy technique to do this in like 3.47 instructions on a 68020 or whatever but I sure as crap can't find it. If anyone knows of one, let me know.

    (If anyone wants the code, just ask.)