253 lines
6.8 KiB
C
253 lines
6.8 KiB
C
//=======================================================================
|
|
// Copyright XashXT Group 2007 ©
|
|
// utils.c - global system utils
|
|
//=======================================================================
|
|
|
|
#include "launch.h"
|
|
#include "mathlib.h"
|
|
#include "const.h"
|
|
|
|
static long idum = 0;
|
|
|
|
#define MAX_RANDOM_RANGE 0x7FFFFFFFUL
|
|
#define IA 16807
|
|
#define IM 2147483647
|
|
#define IQ 127773
|
|
#define IR 2836
|
|
#define NTAB 32
|
|
#define NDIV (1+(IM-1)/NTAB)
|
|
#define AM (1.0/IM)
|
|
#define EPS 1.2e-7
|
|
#define RNMX (1.0 - EPS)
|
|
|
|
void SeedRandomNumberGenerator( long lSeed )
|
|
{
|
|
if( lSeed ) idum = lSeed;
|
|
else idum = -time( NULL );
|
|
|
|
if( 1000 < idum ) idum = -idum;
|
|
else if( -1000 < idum ) idum -= 22261048;
|
|
}
|
|
|
|
long lran1( void )
|
|
{
|
|
int j;
|
|
long k;
|
|
|
|
static long iy = 0;
|
|
static long iv[NTAB];
|
|
|
|
if( idum <= 0 || !iy )
|
|
{
|
|
if(-(idum) < 1) idum=1;
|
|
else idum = -(idum);
|
|
|
|
for( j = NTAB + 7; j >= 0; j-- )
|
|
{
|
|
k = (idum) / IQ;
|
|
idum = IA * (idum - k * IQ) - IR * k;
|
|
if( idum < 0 ) idum += IM;
|
|
if( j < NTAB ) iv[j] = idum;
|
|
}
|
|
iy = iv[0];
|
|
}
|
|
k = (idum)/IQ;
|
|
idum = IA * (idum - k * IQ) - IR * k;
|
|
if( idum < 0 ) idum += IM;
|
|
j = iy / NDIV;
|
|
iy = iv[j];
|
|
iv[j] = idum;
|
|
|
|
return iy;
|
|
}
|
|
|
|
// fran1 -- return a random floating-point number on the interval [0,1)
|
|
float fran1( void )
|
|
{
|
|
float temp = (float)AM * lran1();
|
|
if( temp > RNMX ) return (float)RNMX;
|
|
else return temp;
|
|
}
|
|
|
|
float Com_RandomFloat( float flLow, float flHigh )
|
|
{
|
|
float fl;
|
|
|
|
if( idum == 0 ) SeedRandomNumberGenerator(0);
|
|
|
|
fl = fran1(); // float in [0, 1)
|
|
return (fl * (flHigh - flLow)) + flLow; // float in [low, high)
|
|
}
|
|
|
|
long Com_RandomLong( long lLow, long lHigh )
|
|
{
|
|
dword maxAcceptable;
|
|
dword n, x = lHigh-lLow + 1;
|
|
|
|
if( idum == 0 ) SeedRandomNumberGenerator(0);
|
|
|
|
if( x <= 0 || MAX_RANDOM_RANGE < x-1 )
|
|
return lLow;
|
|
|
|
// The following maps a uniform distribution on the interval [0, MAX_RANDOM_RANGE]
|
|
// to a smaller, client-specified range of [0,x-1] in a way that doesn't bias
|
|
// the uniform distribution unfavorably. Even for a worst case x, the loop is
|
|
// guaranteed to be taken no more than half the time, so for that worst case x,
|
|
// the average number of times through the loop is 2. For cases where x is
|
|
// much smaller than MAX_RANDOM_RANGE, the average number of times through the
|
|
// loop is very close to 1.
|
|
maxAcceptable = MAX_RANDOM_RANGE - ((MAX_RANDOM_RANGE+1) % x );
|
|
do
|
|
{
|
|
n = lran1();
|
|
} while( n > maxAcceptable );
|
|
|
|
return lLow + (n % x);
|
|
}
|
|
|
|
#define MAX_STRINGTABLE_SYSTEMS 8 // separately stringsystems
|
|
|
|
typedef struct stringtable_s
|
|
{
|
|
string name; // system name (for debug targets)
|
|
char *data; // buffer with strings
|
|
size_t datasize; // current buffsize
|
|
size_t maxdatasize; // dynamically resized
|
|
|
|
int *table; // indexes at begining string
|
|
size_t numstrings; // current strings count
|
|
size_t maxstrings; // current system limit
|
|
} stringtable_t;
|
|
|
|
stringtable_t *dstring[MAX_STRINGTABLE_SYSTEMS];
|
|
|
|
bool StringTable_CheckHandle( int handle )
|
|
{
|
|
if( handle < 0 || handle > MAX_STRINGTABLE_SYSTEMS )
|
|
{
|
|
MsgDev( D_ERROR, "StringTable_CheckHandle: invalid system handle %d\n", handle );
|
|
return false;
|
|
}
|
|
if( !dstring[handle] )
|
|
{
|
|
MsgDev( D_ERROR, "StringTable_CheckHandle: system with handle %d inactive\n", handle );
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool StringTable_CheckString( int handle, string_t str )
|
|
{
|
|
if(!StringTable_CheckHandle( handle ))
|
|
return false;
|
|
|
|
if( str < 0 || str > dstring[handle]->numstrings )
|
|
{
|
|
MsgDev( D_ERROR, "StringTable_CheckString: invalid string index %i\n", str );
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
int StringTable_CreateNewSystem( const char *name, size_t max_strings )
|
|
{
|
|
int i;
|
|
|
|
// fisrt, find free stringtable system
|
|
for( i = 0; i < MAX_STRINGTABLE_SYSTEMS; i++ )
|
|
{
|
|
if( !dstring[i] )
|
|
{
|
|
// found free slot
|
|
dstring[i] = Mem_Alloc( Sys.stringpool, sizeof(stringtable_t));
|
|
com_strncpy( dstring[i]->name, name, MAX_STRING );
|
|
dstring[i]->maxstrings = max_strings;
|
|
return i;
|
|
}
|
|
}
|
|
|
|
MsgDev( D_ERROR, "StringTable_CreateNewSystem: no free string systems\n" );
|
|
return -1;
|
|
}
|
|
|
|
void StringTable_DeleteSystem( int handle )
|
|
{
|
|
if(!StringTable_CheckHandle( handle ))
|
|
return;
|
|
|
|
// now free stringtable
|
|
Mem_Free( dstring[handle]->data ); // free strings
|
|
Mem_Free( dstring[handle]->table); // free indices
|
|
Mem_Free( dstring[handle] ); // free himself
|
|
memset( &dstring[handle], 0, sizeof(stringtable_t));
|
|
}
|
|
|
|
const char *StringTable_GetString( int handle, string_t index )
|
|
{
|
|
if(!StringTable_CheckString( handle, index ))
|
|
return "";
|
|
return &dstring[handle]->data[dstring[handle]->table[index]];
|
|
}
|
|
|
|
string_t StringTable_SetString( int handle, const char *string )
|
|
{
|
|
int i, len, table_size, data_size;
|
|
|
|
if(!StringTable_CheckHandle( handle ))
|
|
return -1;
|
|
|
|
for( i = 0; i < dstring[handle]->numstrings; i++ )
|
|
{
|
|
if(!com.stricmp( string, StringTable_GetString( handle, i )))
|
|
return i; // already existing
|
|
}
|
|
|
|
// register new string
|
|
len = com.strlen( string );
|
|
table_size = sizeof(string_t) * (dstring[handle]->numstrings + 1);
|
|
data_size = dstring[handle]->datasize + len + 1;
|
|
|
|
if( table_size >= dstring[handle]->maxstrings )
|
|
{
|
|
MsgDev( D_ERROR, "StringTable_SetString: string table %s limit exeeded\n", dstring[handle]->name );
|
|
return -1;
|
|
}
|
|
|
|
dstring[handle]->table = Mem_Realloc( Sys.stringpool, dstring[handle]->table, table_size );
|
|
dstring[handle]->data = Mem_Realloc( Sys.stringpool, dstring[handle]->data, data_size );
|
|
|
|
com.strcpy( &dstring[handle]->data[dstring[handle]->datasize], string );
|
|
dstring[handle]->table[dstring[handle]->numstrings] = dstring[handle]->datasize;
|
|
dstring[handle]->datasize += len + 1; // null terminator
|
|
dstring[handle]->numstrings++;
|
|
|
|
return dstring[handle]->numstrings - 1; // current index
|
|
}
|
|
|
|
bool StringTable_SaveSystem( int h, wfile_t *wad )
|
|
{
|
|
int table_size;
|
|
|
|
if(!StringTable_CheckHandle( h ))
|
|
return false;
|
|
if(!W_SaveLump( wad, "stringdata", dstring[h]->data, dstring[h]->datasize, TYPE_STRDATA, CMP_ZLIB ))
|
|
return false;
|
|
table_size = dstring[h]->numstrings * sizeof(string_t);
|
|
if(!W_SaveLump( wad, "stringtable", dstring[h]->table, table_size, TYPE_STRDATA, CMP_ZLIB ))
|
|
return false;
|
|
|
|
StringTable_DeleteSystem( h ); // strings dumped, now we can free it
|
|
return true;
|
|
}
|
|
|
|
int StringTable_LoadSystem( wfile_t *wad, const char *name )
|
|
{
|
|
int h = StringTable_CreateNewSystem( name, 0x10000 ); // 65535 unique strings
|
|
int datasize, numstrings;
|
|
|
|
dstring[h]->data = W_LoadLump( wad, "stringdata", &datasize, TYPE_STRDATA );
|
|
dstring[h]->table = (int *)W_LoadLump( wad, "stringtable", &numstrings, TYPE_STRDATA );
|
|
dstring[h]->datasize = datasize;
|
|
dstring[h]->numstrings = numstrings / sizeof(int);
|
|
return h;
|
|
} |