Archived

This topic is now archived and is closed to further replies.

gpalin

RPG damage equation

Recommended Posts

I am working on my first RPG in Visual Basic. I have gotten to a point where I need a good damage equation for when attacking enemies. The statistics I have are Strength, Endurance, Agility, Power, and Intelligence. I have a basic equation using the attacker''s Strength and the enemy''s Endurance, as below.
If characterStrength > enemyEndurance Then
  enemyHP = enemyHP - characterStrength - 5 + Random(characterLevel)
elseif characterStrength < enemyEndurance then
  enemyHP = enemyHP - characterStrength + 5 + Random(characterLevel)
end if
 
If the attacker has greater attack then the defender’s endurance, do extra damage. If attacking strength is less than defending endurance, do less damage. The Random statement adds some randomness to the attack, based on the character’s level. As the character goes up in levels, his attacks can increase too. I also have here the accompanying Random function, just for completeness.
Public Function Random(ByVal num As Long) As Long
  Random = Int(num * Rnd)
End Function
 
Now, this is just some pseudo code I wrote up, just to get started. What I would like to do is to add something to check for the Agility of the character and enemy, and make them both miss sometimes when attacking, and also to sometimes do double damage. As this is my first RPG, I would like some suggestions for including the Agility and occasionally lucky hits through code. Grant Palin

Share this post


Link to post
Share on other sites
Ok well I'm not much of a programmer but equations I can do. If I were you though I think I would check for the miss or lucky hit before like generate a random number off the charater level then say if the number is lower then some number (x) then it will be a miss if the number is between x and n then it is normal and if the number is above n it is lucky and have three equations where if it is a miss damage=0 and if it is normal use the same equation and if lucky make the equation add something else. It might look somthing like this.


