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

Optional high-quality RNG #3780

Merged
merged 23 commits into from
Dec 22, 2023
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
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
13 changes: 13 additions & 0 deletions include/battle.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "pokeball.h"
#include "battle_debug.h"
#include "battle_dynamax.h"
#include "random.h" // for rng_value_t
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you have a particular reason for adding these // for rng_value_t comments to the includes?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a very justifiable one.


// Used to exclude moves learned temporarily by Transform or Mimic
#define MOVE_IS_PERMANENT(battler, moveSlot) \
Expand Down Expand Up @@ -580,6 +581,13 @@ struct LostItem
u16 stolen:1;
};

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

struct BattleStruct
{
u8 turnEffectsTracker;
Expand Down Expand Up @@ -651,7 +659,12 @@ 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
1 change: 1 addition & 0 deletions include/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,5 +79,6 @@
#define EXPANSION_INTRO TRUE // If TRUE, a custom RHH intro will play after the vanilla copyright screen.
#define POKEDEX_PLUS_HGSS FALSE // If TRUE, enables the custom HGSS style Pokedex.
#define SUMMARY_SCREEN_NATURE_COLORS TRUE // If TRUE, nature-based stat boosts and reductions will be red and blue in the summary screen.
#define HQ_RANDOM TRUE // If TRUE, replaces the default RNG with an implementation of SFC32 RNG. May break code that relies on RNG.

#endif // GUARD_CONFIG_H
3 changes: 2 additions & 1 deletion include/contest.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "palette.h"
#include "constants/contest.h"
#include "random.h" // for rng_value_t

enum
{
Expand Down Expand Up @@ -327,7 +328,7 @@ extern struct ContestResources *gContestResources;
extern struct ContestWinner gCurContestWinner;
extern u8 gCurContestWinnerIsForArtist;
extern u8 gCurContestWinnerSaveIdx;
extern u32 gContestRngValue;
extern rng_value_t gContestRngValue;

// contest.c
void ResetLinkContestBoolean(void);
Expand Down
80 changes: 74 additions & 6 deletions include/random.h
Original file line number Diff line number Diff line change
@@ -1,20 +1,88 @@
#ifndef GUARD_RANDOM_H
#define GUARD_RANDOM_H

extern u32 gRngValue;
extern u32 gRng2Value;
// The number 1103515245 comes from the example implementation of rand and srand
// in the ISO C standard.
#define ISO_RANDOMIZE1(val)(1103515245 * (val) + 24691)
#define ISO_RANDOMIZE2(val)(1103515245 * (val) + 12345)

/* Notes about new functions:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it might be good to avoid "new". Perhaps "HQ", or maybe just describe the API?

My gripe with "new" is that more functions could be added in the future, and also that functions like RandomUniform are new from the perspective of vanilla pokeemerald, so I think readers could find it unclear.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe something like “HQ_RANDOM support functions”?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good to me :)

* If using HQ_RANDOM, you MUST call AdvanceRandom() in VBlank handlers.
* If you do not, you risk corruption of the RNG state.
tertu-m marked this conversation as resolved.
Show resolved Hide resolved
* LocalRandom(*val) adapts to either choice of RNG implementation.
* Other new functions should be self-explanatory.
*/

#if HQ_RANDOM == TRUE
struct Sfc32State {
u32 a;
u32 b;
u32 c;
u32 ctr;
};

typedef struct Sfc32State rng_value_t;

#define RNG_VALUE_EMPTY {}

// Calling this function directly is discouraged.
// Use LocalRandom() instead.
static inline u32 _SFC32_Next(struct Sfc32State *state)
{
const u32 result = state->a + state->b + state->ctr++;
state->a = state->b ^ (state->b >> 9);
state->b = state->c * 9;
state->c = result + ((state->c << 21) | (state->c >> 11));
return result;
}

static inline u16 LocalRandom(rng_value_t *val)
{
return _SFC32_Next(val) >> 16;
}

u32 Random32(void);
u32 Random2_32(void);

static inline u16 Random(void)
{
return Random32() >> 16;
}

static inline u16 Random2(void)
{
return Random2_32() >> 16;
}

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);

//Returns a 32-bit pseudorandom number
#define Random32() (Random() | (Random() << 16))
#define Random2_32() (Random2() | (Random2() << 16))

// The number 1103515245 comes from the example implementation of rand and srand
// in the ISO C standard.
#define ISO_RANDOMIZE1(val)(1103515245 * (val) + 24691)
#define ISO_RANDOMIZE2(val)(1103515245 * (val) + 12345)
static inline u16 LocalRandom(rng_value_t *val)
{
*val = ISO_RANDOMIZE1(*val);
return *val >> 16;
}

static inline void AdvanceRandom(void)
{
Random();
}

#endif

extern rng_value_t gRngValue;
extern rng_value_t gRng2Value;

//Sets the initial seed value of the pseudorandom number generator
void SeedRng(u16 seed);
Expand Down
7 changes: 4 additions & 3 deletions include/recorded_battle.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define GUARD_RECORDED_BATTLE_H

#include "constants/battle.h"
#include "random.h" // for rng_value_t

#define BATTLER_RECORD_SIZE 664

Expand All @@ -13,7 +14,7 @@ struct RecordedBattleSave
u8 playersGender[MAX_BATTLERS_COUNT];
u32 playersTrainerId[MAX_BATTLERS_COUNT];
u8 playersLanguage[MAX_BATTLERS_COUNT];
u32 rngSeed;
rng_value_t rngSeed;
mrgriffin marked this conversation as resolved.
Show resolved Hide resolved
u32 battleFlags;
u8 playersBattlers[MAX_BATTLERS_COUNT];
u16 opponentA;
Expand Down Expand Up @@ -49,8 +50,8 @@ enum
RECORDED_ITEM_MOVE,
};

