RPG Combat
spellcaster

I'm currently trying to find an easy way to do combat in an RPG.

My current idea is like this:
You have attributes, like strength, decterity, iq, etc. An average attribute would be 25, with something like 50 really good, 75 legendary and everything higher than 90 would be god like.

Every action (attacks, spells, etc) are skills.
Skills have an upper limit of 20 and are based on an attribute.

Club fighting could be a strength based skill.
Defense is either strength based or dexterity based, depending whether he has a shield or not.
Armor gives you a bonus.

Say, Gargle the Dwarf fights againts StoneStick the Troll.

Gargle uses his club:
Club: 5/20 (25%), Str 45 -> Total 45 * 0.25 = 8.5

StoneStick has no defense weapon, so he has to dodge:
Dodge: 2/20 (1%), Dex 18, Armor (stone skin): 10 -> Total 28 * 0.01 = 2.8

Both roll a d100 now.

Gargle rolls a 20
StoneStick rolls a 55.

We multiply the rolled number by the factor:
Gargle: 8.5 * 20 = 170
StoneStick: 2.8 * 55 = 154

So Gargle hits. The damage inflicted is based on the weapon, his club does 4-10 points of damage.

Ok, comments on that system? How are you guys handling combat normally? (Mandrake?)

I'm just not sure if the idea of making the attacks dice based is a good one. I mean, with some bad luck the player could miss all the time..
which would be really frustrating.

Maybe rolling a d10 or d20 might be better? Help?

23yrold3yrold

Sounds good. You could read up on AD&D rules and steal a few ideas ;) Mind you, it sounds like you already have.

spellcaster

Hm... is this close to D&D? I only know the 3rd edition, and I think my system is different.

In fact, I'm even considering to allow instant-hits (as long as you don't goof up)...

But then I'm not sure how armor would be used, and how to determine the damage... hints? help?

nonnus29

I really couldn't follow the logic in your system. First you calculate attributes and bonuses to come up with a multiplier then multiply that by the percentage rolled by the d100. Seems to be almost complete chance since the d100 outwieghs everything.

An alternative form of dice rolling that alot of paper and pencil rpgs use is to assign a number of six sided dice depending on 1. amount of skill with an item/spell 2. character attributes (str/dex/int etc) 3. dice for any bonuses (ie character had a blessing placed on him/her). Then you would roll your fist full of sixers and pray. Variations of this theme were used by: Shadowrun (FASA), StarWars RPG, Space: 1889, Risk(!), and TMNT (I think). EDIT Warhammer 40k too.

Korval

First question right off the bat: is this a real-time fighting system (where deciding whether you hit/miss is based on whether your sword model/sprite contacts the enemy) or a non-real-time system (where deciding whether your hit/miss is based on a random number)?

If it is the first, then you task is a bit easier: you only have to worry about damage stats (unless you want to get into weapon/recovery speed, where a 2-handed sword is swung slower than a 1-handed sword. If you touch that, then you need to do some damage-over-time balancing, but I digress...).

But, in either case, you do need to do some long-range planning now. First, decide what you maximum level is going to be. In videogames, players expect to level-up fairly often, so having a large level range is a good idea. This means, btw, that the difference between two consecutive levels is not that great.

I would suggest that you have 50 levels or more. Now, there's two ways of going about raising levels.

One way is the common D&D method. Your character is a level-N character. Level N for that character's class(es) provides the following bonuses/detriments in combat. In this case, the player's basic stats don't increase in level, but the player does do more damage with their weapon of choice or gain new abilities.

The other way is that each stat has a particular level. When the player gains XP, he can use those points to buy a level of experience for a particular stat. That way, if you've got a swordsman, you will want to spend time leveling up stats that help his sword skill, not things that make him a better wizard.

The D&D method has several advantages:

1) Easy to balance. Because there is just one number that changes (though potions or the like may change a particular stat, stat changes are rare), it is easy to alter the system. Since the user has little control over it, the user can't find that perfect combination that makes a Level 5 character as powerful as a Level 8 character. You are in full control.

2) Less micromanagement. The user doesn't really have to do anything more than kill stuff. The game will automatically improve their character when he level's up.

But, on the other hand, the second method has its advantages too:

1) Good for a non-class-based (or flexible-class) system. If I want a system where a character doesn't have a particular "class", then I would want to use something like this so that the user can customize the benifits of gaining experience for his character.

2) More micromanagement. Some people like micromanagement (I, personally, prefer just dealing with armor, weapons, and baubles without having to also balance stats). I would suggest, however, that, if you go this route, keep the party small. The total party, not just the number you can bring to a battle simultaneously.

Once you have made those important decisions, you now have one more to make: just how much is a lot of damage, anyway?

The Tarasque, one of the most feared creatures in all of D&D, has less than 200 Hp. A level 10 fighter with 80 Hp is either a fluke of lucky rolling or gets a large constitution bonus (which, ultimately, is the same thing).

On the other hand, in the average Final Fantasy game, 80 Hp is nothing past the middle of the game. The common monster at that point is lobbing 300-400 Hp blows, with powerful boss attacks reacing 1500 or more. The last boss will, likely, have tens, if not hundreds, of thousands of Hp.

One of the reasons for this is obvious: FF is a videogame, while D&D is a board game. In a videogame, you have a large level spread. You, also, have a lot of ground to cover with monsters that are steadily increasing in difficulty. The easiest way to make monsters tougher is to give them more Hp. Of course, this means that your party needs to do more damage per level now.

The way that D&D gets away with relatively low Hp is that they use other means to balance tougher enemies. AC, giving the enemy multiple attacks, making the enemy do more damage to you.

Here's the math of the entire problem. There is a ratio of the following things:

Hp taken by the party
Hp done to a group of monsters

  1. of Hp that the party has (modified for cure spells/items)

  2. of Hp that the enemies have (modified for cure spells/items)

Now, to complicate matters, the damage is not a simple question of, "how much damage does an enemy take from an attack?", but the average damage over time (DOT). If a sword does 10 damage every second, and another sword does 5 damage every .25 seconds, the 5 damage sword has a greater DOT, and ultimately, greater damage output.

Therefore, to lower the DOT done by a particular attack, you can make it do less damage outright, or make it hit fewer times. If the 10 damage sword from above hit 90% of the time, and the 5 damage one hit only 10%, then the 10 damage sword would have a greater DOT.

D&D tends to balance enemies by giving them a few more Hp, better armor, and more powerful attacks (that hit more often). A party, to defeat these enemies, will need to have a bit more Hp (a level or 2 worth of Hit Dice), more DOT (better THAC0), and better armor (lower's enemy's DOT).

