Thoughts on Combat Models
As stated on other pages, combat is an integral part of most Roguelikes (and in fact, most RPGs). Here are some thoughts on possible models for combat. (This may need some cleaning up by someone that's better at it than me.)
In general
All combat systems boil down to just two basic questions:
- What chance do I have to hit the enemy?
- How much damage do I do?
Many systems will also deal with a third, less basic, question:
- What else happens to the enemy?
In specific
For the purposes of discussion, let's assume that the entire combat system consists of three numbers: ATK, DEF and HP. Each combatant has different values for each of these. With such simplicity, you might think that there aren't many different ways the above questions (ignoring the third for now) can be answered. Below is a (non-exhaustive) list of possibilities. In all of the examples, rnd() returns a random number between 0 and 1. (For example, rnd()+rnd() would be a number between 0 and 2, which is most likely near 1; while 2*rnd() would re a number evenly distributed between 0 and 2.) I'll use C-style syntax to represent the examples.
Feel free to expand this list and discuss the pros and cons for each (which can be listed below). Some of the ideas came from this discussion.
Possibility #1
If your ATK is greater than the enemy's DEF, you do ATK-DEF damage (with the option to randomize ATK, DEF, or both)
Enemy.HP -= max(Player.ATK - Enemy.DEF, 0);
or
Enemy.HP -= max(rnd()*(Player.ATK - Enemy.DEF), 0);
or
Enemy.HP -= max(rnd()*Player.ATK - rnd()*Enemy.DEF, 0);
Corollary: For the non-random version, it is always good to increase your ATK, until the point where Your.ATK - Their.DEF is greater than Their.HP.
Possibility #2
As possibility 1 above, but all hits do exactly one damage.
Enemy.HP -= rnd()*Player.ATK > Enemy.DEF;
or
Enemy.HP -= rnd()*Player.ATK > rnd()*Enemy.DEF;
Corollary: If there were a non-random version, then it would only be useful to increase ATK until you barely beat your opponent's DEF, then increase your DEF, because damage is constant. With randomization, it depends on how often you want to hit.
Possibility #3
You deal (constant) damage; accuracy depends on the proportion of your ATK to your enemy's DEF.
Enemy.HP -= rnd() < Player.ATK / (Player.ATK + Enemy.DEF);
or (equivalently)
Enemy.HP -= rnd() > Enemy.DEF / (Player.ATK + Enemy.DEF);
Corollary: you'll always have some chance of hitting, no matter how bad it gets, but there's diminishing returns for increasing your ATK.
Possibility #4
As above in #3, but if you hit, you get to try again.
while(rnd() < Player.ATK / (Player.ATK + Enemy.DEF)) Enemy.HP--;
Corollary: there are critical hits (in a variety of levels). If you get fantastically lucky, you can take out a Balrog in one hit. On the flipside, that grid bug can take down your Level 50 Game-Winner. As a side note, those diminishing returns for increasing ATK no longer seem nearly so diminishing.
Possibility #5
If Your.ATK is bigger than Their.DEF by their HP, then kill them. Random numbers are required for this method to work at all, or else a combat with roughly-equivalent ATK and DEF would never get anywhere.
if(rnd()*Player.ATK - rnd()*Player.DEF > Enemy.HP) Enemy.HP = 0;
Corollary: this is more chaotic than #4 above; the probability distribution is much more even, so expect wild results more often.
Possibility #6
You always hit, doing ATK/DEF damage, plus or minus some tunable proportion (-25% to +33% in this example).
Enemy.HP -= (ATK/DEF)*((3 + rnd())/(3 + rnd());
Corollary: ATK and DEF are roughly balanced, but combat is nearly deterministic, much like in Possiblity #1 above, except that having a very low DEF is very, very bad. (A 3A/3D player will beat a 5A/1D opponent handily, and a 1A/5D opponent, too. It looks like balance is the best strategy here.)
Possibility #7
As possibility #3, except damage is ATK, not constant.
if(rnd() < Player.ATK / (Player.ATK + Enemy.DEF)) Enemy.HP -= Player.ATK;
Corollary: ATK is far more important than DEF.
Question 3
The question of secondary effects can be dealt with is several ways as well.
- Each attack could be limited to one effect or could have the possibility of multiple effects
- Resistance can be handled in several ways
- The list of effects itself can be big or small
Other thoughts
By limiting the system to just three variables (plus some random numbers) it makes things very simple, both to design and to balance. Such simplicity doesn't have to be a major limitation though. For example, imagine you used the list of D&D attributes (STR, DEX, CON, INT, WIS, CHA). You can reduce these to ATK, DEF and HP and with more variables, you can mix it up a little more. A fighter-type with a light melee weapon might use something like HP = CON + DEX/2; ATK = STR + DEX/2 + WIS/2; DEF = DEX + CON/2 + WIS/2;. Other classes and types of equipment would use different equations.
Still, three basic variables can be limiting. By adding just one more, say ACC or DEX, you can make the hit chance more meaningful and the equipment more balanced. With only three variables, weapons would simply increase ATK and armor would increase DEF. With something like DEX, heavier weapons and armor could decrease DEX in addition to increasing ATK and DEF, which would make the player decide between hit chance/dodge rate and damage/defence.
Also, by starting simple and adding complexity slowly, it can (sometimes) be easier to balance the system (assuming that adding complexity doesn't break the system).