If Random(characterLevel) < x Then
enemyHP = enemyHP
elseif Random(characterLevel) >x If characterStrength > enemyEndurance then
enemyHP = enemyHP - characterStrength - 5 + Random(characterLevel)
elseif characterStrength < enemyEndurance then
enemyHP = enemyHP - characterStrength + 5 + Random(characterLevel)
elseif Random(characterLevel >n Then
If characterStrength > enemyEndurance Then
enemyHP = enemyHP - characterStrength - 5 + Random(characterLevel) + Random(characterLevel)
elseif charaterStrengh < enemyEndurance then
enemyHP = enemyHP - characterStrengh + 5 + Random(characterLevel) + Random(characterLevel)
end if


My code prob. won't work I was doing it with not much programming skills but I hope you get my idea. Also you could take the agility of the player into account by adding it like this
(enemyAgility - characterAgility) 
and then add that to the random number. Hope this helps.

Edit: I actually think I would take it into funtions but I don't really know Basic all that well I'm more with C++ but that is two different if statements not one so I prob. need an
endif 
after your equations too.

[edited by - Serge on July 26, 2002 10:38:46 PM]

Share this post


Link to post
Share on other sites
Thanks Serge, the equation you provided looks pretty good. I've revised it as below. I corrected a few errors...There was an End If missing at the bottom.


If Random(characterLevel) < x Then ‘Miss
enemyHP = enemyHP
ElseIf Random(characterLevel) >=x and Random(characterLevel) If characterStrength > enemyEndurance Then
enemyHP = enemyHP - characterStrength - 5 - Random(characterLevel)
ElseIf characterStrength < enemyEndurance Then
enemyHP = enemyHP - characterStrength + 5 - Random(characterLevel)
End If
ElseIf Random(characterLevel) >=n Then ‘Lucky hit- double damage
If characterStrength > enemyEndurance Then
enemyHP = enemyHP - 2*(characterStrength - 5 + Random(characterLevel))
ElseIf characterStrength < enemyEndurance Then
enemyHP = enemyHP - 2*(characterStrength + 5 + Random(characterLevel))
End If
End If


Note that at the bottom of the code, for the double damage section, I removed the second Random number in each of those two equations, and as you can see, added a 2* in front, to double the effect. I also changed the + in front of each of the Random numbers to -, since I don't want to be giving HP back to the enemy! Only in the first set of equations, though. If I did the same in the second set, I would be losing damage. Anyway, let me know if there are any errors in my editing, and if you have any other ideas, just leave a message here!

Grant Palin

[edited by - gpalin on July 26, 2002 12:48:24 AM]

Share this post


Link to post
Share on other sites
If you feel like getting more complex with this (and other parts of the RPG), you may consider getting the Advanced Dungeons And Dragons Rulebook (or another paper and pen based RPG). The AD&D Volume 2 rulebook has some pretty well integrated stuff in there that'd apply in other parts of the game as well. Also, it should give you some idea of how others have handled these sorts of calculations.

If I remember right, I believe their setup is something like this:

Each character has agility, dexterity, intelligence, wisdom, charisma, strength, 'n some others that I can't remember at the moment.

Depending on the character's dexterity and the character's proficiency with whatever weapon he/she's using at the time, they get assigned a THAC0 (To hit armour class 0 (lower armour class=better protection; higher agility may provide bonuses to armour class)). At the beginning of a turn in a fight the character will decide who to attack and they'll calculate what they need to roll to hit that character (if the player has a THAC0 of 7 and the enemy has an armour class of 3, the player must roll a 4 to hit the enemy (remember: lower armour class = good thing)). During a fight the character will roll some dice (I dunno, a bunch let's say) and if the number's higher than whatever they need to hit the enemy, they hit 'em. If it's exactly a certain number (18 I figure, as the sum of three six sided dice), then the player may double the damage that will be dealt to the enemy (critical hit).

Please note, this is all based on whatever I happen to remember of reading a book many years ago, so a good portion of this may be sheer BS.


[Edit: Spellin ish bad while drunch: they're != there != their]

[edited by - Melraidin on July 27, 2002 1:14:28 AM]

Share this post


Link to post
Share on other sites
quote:

If I were you I wouldn''t use arbitrary numbers such as ''2*'' or ''-5''. I''d rather make an universal and logical system.



Why??

Here''s my equation as I have it now, after some revision.


If Random(50) < x Then ‘Miss
Damage = 0
enemyHP = enemyHP
ElseIf Random(50) >= x and Random(50) < n Then ’Normal hit
If characterStrength > enemyEndurance Then
Damage = characterStrength + 5 + Random(characterLevel)
enemyHP = enemyHP - Damage
ElseIf characterStrength < enemyEndurance Then
Damage = characterStrength - 5 + Random(characterLevel)
enemyHP = enemyHP - Damage
End If
ElseIf Random(50) >=n Then ‘Lucky hit- double damage
If characterStrength > enemyEndurance Then
Damage = 2 * (characterStrength + 5 + Random(characterLevel))
enemyHP = enemyHP - Damage
ElseIf characterStrength < enemyEndurance Then
Damage = 2 * (characterStrength - 5 + Random(characterLevel))
enemyHP = enemyHP - Damage
End If
End If


This advanced equation adds checking for the value of a random number; if the random number is below a constant value, no damage is done (a miss). If the value is between the previous constant and the second constant, the damage is a normal amount (normal damage). And if the value is above the second constant, the damage is doubled (lucky attack).

I''d still like to add something for Agility. I''ve got an idea. and I''ll put it online when I''ve got it fleshed out.

Grant Palin

Share this post


Link to post
Share on other sites
Okay, here''s my new equation.


If Random(50) < x Then ‘Miss
Damage = 0
enemyHP = enemyHP
ElseIf Random(50) >= x and Random(50) < n Then ’Normal hit
If characterStrength > enemyEndurance Then
Damage = characterStrength + 5 + (characterAgility - enemyAgility) + Random(characterLevel)
enemyHP = enemyHP - Damage
ElseIf characterStrength < enemyEndurance Then
Damage = characterStrength - 5 + (characterAgility - enemyAgility) + Random(characterLevel)
enemyHP = enemyHP - Damage
End If
ElseIf Random(50) >=n Then ‘Lucky hit- double damage
If characterStrength > enemyEndurance Then
Damage = 2 * (characterStrength + 5 + (characterAgility - enemyAgility) + Random(characterLevel))
enemyHP = enemyHP - Damage
ElseIf characterStrength < enemyEndurance Then
Damage = 2 * (characterStrength - 5 + (characterAgility - enemyAgility) + Random(characterLevel))
enemyHP = enemyHP - Damage
End If
End If


This version of the equation uses the Agility stats of the attacker and defender. If the attacker has more Agility, he does more damage, and less Agility means less damage.

I am thinking of removing the random numbers based on the character levels, since they don''t seem to have much of an effect on the total damage. If anyone has thoughts on this, please let me know.


Grant Palin

Share this post


Link to post
Share on other sites
I wouldn''t use numbers like *2 or -5 because

1. You may forget why they''re there
2. They''re hard to change later

It''s much easier to make a variable such as COMBAT_PENALTY or COMBAT_BONUS and use that instead because it would fix the above problems.

Share this post


Link to post
Share on other sites
Allow me to suggest a few things.

1) Write your character class as an object with all of your listed statistics as properties.

It will be alot easier to keep track of it all, trust me,
but i will stick to your linear method for now.

2) Try not to do as much math on the fly. I''m assuming that like any good RPG there will be alot of combat involved. If your going to call this function alot, which you will, you should resolve as much upfront as possible.

How will you handle armor, how will you change it?

See if any of this looks good:


Const CHAINMAIL_VALUE = 30


Private Function NewAC As Long

NewAC = Agility + EquippedArmorValue

End Function

Private Function ToHit AS Long

ToHit = CharacterStrength + Int(Rnd * 100) + 1

End Function


When your character changes armor then

EquippedArmorValue = CHAINMAIL_VALUE
CurrentAC = NewAC




When your character actually attacks:

If ToHit >= MonsterArmorClass Then

ResolveDamage

Else

You Missed

End If



Kind of tough really to read because i haven''t coded without objects since i''ve learned to do them but definitely don''t recalculate anything in your to hit swing that you can calculate once and carry with you. Invent an ArmorClass that will carry each creatures chance to avoid damage with it, so you don''t have to recalculate it. Also think about your code and your game, you don''t want write a line of code for each incidence in your program, you really just want to write the rules they will use and then toss a bunch of data at your rules. And finally, for the third time(i think) pre-calculate everything you can. VB math functions are really slow. Maybe you could Pre-generate a whole bunch of random numbers when your app loads and then iterate through an array to get your to hit seed. (make any sense?)

Best of Luck!


Dreddnafious Maelstrom

"If i saw farther, it was because I stood on the shoulders of giants."

Sir Isaac Newton

Share this post


Link to post
Share on other sites
quote:
Original post by Dreddnafious Maelstrom
Allow me to suggest a few things.

1) Write your character class as an object with all of your listed statistics as properties.