extern u32 gRecordedBattleRngSeed;
extern u32 gBattlePalaceMoveSelectionRngValue;
extern rng_value_t gRecordedBattleRngSeed;
extern rng_value_t gBattlePalaceMoveSelectionRngValue;
extern u8 gRecordedBattleMultiplayerId;

#define B_RECORD_MODE_RECORDING 1
Expand Down
2 changes: 1 addition & 1 deletion include/test/battle.h
Original file line number Diff line number Diff line change
Expand Up @@ -842,7 +842,7 @@ struct moveWithPP {
void OpenPokemon(u32 sourceLine, u32 side, u32 species);
void ClosePokemon(u32 sourceLine);

void RNGSeed_(u32 sourceLine, u32 seed);
void RNGSeed_(u32 sourceLine, rng_value_t seed);
void AIFlags_(u32 sourceLine, u32 flags);
void AILogScores(u32 sourceLine);
void Gender_(u32 sourceLine, u32 gender);
Expand Down
1 change: 1 addition & 0 deletions src/battle_controller_link_opponent.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "constants/songs.h"
#include "constants/trainers.h"
#include "recorded_battle.h"
#include "random.h" // for rng_value_t

static void LinkOpponentHandleLoadMonSprite(u32 battler);
static void LinkOpponentHandleSwitchInAnim(u32 battler);
Expand Down
1 change: 1 addition & 0 deletions src/battle_controller_link_partner.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "constants/songs.h"
#include "constants/trainers.h"
#include "recorded_battle.h"
#include "random.h" // for rng_value_t

static void LinkPartnerHandleLoadMonSprite(u32 battler);
static void LinkPartnerHandleSwitchInAnim(u32 battler);
Expand Down
9 changes: 8 additions & 1 deletion src/battle_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1713,9 +1713,16 @@ 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 Expand Up @@ -2053,7 +2060,7 @@ void VBlankCB_Battle(void)
{
// Change gRngSeed every vblank unless the battle could be recorded.
if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_FRONTIER | BATTLE_TYPE_RECORDED)))
Random();
AdvanceRandom();

