Remove support for the original LCG random number generator (#5078)
This commit is contained in:
parent
77148f83a6
commit
17f68563eb
7 changed files with 38 additions and 168 deletions
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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]++;
|
||||||
|
|
57
src/main.c
57
src/main.c
|
@ -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
|
||||||
|
|
||||||
|
|
34
src/random.c
34
src/random.c
|
@ -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; \
|
||||||
|
|
|
@ -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
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue