#ifndef GUARD_RANDOM_H #define GUARD_RANDOM_H // The number 1103515245 comes from the example implementation of rand and srand // in the ISO C standard. #define ISO_RANDOMIZE1(val) (1103515245 * (val) + 24691) #define ISO_RANDOMIZE2(val) (1103515245 * (val) + 12345) /* Some functions have been added to support Expansion's RNG implementation. * * LocalRandom(*val) provides a higher-quality replacement for uses of * ISO_RANDOMIZE in vanilla Emerald. You can use LocalRandomSeed(u32) to * create a local state. * * It is no longer possible to call Random() in interrupt handlers safely. * AdvanceRandom() is provided to handle burning numbers in VBlank handlers. * If you need to use random numbers in the VBlank handler, a local state * should be used instead. * * Random2_32() was added, even though it is not used directly, because the * underlying RNG always outputs 32 bits. */ struct Sfc32State { u32 a; u32 b; u32 c; u32 ctr; }; typedef struct Sfc32State rng_value_t; #define RNG_VALUE_EMPTY {} // Calling this function directly is discouraged. // Use LocalRandom() instead. static inline u32 _SFC32_Next(struct Sfc32State *state) { const u32 result = state->a + state->b + state->ctr++; state->a = state->b ^ (state->b >> 9); state->b = state->c * 9; state->c = result + ((state->c << 21) | (state->c >> 11)); return result; } static inline u16 LocalRandom(rng_value_t *val) { return _SFC32_Next(val) >> 16; } u32 Random32(void); u32 Random2_32(void); static inline u16 Random(void) { return Random32() >> 16; } void SeedRng(u32 seed); void SeedRng2(u32 seed); rng_value_t LocalRandomSeed(u32 seed); static inline u16 Random2(void) { return Random2_32() >> 16; } void AdvanceRandom(void); extern rng_value_t gRngValue; extern rng_value_t gRng2Value; void Shuffle8(void *data, size_t n); void Shuffle16(void *data, size_t n); void Shuffle32(void *data, size_t n); void ShuffleN(void *data, size_t n, size_t size); static inline void Shuffle(void *data, size_t n, size_t size) { switch (size) { case 1: Shuffle8(data, n); break; case 2: Shuffle16(data, n); break; case 4: Shuffle32(data, n); break; default: ShuffleN(data, n, size); break; } } /* Structured random number generator. * Instead of the caller converting bits from Random() to a meaningful * value, the caller provides metadata that is used to return the * meaningful value directly. This allows code to interpret the random * call, for example, battle tests know what the domain of a random call * is, and can exhaustively test it. * * RandomTag identifies the purpose of the value. * * RandomUniform(tag, lo, hi) returns a number from lo to hi inclusive * with uniform probability. * * RandomUniformExcept(tag, lo, hi, reject) returns a number from lo to * hi inclusive with uniform probability, excluding those for which * reject returns TRUE. * * RandomElement(tag, array) returns an element in array with uniform * probability. The array must be known at compile-time (e.g. a global * const array). * * RandomPercentage(tag, t) returns FALSE with probability 1-t/100, * and TRUE with probability t/100. * * RandomWeighted(tag, w0, w1, ... wN) returns a number from 0 to N * inclusive. The return value is proportional to the weights, e.g. * RandomWeighted(..., 1, 1) returns 50% 0s and 50% 1s. * RandomWeighted(..., 2, 1) returns 2/3 0s and 1/3 1s. * * RandomChance(tag, successes, total) returns FALSE with probability * 1-successes/total, and TRUE with probability successes/total. */ enum RandomTag { RNG_NONE, RNG_ACCURACY, RNG_CONFUSION, RNG_CRITICAL_HIT, RNG_CURSED_BODY, RNG_CUTE_CHARM, RNG_DAMAGE_MODIFIER, RNG_DIRE_CLAW, RNG_EFFECT_SPORE, RNG_FLAME_BODY, RNG_FORCE_RANDOM_SWITCH, RNG_FROZEN, RNG_G_MAX_STUN_SHOCK, RNG_G_MAX_BEFUDDLE, RNG_G_MAX_REPLENISH, RNG_G_MAX_SNOOZE, RNG_HARVEST, RNG_HITS, RNG_HOLD_EFFECT_FLINCH, RNG_INFATUATION, RNG_LOADED_DICE, RNG_METRONOME, RNG_PARALYSIS, RNG_PICKUP, RNG_POISON_POINT, RNG_POISON_TOUCH, RNG_RAMPAGE_TURNS, RNG_SECONDARY_EFFECT, RNG_SECONDARY_EFFECT_2, RNG_SECONDARY_EFFECT_3, RNG_SHED_SKIN, RNG_SLEEP_TURNS, RNG_SPEED_TIE, RNG_STATIC, RNG_STENCH, RNG_TOXIC_CHAIN, RNG_TRI_ATTACK, RNG_QUICK_DRAW, RNG_QUICK_CLAW, RNG_TRACE, RNG_FICKLE_BEAM, RNG_AI_ABILITY, RNG_AI_SWITCH_HASBADODDS, RNG_AI_SWITCH_BADLY_POISONED, RNG_AI_SWITCH_CURSED, RNG_AI_SWITCH_NIGHTMARE, RNG_AI_SWITCH_SEEDED, RNG_AI_SWITCH_ABSORBING, RNG_AI_SWITCH_NATURAL_CURE, RNG_AI_SWITCH_REGENERATOR, RNG_AI_SWITCH_ENCORE, RNG_AI_SWITCH_STATS_LOWERED, RNG_AI_SWITCH_SE_DEFENSIVE, RNG_SHELL_SIDE_ARM, RNG_RANDOM_TARGET, RNG_HEALER, }; #define RandomWeighted(tag, ...) \ ({ \ const u8 weights[] = { __VA_ARGS__ }; \ u32 sum, i; \ for (i = 0, sum = 0; i < ARRAY_COUNT(weights); i++) \ sum += weights[i]; \ RandomWeightedArray(tag, sum, ARRAY_COUNT(weights), weights); \ }) #define RandomChance(tag, successes, total) (RandomWeighted(tag, total - successes, successes)) #define RandomPercentage(tag, t) \ ({ \ u32 r; \ if (t <= 0) \ { \ r = FALSE; \ } \ else if (t >= 100) \ { \ r = TRUE; \ } \ else \ { \ const u8 weights[] = { 100 - t, t }; \ r = RandomWeightedArray(tag, 100, ARRAY_COUNT(weights), weights); \ } \ r; \ }) #define RandomElement(tag, array) \ ({ \ *(typeof((array)[0]) *)RandomElementArray(tag, array, sizeof((array)[0]), ARRAY_COUNT(array)); \ }) u32 RandomUniform(enum RandomTag, u32 lo, u32 hi); u32 RandomUniformExcept(enum RandomTag, u32 lo, u32 hi, bool32 (*reject)(u32)); u32 RandomWeightedArray(enum RandomTag, u32 sum, u32 n, const u8 *weights); const void *RandomElementArray(enum RandomTag, const void *array, size_t size, size_t count); u32 RandomUniformDefault(enum RandomTag, u32 lo, u32 hi); u32 RandomUniformExceptDefault(enum RandomTag, u32 lo, u32 hi, bool32 (*reject)(u32)); u32 RandomWeightedArrayDefault(enum RandomTag, u32 sum, u32 n, const u8 *weights); const void *RandomElementArrayDefault(enum RandomTag, const void *array, size_t size, size_t count); u8 RandomWeightedIndex(u8 *weights, u8 length); #endif // GUARD_RANDOM_H