SetGpuReg(REG_OFFSET_BG0HOFS, gBattle_BG0_X);
SetGpuReg(REG_OFFSET_BG0VOFS, gBattle_BG0_Y);
Expand Down
5 changes: 2 additions & 3 deletions src/contest.c
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ EWRAM_DATA bool8 gCurContestWinnerIsForArtist = 0;
EWRAM_DATA u8 gCurContestWinnerSaveIdx = 0;

// IWRAM common vars.
u32 gContestRngValue;
rng_value_t gContestRngValue;

extern const u8 gText_LinkStandby4[];
extern const u8 gText_BDot[];
Expand Down Expand Up @@ -1709,7 +1709,7 @@ static void Task_AppealSetup(u8 taskId)
if (++gTasks[taskId].data[0] > 19)
{
eContest.turnNumber = 0;
eContest.unusedRng = gRngValue;
eContest.unusedRng = 0;
if ((gLinkContestFlags & LINK_CONTEST_FLAG_IS_LINK) && IsPlayerLinkLeader())
{
s32 i;
Expand Down Expand Up @@ -6109,4 +6109,3 @@ void StripPlayerAndMonNamesForLinkContest(struct ContestPokemon *mon, s32 langua
name[PLAYER_NAME_LENGTH] = EOS;
}
}

6 changes: 2 additions & 4 deletions src/contest_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -2655,8 +2655,7 @@ void GenerateContestRand(void)

if (gLinkContestFlags & LINK_CONTEST_FLAG_IS_LINK)
{
gContestRngValue = ISO_RANDOMIZE1(gContestRngValue);
random = gContestRngValue >> 16;
random = LocalRandom(&gContestRngValue);
result = &gSpecialVar_Result;
}
else
Expand All @@ -2669,8 +2668,7 @@ void GenerateContestRand(void)

u16 GetContestRand(void)
{
gContestRngValue = ISO_RANDOMIZE1(gContestRngValue);
return gContestRngValue >> 16;
return LocalRandom(&gContestRngValue);
}

bool8 LinkContestWaitForConnection(void)
Expand Down
2 changes: 1 addition & 1 deletion src/debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -2144,7 +2144,7 @@ static void DebugAction_Util_Player_Gender(u8 taskId)

static void DebugAction_Util_Player_Id(u8 taskId)
{
u32 trainerId = ((Random() << 16) | Random());
u32 trainerId = Random32();
SetTrainerId(trainerId, gSaveBlock2Ptr->playerTrainerId);
Debug_DestroyMenu_Full(taskId);
ScriptContext_Enable();
Expand Down
2 changes: 1 addition & 1 deletion src/load_save.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ void MoveSaveBlocks_ResetHeap(void)
gMain.vblankCallback = vblankCB;

// create a new encryption key
encryptionKey = (Random() << 16) + (Random());
encryptionKey = Random32();
ApplyNewEncryptionKeyToAllEncryptedData(encryptionKey);
gSaveBlock2Ptr->encryptionKey = encryptionKey;
}
Expand Down
4 changes: 1 addition & 3 deletions src/lottery_corner.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ static u8 GetMatchingDigits(u16, u16);

void ResetLotteryCorner(void)
{
u16 rand = Random();

SetLotteryNumber((Random() << 16) | rand);
SetLotteryNumber(Random32());
VarSet(VAR_POKELOT_PRIZE_ITEM, 0);
}

Expand Down
2 changes: 1 addition & 1 deletion src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ static void VBlankIntr(void)
TryReceiveLinkBattleData();

if (!gMain.inBattle || !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_FRONTIER | BATTLE_TYPE_RECORDED)))
Random();
AdvanceRandom();

UpdateWirelessStatusIndicatorSprite();

Expand Down
Loading
Loading