You have to find level equations and so forth that keep this ratio in balance for the entire game. If it goes too far out of balance, then either the game is too easy or too hard.

Also, consider at this point whether or not you want it to be class-based or classless. If it is "classless", how classless is it? 3rd edition D&D has some pretty simple rules for multiclassing, which makes for some customizability in your character.

Now that we have thought through all of that, we come to the really hard work: designing the actual system.

If you're using a single level-based system (like both D&D and FF), you need to determine your min/max levels and min/max stats. Then, you need to decide on an equation that converts these stats, plus the stats of the weapon in question, into damage. It should, also, take into account the armor rating of the character being hit.

Note that D&D does not use armor to lessen the blow of attacks. Armor is only used to deflect attacks. The idea is that the armor either prevented the attack or the full attack pierced it. FF, by contrast, factors the armor into the overall damage done by an attack and, typically, uses just a Dexterity-like stat to avoid the damage. Using this method, it is possible to get a hit that ultimately does no damage.

Your equation may, like FF's, want to take into account elemental affinities of the attacking weapon and the defending creature.

The D&D equation (for a basic fighter) is simple: weapon damage + strength bonus/penalty (if any). FF's equations are, typically, much more complex. Typically, you will want some kind of random jitter to the output of the equation.

If you are going to have to-hit rolls (non-realtime systems), then you have to have an additional equation.

BTW, you should create stats as you need them; don't create them beforehand. If you don't have a dodge-roll, then you shouldn't have Dex/Agility unless they factor into something else (like ranged attacks).

Here's an example (off the top of my head) of both to-hit and damage from a table-top RPG I abandoned. This, btw, is a stat level-based system, so there is no character level:

Character stats:
Strength
Agility
Natural Defense
etc... (don't remember the rest, but they don't matter for melee).

To-Hit roll:
Strength Level + Weapon Attack Level vs. Agility Level + Armor Dodge Bonus

The characters both roll (D100) on the resulting levels. The results are computed by looking up that level's entry on a chart and seeing what color it is (there were 6 possible colors). Higher levels had higher probabilities for rolling the higher colors. If the attacker's color is greater than or equal to the defender's color, then the attack hits.

Damage:
(Strength Level + Weapon Attack Level) - (Natural Defense Level + Armor Defense Level)

The resulting of this is looked up in a different table. This table turns a level into a Hp damage amount. The defender suffers this much Hp in damage.

In this system, the color chart and the damage chart are the balancing factors (along with the power of weapons and the species-based caps on Strength Level).

I could have, easily enough, added a "finess" stat that was used in place of Strength, so that high strength (and therefore, higher to-hit changes) didn't mean high damage. But, then again, given the color chart method of determining hits, I found that attackers didn't miss much unless the levels between them were very large.

Once, I designed a combat system on the presumption that all attacks hit unless the defender avoids them. This makes some reasonable amount of sense. So, the attacker didn't even roll on the to-hit; only the defender did. Granted, this roll took into account the appropriate stats on the attacker, but it required only one roll. Think D&D's THAC0, only the defender does the rolling.

Ultio

Why not come up with a completely new system, some system that doesn't seem so damn turn based, unless that's what you're going for. How about a system where both player and enemy decide what action they are going to take at the SAME time, and then they are executed.

For instance, if they both attack, they can both take damage from eachother - in the same "round". Also, if one decides to attack and the other decides to parry, you would get the scenario you have already pointed out. Also, if they both decide to parry, nothing happens. Of course, this would be kind of wacky when you have a battle of 3v3, as one player could be swamped by all 3 of the other enemy at once - but wouldn't this be a totally new spin on things? (If you've ever played DragonSeeds for playstation you'll know vaguely what I'm trying to say. The system in the game is really cool. You have to anticipate what the enemy is going to do and base your actions off of what you THINK is going to happen. Once false move can screw you up real bad.)

To tell you the truth, I'm kind of sick of the repetitive battles that you see in every RPG. Why are monsters stupid? I've never seen a game where the monster realizes that, say, you've been using the same magic spell over and over and over again. Why not cast an anti-magic shell on yourself? Or, how about, the monster is almost dead. Why not heal yourself? Heh. Of course, this might lengthen battles a little too much - but what's the point if you're going to automatically win the battle anyways? Heck. You might as well gain your exp from walking around, and just fight the bosses.

[rant]Waiting for the annoying enemy to cast that spell that takes so damn long is annoying, too. Faster battles by far is way better than fancy looking spells that just get annoying after seeing it for the Nth time. [/rant]

Hm. This post was probably not helpful at all. Oh well. Good luck!

spellcaster
Quote:

I really couldn't follow the logic in your system. First you calculate attributes and bonuses to come up with a multiplier then multiply that by the percentage rolled by the d100. Seems to be almost complete chance since the d100 outwieghs everything.

The idea is that the d100 roll is modified by the attack or defence rating. Ín the above example, the Dwarf is 4.7 times more likely to win the contest than the Troll... but you still have some element of luck.

Quote:

An alternative form of dice rolling that alot of paper and pencil rpgs use is to assign a number of six sided dice depending on 1. amount of skill with an item/spell 2.


Yes, a dice pool system would be an option.
Main problem here is to come up with a system that is not too close to any of those you mention. Oh, "Vampires of the old world" is using a pool system as well.

Hm..

nonnus29

Korval he said:

Quote:

I'm currently trying to find an easy way to do combat in an RPG.

:P

EDIT: Impressive post nonetheless...

Korval
Quote:

Korval he said:

Quote:

I'm currently trying to find an easy way to do combat in an RPG.

Anything worth doing is worth doing well, and nothing is ever easy.

dudaskank

And what about the Pokémon fighting style?

