From f770d12db47172cb89f5599e25385e91254edc10 Mon Sep 17 00:00:00 2001 From: Lincoln-LM <73306575+Lincoln-LM@users.noreply.github.com> Date: Mon, 22 May 2023 08:37:25 -0600 Subject: [PATCH] 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 --- include/common_structs.h | 2 +- include/effects_internal.h | 2 +- include/variables.h | 2 +- src/325AD0.c | 14 +++++--- src/43F0.c | 55 +++++++++++++++++++------------- src/effects/big_smoke_puff.c | 2 +- src/effects/big_snowflakes.c | 10 +++--- src/effects/cloud_puff.c | 2 +- src/effects/cloud_trail.c | 4 +-- src/effects/confetti.c | 2 +- src/effects/drop_leaves.c | 20 ++++++------ src/effects/effect_3D.c | 2 +- src/effects/effect_46.c | 4 +-- src/effects/fire_flower.c | 6 ++-- src/effects/gather_energy_pink.c | 2 +- src/effects/snowfall.c | 12 +++---- src/effects/windy_leaves.c | 8 ++--- ver/us/symbol_addrs.txt | 6 ++-- 18 files changed, 84 insertions(+), 71 deletions(-) diff --git a/include/common_structs.h b/include/common_structs.h index 1226b06c66..05ed09a21a 100644 --- a/include/common_structs.h +++ b/include/common_structs.h @@ -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; diff --git a/include/effects_internal.h b/include/effects_internal.h index a056888c25..48734eaaed 100644 --- a/include/effects_internal.h +++ b/include/effects_internal.h @@ -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); diff --git a/include/variables.h b/include/variables.h index 7640c544be..be6bde4f6d 100644 --- a/include/variables.h +++ b/include/variables.h @@ -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]; diff --git a/src/325AD0.c b/src/325AD0.c index c59cd3cd33..5192eece9a 100644 --- a/src/325AD0.c +++ b/src/325AD0.c @@ -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 diff --git a/src/43F0.c b/src/43F0.c index c32fb4e168..2b79a43d27 100644 --- a/src/43F0.c +++ b/src/43F0.c @@ -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; } } diff --git a/src/effects/big_smoke_puff.c b/src/effects/big_smoke_puff.c index aa9ea9cf8b..412f13bc3d 100644 --- a/src/effects/big_smoke_puff.c +++ b/src/effects/big_smoke_puff.c @@ -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; diff --git a/src/effects/big_snowflakes.c b/src/effects/big_snowflakes.c index cfa2eb08f8..e41e05a99a 100644 --- a/src/effects/big_snowflakes.c +++ b/src/effects/big_snowflakes.c @@ -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; } diff --git a/src/effects/cloud_puff.c b/src/effects/cloud_puff.c index da5f27cda6..0e6d8e9a5a 100644 --- a/src/effects/cloud_puff.c +++ b/src/effects/cloud_puff.c @@ -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; diff --git a/src/effects/cloud_trail.c b/src/effects/cloud_trail.c index 8c090015f3..0954163808 100644 --- a/src/effects/cloud_trail.c +++ b/src/effects/cloud_trail.c @@ -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; } } diff --git a/src/effects/confetti.c b/src/effects/confetti.c index 996ed616b5..38421d73ab 100644 --- a/src/effects/confetti.c +++ b/src/effects/confetti.c @@ -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: diff --git a/src/effects/drop_leaves.c b/src/effects/drop_leaves.c index aa70bd245f..c4cfb8743d 100644 --- a/src/effects/drop_leaves.c +++ b/src/effects/drop_leaves.c @@ -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; } diff --git a/src/effects/effect_3D.c b/src/effects/effect_3D.c index d3ff4c1a54..c1048e6159 100644 --- a/src/effects/effect_3D.c +++ b/src/effects/effect_3D.c @@ -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; diff --git a/src/effects/effect_46.c b/src/effects/effect_46.c index efafc7496e..53243b1572 100644 --- a/src/effects/effect_46.c +++ b/src/effects/effect_46.c @@ -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; diff --git a/src/effects/fire_flower.c b/src/effects/fire_flower.c index bfdb6d9262..02d41650da 100644 --- a/src/effects/fire_flower.c +++ b/src/effects/fire_flower.c @@ -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; diff --git a/src/effects/gather_energy_pink.c b/src/effects/gather_energy_pink.c index f0f2418010..a02d6b744e 100644 --- a/src/effects/gather_energy_pink.c +++ b/src/effects/gather_energy_pink.c @@ -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; diff --git a/src/effects/snowfall.c b/src/effects/snowfall.c index ef1bb1ef39..8e14ad65eb 100644 --- a/src/effects/snowfall.c +++ b/src/effects/snowfall.c @@ -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; } diff --git a/src/effects/windy_leaves.c b/src/effects/windy_leaves.c index dec0f71845..25922199f8 100644 --- a/src/effects/windy_leaves.c +++ b/src/effects/windy_leaves.c @@ -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; diff --git a/ver/us/symbol_addrs.txt b/ver/us/symbol_addrs.txt index 75be3acd98..2c875f0ea3 100644 --- a/ver/us/symbol_addrs.txt +++ b/ver/us/symbol_addrs.txt @@ -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