^ not really, it's in CvGame.cpp
Code:
int CvGame::getSorenRandNum(int iNum, const char* pszLog)
{
return m_sorenRand.get(iNum, pszLog);
}
m_sorenRand is from class CvRandom (in CvRandom.cpp)
Since I had to look up most of this, I might as well share what I found
Code:
void CvRandom::init(unsigned long ulSeed)
{
//--------------------------------
// Init saved data
reset(ulSeed);
//--------------------------------
// Init non-saved data
}
Important thing is m_ulRandomSeed is initialized as ulSeed.
Code:
unsigned short CvRandom::get(unsigned short usNum, const TCHAR* pszLog)
{
if (pszLog != NULL)
{
if (GC.getLogging() && GC.getRandLogging())
{
if (GC.getGameINLINE().getTurnSlice() > 0)
{
TCHAR szOut[1024];
sprintf(szOut, "Rand = %d on %d (%s)\n", getSeed(), GC.getGameINLINE().getTurnSlice(), pszLog);
gDLL->messageControlLog(szOut);
}
}
}
m_ulRandomSeed = ((RANDOM_A * m_ulRandomSeed) + RANDOM_C);
unsigned short us = ((unsigned short)((((m_ulRandomSeed >> RANDOM_SHIFT) & MAX_UNSIGNED_SHORT) * ((unsigned long)usNum)) / (MAX_UNSIGNED_SHORT + 1)));
return us;
}
So if m_sorenrand is in the cvrandom, .get should be the algorithm we're looking for.
creates character string called szOut of length 1024.
Code:
sprintf(szOut, "Rand = %d on %d (%s)\n", getSeed(), GC.getGameINLINE().getTurnSlice(), pszLog);
sprintf prints the second term into our string szOut. The first %d is the number given by getSeed(), second %d is the number given by GC.getGameINLINE()..., and the %s is pszLog, which in our case should be the string "Nuke". Basically it's recording the conditions for our pseudo random variable.
getSeed itself is just m_ulRandomSeed, which is defined in the get function
getTurnSlice isn't in this file, and since I'm sicking of playing Alice in Wonderland I'll assume it has something to do with where we'll check pick out of our random seed based on the position of the event in the turn. Hopefully it's not too important
Code:
m_ulRandomSeed = ((RANDOM_A * m_ulRandomSeed) + RANDOM_C);
unsigned short us = ((unsigned short)((((m_ulRandomSeed >> RANDOM_SHIFT) & MAX_UNSIGNED_SHORT) * ((unsigned long)usNum)) / (MAX_UNSIGNED_SHORT + 1)));
return us;
Ah ha! Here's our random number. First our seed value is changed each time the same way: multiply by a constant and add a constant.
Second to generate our random number, our random seed is shifted by a set amount, something to do with the maximum length of unsigned short integer, (likely binary 2^n-1) it's multiplied by usNum (in our case getsorenrand(100,"nuke") means multiply by 100)), then it's divided by said max_unsigned_short+1 (likely 2^n), so chop off.
Oddly enough our "random" constants are more constant than random.
Code:
#define RANDOM_A (1103515245)
#define RANDOM_C (12345)
#define RANDOM_SHIFT (16)
---
Hmmm, so could we attain strange nuke odds? If getrandsoren works properly and has a nicely random seed, no. In the short run, if calling getrandsoren(100,"nuke") repeatedly does not reset m_ulrandseed, since we're shifting it in the exact same way, albeit in a very large, repetitive way. You could have a really stupid seed, but that's pretty much the same as being unlucky.
Multiplying by 100 could induce some strange division results, but that should show up in basic tests. I have to say the onus is on someone for showing a reasonably large sample size of unlucky SDI interceptions.