You mean like this??

Public Type Character
Name As String
Sex As String
Race As String
Class As String
Strength As Long
Endurance As Long
Agility As Long
Power As Long ''Controls the effectiveness of spells
Intelligence As Long ''Controls the number of spell points
MaxHP As Long ''Maximum Hit points
CurHP As Long ''Current HP
MaxSP As Long ''Maximum Spell points
CurSP As Long ''Current SP
Level As Long ''Current level
Experience As Long ''Current experience
ExpToNextLvl As Long ''Experience to next level
Gold As Long
End Type

Public Hero As Character


quote:

It will be a lot easier to keep track of it all, trust me,
but I will stick to your linear method for now.


No need, I have a fair grasp of classes, like I showed above. If you thought of that because I had all those seperate variables, that was just some pseudocode I wrote up to get me started. Here''s the real code that I have in the game now...


If Random(50) < x Then ''Miss- no damage
Damage = 0
Enemy(CurrentType).CurHP = Enemy(CurrentType).CurHP
ElseIf Random(50) >= x And Random(50) < n Then ''Normal hit
If Hero.Strength > Enemy(CurrentType).Endurance Then
Damage = Hero.Strength + 5 + Random(Hero.Level)
Enemy(CurrentType).CurHP = Enemy(CurrentType).CurHP - Damage
ElseIf Hero.Strength < Enemy(CurrentType).Endurance Then
Damage = Hero.Strength - 5 + Random(Hero.Level)
Enemy(CurrentType).CurHP = Enemy(CurrentType).CurHP - Damage
End If
ElseIf Random(50) >= n Then ''Lucky hit- double damage
If Hero.Strength > Enemy(CurrentType).Endurance Then
Damage = 2 * (Hero.Strength + 5 + Random(Hero.Level))
Enemy(CurrentType).CurHP = Enemy(CurrentType).CurHP - Damage
ElseIf Hero.Strength < Enemy(CurrentType).Endurance Then
Damage = 2 * (Hero.Strength - 5 + Random(Hero.Level))
Enemy(CurrentType).CurHP = Enemy(CurrentType).CurHP - Damage
End If
End If


quote:

2) Try not to do as much math on the fly. I''m assuming that like any good RPG there will be alot of combat involved. If your going to call this function alot, which you will, you should resolve as much upfront as possible.


It''s not a real-time game, if that''s what you''re wondering. I don''t know nearly enough yet to do real-time. My game is played through forms I created in Visual Basic, and combat is turn-based. I don''t think your statement above would be as much of an issue, would it?

That aside, I don''t really understand- should I seperate the calculations somehow? That doesn''t seem to make sense to me, since I''m only doing them in one place: the Combat form. Could you explain yourself some more?

quote:

How will you handle armor, how will you change it?

See if any of this looks good:


Const CHAINMAIL_VALUE = 30


Private Function NewAC As Long

NewAC = Agility + EquippedArmorValue

End Function

Private Function ToHit AS Long

ToHit = CharacterStrength + Int(Rnd * 100) + 1

End Function


When your character changes armor then

EquippedArmorValue = CHAINMAIL_VALUE
CurrentAC = NewAC




When your character actually attacks:

If ToHit >= MonsterArmorClass Then

ResolveDamage

Else

You Missed

End If



Kind of tough really to read because i haven''t coded without objects since i''ve learned to do them but definitely don''t recalculate anything in your to hit swing that you can calculate once and carry with you. Invent an ArmorClass that will carry each creatures chance to avoid damage with it, so you don''t have to recalculate it. Also think about your code and your game, you don''t want write a line of code for each incidence in your program, you really just want to write the rules they will use and then toss a bunch of data at your rules. And finally, for the third time(i think) pre-calculate everything you can. VB math functions are really slow. Maybe you could Pre-generate a whole bunch of random numbers when your app loads and then iterate through an array to get your to hit seed. (make any sense?)


I''m not doing anything with armor yet. I''m trying to get the basic game running first, and to tell the truth, I''m not sure yet exactly which way it''s going to go. All I have (more or less) fully functioning yet are the Character Creation and Combat forms.

However, please do keep up with the helpful advice!

quote:

Best of Luck!



Thanks!!

Grant Palin

Share this post


Link to post
Share on other sites
Ah , the ever popular turn based RPG!!

I don''t suppose it would be a problem if you do the math on the fly if it is turn based, but better to get in the habit of pre-calculating now, before it becomes a problem later!!

Also the example you gave of a class is a user defined TYPE, which is fine really, but i was refering to an actual class file (.cls) so you build your class file very much like you built your User Defined Type, except your class file can be referenced by a collection, which is far easier to navigate through than an array(IMHO) which is what you will be stuck with if you use the UDT data structure, also you can code events into your class file so you don''t have to do a recursive poll to get your current game data, you can raise an event when your character attacks instead of constantly asking, in each game loop if your character has attacked. (oh hell, i guess in a turn based system optimization''s not such a big deal but events are really tidy, and easy to code!)

So you''re using the VB Controls to display your characters? Hey i wrote a few of those before i tackled my first display driver, you can come up with a pretty cool game really (and pump them out every 3 days or so after, just make sure your code is modular enough to re-use it)

Sorry for the long post. G/L


Dreddnafious Maelstrom

"If i saw farther, it was because I stood on the shoulders of giants."

Sir Isaac Newton

Share this post


Link to post
Share on other sites
quote:

