You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
85 lines
2.8 KiB
85 lines
2.8 KiB
/** |
|
* @file random.hpp |
|
* |
|
* Contains convenience functions for random number generation |
|
* |
|
* This includes specific engine/distribution functions for logic that needs to be compatible with the base game. |
|
*/ |
|
#pragma once |
|
|
|
#include <algorithm> |
|
#include <cstdint> |
|
#include <initializer_list> |
|
|
|
namespace devilution { |
|
|
|
/** |
|
* @brief Set the state of the RandomNumberEngine used by the base game to the specific seed |
|
* @param seed New engine state |
|
*/ |
|
void SetRndSeed(uint32_t seed); |
|
|
|
/** |
|
* @brief Returns the current state of the RandomNumberEngine used by the base game |
|
* |
|
* This is only exposed to allow for debugging vanilla code and testing. Using this engine for new code is discouraged |
|
* due to the poor randomness and bugs in the implementation that need to be retained for compatibility. |
|
* |
|
* @return The current engine state |
|
*/ |
|
uint32_t GetLCGEngineState(); |
|
|
|
/** |
|
* @brief Generates a random non-negative integer (most of the time) using the vanilla RNG |
|
* |
|
* This advances the engine state then interprets the new engine state as a signed value and calls std::abs to try |
|
* discard the high bit of the result. This usually returns a positive number but may very rarely return -2^31. |
|
* |
|
* This function is only used when the base game wants to store the seed used to generate an item or level, however |
|
* as the returned value is transformed about 50% of values do not reflect the actual engine state. It would be more |
|
* appropriate to use GetLCGEngineState() in these cases but that may break compatibility with the base game. |
|
* |
|
* @return A random number in the range [0,2^31) or -2^31 |
|
*/ |
|
int32_t AdvanceRndSeed(); |
|
|
|
/** |
|
* @brief Generates a random integer less than the given limit using the vanilla RNG |
|
* |
|
* If v is not a positive number this function returns 0 without calling the RNG. |
|
* |
|
* Limits between 32768 and 65534 should be avoided as a bug in vanilla means this function always returns a value |
|
* less than 32768 for limits in that range. |
|
* |
|
* This can very rarely return a negative value in the range (-v, -1] due to the bug in AdvanceRndSeed() |
|
* |
|
* @see AdvanceRndSeed() |
|
* @param v The upper limit for the return value |
|
* @return A random number in the range [0, v) or rarely a negative value in (-v, -1] |
|
*/ |
|
int32_t GenerateRnd(int32_t v); |
|
|
|
/** |
|
* @brief Generates a random boolean value using the vanilla RNG |
|
* |
|
* This function returns true 50% of the time and false 50% of the time. |
|
* |
|
* @return A random boolean value |
|
*/ |
|
bool FlipCoin(); |
|
|
|
/** |
|
* @brief Picks one of the elements in the list randomly. |
|
* |
|
* @param values The values to pick from |
|
* @return A random value from the 'values' list. |
|
*/ |
|
template <typename T> |
|
const T PickRandomlyAmong(const std::initializer_list<T> &values) |
|
{ |
|
const auto index { std::max<int32_t>(GenerateRnd(values.size()), 0) }; |
|
|
|
return *(values.begin() + index); |
|
} |
|
|
|
} // namespace devilution
|
|
|