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

View file

@ -6,25 +6,21 @@
#define ISO_RANDOMIZE1(val)(1103515245 * (val) + 24691)
#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.
* AdvanceRandom() is provided to handle burning numbers in the VBlank handler
* if you choose to do that, and can be used regardless of HQ_RANDOM setting.
* 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.
*
* LocalRandom(*val) allows you to have local random states that are the same
* type as the global states regardless of HQ_RANDOM setting, which is useful
* 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.
* Random2_32() was added, even though it is not used directly, because the
* underlying RNG always outputs 32 bits.
*/
#if HQ_RANDOM == TRUE
struct Sfc32State {
u32 a;
u32 b;
@ -70,40 +66,6 @@ static inline u16 Random2(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 gRng2Value;

View file

@ -1692,15 +1692,9 @@ static void CB2_HandleStartMultiBattle(void)
case 8:
if (IsLinkTaskFinished())
{
#if HQ_RANDOM == TRUE
struct BattleVideo *ptr = &gBattleStruct->multiBuffer.battleVideo;
ptr->battleTypeFlags = gBattleTypeFlags;
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));
gBattleCommunication[MULTIUSE_STATE]++;

View file

@ -205,12 +205,9 @@ void SetMainCallback2(MainCallback callback)
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;
}
@ -218,24 +215,12 @@ void SeedRngAndSetTrainerId(void)
{
u32 val;
if (HQ_RANDOM)
{
REG_TM1CNT_H = 0;
REG_TM2CNT_H = 0;
val = ((u32)REG_TM2CNT_L) << 16;
val |= REG_TM1CNT_L;
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;
}
REG_TM1CNT_H = 0;
REG_TM2CNT_H = 0;
val = ((u32)REG_TM2CNT_L) << 16;
val |= REG_TM1CNT_L;
SeedRng(val);
sTrainerId = Random();
}
u16 GetGeneratedTrainerIdLower(void)
@ -254,22 +239,16 @@ void EnableVCountIntrAtLine150(void)
#ifdef BUGFIX
static void SeedRngWithRtc(void)
{
#if HQ_RANDOM == FALSE
u32 seed = RtcGetMinuteCount();
seed = (seed >> 16) ^ (seed & 0xFFFF);
SeedRng(seed);
#else
#define BCD8(x) ((((x) >> 4) & 0xF) * 10 + ((x) & 0xF))
u32 seconds;
struct SiiRtcInfo rtc;
RtcGetInfo(&rtc);
seconds =
((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
#define BCD8(x) ((((x) >> 4) & 0xF) * 10 + ((x) & 0xF))
u32 seconds;
struct SiiRtcInfo rtc;
RtcGetInfo(&rtc);
seconds =
((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

View file

@ -8,7 +8,6 @@
rng_value_t gRngValue;
rng_value_t gRng2Value;
#if HQ_RANDOM == TRUE
EWRAM_DATA static volatile bool8 sRngLoopUnlocked;
@ -112,39 +111,6 @@ void AdvanceRandom(void)
#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 \
u32 tmp; \
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)")
{
#if HQ_RANDOM == TRUE
const u32 expectedMulSum = 6;
const u32 expectedModSum = 4;
#else
const u32 expectedMulSum = 3;
const u32 expectedModSum = 4;
#endif
const u32 expectedMulSum = 6;
const u32 expectedModSum = 4;
struct Benchmark mulBenchmark, modBenchmark;
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)")
{
#if HQ_RANDOM == TRUE
const u32 expectedMulSum = 289;
const u32 expectedModSum = 205;
#else
const u32 expectedMulSum = 232;
const u32 expectedModSum = 249;
#endif
const u32 expectedMulSum = 289;
const u32 expectedModSum = 205;
u32 i;
struct Benchmark mulBenchmark, modBenchmark;
u32 mulSum = 0, modSum = 0;
@ -264,7 +254,6 @@ TEST("RandomUniform mul-based faster than mod-based (run-time)")
EXPECT_EQ(modSum, expectedModSum);
}
#if HQ_RANDOM == TRUE
TEST("Thumb and C SFC32 implementations produce the same results")
{
u32 thumbSum;
@ -285,5 +274,4 @@ TEST("Thumb and C SFC32 implementations produce the same results")
}
EXPECT_EQ(thumbSum, cSum);
}
#endif
}

View file

@ -35,20 +35,12 @@
#define STATE gBattleTestRunnerState
#define DATA gBattleTestRunnerState->data
#if HQ_RANDOM == TRUE
#define RNG_SEED_DEFAULT {0, 0, 0, 0}
static inline bool32 RngSeedNotDefault(const rng_value_t *seed)
{
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
#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)
{
#if HQ_RANDOM == TRUE
int i;
rng_value_t result = {0, 0, seed, 1};
for (i = 0; i < 16; i++)
{
int i;
rng_value_t result = {0, 0, seed, 1};
for (i = 0; i < 16; i++)
{
_SFC32_Next(&result);
}
return result;
#else
return ISO_RANDOMIZE1(seed);
#endif
}
return result;
}
static void CB2_BattleTest_NextTrial(void)