m_random.c 6.26 KB
Newer Older
Alam Ed Arias committed
1 2 3 4
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
5
// Copyright (C) 2012-2016 by Matthew "Kaito Sinclaire" Walsh.
James R. committed
6
// Copyright (C) 1999-2020 by Sonic Team Junior.
Alam Ed Arias committed
7 8 9 10 11 12
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file  m_random.c
13
/// \brief RNG for client effects and PRNG for game actions
Alam Ed Arias committed
14 15 16 17 18 19 20 21

#include "doomdef.h"
#include "doomtype.h"
#include "doomstat.h" // totalplaytime

#include "m_random.h"
#include "m_fixed.h"

Inuyasha committed
22 23


Alam Ed Arias committed
24 25 26 27
// ---------------------------
// RNG functions (not synched)
// ---------------------------

Inuyasha committed
28 29
/** Provides a random fixed point number. Distribution is uniform.
  * As with all M_Random functions, not synched in netgames.
Alam Ed Arias committed
30
  *
Inuyasha committed
31
  * \return A random fixed point number from [0,1).
Alam Ed Arias committed
32
  */
Inuyasha committed
33
fixed_t M_RandomFixed(void)
Alam Ed Arias committed
34
{
35 36 37 38 39
#if RAND_MAX < 65535
	// Compensate for insufficient randomness.
	fixed_t rndv = (rand()&1)<<15;
	return rand()^rndv;
#else
Inuyasha committed
40
	return (rand() & 0xFFFF);
41
#endif
Alam Ed Arias committed
42 43
}

Inuyasha committed
44 45
/** Provides a random byte. Distribution is uniform.
  * As with all M_Random functions, not synched in netgames.
Alam Ed Arias committed
46
  *
Inuyasha committed
47
  * \return A random integer from [0, 255].
Alam Ed Arias committed
48
  */
Inuyasha committed
49
UINT8 M_RandomByte(void)
Alam Ed Arias committed
50
{
Inuyasha committed
51
	return (rand() & 0xFF);
Alam Ed Arias committed
52 53
}

Inuyasha committed
54 55 56
/** Provides a random integer for picking random elements from an array.
  * Distribution is uniform.
  * As with all M_Random functions, not synched in netgames.
Alam Ed Arias committed
57
  *
Inuyasha committed
58 59
  * \param a Number of items in array.
  * \return A random integer from [0,a).
Alam Ed Arias committed
60 61 62 63 64 65
  */
INT32 M_RandomKey(INT32 a)
{
	return (INT32)((rand()/((unsigned)RAND_MAX+1.0f))*a);
}

Inuyasha committed
66
/** Provides a random integer in a given range.
Alam Ed Arias committed
67
  * Distribution is uniform.
Inuyasha committed
68
  * As with all M_Random functions, not synched in netgames.
Alam Ed Arias committed
69
  *
Inuyasha committed
70 71 72
  * \param a Lower bound.
  * \param b Upper bound.
  * \return A random integer from [a,b].
Alam Ed Arias committed
73 74 75 76 77 78 79 80 81 82 83 84 85
  */
INT32 M_RandomRange(INT32 a, INT32 b)
{
	return (INT32)((rand()/((unsigned)RAND_MAX+1.0f))*(b-a+1))+a;
}



// ------------------------
// PRNG functions (synched)
// ------------------------

// Holds the current seed.
86
static UINT32 randomseed = 0xBADE4404;
Alam Ed Arias committed
87 88

// Holds the INITIAL seed value.  Used for demos, possibly other debugging.
89
static UINT32 initialseed = 0xBADE4404;
Alam Ed Arias committed
90

Inuyasha committed
91
/** Provides a random fixed point number.
92
  * This is a variant of an xorshift PRNG; state fits in a 32 bit integer structure.
Alam Ed Arias committed
93
  *
94 95 96 97
  * \return A random fixed point number from [0,1).
  */
ATTRINLINE static fixed_t FUNCINLINE __internal_prng__(void)
{
98 99
	randomseed ^= randomseed >> 13;
	randomseed ^= randomseed >> 11;
100
	randomseed ^= randomseed << 21;
101
	return ( (randomseed*36548569) >> 4) & (FRACUNIT-1);
102 103
}

Inuyasha committed
104 105
/** Provides a random fixed point number. Distribution is uniform.
  * Literally a wrapper for the internal PRNG function.
106
  *
Inuyasha committed
107
  * \return A random fixed point number from [0,1).
Alam Ed Arias committed
108 109
  */
