#include "engine/random.hpp" #include #include #include #include "utils/stdcompat/abs.hpp" namespace devilution { /** Current game seed */ uint32_t sglGameSeed; /** Borland C/C++ psuedo-random number generator needed for vanilla compatibility */ std::linear_congruential_engine diabloGenerator; void SetRndSeed(uint32_t seed) { diabloGenerator.seed(seed); sglGameSeed = seed; } uint32_t GetLCGEngineState() { return sglGameSeed; } void DiscardRandomValues(unsigned count) { while (count != 0) { GenerateSeed(); count--; } } uint32_t GenerateSeed() { sglGameSeed = diabloGenerator(); return sglGameSeed; } int32_t AdvanceRndSeed() { const int32_t seed = static_cast(GenerateSeed()); // since abs(INT_MIN) is undefined behavior, handle this value specially return seed == std::numeric_limits::min() ? std::numeric_limits::min() : abs(seed); } int32_t GenerateRnd(int32_t v) { if (v <= 0) return 0; if (v <= 0x7FFF) // use the high bits to correct for LCG bias return (AdvanceRndSeed() >> 16) % v; return AdvanceRndSeed() % v; } bool FlipCoin(unsigned frequency) { // Casting here because GenerateRnd takes a signed argument when it should take and yield unsigned. return GenerateRnd(static_cast(frequency)) == 0; } } // namespace devilution