Ah , the ever popular turn based RPG!!


Yeah, I''ve played some before, and enjoyed them, so I wanted to try making one of my own. I didn''t think it would be a bad idea for a first game, so here I am!

quote:

I don''t suppose it would be a problem if you do the math on the fly if it is turn based, but better to get in the habit of pre-calculating now, before it becomes a problem later!!



By pre-calculating, do you mean to do all these calculation beforehand and store the results in an array or such? I don''t know if that would work, since my character generation system randomly generates statistics for the character being created, so the results would undoubtedly be different from the previous result. Or do you mean to do the calculating right after you finish creating thr character?

quote:

Also the example you gave of a class is a user defined TYPE, which is fine really, but i was refering to an actual class file (.cls) so you build your class file very much like you built your User Defined Type, except your class file can be referenced by a collection, which is far easier to navigate through than an array(IMHO) which is what you will be stuck with if you use the UDT data structure, also you can code events into your class file so you don''t have to do a recursive poll to get your current game data, you can raise an event when your character attacks instead of constantly asking, in each game loop if your character has attacked. (oh hell, I guess in a turn based system optimization''s not such a big deal but events are really tidy, and easy to code!)



So do you think I should convert the User Defined Type section to a seperate class file, then? I''ve never had to use class files before...I guess I''ll have to do some research on those.

quote:

So you''re using the VB Controls to display your characters? Hey I wrote a few of those before I tackled my first display driver, you can come up with a pretty cool game really (and pump them out every 3 days or so after, just make sure your code is modular enough to re-use it)



I haven''t even gottoen to the graphics yet...I''m still trying to get the basic game running, like I said before. You wrote a few VB controls before? How do you mean that? And what''s that about display drivers?

Grant Palin

Share this post


Link to post
Share on other sites
I have a new, simplified equation now. Take a look.

Old equation:

If Random(50) < x Then ‘Miss
Damage = 0
enemyHP = enemyHP
ElseIf Random(50) >= x and Random(50) < n Then ’Normal hit
If characterStrength > enemyEndurance Then
Damage = characterStrength + 5 + (characterAgility - enemyAgility) + Random(characterLevel)
enemyHP = enemyHP - Damage
ElseIf characterStrength < enemyEndurance Then
Damage = characterStrength - 5 + (characterAgility - enemyAgility) + Random(characterLevel)
enemyHP = enemyHP - Damage
End If
ElseIf Random(50) >=n Then ‘Lucky hit- double damage
If characterStrength > enemyEndurance Then
Damage = 2 * (characterStrength + 5 + (characterAgility - enemyAgility) + Random(characterLevel))
enemyHP = enemyHP - Damage
ElseIf characterStrength < enemyEndurance Then
Damage = 2 * (characterStrength - 5 + (characterAgility - enemyAgility) + Random(characterLevel))
enemyHP = enemyHP - Damage
End If
End If


New equation:

If Random(50) < x Then ‘Miss
Damage = 0
enemyHP = enemyHP
ElseIf Random(50) >= x and Random(50) < n Then ’Normal hit
Damage = characterStrength + (characterStrength - enemyEndurance) + (characterAgility - enemyAgility)
enemyHP = enemyHP - Damage
ElseIf Random(50) >=n Then ‘Lucky hit- double damage
Damage = 2 * (characterStrength + (characterStrength - enemyEndurance) + (characterAgility - enemyAgility))
enemyHP = enemyHP - Damage
End If


This simplified version removes the Random number using the characterLevel, since it doesn’t seem to have an impact on the damage done. Also, new statements have been added subtracting the enemyEndurance from the characterStrength. If the difference is positive, do more damage; if it is less, do less damage. This allowed the removal of several lines of code, which compared the characterStrength and enemyEndurance, adding or subtracting constant values from the flowing damage equation where appropriate. This equation does the job in less work, and is considerably shorter. This equation is only 10 lines, and the previous equation is 20 lines.

Please let me know what you think of this new equation. Thoughts on efficiency, comprehension etc are welcome.

Grant Palin