Ok, not so complex / impressive like the others mentioned, but I like it!

  • choose the attack of each pokémon

  • Determine the first pokémon to attack
  • if(pkmn1.speed > pkmn2.speed)
       first = pkmn1;
       second = pkmn2;
    else
       first = pkmn2;
       second = pkmn1;
    attack(first, second);
    attack(second, first);
    

  • Determine if hit or no based on attack chance of hit

  • Each attack have different powers (i.e. tackle = 20, explosion = 150) and type (normal, fire), calc the damage based on strenght or special stats and type of the two pkmn
  • 1void attack(POKEMON p1, p2)
    2{
    3 int damage;
    4 // hit return truee if hit the enemy
    5 if(!hit(p1.attack))
    6 return;
    7 switch(p1.attack.type) {
    8 // phisical
    9 case PHISICAL :
    10 // I don't have any idea how this is calculated
    11 damage = (p1.attack.power * p1.strenght) - (p1.attack.power * p2.defense);
    12 break;
    13 // special attack
    14 case SPECIAL :
    15 // I don't have any idea how this is calculated too
    16 damage = (p1.attack.power * p1.special) - (p1.attack.power * p2.special);
    17 break;
    18 }
    19 if(critucal_hit())
    20 damage *= 1.5;
    21 if(super_efetive(p1, p2)
    22 damage *= 1.5;
    23 if(not_very_effective(p1, p2)
    24 damage /= 1.5;
    25 if(damage < 1)
    26 damage = 1;
    27 p2.hp -= damage;
    28}

    Hope it helps you in something...

    ^__^

    Inphernic

    Valkyrie Profile's battle system was pretty great. It was both turn-based and real-time - you could toggle characters to attack at any time (if it was your turn), creating some massive havoc if all of your 4 characters were attacking at once (and one hit added to the combo counter, which allowed super attacks when full).

    Also if the enemy ended up flying because of someone's attack, and then one of your characters came with a "land" attack, he/she couldn't hit the enemy.

    Timing and knowing your characters' attacks was everything.

    Quoting Working Designs : "For all the ways that I loved Valkyrie Profile is was the combat that was the real tour-de-force. Battles begin as frenetic swirls of sprites and sounds and button mashing that eventually sort themselves into a rhythmic sort of combat-song. The bangs and crashes and swipes and smashes frame the screamed lyrics of the Einherjar - lines like "My life is strewn with corpses" and "This is the law of heaven." It's almost physical and at the same time sublime, especially the moment you realize that the chaos on the screen is perfectly under your control."

    The whole game reeks of mad leetness. :D :D :D Needless to say, I <3 VP.

    Star Ocean 1 & 2 had a similar system in a more real-time form.

    spellcaster

    Inphernic: Sounds good... do you have some more information on the mechanics?

    dudaskrank: I'd like to have something like pokemon, but the problem is: how do you determine if an attack is a success?

    Say you have a ATK and DEF rating.
    If you simply compare if ATK >= DEF to determine if you hit, you have no chance at all to hit if the DEF value is higher than your ATK... which is not that good. You should always have a small chance to hit.
    Maybe with a dice pool?
    If you have as many dice as points in your ATK and DEF? So, for each point you roll a D10. At the end you compare the sum of the ATK and DEF values.
    That could work.
    Armor could now simply add points to the DEF value. And the damage inflicted could be simply a formula based on the STR and weapon data.
    Hm... and if the rolls are really good, you could give him a damage bonus...

    Yes, I think I like this.

    Any other suggestions?

    dudaskank

    In Pokémon, each attack have your own success rate:

    I.e. a tackle, thunderbolt and surf attacks is 100% hit chance, but other like thunder, blizzard, fire blast, fissure and others are less than 100%.

    But remember you can alter this rate using some attacks like flash and sand attack (decreasing attack rate)

    So, to calc if the pokemon1 hit the other, do like this:

    int hit(PKMN_ATTACK attack)
    {
       int n;
       // 0 to 100
       n = rand() % 101;
       if(attack.hit_chance <= n)
          return 1;
       else
          return 0;
    }
    

    ^__^

    Derezo

    Well, I'm doing it like so right now, in my MUD:

        diceroll = rand()%100;
    
        if ( diceroll == 0 || ( diceroll != 99 && diceroll < (victim->agi/10)-(ch->agi/10)))
        {
      // miss.
      return 0;
        }
    

    For a regular hit. :)
    It's dependant on the aggressor's agility (ch) and the victim's agility. Agility ranges from 0 to 255.
    Skills would be the same, and currently spell success rate is 100%.. ::)

    I haven't tested this system a lot, but it seems to work rather well in terms of hit/miss calculations.

    As for defense.. I use that in determining the damage dealt.. rather than the success rate. If you're strapped down in armor, they'll still be able to hit you just as easily.. it just might not cause any/much damage :P

    Korval
    Quote:

    diceroll = rand()%100;

    I don't think that's going to give the proper behavior. If RAND_MAX (implementation dependent) is not divisible by 100, then your results will be skewed. Don't take this probability skewing lightly; it will ultimately effect how things work out.

    Back to the actual question.

    OK, so you're looking for to-hit rolls. Step one is to think about what you want.

    There are 2 sides to the equation: the attacker and the defender. The attacker has some computation that determine's his attack to-hit (ATH). The defender has a computation that determine's his defender evade (DE).

    Now, we need to decide what these numbers mean. Since they are fairly abstract at this point, we only have the relationships between them.

    Let's take a simple, and very important, relationship:

    ATH == DE.

    In this case, what should happen? Does this mean that the attacker should win the majority of the time, the defender should win the majority of the time, or that it should be a coin toss?

    I would suggest that it should be a coin toss. Literally 50-50 percentage if they are equal.

    Now, another relationship:

    ATH >= 2 * DE

    The attacker has, at least, twice the value of the defender. I would suggest, depending on what you want, that this means the attacker should will a proponderance of the time. Possibley 75-80% of the hits.

    Next:

    ATH >= 4 * DE

    I would suggest that, in this case, the attacker automatically hits (roll anyway for critical fumbles/hits if you want them).

    The probability relationship seems relatively simple. The probability is based on the following number:

    ATH / DE = ProbValue;

    The easiest way to implement this in code is to use a bunch of if-then statements on the value of ProbValue, and interpolate the probability between two ProbValue numbers. Take the following:

    1int iToHitNumber;
    2 
    3if(ProbValue < 0.25f)
    4{
    5 iToHitNumber = 0;
    6}
    7else if(0.25f <= ProbValue && ProbValue < 0.5f)
    8{
    9 float fNormDiff;
    10 fNormDiff = (ProbValue - 0.25f) * 4.0f;
    11 iToHitNumber = (int)(25.0f * fNormDiff);
    12}
    13else if(0.5f <= ProbValue && ProbValue < 1.0f)
    14{
    15 float fNormDiff;
    16 fNormDiff = (ProbValue - 0.5f) * 2.0f;
    17 iToHitNumber = (int)(25.0f * fNormDiff) + 25;
    18}
    19else if(1.0f <= ProbValue && ProbValue < 2.0f)
    20{
    21 float fNormDiff;
    22 fNormDiff = (ProbValue - 1.0f);
    23 iToHitNumber = (int)(25.0f * fNormDiff) + 50;
    24}
    25else if(2.0f < ProbValue && ProbValue < 4.0f)
    26{
    27 float fNormDiff;
    28 fNormDiff = (ProbValue - 2.0f) / 2.0f;
    29 iToHitNumber = (int)(25.0f * fNormDiff) + 75;
    30}
    31else
    32{
    33 iToHitNumber = 100;
    34}

    iToHitNumber is then tested against a D100 roll. if(iToHitNumber < roll), then you hit. Otherwise, you miss.

    BTW, note that, if you're paying attention and thinking about code, you can see classes and object naturally develop from the above. You can see you'll need a class that can generate ATH and DE for a given type of attack. You will, also, need a mediator class that will take ATH and DE, do the required probability roll, and get the results.

    The good thing about this method is that it is open-ended. ATH and DE are both floats and are computed in a completely unimportant way. There are no limits placed on ATH or DE; they could be between 0 and 10, or they could be any arbiturary number. This way, all you need to think about in terms of balancing this method is what factors into ATH and choosing good monster DE's so that you get the results you're looking for. If you want lots of hitting on both sides, each side's ATH should be at least 3x the expected DE of the other side. If you like lots of misses (you should make up for this by making monsters die in a very few hits), keep ATH close to DE, or let DE slip a little higher.

    dudaskank
    Quote:

    else if(0.25f <= ProbValue && ProbValue < 0.5f)

    The first part (o.25 <= ProbValue) don't need to be tested, since if the value is minor than 0.25, only the first if is entered, so:

    if(ProbValue < 0.5)

    Will do the work, and the same to all the others if's

    Quote:

    I don't think that's going to give the proper behavior. If RAND_MAX (implementation dependent) is not divisible by 100, then your results will be skewed

    Well, I don't know what is "skewed" (I'm Brazilian) :P, but, what matters if RAND_MAN is not divisble by 100? It's used only to get a random number between 0 and 99. (and in my code I pu rand() % 101, but maybe the correct is 100)

    ???

    spellcaster

    Guess I'm using something like this:

    resultATK = rollDice() - attacker.attack;
    if resultATK >= 0 {
         resultDEF = rollDice() - defender.defense;
         if (resultDEF < 0 || resultATK < resultDEF) {
              /* attack succesful */
         } else {
              /* defense succesful */
         }
    }
    

    This seems to be the most simple solution :)
    And I want to have something very simple...

    Korval
    Quote:

    Well, I don't know what is "skewed" (I'm Brazilian) , but, what matters if RAND_MAN is not divisble by 100? It's used only to get a random number between 0 and 99. (and in my code I pu rand() % 101, but maybe the correct is 100)

    Well, if you went and actually rolled 2D10 several million times (limit as number of rolls approaches infinity), you should hit each number the same number of times. In short, the probability of rolling a 4 is the same as rolling an 86 or a 34, or any other values from 0 to 99.

    Keeping that in mind, let's say RAND_MAX is 150. It probably isn't, but let's say it is for the sake of argument.

    What is the probability, using rand() % 100, of rolling a 66? The only way rand() % 100 == 66 is if rand() == 66. So, the probability (assuming a perfect rand()), is 1/150.

    What is the probability of rolling 8? Well, if rand() == 8, then rand()%100 == 8. But, if rand() == 108, then rand()%100 == 8 too. Therefore, the probability is 2/150.

    Your probabilities are now no longer correct. Given this example, it is twice as likely to come up with a number less than 50 than it is to come up with one greater than 50.

    The correct way to do this is to check to see if rand() >= (RAND_MAX - RAND_MAX % 100). If it is, then redo the rand() until it is. BTW, good coding practice says that this should be made its own function.

    This way, your probabilities will be correct, to the degree that rand() is probabilistically accurate.

    Quote:

    Guess I'm using something like this:

    Several problems/concerns:

    1) Why should a negative "resultATK" be an automatic failure? It is entirely possible that, through a very poor roll on the defender's part, that "resultATK" will be higher than "resultDEF".

    2) Right now, if "resultATK" is negative, then nothing happens. Presumably, "defense successful" should be the result.

    3) Both "attacker.attack" and "defender.defense" should be function calls, not variable accesses. Preferably, they should be function calls with an argument that tells them the kind of attack (melee, magic, etc).

    4) This doesn't address the other half of your querry; that is, dealing damage. I have a number of ideas on the subject, but you've made it perfectly clear that explaining them would be a waste of my time, so I shall refrain. I'm sure you can find something... simple to do.

    spellcaster
    Quote:

    1) Why should a negative "resultATK" be an automatic failure? It is entirely possible that, through a very poor roll on the defender's part, that "resultATK" will be higher than "resultDEF".

    Because that means that the attacker spoiled his attack role. He managed to roll a number larger than his skill... so it's a failure. No need for the defender to defend... the attacker will miss the target by a mile.

    Quote:

    2) Right now, if "resultATK" is negative, then nothing happens. Presumably, "defense successful" should be the result.

    Displaying "Miss" or something would do the job :)

    Quote:

    3) Both "attacker.attack" and "defender.defense" should be function calls, not variable accesses. Preferably, they should be function calls with an argument that tells them the kind of attack (melee, magic, etc).

    Agreed. This was more meant to be pseudo code. But you won't use ATK and DEF for magic ;)

    Quote:

    4) This doesn't address the other half of your querry; that is, dealing damage

    Damage will be based on the "quality" of the result (so how much larger resultATK is than resultDEF) and a weapon modifier.

    Quote:

    . I have a number of ideas on the subject, but you've made it perfectly clear that explaining them would be a waste of my time,

    I'm always open for new idea :)
    My bookshelf is full of RPG systems (gurps, d&d, palladium, shadowrun, ars magica, rolemaster, vampires of the old world, and some lesser known ones) and source books.

    If you have good ideas, let's discuss them ;)
    I might have found the system I'm going to use for that project, butu it doesn't mean we can discuss other systems...

    dudaskank
    if (resultDEF < 0 || resultATK < resultDEF)
       /* attack succesful */
    

    ???

    Is it correctly, or is:

    if (resultDEF < 0 || resultDEF < resultATK)
       /* attack succesful */
    

    Korval: Ahh... I get it!

    Tell me if my new d_100() will be better:

    int d_100(void)
    {
       int d;
       int max;
    
       max = 100;
       d = max * (rand() / RAND_MAX);
       return d;
    }
    

    If the probability of each result is correct now, only changing the max to other value to make a D20 or d10 or d1981 :P

    ;D

    Kitty Cat

    almost, but not quite:

    /* removed unnecessary variables, casted rand() and RAND_MAX to float(result would always be 0 otherwise), which, after being multiplied by 100(max), recasts to an int */
    int d_100(void)
    {
    return ((float)rand() / (float)RAND_MAX) * 100.0;
    }

    spellcaster

    dudaskrnak, you're right. It's a typo :)

    Regarding the d_100 routine...

    int roll_dice(int kindOfDice) {
        int dice   = 0;
        int result = 0;
        int count  = 0;
        int max    = 2;
    
        result = dice = (rand() % kindOfDice) +1;
        count++;
        while (dice == kindOfDice && count < max) {
            dice = (rand() % kindOfDice) +1;
            result += dice;
            count++;
        }
    }
    

    This routined calcs "adjusted" dice. So if you roll the maximum value, you can roll again (up to two times, in that example).

    dudaskank

    Chris: Yes, some optimizations will be good in my little function, I know ;D

    spellcaster: But... this is the same thing I've done before... the probability is different for each result, like korval wrote...

    Quote:

    This routined calcs "adjusted" dice. So if you roll the maximum value, you can roll again (up to two times, in that example).

    Yes, great idea too!

    ^__^

    spellcaster
    Quote:

    spellcaster: But... this is the same thing I've done before... the probability is different for each result, like korval wrote...

    Why do you think so?

    1#include <stdio.h>
    2#include <stdlib.h>
    3#include <limits.h>
    4 
    5#define INSANE
    6 
    7#ifdef INSANE
    8#define MAX_TEST ((unsigned int)((~0)-1))
    9#else
    10#define MAX_TEST 100000
    11#endif
    12 
    13int main(int ragc, char** argv) {
    14
    15
    16 unsigned int a;
    17 unsigned int min;
    18 unsigned int max;
    19 float avg;
    20
    21 int value;
    22 int minIndex, maxIndex;
    23 int count[100];
    24
    25 for (a=0; a < 100; a++) {
    26 count[a] = 0;
    27 }
    28 printf("Doing %u rolls...\n", MAX_TEST);
    29 fflush(stdout);
    30
    31 for (a=0; a < MAX_TEST; a++) {
    32 value = rand()%100;
    33 count[value]++;
    34 }
    35
    36 min = MAX_TEST;
    37 max = 0;
    38 avg = 0;
    39 maxIndex = minIndex = 0;
    40 for (a=0; a < 100; a++) {
    41 if (count[a] > max) {
    42 max = count[a];
    43 maxIndex = a;
    44 }
    45 if (count[a] < min) {
    46 min = count[a];
    47 minIndex = a;
    48 }
    49 avg += count[a];
    50 }
    51 avg = avg / 100.0;
    52 printf("Number most often rolled: %5i (%5i times == %2.2f per cent)\n",
    53 maxIndex, max, max*100.0 / (float) MAX_TEST);
    54 printf("Number least often rolled: %5i (%5i times == %2.2f per cent)\n",
    55 minIndex, min, min*100.0 / (float) MAX_TEST);
    56 printf("In average every number got rolled: %3.2f times. That's %3.2f percent\n",
    57 avg, avg*100.0 / (float) MAX_TEST);
    58
    59 return 0;
    60}

    Result:

    Quote:

    Doing 4294967294 rolls...
    Number most often rolled: 1 (42991616 times)
    Number least often rolled: 68 (42860544 times)
    In average every number got rolled: 42949672 times. That's 1.00 percent

    So, since you have 100 numbers you'd expect every number to be rolled around 1 per cent of time :)

    If you try this code, please be patient... it'll take some time.
    Take the #define INSANE out if you want a faster result..

    So, what's the problem with using that algo?
    ::)

    But korval is right. If your upper limit gets close to rand max, you'll get problems.
    But even if you roll d20000 you won't have a problem. ;)

    Korval
    Quote:

    But even if you roll d20000 you won't have a problem.

    Well, unless your RAND_MAX is 0x7FFF (32767), of course. VC++'s RAND_MAX is.

    BTW, you're cheating. By your equation, the percent can't be anything but 1%. Observe:

    Before the divide by 100, "ave" will guarenteeably equal MAX_TEST. Just look at the code: for each MAX_TEST number of times, some entry in count[] is being incremented. Add all of these up, and you get MAX_TEST. Therefore, the percentage is computed as follows:

    ((MAX_TEST / 100) * 100) / MAX_TEST. This is precisely 1.0f, regardless of which element we choose to increment in count[].

    The correct analysis would be to take the count[] variable and do some statistical analysis techniques on them. I don't remember most of my statistical analysis from chemistry, but there are ways to determine how far off your probabilities are from the true amount.

    Besides, you haven't even attempted to answer my logical argument above. Just because you can write code that looks like it isn't broken doesn't mean that it isn't. Trust me; just do it the right way.

    spellcaster

    I know :)
    That's something I realized after posting.
    But anyway, in the above example I've around 0.1% variation for the most often / least often rolled die.

    It's not a real issue here.
    If you need higher precision, just grab one of the many existing generators from the net, or use a floating point generator. But then your distribution might be even worse...

    For your normal RPG issues, it's not a big problem. Hope you agree here ;)

    Korval
    Quote:

    For your normal RPG issues, it's not a big problem.

    So, let me get this right.

    Rather than taking a minimal amount of effort to correct the random function, you'd rather just do it the wrong way and live with the slightly skewed probability? It's not like you even have to think of a solution; it's right here in this thread! You're arguing against chaning one line of code from doing something that's slightly wrong to doing something that perfectly right.

    Um, OK, whatever you want to do. It's your code.

    spellcaster
    Quote:

    Rather than taking a minimal amount of effort to correct the random function, you'd rather just do it the wrong way and live with the slightly skewed probability?

    Nope.
    I'd simply choose another random number generator.
    Please feel free to use your algo in my program above... I'd like to see what distribution you get -and how long it takes to calculate it.

    As I said, I had always around 0.1 percent fluctation. And that's good enough for me ;)
    I'm not really convinced that you get a better distribution.

    [EDIT]
    Ok, I tried your function.

    Quote:

    Doing 4294967294 rolls...
    Rand max is:32767
    Number most often rolled: 1 (42991616 times == 1.00 per cent)
    Number least often rolled: 68 (42860544 times == 1.00 per cent)

    Doing 4294967294 rolls the Korval way...
    Rand max is:32767
    Number most often rolled: 0 (42991616 times == 1.00 per cent)
    Number least often rolled: 48 (42860543 times == 1.00 per cent)

    In other words... there's no difference.
    The funny thing is, that if I use less iterations, the variation in both algos is the same amount.
    Which leads to the though that the basic RNG is the thriving factor.
    But, just for the record... it took really long to calculate your rand value.

    Never assume. Always test :)

    Korval
    Quote:

    Ok, I tried your function.

    It isn't my function or your function. There is simply the right way and the wrong way.

    Quote:

    Never assume. Always test

    Whatever.

    All your "tests" have shown is a lack of understanding of probability, statistics, and statistical variance. You aren't even doing the right tests (and you don't even use "srand" to seed the generator beforehand).

    The fact is that, given a roll between 0 and 99, using a RAND_MAX of 0x7FFF, using the %100 method, the chance of rolling a number greater than 67 is precisely 31.93% (32 numbers greater than 67 * 327/32767). However, that's not what it should be. The chance of rolling a number greater than 67 should be precisely 32%. You are off by a 0.07%. This is not something that came up through testing. This number is an absolute, incontrovertible fact.

    0.07% may not seem like much, but it is significant. And I can even make it show up in your program, simply by doing the right test.

    Add up all counts <= 67. Add up all counts > 67. Divide both by MAX_TEST and * 100.0f to get percent. Given sufficient tests (0xFFFFFFF works and is faster than the full MAX_INT), you will never get the percentages you should. In fact, you will get precisely what the math says you should (ie, skewed probabilities). And if you switch to the right random method, you'll get the right probabilities.

    Bob

    Let's not resort to flames, shall we?

    dudaskank

    dudaskank: FireBlast!!!

    hehehe

    Hmm... I will test the codes tomorrow... my idea too...

    I don't like much statistics :-P

    see you space cowboy

    ^__^

    spellcaster
    Quote:

    All your "tests" have shown is a lack of understanding of probability, statistics, and statistical variance. You aren't even doing the right tests (and you don't even use "srand" to seed the generator beforehand).

    Hm... a random number generator returns random numbers... so I thought the best way to test it would be by using it to create random numbers?
    And I am calling srand() once before I use the modulo way to create the numbers, and once before I call yours.
    But calling srand will not change the distribution of the numbers generated... so it won't make a big difference :)

    But I must admit that I'm surprised that your way works as good as the modulo way. In fact, I expected it to create worse numbers (due to the lack of precision if using floats).
    It's also not as slow as I suspected...

    Hm... and given the fact that using floats (your method) generates the same distribution of numbers clearly shows that it doesn't make a big difference.
    Maybe it should make a difference, but the fact its: It doesn't.

    I'm not sure you understand this:
    if I use your formula I get exactly the same distribution of numbers...

    So, could you please tell me, if I get exectly the same results with either method, why is your method better?

    If you believe it should be better, then this shows that rand() itself is the main problem, not the if you use a modulo or multiplication...

    Quote:

    Add up all counts <= 67. Add up all counts > 67. Divide both by MAX_TEST and * 100.0f to get percent. Given sufficient tests (0xFFFFFFF works and is faster than the full MAX_INT), you will never get the percentages you should

    What results should I get?
    I tried this using both max int and the value you suggested.
    Both with modulo and your method (I won't tell you yet that the result is the same with both ways - yet)

    I don't get your point.
    Do you want to tell me that your version, even if it's slower in prodcuing the same results, is the better way of doing it?

    I don't get it.
    (really. If I'm slow here, please take the time to explain. I'd like to understand why it's better to use your method. Right now, I don't see a reason ... it's slower and produces the same result).

    I even made a version which created buffers showing the distribution of the numbers... I still don't see a difference.
    I even used doubles instead of floats to ensure it's not a rounding problem.

    Could you please provide me with an example?

    Oh, and just in case you want to have the latest version of the test proggy:

    1#include <allegro.h>
    2#include <stdio.h>
    3#include <stdlib.h>
    4#include <limits.h>
    5#include <time.h>
    6 
    7#define INSANE_
    8 
    9#ifdef INSANE
    10#define MAX_TEST ((unsigned int)((~0)-1))
    11#else
    12#define MAX_TEST 100000
    13#endif
    14 
    15BITMAP *buffer;
    16 
    17int d_100_float(void) {
    18 return (int) ((float)rand() / (float)RAND_MAX) * 100.0;
    19}
    20 
    21int d_100_modulo(void) {
    22 return rand() % 100;
    23}
    24 
    25void perform_test(int (*func)(void), int y, int col) {
    26
    27 unsigned int a;
    28 unsigned int min;
    29 unsigned int max;
    30 float avg;
    31
    32 int value;
    33 int minIndex, maxIndex;
    34 int count[100];
    35
    36 for (a=0; a < 100; a++) {
    37 count[a] = 0;
    38 }
    39
    40 /* Make sure we use the same seed for both tests */
    41 srand(100);
    42 for (a=0; a < MAX_TEST; a++) {
    43 value = rand()%100;
    44 count[value]++;
    45 }
    46
    47 min = MAX_TEST;
    48 max = 0;
    49 avg = 0;
    50 maxIndex = minIndex = 0;
    51 line(buffer,0,100,buffer->w,100, makecol(128,128,128));
    52 for (a=0; a < 100; a++) {
    53 if (count[a] > max) {
    54 max = count[a];
    55 maxIndex = a;
    56 }
    57 if (count[a] < min) {
    58 min = count[a];
    59 minIndex = a;
    60 }
    61
    62 putpixel(buffer, a, 100+ ((int)((count[a]*100.0) / (float) MAX_TEST)), col);
    63
    64 avg += count[a];
    65 }
    66 avg = avg / 100.0;
    67 textprintf(buffer, font, 0, 0, makecol(255,255,255),"Number most often rolled: %5i (%5i times == %2.2f per cent)\n", maxIndex, max, max*100.0 / (float) MAX_TEST);
    68 textprintf(buffer, font, 0, 10, makecol(255,255,255),"Number least often rolled: %5i (%5i times == %2.2f per cent)\n", minIndex, min, min*100.0 / (float) MAX_TEST);
    69
    70}
    71 
    72 
    73int main(int ragc, char** argv) {
    74
    75
    76 unsigned int a;
    77 unsigned int min;
    78 unsigned int max;
    79 float avg;
    80
    81 int value;
    82 int minIndex, maxIndex;
    83 int count[100];
    84
    85 allegro_init();
    86 set_color_depth(16);
    87 set_gfx_mode(GFX_AUTODETECT_WINDOWED, 800, 100, 0, 0);
    88 buffer = create_bitmap(800, 200);
    89
    90 clear(buffer);
    91 perform_test(d_100_modulo, 0 , makecol(255,0,0));
    92 save_bitmap("result1.bmp", buffer, NULL);
    93
    94 clear(buffer);
    95 perform_test(d_100_float , 20, makecol(0,255,0));
    96 save_bitmap("result2.bmp", buffer, NULL);
    97
    98
    99 return 0;
    100}
    101END_OF_MAIN();

    Korval

    I thought I had made the problem appropriately clear in my original post on the subject. So, let me made an addendum to it.

    Original:

    Quote:

    Well, if you went and actually rolled 2D10 several million times (limit as number of rolls approaches infinity), you should hit each number the same number of times. In short, the probability of rolling a 4 is the same as rolling an 86 or a 34, or any other values from 0 to 99.

    Keeping that in mind, let's say RAND_MAX is 150. It probably isn't, but let's say it is for the sake of argument.

    What is the probability, using rand() % 100, of rolling a 66? The only way rand() % 100 == 66 is if rand() == 66. So, the probability (assuming a perfect rand()) is 1/150.

    What is the probability of rolling 8? Well, if rand() == 8, then rand()%100 == 8. But, if rand() == 108, then rand()%100 == 8 too. Therefore, the probability is 2/150.

    Your probabilities are now no longer correct. Given this example, it is twice as likely to come up with a number less than 50 than it is to come up with one greater than 50.

    The correct way to do this is to check to see if rand() >= (RAND_MAX - RAND_MAX % 100). If it is, then redo the rand() until it is. BTW, good coding practice says that this should be made its own function.

    This way, your probabilities will be correct, to the degree that rand() is probabilistically accurate.

    Taking the case where RAND_MAX is 32767, there are 327 ways of coming up with the number 99 from "rand()%100". That is ***99, where *** is any number less than 327, including 000. As such, the probability of comping up with 99 is 327/32767. Note that, because 99 is greater than 67, if *** is 327, rand() will never return 99.

    Now, the probability of getting 2 is different from 99. This is because, unlike the 99 case, *** can be 327. rand() could return 32702, and this would come up with 2 as a result. Therefore, the number of ways to get 2 from "rand()%100" is 328, not 327 as above. And, therefore, the probability is 328/32767.

    Given a probabilistically correct 0-99 roll, the probability of rolling a number less than or equal to n (0 <= n <= 99) is exactly (n+1)%. That is, the probability of rolling a number less than or equal to 67 should be exactly 68%.

    BTW, to make sure you follow along, you get this by taking the probability of rolling any number 0-99 (this should be 1/100, one chance in a hundred) and multiply it times the number of values you're checking. Since there are 68 numbers <= 67, you get 68 *1/100, or 68/100, or 68%.

    If you use your method to compute the probability (using the following code), then you will find that the chances of rolling a number <= 67 is actually 68.07%. This is because the probability of rolling a number <= 67 is actually 328/32767. This number is slightly more than 1/100. The probability of rolling <= 67 in your method is 68 * 328/32767 which equals 68.07%.

    Likewise, the probability of rolling avobe 67 is altered as well (obviously, since the probability of rolling <= or > 68 must be 100% ;) ). Using the correct probability distribution, you get a 32% chance. Using your method, you get 31.93%.

    Here's a version of your tester program that will verify this. Note that it computes the probability of rolling <= 67 and > 67. You will find, even under repeated testing, that your method and mine differ significantly. You can change them easily enough by uncommenting my method out.

    1#include <stdio.h>
    2#include <stdlib.h>
    3#include <limits.h>
    4 
    5//#define INSANE
    6 
    7#ifdef INSANE
    8#define MAX_TEST ((unsigned int)((~0)-1))
    9#else
    10#define MAX_TEST 0xFFFFFFF
    11#endif
    12 
    13int main(int ragc, char** argv) {
    14
    15
    16 int a;
    17 int min;
    18 int max;
    19 float avg;
    20 
    21 int iCtBelow = 0;
    22 int iCtAbove = 0;
    23
    24 int value;
    25 int minIndex, maxIndex;
    26 int count[100];
    27
    28 for (a=0; a < 100; a++) {
    29 count[a] = 0;
    30 }
    31 printf("Doing %u rolls...\n", MAX_TEST);
    32 fflush(stdout);
    33
    34 for (a=0; a < MAX_TEST; a++)
    35 {
    36 value = rand()%100;
    37// value = (int)(((float)rand() / (float)RAND_MAX) * 100.0);
    38 count[value]++;
    39 }
    40
    41 min = MAX_TEST;
    42 max = 0;
    43 avg = 0;
    44 maxIndex = minIndex = 0;
    45 for (a=0; a < 100; a++)
    46 {
    47 if (count[a] > max)
    48 {
    49 max = count[a];
    50 maxIndex = a;
    51 }
    52 if (count[a] < min)
    53 {
    54 min = count[a];
    55 minIndex = a;
    56 }
    57 
    58 if(a <= 67)
    59 {
    60 iCtBelow += count[a];
    61 }
    62 else
    63 {
    64 iCtAbove += count[a];
    65 }
    66 
    67 avg += count[a];
    68 }
    69 avg = avg / 100.0;
    70 printf("Number most often rolled: %5i (%5i times == %2.2f per cent)\n", maxIndex, max, max*100.0 / (float) MAX_TEST);
    71 printf("Number least often rolled: %5i (%5i times == %2.2f per cent)\n", minIndex, min, min*100.0 / (float) MAX_TEST);
    72 printf("In average every number got rolled: %3.2f times. That's %3.2f percent\n", avg, avg*100.0 / (float) MAX_TEST);
    73 printf("Percent below or equal to 67: %f\n", (iCtBelow * 100.0f) / (float)MAX_TEST);
    74 printf("Percent above 67: %f\n", (iCtAbove * 100.0f) / (float)MAX_TEST);
    75
    76 return 0;
    77}

    As for your concerns about precision: don't be. As long as RAND_MAX is only 32767, floats will work just find. Granted, you might want to use doubles anyway, just to be safe (incase some implementation uses an int RAND_MAX rather than a short one). Granted, if RAND_MAX is that huge, the probability skew won't be very significant.

    As for your concerns about speed: don't be. After all, how many times are you planning on calling this function per frame? 20? 30? Compared to rendering, this is nothing.

    spellcaster

    Ok, I understand that theory.
    But I also tested it.

    10.000 times I rolled 6600000 random numbers using both your method and mine.

    Result:

    Quote:

    Per cent below 67 (spellcaster) : 67.087
    Per cent below 67 (korval) : 67.008

    But I don't see in which application this would become a problem?

    But I bet you're going to say that this distribution will cause a problem, right?
    Ok, so I switched my random number generator. If I use a MT19937 algo, we get the following distribution:

    Quote:

    Per cent below 67 (spellcaster) : 67.006
    Per cent below 67 (korval) : 66.987

    Oups :)
    The MT genrates equal distribution between 0 and 2^32 -1.
    I even switched from float to double for your algo, but it doesn't change anything.

    Hm.. guess we have a draw here. :)
    Seems like your algo works better than mine using the current libc rand(). But as soon as a better random number generator will be used... hm...

    So, use your method for number genrators with a low RAND_MAX, and use the modulo as soon as you can use better RNGs...

    dudaskank

    Here is the code:

    1#include <stdio.h>
    2#include <stdlib.h>
    3#include <limits.h>
    4#include <time.h>
    5 
    6#define INSANE
    7 
    8#ifdef INSANE
    9#define MAX_TEST 0x7FFFFFFF
    10#else
    11#define MAX_TEST RAND_MAX
    12#endif
    13 
    14#define N 20
    15 
    16int main(void) {
    17
    18
    19 int a;
    20 int min;
    21 int max;
    22
    23 int value;
    24 int minIndex, maxIndex;
    25 int count[N];
    26 
    27 FILE *f;
    28 f = fopen("dice2.txt", "w");
    29 
    30 srand(time(NULL));
    31
    32 for (a=0; a < N; a++) {
    33 count[a] = 0;
    34 }
    35 fprintf(f, "Doing %u rolls...\n", MAX_TEST);
    36 fflush(f);
    37 
    38 for (a=0; a < MAX_TEST; a++) {
    39 value = (int) (N * (float)rand() / (float)RAND_MAX);
    40 count[value]++;
    41 }
    42
    43 min = MAX_TEST;
    44 max = 0;
    45 maxIndex = minIndex = 0;
    46 for (a=0; a < N; a++) {
    47 if (count[a] > max) {
    48 max = count[a];
    49 maxIndex = a;
    50 }
    51 if (count[a] < min) {
    52 min = count[a];
    53 minIndex = a;
    54 }
    55 }
    56 fprintf(f, "Number most often rolled: %5d (%5d times == %f per cent)\n",
    57 maxIndex, max, (float)max*100.0 / (float) MAX_TEST);
    58 fprintf(f, "Number least often rolled: %5d (%5d times == %f per cent)\n\n",
    59 minIndex, min, (float)min*100.0 / (float) MAX_TEST);
    60 
    61 for(a = 0; a < N; a++) {
    62 fprintf(f, "%5d = %5d\n", a, count[a]);
    63 }
    64 
    65 fclose(f);
    66
    67 return 0;
    68}

    And my results, using D20:

    1Doing 2147483647 rolls...
    2Number most often rolled: 0 (107413504 times == 5.001831 per cent)
    3Number least often rolled: 9 (107347967 times == 4.998779 per cent)
    4 
    5 0 = 107413504
    6 1 = 107347968
    7 2 = 107413504
    8 3 = 107347968
    9 4 = 107347968
    10 5 = 107413504
    11 6 = 107347968
    12 7 = 107347968
    13 8 = 107413504
    14 9 = 107347967
    15 10 = 107347968
    16 11 = 107413504
    17 12 = 107347968
    18 13 = 107347968
    19 14 = 107413504
    20 15 = 107347968
    21 16 = 107347968
    22 17 = 107413504
    23 18 = 107347968
    24 19 = 107347968
    25 
    26-------------------
    27 
    28Doing 32767 rolls...
    29Number most often rolled: 6 ( 1725 times == 5.264443 per cent)
    30Number least often rolled: 11 ( 1586 times == 4.840236 per cent)
    31 
    32 0 = 1608
    33 1 = 1661
    34 2 = 1596
    35 3 = 1636
    36 4 = 1623
    37 5 = 1627
    38 6 = 1725
    39 7 = 1600
    40 8 = 1723
    41 9 = 1625
    42 10 = 1647
    43 11 = 1586
    44 12 = 1641
    45 13 = 1643
    46 14 = 1669
    47 15 = 1610
    48 16 = 1675
    49 17 = 1627
    50 18 = 1637
    51 19 = 1607

    and other results, with spellcaster modulo:

    1Doing 32767 rolls...
    2Number most often rolled: 2 ( 1724 times == 5.261391 per cent)
    3Number least often rolled: 3 ( 1547 times == 4.721213 per cent)
    4 
    5 0 = 1653
    6 1 = 1560
    7 2 = 1724
    8 3 = 1547
    9 4 = 1594
    10 5 = 1582
    11 6 = 1666
    12 7 = 1674
    13 8 = 1636
    14 9 = 1584
    15 10 = 1612
    16 11 = 1650
    17 12 = 1694
    18 13 = 1612
    19 14 = 1659
    20 15 = 1651
    21 16 = 1689
    22 17 = 1706
    23 18 = 1652
    24 19 = 1622
    25 
    26-----------
    27 
    28Doing 2147483647 rolls...
    29Number most often rolled: 0 (107413504 times == 5.001831 per cent)
    30Number least often rolled: 8 (107347968 times == 4.998779 per cent)
    31 
    32 0 = 107413504
    33 1 = 107413504
    34 2 = 107413504
    35 3 = 107413503
    36 4 = 107413504
    37 5 = 107413504
    38 6 = 107413504
    39 7 = 107413504
    40 8 = 107347968
    41 9 = 107347968
    42 10 = 107347968
    43 11 = 107347968
    44 12 = 107347968
    45 13 = 107347968
    46 14 = 107347968
    47 15 = 107347968
    48 16 = 107347968
    49 17 = 107347968
    50 18 = 107347968
    51 19 = 107347968

    See, the results is very dependent of the ammount of rolls, because the result of rand() depends of the last result.

    spellcaster

    Dudaskank... if you need a good ditribution, use this random number generator:
    [url http://www.math.keio.ac.jp/~matumoto/mt19937int.c]

    You could also check for other generators, ther're some generators available which are pretty good and really fast.

    Thread #214381. Printed from Allegro.cc