Fix core RNG collapsing to ~0-1 on Linux due to integer overflow

CWorldServer::RandNumber (and three inlined copies of the same pattern
in worldpackets.cpp's item-refine code) computed "range*rand()" in
integer arithmetic before dividing by (RAND_MAX + 1.0). On Windows
RAND_MAX is 32767 (15-bit), so this never overflowed. On Linux/glibc
RAND_MAX is 2147483647 (2^31-1), so "range*rand()" overflows a 32-bit
UINT for the vast majority of rand() outputs, wrapping to a small
value -- the division by ~2^31 then collapses the result to ~0 or 1
almost always, regardless of the requested range. This made every
percentage-based roll in the game (item drop selection, refine
durability/stats, and anything else using RandNumber) behave as if
called with range 1-2 instead of the real range, which is why item
drops effectively never triggered post-port. Cast to double before
the multiply so it can't overflow.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
ThomasandClaude Sonnet 5 committed 2026-07-09 07:24:14 +02:00
1 parent 560f6a968f
commit f053a06920
2 files changed
+11 -7

No files matched your search

+8 -4
View File
@@ -1048,15 +1048,19 @@ UINT CWorldServer::RandNumber( UINT init, UINT range, UINT seed )
if(range>RAND_MAX)
{
UINT max = (UINT)GServer->round(sqrt((double)range));
UINT num1 = init+int(max*rand()/(RAND_MAX + 1.0));
UINT num2 = init+int(max*rand()/(RAND_MAX + 1.0));
UINT num3 = init+int(max*rand()/(RAND_MAX + 1.0));
// NOTE: multiply in double first -- on Linux RAND_MAX is 2^31-1 (vs.
// Windows' 15-bit 32767), so "max*rand()" done in integer arithmetic
// before dividing overflows UINT for nearly every rand() result,
// collapsing the output to ~0-1 regardless of range/max.
UINT num1 = init+int((double)max*rand()/(RAND_MAX + 1.0));
UINT num2 = init+int((double)max*rand()/(RAND_MAX + 1.0));
UINT num3 = init+int((double)max*rand()/(RAND_MAX + 1.0));
UINT res = (num1 * num2)+num3;
return res>range?range:res;
}
else
{
UINT ranum = init+int(range*rand()/(RAND_MAX + 1.0));
UINT ranum = init+int((double)range*rand()/(RAND_MAX + 1.0));
return ranum;
}