[edited by - gpalin on July 29, 2002 1:42:38 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by gpalin

If Random(50) < x Then ‘Miss
Damage = 0
enemyHP = enemyHP
ElseIf Random(50) >= x and Random(50) < n Then ’Normal hit
Damage = characterStrength + (characterStrength - enemyEndurance) + (characterAgility - enemyAgility)
enemyHP = enemyHP - Damage
ElseIf Random(50) >=n Then ‘Lucky hit- double damage
Damage = 2 * (characterStrength + (characterStrength - enemyEndurance) + (characterAgility - enemyAgility))
enemyHP = enemyHP - Damage
End If


i think you havea logic problem with your Random() function... assuming that it generates a random number each time it is called, there is a chance that none of your statements will be called; for example, if it is >=x the first time, then =n the third time, then also (and this following part is simply opinion and not debug help), you should use the agility of the character and enemy to determine if there is a hit, or maybe multiple hits, and leave the damage numbers to the strength. it kinda makes sense: it would be agility that determines if you hit or miss something, and also agility that determines if they can dodge it; the amount you hurt them (assuming you hit) would be based on how string you were and how strong they were (you might even want to put in another character trait for this, such as "defense" or something).
just my $0.02...

--- krez (krezisback@aol.com)

Share this post


Link to post
Share on other sites
quote:
Original post by krez
i think you havea logic problem with your Random() function... assuming that it generates a random number each time it is called, there is a chance that none of your statements will be called; for example, if it is >=x the first time, then =n the third time, then


I don't really understand...could you elaborate bit on that please?

quote:

also (and this following part is simply opinion and not debug help), you should use the agility of the character and enemy to determine if there is a hit, or maybe multiple hits, and leave the damage numbers to the strength. it kinda makes sense: it would be agility that determines if you hit or miss something, and also agility that determines if they can dodge it; the amount you hurt them (assuming you hit) would be based on how string you were and how strong they were (you might even want to put in another character trait for this, such as "defense" or something).



I thought of that too; for instance, the enemy is too fast to hit. I got that idea from other games. The problem is, I'm not sure yet how to implement it. Endurance is my defense-ish trait- it determines how much damage I can handle.

Grant Palin

[edited by - gpalin on July 29, 2002 8:26:02 PM]

Share this post


Link to post
Share on other sites
every time "Random(50)" appears in your formulas, it will pick a new random number between 0 and 50... so, the first line will pick a random number and compare it to "x". let''s say it picks a number greater than x, then it goes to the the "elseif" on line #4. now it picks a NEW random number and ocmpares it to x, then picks YET ANOTHER random number and compares it to n... because it is picking a new random number each time, it is quite possible that all of those conditions will be false, and nothing will happen (not even a "miss").
what you should do it get another variable and set it to Random(50), then use that variable in all of those IF statements...
did i make sense that time?

*** "timeout expired" error ***

Share this post


Link to post
Share on other sites
quote:
Original post by krez
every time "Random(50)" appears in your formulas, it will pick a new random number between 0 and 50... so, the first line will pick a random number and compare it to "x". let''s say it picks a number greater than x, then it goes to the the "elseif" on line #4. now it picks a NEW random number and ocmpares it to x, then picks YET ANOTHER random number and compares it to n... because it is picking a new random number each time, it is quite possible that all of those conditions will be false, and nothing will happen (not even a "miss").
what you should do it get another variable and set it to Random(50), then use that variable in all of those IF statements...
did i make sense that time?



All right, I understand now. How''s this, then?

z = Random(50)
If z < x Then ‘Miss
Damage = 0
enemyHP = enemyHP
ElseIf z >= x and z < n Then ’Normal hit
Damage = characterStrength + (characterStrength - enemyEndurance) + (characterAgility - enemyAgility)
enemyHP = enemyHP - Damage
ElseIf z >=n Then ‘Lucky hit- double damage
Damage = 2 * (characterStrength + (characterStrength - enemyEndurance) + (characterAgility - enemyAgility))
enemyHP = enemyHP - Damage
End If

The way you explained it helped me understand. Thanks!

Grant Palin

Share this post


Link to post
Share on other sites