Remove support for the original LCG random number generator (#5078)

This commit is contained in:
tertu 2024-08-24 12:07:00 -05:00 committed by GitHub
parent 77148f83a6
commit 17f68563eb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 38 additions and 168 deletions

View file

@ -600,12 +600,10 @@ struct LostItem
u16 stolen:1; u16 stolen:1;
}; };
#if HQ_RANDOM == TRUE
struct BattleVideo { struct BattleVideo {
u32 battleTypeFlags; u32 battleTypeFlags;
rng_value_t rngSeed; rng_value_t rngSeed;
}; };
#endif
enum BattleIntroStates enum BattleIntroStates
{ {
@ -707,12 +705,7 @@ struct BattleStruct
u16 lastTakenMoveFrom[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT]; // a 2-D array [target][attacker] u16 lastTakenMoveFrom[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT]; // a 2-D array [target][attacker]
union { union {
struct LinkBattlerHeader linkBattlerHeader; struct LinkBattlerHeader linkBattlerHeader;
#if HQ_RANDOM == FALSE
u32 battleVideo[2];
#else
struct BattleVideo battleVideo; struct BattleVideo battleVideo;
#endif
} multiBuffer; } multiBuffer;
u8 wishPerishSongState; u8 wishPerishSongState;
u8 wishPerishSongBattlerId; u8 wishPerishSongBattlerId;

View file

@ -6,25 +6,21 @@
#define ISO_RANDOMIZE1(val)(1103515245 * (val) + 24691) #define ISO_RANDOMIZE1(val)(1103515245 * (val) + 24691)
#define ISO_RANDOMIZE2(val)(1103515245 * (val) + 12345) #define ISO_RANDOMIZE2(val)(1103515245 * (val) + 12345)
/* Some functions have been added to support HQ_RANDOM. /* Some functions have been added to support Expansion's RNG implementation.
* *
* If using HQ_RANDOM, you cannot call Random() in interrupt handlers safely. * LocalRandom(*val) provides a higher-quality replacement for uses of
* AdvanceRandom() is provided to handle burning numbers in the VBlank handler * ISO_RANDOMIZE in vanilla Emerald. You can use LocalRandomSeed(u32) to
* if you choose to do that, and can be used regardless of HQ_RANDOM setting. * 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 * If you need to use random numbers in the VBlank handler, a local state
* should be used instead. * should be used instead.
* *
* LocalRandom(*val) allows you to have local random states that are the same * Random2_32() was added, even though it is not used directly, because the
* type as the global states regardless of HQ_RANDOM setting, which is useful * underlying RNG always outputs 32 bits.
* if you want to be able to set them from or assign them to gRngValue.
* LocalRandomSeed(u32) returns a properly seeded rng_value_t.
*
* Random2_32() was added to HQ_RANDOM because the output of the generator is
* always 32 bits and Random()/Random2() are just wrappers in that mode. It is
* also available in non-HQ mode for consistency.
*/ */
#if HQ_RANDOM == TRUE
struct Sfc32State { struct Sfc32State {
u32 a; u32 a;
u32 b; u32 b;
@ -70,40 +66,6 @@ static inline u16 Random2(void)
} }
void AdvanceRandom(void); void AdvanceRandom(void);
#else
typedef u32 rng_value_t;
#define RNG_VALUE_EMPTY 0
//Returns a 16-bit pseudorandom number
u16 Random(void);
u16 Random2(void);
//Sets the initial seed value of the pseudorandom number generator
void SeedRng(u16 seed);
void SeedRng2(u16 seed);
//Returns a 32-bit pseudorandom number
#define Random32() (Random() | (Random() << 16))
#define Random2_32() (Random2() | (Random2() << 16))
static inline u16 LocalRandom(rng_value_t *val)
{
*val = ISO_RANDOMIZE1(*val);
return *val >> 16;
}
static inline void AdvanceRandom(void)
{
Random();
}
static inline rng_value_t LocalRandomSeed(u32 seed)
{
return seed;
}
#endif
extern rng_value_t gRngValue; extern rng_value_t gRngValue;
extern rng_value_t gRng2Value; extern rng_value_t gRng2Value;

View file

@ -1692,15 +1692,9 @@ static void CB2_HandleStartMultiBattle(void)
case 8: case 8:
if (IsLinkTaskFinished()) if (IsLinkTaskFinished())
{ {
#if HQ_RANDOM == TRUE
struct BattleVideo *ptr = &gBattleStruct->multiBuffer.battleVideo; struct BattleVideo *ptr = &gBattleStruct->multiBuffer.battleVideo;
ptr->battleTypeFlags = gBattleTypeFlags; ptr->battleTypeFlags = gBattleTypeFlags;
ptr->rngSeed = gRecordedBattleRngSeed; ptr->rngSeed = gRecordedBattleRngSeed;
#else
u32 *ptr = gBattleStruct->multiBuffer.battleVideo;
ptr[0] = gBattleTypeFlags;
ptr[1] = gRecordedBattleRngSeed; // UB: overwrites berry data
#endif
SendBlock(BitmaskAllOtherLinkPlayers(), ptr, sizeof(gBattleStruct->multiBuffer.battleVideo)); SendBlock(BitmaskAllOtherLinkPlayers(), ptr, sizeof(gBattleStruct->multiBuffer.battleVideo));
gBattleCommunication[MULTIUSE_STATE]++; gBattleCommunication[MULTIUSE_STATE]++;

View file

@ -205,12 +205,9 @@ void SetMainCallback2(MainCallback callback)
void StartTimer1(void) void StartTimer1(void)
{ {
if (HQ_RANDOM)
{
REG_TM2CNT_L = 0;
REG_TM2CNT_H = TIMER_ENABLE | TIMER_COUNTUP;
}
REG_TM2CNT_L = 0;
REG_TM2CNT_H = TIMER_ENABLE | TIMER_COUNTUP;
REG_TM1CNT_H = TIMER_ENABLE; REG_TM1CNT_H = TIMER_ENABLE;
} }
@ -218,24 +215,12 @@ void SeedRngAndSetTrainerId(void)
{ {
u32 val; u32 val;
if (HQ_RANDOM) REG_TM1CNT_H = 0;
{ REG_TM2CNT_H = 0;
REG_TM1CNT_H = 0; val = ((u32)REG_TM2CNT_L) << 16;
REG_TM2CNT_H = 0; val |= REG_TM1CNT_L;
val = ((u32)REG_TM2CNT_L) << 16; SeedRng(val);
val |= REG_TM1CNT_L; sTrainerId = Random();
SeedRng(val);
sTrainerId = Random();
}
else
{
// Do it exactly like it was originally done, including not stopping
// the timer beforehand.
val = REG_TM1CNT_L;
SeedRng((u16)val);
REG_TM1CNT_H = 0;
sTrainerId = val;
}
} }
u16 GetGeneratedTrainerIdLower(void) u16 GetGeneratedTrainerIdLower(void)
@ -254,22 +239,16 @@ void EnableVCountIntrAtLine150(void)
#ifdef BUGFIX #ifdef BUGFIX
static void SeedRngWithRtc(void) static void SeedRngWithRtc(void)
{ {
#if HQ_RANDOM == FALSE #define BCD8(x) ((((x) >> 4) & 0xF) * 10 + ((x) & 0xF))
u32 seed = RtcGetMinuteCount(); u32 seconds;
seed = (seed >> 16) ^ (seed & 0xFFFF); struct SiiRtcInfo rtc;
SeedRng(seed); RtcGetInfo(&rtc);
#else seconds =
#define BCD8(x) ((((x) >> 4) & 0xF) * 10 + ((x) & 0xF)) ((HOURS_PER_DAY * RtcGetDayCount(&rtc) + BCD8(rtc.hour))
u32 seconds; * MINUTES_PER_HOUR + BCD8(rtc.minute))
struct SiiRtcInfo rtc; * SECONDS_PER_MINUTE + BCD8(rtc.second);
RtcGetInfo(&rtc); SeedRng(seconds);
seconds = #undef BCD8
((HOURS_PER_DAY * RtcGetDayCount(&rtc) + BCD8(rtc.hour))
* MINUTES_PER_HOUR + BCD8(rtc.minute))
* SECONDS_PER_MINUTE + BCD8(rtc.second);
SeedRng(seconds);
#undef BCD8
#endif
} }
#endif #endif

View file

@ -8,7 +8,6 @@
rng_value_t gRngValue; rng_value_t gRngValue;
rng_value_t gRng2Value; rng_value_t gRng2Value;
#if HQ_RANDOM == TRUE
EWRAM_DATA static volatile bool8 sRngLoopUnlocked; EWRAM_DATA static volatile bool8 sRngLoopUnlocked;
@ -112,39 +111,6 @@ void AdvanceRandom(void)
#define LOOP_RANDOM ((u16)(_SFC32_Next(state) >> 16)) #define LOOP_RANDOM ((u16)(_SFC32_Next(state) >> 16))
#else
EWRAM_DATA static u32 sRandCount = 0;
u16 Random(void)
{
gRngValue = ISO_RANDOMIZE1(gRngValue);
sRandCount++;
return gRngValue >> 16;
}
void SeedRng(u16 seed)
{
gRngValue = seed;
}
void SeedRng2(u16 seed)
{
gRng2Value = seed;
}
u16 Random2(void)
{
gRng2Value = ISO_RANDOMIZE1(gRng2Value);
return gRng2Value >> 16;
}
#define LOOP_RANDOM_START
#define LOOP_RANDOM_END
#define LOOP_RANDOM (Random())
#endif
#define SHUFFLE_IMPL \ #define SHUFFLE_IMPL \
u32 tmp; \ u32 tmp; \
LOOP_RANDOM_START; \ LOOP_RANDOM_START; \

View file

@ -196,13 +196,8 @@ TEST("RandomElement generates a uniform distribution")
TEST("RandomUniform mul-based faster than mod-based (compile-time)") TEST("RandomUniform mul-based faster than mod-based (compile-time)")
{ {
#if HQ_RANDOM == TRUE const u32 expectedMulSum = 6;
const u32 expectedMulSum = 6; const u32 expectedModSum = 4;
const u32 expectedModSum = 4;
#else
const u32 expectedMulSum = 3;
const u32 expectedModSum = 4;
#endif
struct Benchmark mulBenchmark, modBenchmark; struct Benchmark mulBenchmark, modBenchmark;
u32 mulSum = 0, modSum = 0; u32 mulSum = 0, modSum = 0;
@ -234,13 +229,8 @@ TEST("RandomUniform mul-based faster than mod-based (compile-time)")
TEST("RandomUniform mul-based faster than mod-based (run-time)") TEST("RandomUniform mul-based faster than mod-based (run-time)")
{ {
#if HQ_RANDOM == TRUE const u32 expectedMulSum = 289;
const u32 expectedMulSum = 289; const u32 expectedModSum = 205;
const u32 expectedModSum = 205;
#else
const u32 expectedMulSum = 232;
const u32 expectedModSum = 249;
#endif
u32 i; u32 i;
struct Benchmark mulBenchmark, modBenchmark; struct Benchmark mulBenchmark, modBenchmark;
u32 mulSum = 0, modSum = 0; u32 mulSum = 0, modSum = 0;
@ -264,7 +254,6 @@ TEST("RandomUniform mul-based faster than mod-based (run-time)")
EXPECT_EQ(modSum, expectedModSum); EXPECT_EQ(modSum, expectedModSum);
} }
#if HQ_RANDOM == TRUE
TEST("Thumb and C SFC32 implementations produce the same results") TEST("Thumb and C SFC32 implementations produce the same results")
{ {
u32 thumbSum; u32 thumbSum;
@ -286,4 +275,3 @@ TEST("Thumb and C SFC32 implementations produce the same results")
EXPECT_EQ(thumbSum, cSum); EXPECT_EQ(thumbSum, cSum);
} }
#endif

View file

@ -35,20 +35,12 @@
#define STATE gBattleTestRunnerState #define STATE gBattleTestRunnerState
#define DATA gBattleTestRunnerState->data #define DATA gBattleTestRunnerState->data
#if HQ_RANDOM == TRUE
#define RNG_SEED_DEFAULT {0, 0, 0, 0} #define RNG_SEED_DEFAULT {0, 0, 0, 0}
static inline bool32 RngSeedNotDefault(const rng_value_t *seed) static inline bool32 RngSeedNotDefault(const rng_value_t *seed)
{ {
return (seed->a | seed->b | seed->c | seed->ctr) != 0; return (seed->a | seed->b | seed->c | seed->ctr) != 0;
} }
#else
#define RNG_SEED_DEFAULT 0x00000000
static inline bool32 RngSeedNotDefault(const rng_value_t *seed)
{
return *seed != RNG_SEED_DEFAULT;
}
#endif
#undef Q_4_12 #undef Q_4_12
#define Q_4_12(n) (s32)((n) * 4096) #define Q_4_12(n) (s32)((n) * 4096)
@ -1357,17 +1349,13 @@ static void CB2_BattleTest_NextParameter(void)
static inline rng_value_t MakeRngValue(const u16 seed) static inline rng_value_t MakeRngValue(const u16 seed)
{ {
#if HQ_RANDOM == TRUE int i;
int i; rng_value_t result = {0, 0, seed, 1};
rng_value_t result = {0, 0, seed, 1}; for (i = 0; i < 16; i++)
for (i = 0; i < 16; i++) {
{
_SFC32_Next(&result); _SFC32_Next(&result);
} }
return result; return result;
#else
return ISO_RANDOMIZE1(seed);
#endif
} }
static void CB2_BattleTest_NextTrial(void) static void CB2_BattleTest_NextTrial(void)