Have I ever told you how I enjoy interpreting game mechanics? RPGs, specifically... Roll the dice and compare and add and manipulate the numbers based on what you have equipped and trained. Dungeons and Dragons just plain confuses me, though. I think it's too bloated to be any real fun... I've looked that the core books before and my eyes kind of glazed over and I put it back down. On the flip side, World of Warcraft's system is left to pure observation. You more or less have to reverse engineer the numbers you see on the screen. It's a pain, but someone's gotta do it, and lots of people have produced some really amazing formulas. And then there's CircleMUD... Pride of the multiplayer text adventure genre. (At least to me.) To understand how CircleMUD works, you have to look at the code.
When you build for CircleMUD, you have to know terms like damage roll and hit roll and THACO and AC in order to determine how hard something hits and how often something hits. I've spent the last couple of days deep in the code of CircleMUD to determine exactly how it figures up if a creature lands a hit against a player! Here's what I've come up with:
THAC0. THAC0 stands for "To Hit Armor Class Zero". It's derived from old D&D rules, and I'm not sure how it worked in D&D, but here's the code from CircleMUD 3.1 stock:
int compute_thaco(struct char_data *ch, struct char_data *victim)
{
int calc_thaco;
if (!IS_NPC(ch))
calc_thaco = thaco(GET_CLASS(ch), GET_LEVEL(ch));
else /* THAC0 for monsters is set in the HitRoll */
calc_thaco = 20;
calc_thaco -= str_app[STRENGTH_APPLY_INDEX(ch)].tohit;
calc_thaco -= GET_HITROLL(ch);
calc_thaco -= (int) ((GET_INT(ch) - 13) / 1.5); /* Intelligence helps! */
calc_thaco -= (int) ((GET_WIS(ch) - 13) / 1.5); /* So does wisdom */
return calc_thaco;
}
Gotta love C programming code. I haven't really investigated the first part, where it's trying to figure THAC0 for the player. Right now, I'm only interested in how hard NPCs hit players, and that's on the lower half. In a nut shell, THAC0 starts at 20, and then it examines the strength points of the NPC and references a manually generated array that returns a little value and subtracts that from 20. Then it gets the value of the hit roll and subtracts it, and then it uses a formula to subtract a special non-floating-point value. For NPCs without any hit roll, the default THAC0 is always +22. They begin with 11 points in both Intelligence and Wisdom, which translates to about -1, which is then subtracted from 20. ((20)-(-1)) is 21. The lower the THAC0, the better, so having 11 points in Intelligence and Wisdom is bad. The maximum is 18, normally, so the more the merrier!
Then you have to figure up the Armor Class for the player:
int compute_armor_class(struct char_data *ch)
{
int armorclass = GET_AC(ch);
if (AWAKE(ch))
armorclass += dex_app[GET_DEX(ch)].defensive * 10;
return (MAX(-100, armorclass)); /* -100 is lowest */
}
First it gets the AC, which is, by default, anywhere between -100 (best) to +100 (worst). Then, if the player is awake, it checks the points in Dexterity and compares it to a manually created array of numbers, very similar to how THAC0 checks Strength. It then multiplies this number by 10 and adds it to the Armor Class. Then it makes sure the armor isn't out of range. But wait! There's more! When it comes to actually checking if there's a hit or miss, it first calculates THAC0, then Armor Class, and then it rolls a d20. (A 20-sided dice.) If the d20 is 1, then you automatically miss and the THAC0 and Armor Class checks were for nothing. If the d20 is 20, then you automatically hit. If it's anywhere from 2 to 18, then the program advances to THAC0 vs AC calculations:
if (diceroll == 20 || !AWAKE(victim))
dam = TRUE;
else if (diceroll == 1)
dam = FALSE;
else
dam = (calc_thaco - diceroll <= victim_ac);
It takes the calculated THAC0 and subtracts the d20, and with THAC0, lower is better, so you want a high d20 roll to subtract... Then, if THAC0 is equal to or lower than the Armor Class, it's a hit. I'm not working with a stock CircleMUD, so things are slightly different, but as you can see, it's a complicated procedure. To hit someone with -100 AC, your THAC0 needs to be -100 or lower. That means you'd need a hit roll of at least 120 to be assured a hit. (After calculations, a default mob with a hit roll of 120 gets you a THAC0 of -98, but remember, the lowest you can roll that d20 is a 2 (because a 1 is a miss), which is subtracted from the THAC0 to always give you at least -100.)
Pretty insane... But, somehow, I enjoy it. I'm telling you, if I had programming experience, I'd be writing my own MUD engine. Something that's easy to document and explain so other people can easily figure out what numbers are best to have. None of this "check Dexterity and compare it to this chart so you can pull a random number so you can multiply it by 10 to subtract from Armor Class." I would settle for a simple statistics system. Strength, Dexterity, Intelligence, etc... They would all start at 10, like most D&D related games. At 10, you get no bonuses and under 10, you get penalized. 25 would be the maximum you could have in any statistic, and it would be a flat out: "Okay, Strength is 20, so add 20 to damage." It would be simple, and if the entire engine was built with that in mind, it would be perfectly balanced.
Honestly, if anyone says games aren't educational, point them here! That'll teach them to generalize. And... I really don't know why I bored you all with this. I'm just bored.