Document PRNG Related Functions (#1060)

* document gfx_rand

* document global LCG

* rename func_80029994

* clarify rand_int_internal comment

* gfx_rand -> gfx_rand_int

* remove unneeded parens

* gfx_rand_int -> effect_rand_int

* gfx_prng_seed -> effect_prng_seed

* fix local variable case
This commit is contained in:
Lincoln-LM 2023-05-22 08:37:25 -06:00 committed by GitHub
parent 2e926567e3
commit f770d12db4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 84 additions and 71 deletions

View File

@ -1455,7 +1455,7 @@ typedef struct GameStatus {
/* 0x128 */ Vec3f playerGroundTraceNormal;
/* 0x134 */ u16 frameCounter;
/* 0x136 */ char unk_136[2];
/* 0x138 */ s32 nextRNG;
/* 0x138 */ u32 nextRNG;
/* 0x13C */ s16 unk_13C;
/* 0x13E */ char unk_13E[2];
/* 0x140 */ ShopItemEntity* shopItemEntities;

View File

@ -3,7 +3,7 @@
#include "effects.h"
s32 func_E0200000(s32);
s32 effect_rand_int(s32);
s32 func_E0200044(s32, s32);
EffectInstance* shim_create_effect_instance(EffectBlueprint* effectBp);

View File

@ -11,7 +11,7 @@ extern PlayerStatus* gPlayerStatusPtr;
extern CollisionStatus gCollisionStatus;
extern GameStatus gGameStatus;
extern GameStatus* gGameStatusPtr;
extern s32 gRandSeed;
extern u32 gRandSeed;
extern ItemData gItemTable[365];
extern UNK_FUN_PTR(gCurrentUpdateFunction);
extern MoveData gMoveTable[185];

View File

@ -2,7 +2,7 @@
#include "effects.h"
#include "nu/nusys.h"
u32 D_E0200690 = 0x1E6D3457;
u32 effect_prng_seed = 0x1E6D3457;
void* effectFuncs[] = {
guRotateF, guTranslateF, guTranslate, guScaleF, guMtxCatF, guMtxF2L, guMtxL2F, queue_render_task,
@ -33,12 +33,16 @@ s32 D_E0200734[128] = {
};
// very simple 'random' number generator that mutates a single value in memory
u32 func_E0200000(s32 max) {
s32 temp_v0 = D_E0200690 * 4;
// prng implementation is identical to that of guRandom
u32 effect_rand_int(s32 max) {
u32 seed = (effect_prng_seed << 2) + 2;
D_E0200690 = (u32)((temp_v0 + 2) * (temp_v0 + 3)) / 4;
seed *= (seed + 1);
seed = seed >> 2;
return D_E0200690 % (max + 1);
effect_prng_seed = seed;
return effect_prng_seed % (max + 1);
}
// very simple 'random' number generator using a LUT

View File

@ -25,7 +25,7 @@ u8 sIntegerDigits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
s32 gRandSeed = 1;
u32 gRandSeed = 1;
f32 sAtanFactors[] = {
1.0f, 1.273187f, 1.27303f, 1.272768f, 1.272402f, 1.271932f, 1.271358f, 1.270681f, 1.269902f, 1.269021f, 1.268038f,
@ -487,53 +487,62 @@ void dma_write_block(Addr dramAddr, u32 devAddr, s32 size) {
osRecvMesg(&osMesgQueue, &osMesg, 1);
}
s32 advance_rng(void) {
gRandSeed *= 0x5D588B65;
gRandSeed++;
// advance the global RNG via LCG algorithm and return a random integer [0,2^32)
u32 advance_rng(void) {
gRandSeed = gRandSeed * 0x5D588B65 + 1;
gGameStatusPtr->nextRNG = gRandSeed;
return gRandSeed;
}
// return a random float [0,1)
f32 rand_float(void) {
u32 temp_v0 = advance_rng() & 0x7FFF;
return temp_v0 / 32768.0;
return (advance_rng() & 0x7FFF) / 32768.0;
}
s32 func_80029994(s32 arg0) {
u32 div = -1;
s32 plusOne = arg0 + 1;
// return a random integer [0,max]
s32 rand_int_internal(u32 max) {
u32 partitionSize = 0xFFFFFFFF;
u32 maxPlusOne = max + 1;
u32 result;
div /= plusOne;
if (div == 0) {
div = 1;
// split [0,2^32) into ``maxPlusOne`` equally sized partitions
// [0, partitionSize), [partitionSize, 2*partitionSize), ... [maxPlusOne*partitionSize, 2^32)
partitionSize /= maxPlusOne;
if (partitionSize == 0) {
partitionSize = 1;
}
do {
result = advance_rng() / div;
} while (result >= plusOne);
// numbers in the leftover [maxPlusOne*partitionSize, 2^32) are rejected as they would return maxPlusOne
// this ensures the result is [0,max] whilst also ensuring each partition is the same size and equally probable
do {
// determine which partition the random number is in by dividing it by partitionSize
result = advance_rng() / partitionSize;
} while (result >= maxPlusOne);
return result;
}
s32 rand_int(s32 arg0) {
// return a random integer [0,|max|] with specific distributions for |max| = 1 and |max| = 100
s32 rand_int(s32 max) {
s32 ret = 0;
arg0 = abs(arg0);
max = abs(max);
if (arg0 != 0) {
switch (arg0) {
if (max != 0) {
switch (max) {
case 1:
ret = func_80029994(1000) > 500;
// due to the off-by-one input of 1000 and the > operator being used,
// there is a 501/1001 chance of returning 0 and a 500/1001 chance of returning 1
// (assuming statistical randomness of rand_int_internal).
ret = rand_int_internal(1000) > 500;
break;
default:
ret = func_80029994(arg0);
ret = rand_int_internal(max);
break;
case 100:
ret = func_80029994(1009) / 10;
ret = rand_int_internal(1009) / 10;
break;
}
}

View File

@ -52,7 +52,7 @@ void big_smoke_puff_main(f32 x, f32 y, f32 z) {
for (i = 0; i < effect->numParts; i++, data++) {
data->unk_00 = 0;
data->unk_02 = data->unk_04 = func_E0200000(6) + 0x10;
data->unk_02 = data->unk_04 = effect_rand_int(6) + 0x10;
data->unk_06 = 4;
data->unk_08 = 0;
data->x = x;

View File

@ -46,12 +46,12 @@ void big_snowflakes_main(s32 arg0, f32 arg1, f32 arg2, f32 arg3) {
data++;
for (i = 1; i < numParts; i++, data++) {
data->unk_04 = func_E0200000(10) - 5;
data->unk_08 = func_E0200000(10) + 5;
data->unk_04 = effect_rand_int(10) - 5;
data->unk_08 = effect_rand_int(10) + 5;
data->unk_0C = 10.0f;
data->unk_18 = func_E0200000(360);
data->unk_20 = func_E0200000(360);
data->unk_1C = func_E0200000(100) / 10;
data->unk_18 = effect_rand_int(360);
data->unk_20 = effect_rand_int(360);
data->unk_1C = effect_rand_int(100) / 10;
data->unk_10 = 0;
data->unk_14 = 2.0f;
}

View File

@ -44,7 +44,7 @@ void cloud_puff_main(f32 arg0, f32 arg1, f32 arg2, f32 arg3) {
part->alpha = 255;
part->unk_24 = (shim_rand_int(10) * 0.03) + 1.0;
part->unk_28 = (shim_rand_int(10) * 0.03) + 1.7;
part->unk_2C = func_E0200000(60);
part->unk_2C = effect_rand_int(60);
part->timeLeft = 30;
part->unk_34 = 0.5f;
part->unk_38 = -0.02f;

View File

@ -46,12 +46,12 @@ void cloud_trail_main(s32 arg0, f32 arg1, f32 arg2, f32 arg3) {
part->alpha = -1;
part->unk_28 = (shim_rand_int(10) * 0.03) + 1.4;
part->unk_2C = (shim_rand_int(10) * 0.03) + 1.5;
part->unk_30 = func_E0200000(60);
part->unk_30 = effect_rand_int(60);
part->unk_04 = arg0;
part->lifetime = 15;
part->unk_38 = 2.0f;
part->unk_3C = -0.5f;
part->unk_18 = func_E0200000(360);
part->unk_18 = effect_rand_int(360);
part->alpha = -1;
}
}

View File

@ -126,7 +126,7 @@ EffectInstance* confetti_main(s32 arg0, f32 arg1, f32 arg2, f32 arg3, f32 arg4,
temp_fp = shim_rand_int(360);
for (i = 0; i < np; i++, data++) {
temp_f30 = sp28 * (func_E0200000(100) * 0.01f);
temp_f30 = sp28 * (effect_rand_int(100) * 0.01f);
switch (arg0) {
case 0:
case 4:

View File

@ -39,21 +39,21 @@ void drop_leaves_main(s32 arg0, f32 arg1, f32 arg2, f32 arg3, s32 arg4) {
part++;
for (i = 1; i < numParts; i++, part++) {
if (arg0 == 0) {
part->unk_04 = func_E0200000(50) - 25;
part->unk_08 = func_E0200000(50) - 25;
part->unk_04 = effect_rand_int(50) - 25;
part->unk_08 = effect_rand_int(50) - 25;
part->unk_0C = 0.0f;
part->unk_18 = func_E0200000(360);
part->unk_20 = func_E0200000(360);
part->unk_1C = func_E0200000(100) / 10.0f;
part->unk_18 = effect_rand_int(360);
part->unk_20 = effect_rand_int(360);
part->unk_1C = effect_rand_int(100) / 10.0f;
part->unk_10 = 0;
part->unk_14 = 0;
} else {
part->unk_04 = func_E0200000(10) - 5;
part->unk_08 = func_E0200000(10) + 5;
part->unk_04 = effect_rand_int(10) - 5;
part->unk_08 = effect_rand_int(10) + 5;
part->unk_0C = 10.0f;
part->unk_18 = func_E0200000(360);
part->unk_20 = func_E0200000(360);
part->unk_1C = func_E0200000(100) / 10.0f;
part->unk_18 = effect_rand_int(360);
part->unk_20 = effect_rand_int(360);
part->unk_1C = effect_rand_int(100) / 10.0f;
part->unk_10 = 0;
part->unk_14 = 2.0f;
}

View File

@ -99,7 +99,7 @@ void effect_3D_main(s32 arg0, f32 arg1, f32 arg2, f32 arg3, f32 arg4, f32 arg5,
part->unk_44 = 0.5f;
part->unk_48 = 4.0f;
part->unk_50 = 20.0f;
part->unk_4C = part->unk_54 = func_E0200000(360);
part->unk_4C = part->unk_54 = effect_rand_int(360);
part->unk_58 = 255;
part->unk_64 = ((i - 1) / 5) * 2;
part->unk_5C = 10;

View File

@ -87,9 +87,9 @@ EffectInstance* effect_46_main(s32 arg0, PlayerStatus* arg1, f32 arg2, s32 arg3)
part->unk_08 = 0;
part->unk_0C = arg1->colliderHeight * 0.5;
part->unk_10 = 0;
part->unk_38 = func_E0200000(1) * 8 - 4;
part->unk_38 = effect_rand_int(1) * 8 - 4;
part->unk_3C = 0;
part->unk_40 = func_E0200000(1) * 8 - 4;
part->unk_40 = effect_rand_int(1) * 8 - 4;
part->unk_2C = i * 25;
part->unk_30 = (i - 1) * 360 / (numParts - 1);
part->unk_34 = 360 - i * 38;

View File

@ -63,9 +63,9 @@ EffectInstance* fire_flower_main(s32 arg0, f32 arg1, f32 arg2, f32 arg3, s32 arg
part->pos.z = 0;
part->unk_14 = 8.0f;
part->unk_18 = 0;
part->unk_1C = func_E0200000(20) - 8;
part->unk_20 = (func_E0200000(10) - 5) * 0.05;
part->unk_24 = func_E0200000(80) + 5;
part->unk_1C = effect_rand_int(20) - 8;
part->unk_20 = (effect_rand_int(10) - 5) * 0.05;
part->unk_24 = effect_rand_int(80) + 5;
part->unk_3C = 255;
partData->z = i - 1;
partData->x = 10;

View File

@ -58,7 +58,7 @@ void gather_energy_pink_main(s32 type, f32 posX, f32 posY, f32 posZ, f32 scale,
data->unk_1C = 10.0f;
data->unk_58 = func_E0200000(360);
data->unk_58 = effect_rand_int(360);
data->unk_5C = 4.0f;
data->unk_50 = 0;

View File

@ -14,12 +14,12 @@ Gfx* D_E008AA50[] = { D_09000D50_38DDC0, D_09000D50_38DDC0 };
void func_E008A000(SnowfallFXData* data) {
Camera* camera = &gCameras[gCurrentCameraID];
data->unk_08 = (camera->lookAt_eye.x + func_E0200000(2000)) - 1000.0f;
data->unk_0C = (camera->lookAt_eye.y + func_E0200000(2000)) - 1000.0f;
data->unk_10 = (camera->lookAt_eye.z + func_E0200000(2000)) - 1000.0f;
data->unk_14 = (func_E0200000(20) - 10.0f) * 0.05;
data->unk_18 = -1.2 - (func_E0200000(80) * 0.01);
data->unk_1C = (func_E0200000(20) - 10.0f) * 0.05;
data->unk_08 = (camera->lookAt_eye.x + effect_rand_int(2000)) - 1000.0f;
data->unk_0C = (camera->lookAt_eye.y + effect_rand_int(2000)) - 1000.0f;
data->unk_10 = (camera->lookAt_eye.z + effect_rand_int(2000)) - 1000.0f;
data->unk_14 = (effect_rand_int(20) - 10.0f) * 0.05;
data->unk_18 = -1.2 - (effect_rand_int(80) * 0.01);
data->unk_1C = (effect_rand_int(20) - 10.0f) * 0.05;
data->unk_28 = 255;
}

View File

@ -41,10 +41,10 @@ void windy_leaves_main(s32 type, f32 arg1, f32 arg2, f32 arg3) {
part++;
for (i = 1; i < numParts; i++, part++) {
s32 temp_s0_2 = func_E0200000(50);
s32 temp_s1 = func_E0200000(20);
s32 temp_s2 = func_E0200000(360);
s32 temp_v0_2 = func_E0200000(100);
s32 temp_s0_2 = effect_rand_int(50);
s32 temp_s1 = effect_rand_int(20);
s32 temp_s2 = effect_rand_int(360);
s32 temp_v0_2 = effect_rand_int(100);
part->unk_04.x = temp_s0_2 + 75;
part->unk_04.y = temp_s1 + 70;
part->unk_04.z = 0;

View File

@ -55,7 +55,7 @@ dma_write = 0x800297D4; // type:func rom:0x4BD4
dma_write_block = 0x80029860; // type:func rom:0x4C60
advance_rng = 0x80029900; // type:func rom:0x4D00
rand_float = 0x80029934; // type:func rom:0x4D34
func_80029994 = 0x80029994; // type:func rom:0x4D94
rand_int_internal = 0x80029994; // type:func rom:0x4D94
rand_int = 0x800299FC; // type:func rom:0x4DFC
signF = 0x80029A7C; // type:func rom:0x4E7C
round = 0x80029AC4; // type:func rom:0x4EC4
@ -7953,7 +7953,7 @@ EVS_WorldItem_ShowUsedItem = 0x802C0410; // type:data rom:0x3255E0
EVS_WorldItem_PlayEatingSounds = 0x802C04F4; // type:data rom:0x3256C4
EVS_WorldItem_PlayDrinkingSounds = 0x802C0560; // type:data rom:0x325730
EVS_World_UseItem = 0x802C05CC; // type:data rom:0x32579C
func_E0200000 = 0xE0200000; // type:func rom:0x325AD0
effect_rand_int = 0xE0200000; // type:func rom:0x325AD0
func_E0200044 = 0xE0200044; // type:func rom:0x325B14
func_E02000AC = 0xE02000AC; // type:func rom:0x325B7C
shim_guRotateF = 0xE0200410; // type:func rom:0x325EE0
@ -7996,7 +7996,7 @@ shim_draw_msg = 0xE0200650; // type:func rom:0x326120
shim_get_msg_width = 0xE0200660; // type:func rom:0x326130
shim_get_background_color_blend = 0xE0200670; // type:func rom:0x326140
shim_sfx_play_sound_at_position = 0xE0200680; // type:func rom:0x326150
D_E0200690 = 0xE0200690; // type:data rom:0x326160
effect_prng_seed = 0xE0200690; // type:data rom:0x326160
effectFuncs = 0xE0200694; // type:data rom:0x326164
D_E0200734 = 0xE0200734; // type:data rom:0x326204
D_09000000_326410 = 0x9000000; // type:data rom:0x326410