/* Copyright (C) Kimmo Kulovesi 1997, 1998

                    *  Use and modify this at will, but please do not remove
                       the names of any authors from the SOURCES, and mark all
                       the changes you have made to the sources.
                       E-mail me at "arkhan@softhome.net" for... anything. ;>

        This module includes functions for all sorts of advanced random number
    generation, giving more random results than "rand()", and also being faster
    in many cases.

        The functions:
***
    Init_Dice(seed)           Initializes the random number generator with
                              an unsigned long seed, such as "time(NULL)".
                              "srand()" will not work with this random number
                              generator.

    RollDie(sides)            Simulates the rolling of a number of dice with
    RollDice(number, sides)   a specified number of sides each.
                                The number of sides must NEVER be 0, or it will
                              crash with a divide by zero. The values are given
                              as UNSIGNED ints, so do not attempt to give
                              negative values to the generator, or you might
                              experience odd errors.
                                About as fast or slightly faster than "rand()",
                              but these still give more random results.

    RDie(sides)               As above, but about 35% faster. The values given
    RDice(sides)              are slightly less "random", but probably does not
                              matter in any purposes which requires the speed.
                                Still way better and faster than "rand()".

    RollDie_B(sides)          Just as the ones above, without the "_B", but
    RollDice_B(number, sides) take the values as SIGNED ints, and can take
    RDie_B(sides              <= 0 values in "sides" without causing errors.
    RDice_B(sides)            In fact, if "sides" negative, it will return a
                              negative number randomized on the basis.
                                Number of dice can also be negative or 0, but
                              in either case it simply returns "0".
                                Because of the checks, they are, naturally,
                              slightly slower, but I definitely recommend these
                              if it is possible that "sides" might be 0...
***
            Also defined are the standard roleplaying dice =

        RollD2(),       1 -    2    (a coin flip, also; 1 = heads, 2 = tails)
        RollD3(),       1 -    3
        RollD4(),       1 -    4
        RollD6(),       1 -    6
        RollD8(),       1 -    8
        RollD10(),      1 -   10
        RollD12(),      1 -   12
        RollD20(),      1 -   20
        RollD100(),     1 -  100
        RollD1000(),    1 - 1000

            And the faster, but ever-so-slightly less random versions:

        RD2(),          1 -    2
        RD3(),          1 -    3
        RD4(),          1 -    4
        RD6(),          1 -    6
        RD8(),          1 -    8
        RD10(),         1 -   10
        RD12(),         1 -   12
        RD20(),         1 -   20
        RD100(),        1 -  100
        RD1000(),       1 - 1000
***
        Then, there is the raw R250 generator, which the rest of these are
based on:

        r250()          Use this for a replacement for "rand()", since it is
                        about 35-45% faster, and gives better random numbers.

    The R250 engine first written by W. L. Maier, as described by
    S. Kirkpatrick and E. Stoll, Journal of Computational Physics,
    40, p. 517 (1981). Modified and optimized for this purpose by
    me.
***
-----------------------------------------------------------------------------*/
#ifndef ARKHAN_DICE_H
#define ARKHAN_DICE_H

#define RollDie(n)   (1 + (((r250() / 211) & 0777777) % (n)))
#define RollD2()     (1 + (((r250() / 211) & 0777777) % 2))
#define RollD3()     (1 + (((r250() / 211) & 0777777) % 3))
#define RollD4()     (1 + (((r250() / 211) & 0777777) % 4))
#define RollD6()     (1 + (((r250() / 211) & 0777777) % 6))
#define RollD8()     (1 + (((r250() / 211) & 0777777) % 8))
#define RollD10()    (1 + (((r250() / 211) & 0777777) % 10))
#define RollD12()    (1 + (((r250() / 211) & 0777777) % 12))
#define RollD20()    (1 + (((r250() / 211) & 0777777) % 20))
#define RollD100()   (1 + (((r250() / 211) & 0777777) % 100))
#define RollD1000()  (1 + (((r250() / 211) & 0777777) % 1000))

#define RDie(n)      (1 + r250() % (n))
#define RD2()        (1 + r250() % 2)
#define RD3()        (1 + r250() % 3)
#define RD4()        (1 + r250() % 4)
#define RD6()        (1 + r250() % 6)
#define RD8()        (1 + r250() % 8)
#define RD10()       (1 + r250() % 10)
#define RD12()       (1 + r250() % 12)
#define RD20()       (1 + r250() % 20)
#define RD100()      (1 + r250() % 100)
#define RD1000()     (1 + r250() % 1000)

    /* And the prototypes : */

extern void          Init_Dice(unsigned long seed);
extern unsigned long RollDice  (const register unsigned int num_dice, const register unsigned int num_sides);
extern long          RollDice_B(const register int num_dice, const int register num_sides);
extern int           RollDie_B (const register int num_sides);
extern unsigned long RDice     (const register unsigned int num_dice, const register unsigned int num_sides);
extern long          RDice_B   (const register int num_dice, const register int num_sides);
extern int           RDie_B    (const register int num_sides);
extern unsigned int  r250();

#endif
