Very close to be "more suited for a forum" but still answerable.
When designing damage formulas and related mechanics, there are well tested approaches. As we have now an entire universe of games to analyze.
First: I have seen Attack + Skill
but mostly on RTE games or top down action RPGs. While Character.Strength + Weapon.Attack
is more common for RPGs/JRPGs. We are still missing target's defenses/resistances/armors
.
It is better to multiply/scale Character.Attack/Strength
rather than add Skill.Power
to it. Otherwise your skill will became obsolete in late game, and you will need a growth system that gives your Character more powerful skills with time, so player stop using obsolete skill in favor of the newer ones.
And this damage skills going obsolete is very common in JRPGs
. They do this to give the player a sense of progression. In those games, you need the leveling, but also the skills. Raw stats alone won't be enough. You need both.
A notable example of this are most 2D Final Fantasy titles.
Add the weapon power to the Character attack/strength is more acceptable, as weapons are OK to became obsolete in late game, forcing the playing to buy more expensive weapons.
Western RPGs are more tactical, in average. A damage skill may have a stronger version, but this doesn't have to mean the previous one is obsolete. It may still be useful because it costs less MP or whatever.
There is also the possibility of leveling skills rather than learning new ones. The idea here is that different skills must do different things. If you just want more damage, but same effect, then just level the same skill, don't learn new ones. Think Diablo/Torchlight.
This is what happens when you use the + operator.
Skill:
{
Name: "Slash",
Power: 10,
Stat: "Attack",
DamageType: "Physical",
Cost: 32
}
Damage Formula:
if DamageType == "Physical":
Damage = Character.Attack + Skill.Power - Target.Defense
else if DamateType == "Magical":
Damage = Skill.Power - Target.MDefense
Leveling Formula: final_stat = base_stat * level
HP also levels by this formula.
Note: this is for simplicity. But nobody does this kind of leveling. Notes on this at the end.
Let's take some time to wonder why magical damage is raw. Because we don't have a stat for magic casting. In our worldbuilding, magic doesn't depend on a Character' stat. Who knows the most powerful spells wins. And yes, this was done before, in Earthbound, PSI (magic) abilities do raw damage, with a random variance between a minimum and a maximum, and magic defense doesn't exist.
We will introduce variance
based on Character.Luck
latter.
Then let's look how the damage becomes obsolete with leveling. Assuming same Character and Enemy level. Let's look at the turns requiring to kill a foe. Note: if your game is real time, it's possible to extrapolate damage per turn
to damage per second
.
The same foe, as long as levels match, takes more turns to be killed by the same skill in late game.
Your game may or may not be OK with this.
If not OK, then you have some options: allow skills to gain levels too. There are real world examples of this system. Think in Skill Trees of most MMORPGs out there, where you can expend skill points in skills you already learned, to make them stronger.
Doing this you can compensate for the numeric effect shown in the graph.
Now let's hack the damage formula. We can make Defense
a division, but for simplicity, let's change one thing at a time.
Damage Formula:
if DamageType == "Physical":
Damage = Character.Attack * Skill.Power - Target.Defense
Ignore that a level 1 it takes 4 turns to kill the foe. That's a rounding artifact. I forced all damages to round down, and all turns to round up.
What that graph shows is that, as long as there aren't other factors like equipment (armor/weapons) at play, the same foe, as long as levels match, will die in the same amount of turns.
I think that is a lot more "elegant" from a mathematical point of view. I like more this damage formula.
There are room for improvement. Try this: do your spreadsheet, but use this damage formula: Character.Attack * Skill.Power / Target.Defense
Also watch for the negative damage artifact. With the subtract defense formula, you may heal the target, in place of damaging it, if defense is too high. In this case, just code an extra if
at the end of damage calculation, and round to 0 if value is negative.
While a division will never change the sign of damage. But watch for other parts of your final damage formula that may.
You still may add skill leveling to your design, but it will be to match lore, or because you think it gives player something extra to do. But not because you need to fight your math.
Damage formula expanded
There is room for improvement.
Most games also have the concepts of elemental attacks. Imbue weapons. Etc.
Variance
In PokeMon there isn't variance in damage calculation except a move has a unique mechanic. There are such moves.
But in most RPGs out there there is variance as a way to add uncertainty to action outcomes.
Example: Damage = Damage + Damage * Math.random(-0.10, 0.10)
Where Math.random
is your favorite runtime random function. And Damage is a variable already containing a value as result of your damage formula.
Pay attention to operator priority. Multiplication solves first.
In words: damage plus a random value that goes from -10% of damage to +10% of damage.
This is a good place to give that Luck
stat a reason to exists.
You can make luck
affect the variance somehow.
Example: Damage = Damage + Damage * Math.random(-0.10 + 0.10 * (LUCK/MAX_POSSIBLE_LUCK), 0.10)
In this case, we use Luck
to shift the lower limit of variance to the right. You may do the same for the upper limit, if you want.
MAX_POSSIBLE_LUCK
is a constant. And is must be set to the max allowed LUCK
, for a legal, non hacked, character in your game. And here is our first problem. This requires you to know your max allowed legal LUCK
in advance.
Mechanic has implied narrative or must be coherent with lore
This is an open debate. Some say yes, some say no. I say yes.
What exactly is Luck
?
Because I understand Strength
. It implies the Character has big muscles.
And I also may understand Attack
. It is more general, for better or worse. It implies the Character does more damage with physical attacks but it doesn't tell us exactly how. It may have big muscles, or it may use its martial arts knowledge to compensate the lack of muscles/size and hit as hard as a very tall person.
Now, while I don't really get Luck
, its use is common. Truth be said.
For Fire Emblem (I don't sure if all of them, but at least the 2D ones). Luck is used in Critical Hit Chance
calculation:
Unit's skill/2 + the weapon critical chance + the support bonus (if any) + the class critical bonus (if any) + character's skills (if any) - the enemy's Luck
Source
I think it comes from Tolkien's: "Luck is also an skill". He didn't invented it, its common belief, but I'm sure it got to gamedevs thanks to him.
But... What exactly it is telling us? That universe is more on the side of that character than on the side of others?
Be digital, not analog
Specially true for Luck
.
In my experience, players don't notice oscillating values. Think in analog radio signals. They won't notice a stat is affecting something analog. The only way they will notice is if you tell them with a help text in your game gui.
Global variance is OK. But nobody will notice if a stat affect it.
Making luck oscillate between -10% and +10%, or between 0% and +5%, is no good.
The mechanic of Critical hits comes to the rescue.
Refer to the Fire Emblem formula once more. The analog part is hidden in the game code. The player will get a digital, binary, experience. It's critical or not critical. But they will notice that more Luck
affect the frequency of critical hits.
Said all that, all game is unique. Just do what you feel.
Notes on leveling
base_stat * level
isn't good. Nobody does that.
You start with very small numbers at level 1 and you end with very big ones at level 100.
Take inspiration from PokeMon, again.
You can define your character structures as a set of initial and maximum stats. The advantage of this, is that you know, and control, the final shape of your characters. Then level will change a stat from minimum to maximum in steps of 1/100. This, assuming you want to cap at level 100.
In JavaScript:
var UniqueCharacterDatabase = {
Hero: {
BaseStatsMin: {
hp: 50,
mp: 25,
attack: 21,
defense: 18,
luck: 8
},
BaseStatsMax: {
hp: 2000,
mp: 800,
attack: 243,
defense: 204,
luck: 97
}
}
}
Formula to calculate current stats:
var level_cap = 100;
var any_stat = Math.floor(any_stat_min + (any_stat_max - any_stat_min) / level_cap * (current_level - 1));
Example, at level 50, attack would be 129
. And that is a nice number for level 50.
You can tune the "growth formula" to include some form of easing. But I think it's not needed.
Note: It's not a good idea redo the numeric simulations shown in graphs with this new proposed leveling system. Because with the simpler stat * level
formula, a characters is, to other characters, always the same as long as levels match.
But with the new leveling system, depending of how you shape two characters final shape, the distance between them may get smaller or bigger, as they approach to their final shape. This would introduce "noise" in the graphs if we only want to analyze the damage formulae.