summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--functions.h27
-rw-r--r--mersenne.c72
-rw-r--r--misc.c63
-rw-r--r--network.c2
-rw-r--r--network_client.c2
-rw-r--r--network_server.c4
-rw-r--r--openttd.c2
-rw-r--r--unix.c47
-rw-r--r--variables.h3
-rw-r--r--win32.c7
10 files changed, 173 insertions, 56 deletions
diff --git a/functions.h b/functions.h
index 4960eb338..1ea2c9a8e 100644
--- a/functions.h
+++ b/functions.h
@@ -93,6 +93,21 @@ void NORETURN CDECL error(const char *str, ...);
//#define RANDOM_DEBUG
+
+// Enable this to produce higher quality random numbers.
+// Doesn't work with network yet.
+//#define MERSENNE_TWISTER
+
+// Mersenne twister functions
+void SeedMT(uint32 seed);
+uint32 RandomMT(void);
+
+
+#ifdef MERSENNE_TWISTER
+ static inline uint32 Random(void) { return RandomMT(); }
+ uint RandomRange(uint max);
+#else
+
#ifdef RANDOM_DEBUG
#define Random() DoRandom(__LINE__, __FILE__)
uint32 DoRandom(int line, const char *file);
@@ -101,12 +116,18 @@ void NORETURN CDECL error(const char *str, ...);
#else
uint32 Random(void);
uint RandomRange(uint max);
-
- static inline TileIndex RandomTileSeed(uint32 r) { return TILE_MASK(r); }
- static inline TileIndex RandomTile(void) { return TILE_MASK(Random()); }
#endif
+#endif // MERSENNE_TWISTER
+
+static inline TileIndex RandomTileSeed(uint32 r) { return TILE_MASK(r); }
+static inline TileIndex RandomTile(void) { return TILE_MASK(Random()); }
+
+#ifdef PLAYER_SEED_RANDOM
void InitPlayerRandoms(void);
+#endif
+
+
uint32 InteractiveRandom(void); /* Used for random sequences that are not the same on the other end of the multiplayer link */
uint InteractiveRandomRange(uint max);
diff --git a/mersenne.c b/mersenne.c
new file mode 100644
index 000000000..98170084f
--- /dev/null
+++ b/mersenne.c
@@ -0,0 +1,72 @@
+#include "stdafx.h"
+#include "openttd.h"
+
+#ifdef MERSENNE_TWISTER
+
+// Source code for Mersenne Twister.
+// A Random number generator with much higher quality random numbers.
+
+#define N (624) // length of _mt_state vector
+#define M (397) // a period parameter
+#define K (0x9908B0DFU) // a magic constant
+#define hiBit(u) ((u) & 0x80000000U) // mask all but highest bit of u
+#define loBit(u) ((u) & 0x00000001U) // mask all but lowest bit of u
+#define loBits(u) ((u) & 0x7FFFFFFFU) // mask the highest bit of u
+#define mixBits(u, v) (hiBit(u)|loBits(v)) // move hi bit of u to hi bit of v
+
+static uint32 _mt_state[N+1]; // _mt_state vector + 1 extra to not violate ANSI C
+static uint32 *_mt_next; // _mt_next random value is computed from here
+static int _mt_left = -1; // can *_mt_next++ this many times before reloading
+
+void SeedMT(uint32 seed)
+{
+ register uint32 x = (seed | 1U) & 0xFFFFFFFFU, *s = _mt_state;
+ register int j;
+
+ for(_mt_left=0, *s++=x, j=N; --j;
+ *s++ = (x*=69069U) & 0xFFFFFFFFU);
+ }
+
+
+static uint32 ReloadMT(void)
+ {
+ register uint32 *p0=_mt_state, *p2=_mt_state+2, *pM=_mt_state+M, s0, s1;
+ register int j;
+
+ if(_mt_left < -1)
+ SeedMT(4357U);
+
+ _mt_left=N-1, _mt_next=_mt_state+1;
+
+ for(s0=_mt_state[0], s1=_mt_state[1], j=N-M+1; --j; s0=s1, s1=*p2++)
+ *p0++ = *pM++ ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U);
+
+ for(pM=_mt_state, j=M; --j; s0=s1, s1=*p2++)
+ *p0++ = *pM++ ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U);
+
+ s1=_mt_state[0], *p0 = *pM ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U);
+ s1 ^= (s1 >> 11);
+ s1 ^= (s1 << 7) & 0x9D2C5680U;
+ s1 ^= (s1 << 15) & 0xEFC60000U;
+ return(s1 ^ (s1 >> 18));
+ }
+
+
+uint32 RandomMT(void)
+{
+ uint32 y;
+
+ if(--_mt_left < 0)
+ return ReloadMT();
+
+ y = *_mt_next++;
+ y ^= (y >> 11);
+ y ^= (y << 7) & 0x9D2C5680U;
+ y ^= (y << 15) & 0xEFC60000U;
+ return y ^ (y >> 18);
+}
+#else
+
+void SeedMT(uint32 seed) {}
+
+#endif \ No newline at end of file
diff --git a/misc.c b/misc.c
index b4ef52821..0beffba71 100644
--- a/misc.c
+++ b/misc.c
@@ -29,13 +29,14 @@ static inline uint32 ROR(uint32 x, int n)
it completely! -- TrueLight */
#undef PLAYER_SEED_RANDOM
+#ifndef MERSENNE_TWISTER
+
#ifdef RANDOM_DEBUG
#include "network_data.h"
-
uint32 DoRandom(int line, const char *file)
-#else
+#else // RANDOM_DEBUG
uint32 Random(void)
-#endif
+#endif // RANDOM_DEBUG
{
uint32 s;
@@ -66,8 +67,9 @@ uint32 t;
return _random_seeds[0][1] = ROR(s, 3) - 1;
#endif
}
+#endif // MERSENNE_TWISTER
-#ifdef RANDOM_DEBUG
+#if defined(RANDOM_DEBUG) && !defined(MERSENNE_TWISTER)
uint DoRandomRange(uint max, int line, const char *file)
{
return (uint16)DoRandom(line, file) * max >> 16;
@@ -79,6 +81,7 @@ uint RandomRange(uint max)
}
#endif
+
uint32 InteractiveRandom(void)
{
uint32 t = _random_seeds[1][1];
@@ -92,6 +95,8 @@ uint InteractiveRandomRange(uint max)
return (uint16)InteractiveRandom() * max >> 16;
}
+
+#ifdef PLAYER_SEED_RANDOM
void InitPlayerRandoms(void)
{
int i;
@@ -100,6 +105,7 @@ void InitPlayerRandoms(void)
_player_seeds[i][1]=InteractiveRandom();
}
}
+#endif
void SetDate(uint date)
{
@@ -112,55 +118,6 @@ void SetDate(uint date)
#endif /* ENABLE_NETWORK */
}
-
-#ifdef ENABLE_NETWORK
-
-// multi os compatible sleep function
-
-#ifdef __AMIGA__
-// usleep() implementation
-# include <devices/timer.h>
-# include <dos/dos.h>
-
- extern struct Device *TimerBase = NULL;
- extern struct MsgPort *TimerPort = NULL;
- extern struct timerequest *TimerRequest = NULL;
-#endif // __AMIGA__
-
-void CSleep(int milliseconds)
-{
- #if defined(WIN32)
- Sleep(milliseconds);
- #endif
- #if defined(UNIX)
- #if !defined(__BEOS__) && !defined(__AMIGA__)
- usleep(milliseconds * 1000);
- #endif
- #ifdef __BEOS__
- snooze(milliseconds * 1000);
- #endif
- #if defined(__AMIGA__)
- {
- ULONG signals;
- ULONG TimerSigBit = 1 << TimerPort->mp_SigBit;
-
- // send IORequest
- TimerRequest->tr_node.io_Command = TR_ADDREQUEST;
- TimerRequest->tr_time.tv_secs = (milliseconds * 1000) / 1000000;
- TimerRequest->tr_time.tv_micro = (milliseconds * 1000) % 1000000;
- SendIO((struct IORequest *)TimerRequest);
-
- if (!((signals = Wait(TimerSigBit | SIGBREAKF_CTRL_C)) & TimerSigBit) ) {
- AbortIO((struct IORequest *)TimerRequest);
- }
- WaitIO((struct IORequest *)TimerRequest);
- }
- #endif // __AMIGA__
- #endif
-}
-
-#endif /* ENABLE_NETWORK */
-
void InitializeVehicles(void);
void InitializeWaypoints(void);
void InitializeDepot(void);
diff --git a/network.c b/network.c
index e422c5e20..778353005 100644
--- a/network.c
+++ b/network.c
@@ -773,7 +773,9 @@ static void NetworkInitialize(void)
_network_reconnect = 0;
+#ifdef PLAYER_SEED_RANDOM
InitPlayerRandoms();
+#endif
NetworkUDPInitialize();
}
diff --git a/network_client.c b/network_client.c
index aad7e57ad..5b6a8bf27 100644
--- a/network_client.c
+++ b/network_client.c
@@ -488,11 +488,13 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_MAP)
// Check if this was the last packet
if (maptype == MAP_PACKET_END) {
// We also get, very nice, the player_seeds in this packet
+#ifdef PLAYER_SEED_RANDOM
int i;
for (i = 0; i < MAX_PLAYERS; i++) {
_player_seeds[i][0] = NetworkRecv_uint32(MY_CLIENT, p);
_player_seeds[i][1] = NetworkRecv_uint32(MY_CLIENT, p);
}
+#endif
fclose(file_pointer);
diff --git a/network_server.c b/network_server.c
index 99150aa8a..76223dfd2 100644
--- a/network_server.c
+++ b/network_server.c
@@ -323,7 +323,9 @@ DEF_SERVER_SEND_COMMAND(PACKET_SERVER_MAP)
NetworkSend_Packet(p, cs);
if (feof(file_pointer)) {
// Done reading!
+#ifdef PLAYER_SEED_RANDOM
int i;
+#endif
Packet *p;
// XXX - Delete this when patch-settings are saved in-game
@@ -331,11 +333,13 @@ DEF_SERVER_SEND_COMMAND(PACKET_SERVER_MAP)
p = NetworkSend_Init(PACKET_SERVER_MAP);
NetworkSend_uint8(p, MAP_PACKET_END);
+#ifdef PLAYER_SEED_RANDOM
// Send the player_seeds in this packet
for (i = 0; i < MAX_PLAYERS; i++) {
NetworkSend_uint32(p, _player_seeds[i][0]);
NetworkSend_uint32(p, _player_seeds[i][1]);
}
+#endif
NetworkSend_Packet(p, cs);
// Set the status to DONE_MAP, no we will wait for the client
diff --git a/openttd.c b/openttd.c
index 26057a517..3ab0a75cb 100644
--- a/openttd.c
+++ b/openttd.c
@@ -676,7 +676,9 @@ int ttd_main(int argc, char* argv[])
InitializeGUI();
IConsoleCmdExec("exec scripts/autoexec.scr 0");
+#ifdef PLAYER_SEED_RANDOM
InitPlayerRandoms();
+#endif
GenerateWorld(1, 64, 64); // Make the viewport initialization happy
diff --git a/unix.c b/unix.c
index c2b81b3d7..f40783247 100644
--- a/unix.c
+++ b/unix.c
@@ -474,6 +474,7 @@ int CDECL main(int argc, char* argv[])
#endif
_random_seeds[0][1] = _random_seeds[0][0] = time(NULL);
+ SeedMT(_random_seeds[0][1]);
signal(SIGPIPE, SIG_IGN);
@@ -581,3 +582,49 @@ void JoinOTTDThread(void)
pthread_join(thread1, NULL);
}
+
+
+
+#ifdef ENABLE_NETWORK
+
+// multi os compatible sleep function
+
+#ifdef __AMIGA__
+// usleep() implementation
+# include <devices/timer.h>
+# include <dos/dos.h>
+
+ extern struct Device *TimerBase = NULL;
+ extern struct MsgPort *TimerPort = NULL;
+ extern struct timerequest *TimerRequest = NULL;
+#endif // __AMIGA__
+
+void CSleep(int milliseconds)
+{
+ #if !defined(__BEOS__) && !defined(__AMIGA__)
+ usleep(milliseconds * 1000);
+ #endif
+ #ifdef __BEOS__
+ snooze(milliseconds * 1000);
+ #endif
+ #if defined(__AMIGA__)
+ {
+ ULONG signals;
+ ULONG TimerSigBit = 1 << TimerPort->mp_SigBit;
+
+ // send IORequest
+ TimerRequest->tr_node.io_Command = TR_ADDREQUEST;
+ TimerRequest->tr_time.tv_secs = (milliseconds * 1000) / 1000000;
+ TimerRequest->tr_time.tv_micro = (milliseconds * 1000) % 1000000;
+ SendIO((struct IORequest *)TimerRequest);
+
+ if (!((signals = Wait(TimerSigBit | SIGBREAKF_CTRL_C)) & TimerSigBit) ) {
+ AbortIO((struct IORequest *)TimerRequest);
+ }
+ WaitIO((struct IORequest *)TimerRequest);
+ }
+ #endif // __AMIGA__
+}
+
+#endif /* ENABLE_NETWORK */
+
diff --git a/variables.h b/variables.h
index 985390095..011627fe2 100644
--- a/variables.h
+++ b/variables.h
@@ -82,7 +82,10 @@ VARDEF uint16 _disaster_delay;
VARDEF uint16 _station_tick_ctr;
VARDEF uint32 _random_seeds[2][2];
+
+#ifdef PLAYER_SEED_RANDOM
VARDEF uint32 _player_seeds[MAX_PLAYERS][2];
+#endif
// Iterator through all towns in OnTick_Town
VARDEF uint32 _cur_town_ctr;
diff --git a/win32.c b/win32.c
index 00107cc55..f6d416833 100644
--- a/win32.c
+++ b/win32.c
@@ -2124,6 +2124,7 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
_random_seeds[0][0] = GetTickCount();
_random_seeds[0][1] = _random_seeds[0][0] * 0x1234567;
#endif
+ SeedMT(_random_seeds[0][0]);
argc = ParseCommandLine(GetCommandLine(), argv, lengthof(argv));
@@ -2263,3 +2264,9 @@ void JoinOTTDThread(void)
WaitForSingleObject(hThread, INFINITE);
}
+
+
+void CSleep(int milliseconds)
+{
+ Sleep(milliseconds);
+} \ No newline at end of file