Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove support for the original LCG random number generator #5078

Merged
merged 1 commit into from
Aug 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions include/battle.h
Original file line number Diff line number Diff line change
Expand Up @@ -600,12 +600,10 @@ struct LostItem
u16 stolen:1;
};

#if HQ_RANDOM == TRUE
struct BattleVideo {
u32 battleTypeFlags;
rng_value_t rngSeed;
};
#endif

struct BattleStruct
{
Expand Down Expand Up @@ -682,12 +680,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;
Expand Down
56 changes: 9 additions & 47 deletions include/random.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
6 changes: 0 additions & 6 deletions src/battle_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1691,15 +1691,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]++;
Expand Down
57 changes: 18 additions & 39 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,37 +205,22 @@ 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;
}

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)
Expand All @@ -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

Expand Down
34 changes: 0 additions & 34 deletions src/random.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
rng_value_t gRngValue;
rng_value_t gRng2Value;

#if HQ_RANDOM == TRUE

EWRAM_DATA static volatile bool8 sRngLoopUnlocked;

Expand Down Expand Up @@ -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; \
Expand Down
22 changes: 5 additions & 17 deletions test/random.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -285,5 +274,4 @@ TEST("Thumb and C SFC32 implementations produce the same results")
}

EXPECT_EQ(thumbSum, cSum);
}
#endif
}
24 changes: 6 additions & 18 deletions test/test_runner_battle.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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)
{
Expand Down
Loading