dethrace icon indicating copy to clipboard operation
dethrace copied to clipboard

Issue/fix: IRandomBetween() not working properly on Win32/x86

Open PierreMarieBaty opened this issue 1 year ago • 2 comments

When compiling on Win32/x86, I couldn't get the new game video, which should be 50% chance either GARAGE1.SMK or GARAGE2.SMK to play the first one.

After investigation it turned out the culprit was this function in src/DETHRACE/common/utility.c:

// IDA: int __usercall IRandomBetween@<EAX>(int pA@<EAX>, int pB@<EDX>)
int IRandomBetween(int pA, int pB) {
    int num;
    char s[32];

    num = rand();
#if RAND_MAX == 0x7fff
    //  If RAND_MAX == 0x7fff, then `num` can be seen as a fixed point number with 15 fractional and 17 integral bits
    return pA + ((num * (pB + 1 - pA)) >> 15);
#else
    //  If RAND_MAX != 0x7fff, then use floating numbers (alternative is using modulo)
    return pA + (int)((pB + 1 - pA) * (num / ((float)RAND_MAX + 1)));
#endif
}

I changed it to the following so that it falls back on the floating-point based code when sizeof(int) is 32 bit:

// IDA: int __usercall IRandomBetween@<EAX>(int pA@<EAX>, int pB@<EDX>)
int IRandomBetween(int pA, int pB) {
    int num;
    char s[32];

    num = rand();
#if (INT_MAX > 0x7fffffff) && (RAND_MAX == 0x7fff) // Pierre-Marie Baty -- looks like this hack doesn't work when sizeof(int) == 4 (e.g. on Windows)
    //  If RAND_MAX == 0x7fff, then `num` can be seen as a fixed point number with 15 fractional and 17 integral bits
    return pA + ((num * (pB + 1 - pA)) >> 15);
#else
    //  If RAND_MAX != 0x7fff, then use floating numbers (alternative is using modulo)
    return pA + (int)((pB + 1 - pA) * (num / ((float)RAND_MAX + 1)));
#endif
}

I haven't tested when compiling for Win32/x64 though, but considering Windows is the only well-known x64 platform where sizeof(int) is 4, it should be the same.

PierreMarieBaty avatar Dec 22 '23 16:12 PierreMarieBaty