#ifndef DEBUGRANDOM
Inuyasha committed
110
fixed_t P_RandomFixed(void)
Alam Ed Arias committed
111 112
{
#else
113
fixed_t P_RandomFixedD(const char *rfile, INT32 rline)
Alam Ed Arias committed
114
{
Inuyasha committed
115
	CONS_Printf("P_RandomFixed() at: %sp %d\n", rfile, rline);
Alam Ed Arias committed
116
#endif
Inuyasha committed
117
	return __internal_prng__();
Alam Ed Arias committed
118 119
}

Inuyasha committed
120 121 122
/** Provides a random byte. Distribution is uniform.
  * If you're curious, (&0xFF00) >> 8 gives the same result
  * as a fixed point multiplication by 256.
Alam Ed Arias committed
123
  *
Inuyasha committed
124
  * \return Random integer from [0, 255].
125
  * \sa __internal_prng__
Alam Ed Arias committed
126 127
  */
#ifndef DEBUGRANDOM
Inuyasha committed
128
UINT8 P_RandomByte(void)
129 130
{
#else
Inuyasha committed
131
UINT8 P_RandomByteD(const char *rfile, INT32 rline)
132
{
Inuyasha committed
133
	CONS_Printf("P_RandomByte() at: %sp %d\n", rfile, rline);
134
#endif
Inuyasha committed
135
	return (UINT8)((__internal_prng__()&0xFF00)>>8);
136 137 138 139
}

/** Provides a random integer for picking random elements from an array.
  * Distribution is uniform.
Inuyasha committed
140
  * NOTE: Maximum range is 65536.
141
  *
Inuyasha committed
142
  * \param a Number of items in array.
143 144
  * \return A random integer from [0,a).
  * \sa __internal_prng__
Alam Ed Arias committed
145 146 147 148 149 150 151
  */
#ifndef DEBUGRANDOM
INT32 P_RandomKey(INT32 a)
{
#else
INT32 P_RandomKeyD(const char *rfile, INT32 rline, INT32 a)
{
Alam Ed Arias committed
152
	CONS_Printf("P_RandomKey() at: %sp %d\n", rfile, rline);
Alam Ed Arias committed
153
#endif
154
	return (INT32)(((INT64)__internal_prng__() * a) >> FRACBITS);
Alam Ed Arias committed
155 156
}

157 158
/** Provides a random integer in a given range.
  * Distribution is uniform.
Inuyasha committed
159
  * NOTE: Maximum range is 65536.
Alam Ed Arias committed
160
  *
Inuyasha committed
161 162 163
  * \param a Lower bound.
  * \param b Upper bound.
  * \return A random integer from [a,b].
164
  * \sa __internal_prng__
Alam Ed Arias committed
165 166 167 168 169 170 171
  */
#ifndef DEBUGRANDOM
INT32 P_RandomRange(INT32 a, INT32 b)
{
#else
INT32 P_RandomRangeD(const char *rfile, INT32 rline, INT32 a, INT32 b)
{
Alam Ed Arias committed
172
	CONS_Printf("P_RandomRange() at: %sp %d\n", rfile, rline);
Alam Ed Arias committed
173
#endif
174
	return (INT32)(((INT64)__internal_prng__() * (b-a+1)) >> FRACBITS) + a;
Alam Ed Arias committed
175 176
}

177 178 179 180 181 182 183 184


// ----------------------
// PRNG seeds & debugging
// ----------------------

/** Peeks to see what the next result from the PRNG will be.
  * Used for debugging.
Alam Ed Arias committed
185
  *
186 187
  * \return A 'random' fixed point number from [0,1).
  * \sa __internal_prng__
Alam Ed Arias committed
188
  */
189
fixed_t P_RandomPeek(void)
Alam Ed Arias committed
190
{
191 192 193 194
	UINT32 r = randomseed;
	fixed_t ret = __internal_prng__();
	randomseed = r;
	return ret;
Alam Ed Arias committed
195 196 197 198 199 200 201
}

/** Gets the current random seed.  Used by netgame savegames.
  *
  * \return Current random seed.
  * \sa P_SetRandSeed
  */
Alam Ed Arias committed
202
#ifndef DEBUGRANDOM
Alam Ed Arias committed
203 204
UINT32 P_GetRandSeed(void)
{
Alam Ed Arias committed
205 206 207 208 209
#else
UINT32 P_GetRandSeedD(const char *rfile, INT32 rline)
{
	CONS_Printf("P_GetRandSeed() at: %sp %d\n", rfile, rline);
#endif
Alam Ed Arias committed
210 211 212 213 214 215 216 217
	return randomseed;
}

/** Gets the initial random seed.  Used by demos.
  *
  * \return Initial random seed.
  * \sa P_SetRandSeed
  */
Alam Ed Arias committed
218
#ifndef DEBUGRANDOM
Alam Ed Arias committed
219 220
UINT32 P_GetInitSeed(void)
{
Alam Ed Arias committed
221 222 223 224 225
#else
UINT32 P_GetInitSeedD(const char *rfile, INT32 rline)
{
	CONS_Printf("P_GetInitSeed() at: %sp %d\n", rfile, rline);
#endif
Alam Ed Arias committed
226 227 228 229 230 231 232 233 234
	return initialseed;
}

/** Sets the random seed.
  * Used at the beginning of the game, and also for netgames.
  *
  * \param rindex New random index.
  * \sa P_GetRandSeed
  */
Alam Ed Arias committed
235
#ifndef DEBUGRANDOM
Alam Ed Arias committed
236 237
void P_SetRandSeed(UINT32 seed)
{
Alam Ed Arias committed
238 239 240 241 242
#else
void P_SetRandSeedD(const char *rfile, INT32 rline, UINT32 seed)
{
	CONS_Printf("P_SetRandSeed() at: %sp %d\n", rfile, rline);
#endif
243 244 245
	// xorshift requires a nonzero seed
	// this should never happen, but just in case it DOES, we check
	if (!seed) seed = 0xBADE4404;
Alam Ed Arias committed
246 247 248 249 250 251 252 253 254
	randomseed = initialseed = seed;
}

/** Gets a randomized seed for setting the random seed.
  *
  * \sa P_GetRandSeed
  */
UINT32 M_RandomizedSeed(void)
{
255
	return ((totalplaytime & 0xFFFF) << 16)|M_RandomFixed();
Alam Ed Arias committed
256
}