Portable Half-Life SDK. GoldSource and Xash3D. Crossplatform.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2924 lines
72 KiB

7 years ago
/***
*
* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
7 years ago
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
/*
===== util.cpp ========================================================
Utility code. Really not optional after all.
*/
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "saverestore.h"
#include <time.h>
#include "shake.h"
#include "decals.h"
#include "player.h"
#include "weapons.h"
#include "gamerules.h"
#include "movewith.h"
#include "locus.h"
float UTIL_WeaponTimeBase( void )
{
#if CLIENT_WEAPONS
return 0.0f;
7 years ago
#else
return gpGlobals->time;
#endif
}
static unsigned int glSeed = 0;
8 years ago
unsigned int seed_table[256] =
7 years ago
{
28985, 27138, 26457, 9451, 17764, 10909, 28790, 8716, 6361, 4853, 17798, 21977, 19643, 20662, 10834, 20103,
27067, 28634, 18623, 25849, 8576, 26234, 23887, 18228, 32587, 4836, 3306, 1811, 3035, 24559, 18399, 315,
26766, 907, 24102, 12370, 9674, 2972, 10472, 16492, 22683, 11529, 27968, 30406, 13213, 2319, 23620, 16823,
10013, 23772, 21567, 1251, 19579, 20313, 18241, 30130, 8402, 20807, 27354, 7169, 21211, 17293, 5410, 19223,
10255, 22480, 27388, 9946, 15628, 24389, 17308, 2370, 9530, 31683, 25927, 23567, 11694, 26397, 32602, 15031,
18255, 17582, 1422, 28835, 23607, 12597, 20602, 10138, 5212, 1252, 10074, 23166, 19823, 31667, 5902, 24630,
18948, 14330, 14950, 8939, 23540, 21311, 22428, 22391, 3583, 29004, 30498, 18714, 4278, 2437, 22430, 3439,
28313, 23161, 25396, 13471, 19324, 15287, 2563, 18901, 13103, 16867, 9714, 14322, 15197, 26889, 19372, 26241,
31925, 14640, 11497, 8941, 10056, 6451, 28656, 10737, 13874, 17356, 8281, 25937, 1661, 4850, 7448, 12744,
21826, 5477, 10167, 16705, 26897, 8839, 30947, 27978, 27283, 24685, 32298, 3525, 12398, 28726, 9475, 10208,
617, 13467, 22287, 2376, 6097, 26312, 2974, 9114, 21787, 28010, 4725, 15387, 3274, 10762, 31695, 17320,
18324, 12441, 16801, 27376, 22464, 7500, 5666, 18144, 15314, 31914, 31627, 6495, 5226, 31203, 2331, 4668,
12650, 18275, 351, 7268, 31319, 30119, 7600, 2905, 13826, 11343, 13053, 15583, 30055, 31093, 5067, 761,
9685, 11070, 21369, 27155, 3663, 26542, 20169, 12161, 15411, 30401, 7580, 31784, 8985, 29367, 20989, 14203,
29694, 21167, 10337, 1706, 28578, 887, 3373, 19477, 14382, 675, 7033, 15111, 26138, 12252, 30996, 21409,
25678, 18555, 13256, 23316, 22407, 16727, 991, 9236, 5373, 29402, 6117, 15241, 27715, 19291, 19888, 19847
};
unsigned int U_Random( void )
{
glSeed *= 69069;
8 years ago
glSeed += seed_table[glSeed & 0xff];
7 years ago
return ( ++glSeed & 0x0fffffff );
}
void U_Srand( unsigned int seed )
{
8 years ago
glSeed = seed_table[seed & 0xff];
7 years ago
}
/*
=====================
UTIL_SharedRandomLong
=====================
*/
int UTIL_SharedRandomLong( unsigned int seed, int low, int high )
{
unsigned int range;
U_Srand( (int)seed + low + high );
range = high - low + 1;
8 years ago
if( !( range - 1 ) )
7 years ago
{
return low;
}
else
{
int offset;
int rnum;
rnum = U_Random();
offset = rnum % range;
8 years ago
return ( low + offset );
7 years ago
}
}
/*
=====================
UTIL_SharedRandomFloat
=====================
*/
float UTIL_SharedRandomFloat( unsigned int seed, float low, float high )
{
unsigned int range;
U_Srand( (int)seed + *(int *)&low + *(int *)&high );
U_Random();
U_Random();
range = (int)( high - low );
8 years ago
if( !range )
7 years ago
{
return low;
}
else
{
int tensixrand;
float offset;
tensixrand = U_Random() & 65535;
offset = (float)tensixrand / 65536.0f;
7 years ago
8 years ago
return ( low + offset * range );
7 years ago
}
}
void UTIL_ParametricRocket( entvars_t *pev, Vector vecOrigin, Vector vecAngles, edict_t *owner )
{
pev->startpos = vecOrigin;
// Trace out line to end pos
TraceResult tr;
UTIL_MakeVectors( vecAngles );
8 years ago
UTIL_TraceLine( pev->startpos, pev->startpos + gpGlobals->v_forward * 8192, ignore_monsters, owner, &tr );
7 years ago
pev->endpos = tr.vecEndPos;
// Now compute how long it will take based on current velocity
Vector vecTravel = pev->endpos - pev->startpos;
float travelTime = 0.0f;
if( pev->velocity.Length() > 0.0f )
7 years ago
{
travelTime = vecTravel.Length() / pev->velocity.Length();
}
pev->starttime = gpGlobals->time;
pev->impacttime = gpGlobals->time + travelTime;
}
int g_groupmask = 0;
int g_groupop = 0;
// Normal overrides
void UTIL_SetGroupTrace( int groupmask, int op )
{
8 years ago
g_groupmask = groupmask;
g_groupop = op;
7 years ago
ENGINE_SETGROUPMASK( g_groupmask, g_groupop );
}
void UTIL_UnsetGroupTrace( void )
{
8 years ago
g_groupmask = 0;
g_groupop = 0;
7 years ago
ENGINE_SETGROUPMASK( 0, 0 );
}
// Smart version, it'll clean itself up when it pops off stack
UTIL_GroupTrace::UTIL_GroupTrace( int groupmask, int op )
{
8 years ago
m_oldgroupmask = g_groupmask;
m_oldgroupop = g_groupop;
7 years ago
8 years ago
g_groupmask = groupmask;
g_groupop = op;
7 years ago
ENGINE_SETGROUPMASK( g_groupmask, g_groupop );
}
UTIL_GroupTrace::~UTIL_GroupTrace( void )
{
8 years ago
g_groupmask = m_oldgroupmask;
g_groupop = m_oldgroupop;
7 years ago
ENGINE_SETGROUPMASK( g_groupmask, g_groupop );
}
TYPEDESCRIPTION gEntvarsDescription[] =
7 years ago
{
DEFINE_ENTITY_FIELD( classname, FIELD_STRING ),
DEFINE_ENTITY_GLOBAL_FIELD( globalname, FIELD_STRING ),
7 years ago
DEFINE_ENTITY_FIELD( origin, FIELD_POSITION_VECTOR ),
DEFINE_ENTITY_FIELD( oldorigin, FIELD_POSITION_VECTOR ),
DEFINE_ENTITY_FIELD( velocity, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( basevelocity, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( movedir, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( angles, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( avelocity, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( punchangle, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( v_angle, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( fixangle, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( idealpitch, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( pitch_speed, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( ideal_yaw, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( yaw_speed, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( modelindex, FIELD_INTEGER ),
DEFINE_ENTITY_GLOBAL_FIELD( model, FIELD_MODELNAME ),
DEFINE_ENTITY_FIELD( viewmodel, FIELD_MODELNAME ),
DEFINE_ENTITY_FIELD( weaponmodel, FIELD_MODELNAME ),
DEFINE_ENTITY_FIELD( absmin, FIELD_POSITION_VECTOR ),
DEFINE_ENTITY_FIELD( absmax, FIELD_POSITION_VECTOR ),
DEFINE_ENTITY_GLOBAL_FIELD( mins, FIELD_VECTOR ),
DEFINE_ENTITY_GLOBAL_FIELD( maxs, FIELD_VECTOR ),
DEFINE_ENTITY_GLOBAL_FIELD( size, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( ltime, FIELD_TIME ),
DEFINE_ENTITY_FIELD( nextthink, FIELD_TIME ),
DEFINE_ENTITY_FIELD( solid, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( movetype, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( skin, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( body, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( effects, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( gravity, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( friction, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( light_level, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( frame, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( scale, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( sequence, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( animtime, FIELD_TIME ),
DEFINE_ENTITY_FIELD( framerate, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( controller, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( blending, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( rendermode, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( renderamt, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( rendercolor, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( renderfx, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( health, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( frags, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( weapons, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( takedamage, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( deadflag, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( view_ofs, FIELD_VECTOR ),
DEFINE_ENTITY_FIELD( button, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( impulse, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( chain, FIELD_EDICT ),
DEFINE_ENTITY_FIELD( dmg_inflictor, FIELD_EDICT ),
DEFINE_ENTITY_FIELD( enemy, FIELD_EDICT ),
DEFINE_ENTITY_FIELD( aiment, FIELD_EDICT ),
DEFINE_ENTITY_FIELD( owner, FIELD_EDICT ),
DEFINE_ENTITY_FIELD( groundentity, FIELD_EDICT ),
DEFINE_ENTITY_FIELD( spawnflags, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( flags, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( colormap, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( team, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( max_health, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( teleport_time, FIELD_TIME ),
DEFINE_ENTITY_FIELD( armortype, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( armorvalue, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( waterlevel, FIELD_INTEGER ),
DEFINE_ENTITY_FIELD( watertype, FIELD_INTEGER ),
// Having these fields be local to the individual levels makes it easier to test those levels individually.
DEFINE_ENTITY_GLOBAL_FIELD( target, FIELD_STRING ),
DEFINE_ENTITY_GLOBAL_FIELD( targetname, FIELD_STRING ),
DEFINE_ENTITY_FIELD( netname, FIELD_STRING ),
DEFINE_ENTITY_FIELD( message, FIELD_STRING ),
DEFINE_ENTITY_FIELD( dmg_take, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( dmg_save, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( dmg, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( dmgtime, FIELD_TIME ),
DEFINE_ENTITY_FIELD( noise, FIELD_SOUNDNAME ),
DEFINE_ENTITY_FIELD( noise1, FIELD_SOUNDNAME ),
DEFINE_ENTITY_FIELD( noise2, FIELD_SOUNDNAME ),
DEFINE_ENTITY_FIELD( noise3, FIELD_SOUNDNAME ),
DEFINE_ENTITY_FIELD( speed, FIELD_FLOAT ),
DEFINE_ENTITY_FIELD( air_finished, FIELD_TIME ),
DEFINE_ENTITY_FIELD( pain_finished, FIELD_TIME ),
DEFINE_ENTITY_FIELD( radsuit_finished, FIELD_TIME ),
};
8 years ago
#define ENTVARS_COUNT ( sizeof(gEntvarsDescription) / sizeof(gEntvarsDescription[0]) )
7 years ago
4 years ago
#if DEBUG
7 years ago
edict_t *DBG_EntOfVars( const entvars_t *pev )
{
8 years ago
if( pev->pContainingEntity != NULL )
7 years ago
return pev->pContainingEntity;
8 years ago
ALERT( at_console, "entvars_t pContainingEntity is NULL, calling into engine" );
edict_t *pent = (*g_engfuncs.pfnFindEntityByVars)( (entvars_t*)pev );
if( pent == NULL )
ALERT( at_console, "DAMN! Even the engine couldn't FindEntityByVars!" );
( (entvars_t *)pev )->pContainingEntity = pent;
7 years ago
return pent;
}
void DBG_AssertFunction( BOOL fExpr, const char* szExpr, const char* szFile, int szLine, const char* szMessage )
{
8 years ago
if( fExpr )
7 years ago
return;
char szOut[512];
8 years ago
if( szMessage != NULL )
sprintf( szOut, "ASSERT FAILED:\n %s \n(%s@%d)\n%s", szExpr, szFile, szLine, szMessage );
7 years ago
else
8 years ago
sprintf( szOut, "ASSERT FAILED:\n %s \n(%s@%d)", szExpr, szFile, szLine );
8 years ago
ALERT( at_console, szOut );
}
7 years ago
#endif // DEBUG
BOOL UTIL_GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon )
{
return g_pGameRules->GetNextBestWeapon( pPlayer, pCurrentWeapon );
}
// ripped this out of the engine
float UTIL_AngleMod( float a )
7 years ago
{
8 years ago
/*if( a < 0 )
7 years ago
{
8 years ago
a = a + 360 * ( (int)( a / 360 ) + 1 );
7 years ago
}
8 years ago
else if( a >= 360 )
7 years ago
{
8 years ago
a = a - 360 * ( (int)( a / 360 ) );
}*/
8 years ago
// a = ( 360.0 / 65536 ) * ( (int)( a * ( 65536 / 360.0 ) ) & 65535 );
a = fmod( a, 360.0f );
8 years ago
if( a < 0 )
a += 360;
7 years ago
return a;
}
float UTIL_AngleDiff( float destAngle, float srcAngle )
{
float delta;
delta = destAngle - srcAngle;
8 years ago
if( destAngle > srcAngle )
7 years ago
{
8 years ago
if( delta >= 180 )
7 years ago
delta -= 360;
}
else
{
8 years ago
if( delta <= -180 )
7 years ago
delta += 360;
}
return delta;
}
Vector UTIL_VecToAngles( const Vector &vec )
{
float rgflVecOut[3];
8 years ago
VEC_TO_ANGLES( vec, rgflVecOut );
return Vector( rgflVecOut );
7 years ago
}
7 years ago
//LRC - pass in a normalised axis vector and a number of degrees, and this returns the corresponding
// angles value for an entity.
Vector UTIL_AxisRotationToAngles( const Vector &vecAxis, float flDegs )
{
Vector vecTemp = UTIL_AxisRotationToVec( vecAxis, flDegs );
float rgflVecOut[3];
//ugh, mathsy.
rgflVecOut[0] = asin(vecTemp.z) * (-180.0f / M_PI_F);
rgflVecOut[1] = acos(vecTemp.x) * (180.0f / M_PI_F);
7 years ago
if (vecTemp.y < 0)
rgflVecOut[1] = -rgflVecOut[1];
rgflVecOut[2] = 0; //for now
return Vector(rgflVecOut);
}
//LRC - as above, but returns the position of point 1 0 0 under the given rotation
Vector UTIL_AxisRotationToVec( const Vector &vecAxis, float flDegs )
{
float rgflVecOut[3];
float flRads = flDegs * (M_PI_F / 180.0f);
7 years ago
float c = cos(flRads);
float s = sin(flRads);
float v = vecAxis.x * (1-c);
//ugh, more maths. Thank goodness for internet geometry sites...
rgflVecOut[0] = vecAxis.x*v + c;
rgflVecOut[1] = vecAxis.y*v + vecAxis.z*s;
rgflVecOut[2] = vecAxis.z*v - vecAxis.y*s;
return Vector(rgflVecOut);
}
// float UTIL_MoveToOrigin( edict_t *pent, const Vector vecGoal, float flDist, int iMoveType )
7 years ago
void UTIL_MoveToOrigin( edict_t *pent, const Vector &vecGoal, float flDist, int iMoveType )
{
float rgfl[3];
8 years ago
vecGoal.CopyToArray( rgfl );
//return MOVE_TO_ORIGIN( pent, rgfl, flDist, iMoveType );
MOVE_TO_ORIGIN( pent, rgfl, flDist, iMoveType );
7 years ago
}
int UTIL_EntitiesInBox( CBaseEntity **pList, int listMax, const Vector &mins, const Vector &maxs, int flagMask )
{
8 years ago
edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex( 1 );
7 years ago
CBaseEntity *pEntity;
8 years ago
int count;
7 years ago
count = 0;
8 years ago
if( !pEdict )
7 years ago
return count;
8 years ago
for( int i = 1; i < gpGlobals->maxEntities; i++, pEdict++ )
7 years ago
{
8 years ago
if( pEdict->free ) // Not in use
7 years ago
continue;
8 years ago
if( flagMask && !( pEdict->v.flags & flagMask ) ) // Does it meet the criteria?
7 years ago
continue;
8 years ago
if( mins.x > pEdict->v.absmax.x ||
mins.y > pEdict->v.absmax.y ||
mins.z > pEdict->v.absmax.z ||
maxs.x < pEdict->v.absmin.x ||
maxs.y < pEdict->v.absmin.y ||
maxs.z < pEdict->v.absmin.z )
continue;
7 years ago
8 years ago
pEntity = CBaseEntity::Instance( pEdict );
if( !pEntity )
7 years ago
continue;
8 years ago
pList[count] = pEntity;
7 years ago
count++;
8 years ago
if( count >= listMax )
7 years ago
return count;
}
return count;
}
int UTIL_MonstersInSphere( CBaseEntity **pList, int listMax, const Vector &center, float radius )
{
8 years ago
edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex( 1 );
7 years ago
CBaseEntity *pEntity;
8 years ago
int count;
7 years ago
float distance, delta;
count = 0;
float radiusSquared = radius * radius;
8 years ago
if( !pEdict )
7 years ago
return count;
8 years ago
for( int i = 1; i < gpGlobals->maxEntities; i++, pEdict++ )
7 years ago
{
8 years ago
if( pEdict->free ) // Not in use
7 years ago
continue;
8 years ago
if( !( pEdict->v.flags & ( FL_CLIENT | FL_MONSTER ) ) ) // Not a client/monster ?
7 years ago
continue;
// Use origin for X & Y since they are centered for all monsters
// Now X
delta = center.x - pEdict->v.origin.x;//( pEdict->v.absmin.x + pEdict->v.absmax.x ) * 0.5f;
7 years ago
delta *= delta;
8 years ago
if( delta > radiusSquared )
7 years ago
continue;
distance = delta;
7 years ago
// Now Y
delta = center.y - pEdict->v.origin.y;//( pEdict->v.absmin.y + pEdict->v.absmax.y ) * 0.5f;
7 years ago
delta *= delta;
distance += delta;
8 years ago
if( distance > radiusSquared )
7 years ago
continue;
// Now Z
delta = center.z - ( pEdict->v.absmin.z + pEdict->v.absmax.z ) * 0.5f;
7 years ago
delta *= delta;
distance += delta;
8 years ago
if( distance > radiusSquared )
7 years ago
continue;
8 years ago
pEntity = CBaseEntity::Instance( pEdict );
if( !pEntity )
7 years ago
continue;
8 years ago
pList[count] = pEntity;
7 years ago
count++;
8 years ago
if( count >= listMax )
7 years ago
return count;
}
return count;
}
CBaseEntity *UTIL_FindEntityInSphere( CBaseEntity *pStartEntity, const Vector &vecCenter, float flRadius )
{
edict_t *pentEntity;
8 years ago
if( pStartEntity )
7 years ago
pentEntity = pStartEntity->edict();
else
pentEntity = NULL;
8 years ago
pentEntity = FIND_ENTITY_IN_SPHERE( pentEntity, vecCenter, flRadius );
7 years ago
8 years ago
if( !FNullEnt( pentEntity ) )
return CBaseEntity::Instance( pentEntity );
7 years ago
return NULL;
}
CBaseEntity *UTIL_FindEntityByString( CBaseEntity *pStartEntity, const char *szKeyword, const char *szValue )
{
edict_t *pentEntity;
CBaseEntity *pEntity;
8 years ago
if( pStartEntity )
7 years ago
pentEntity = pStartEntity->edict();
else
pentEntity = NULL;
for (;;)
{
// Don't change this to use UTIL_FindEntityByString!
pentEntity = FIND_ENTITY_BY_STRING( pentEntity, szKeyword, szValue );
7 years ago
// if pentEntity (the edict) is null, we're at the end of the entities. Give up.
if (FNullEnt(pentEntity))
{
return NULL;
}
7 years ago
else
{
// ...but if only pEntity (the classptr) is null, we've just got one dud, so we try again.
pEntity = CBaseEntity::Instance(pentEntity);
if (pEntity)
return pEntity;
}
}
}
CBaseEntity *UTIL_FindEntityByClassname( CBaseEntity *pStartEntity, const char *szName )
{
return UTIL_FindEntityByString( pStartEntity, "classname", szName );
}
#define MAX_ALIASNAME_LEN 80
//LRC - things get messed up if aliases change in the middle of an entity traversal.
// so instead, they record what changes should be made, and wait until this function gets
// called.
void UTIL_FlushAliases( void )
{
// ALERT(at_console, "Flushing alias list\n");
if (!g_pWorld)
{
ALERT(at_console, "FlushAliases has no AliasList!\n");
7 years ago
return;
}
while (g_pWorld->m_pFirstAlias)
{
if (g_pWorld->m_pFirstAlias->m_iLFlags & LF_ALIASLIST)
{
// ALERT(at_console, "call FlushChanges for %s \"%s\"\n", STRING(g_pWorld->m_pFirstAlias->pev->classname), STRING(g_pWorld->m_pFirstAlias->pev->targetname));
g_pWorld->m_pFirstAlias->FlushChanges();
g_pWorld->m_pFirstAlias->m_iLFlags &= ~LF_ALIASLIST;
}
g_pWorld->m_pFirstAlias = g_pWorld->m_pFirstAlias->m_pNextAlias;
}
}
void UTIL_AddToAliasList( CBaseAlias *pAlias )
{
if (!g_pWorld)
{
ALERT(at_console, "AddToAliasList has no AliasList!\n");
7 years ago
return;
}
pAlias->m_iLFlags |= LF_ALIASLIST;
// ALERT(at_console, "Adding %s \"%s\" to alias list\n", STRING(pAlias->pev->classname), STRING(pAlias->pev->targetname));
if (g_pWorld->m_pFirstAlias == NULL)
{
g_pWorld->m_pFirstAlias = pAlias;
pAlias->m_pNextAlias = NULL;
}
else if (g_pWorld->m_pFirstAlias == pAlias)
{
// already in the list
return;
}
else
{
CBaseAlias *pCurrent = g_pWorld->m_pFirstAlias;
while (pCurrent->m_pNextAlias != NULL)
{
if (pCurrent->m_pNextAlias == pAlias)
{
// already in the list
return;
}
pCurrent = pCurrent->m_pNextAlias;
}
pCurrent->m_pNextAlias = pAlias;
pAlias->m_pNextAlias = NULL;
}
}
// for every alias which has the given name, find the earliest entity which any of them refers to
// and which is later than pStartEntity.
CBaseEntity *UTIL_FollowAliasReference(CBaseEntity *pStartEntity, const char* szValue)
{
CBaseEntity* pEntity;
CBaseEntity* pBestEntity = NULL; // the entity we're currently planning to return.
int iBestOffset = -1; // the offset of that entity.
CBaseEntity* pTempEntity;
int iTempOffset;
pEntity = UTIL_FindEntityByTargetname(NULL,szValue);
while ( pEntity )
{
if (pEntity->IsAlias())
{
pTempEntity = ((CBaseAlias*)pEntity)->FollowAlias( pStartEntity );
if ( pTempEntity )
{
// We've found an entity; only use it if its offset is lower than the offset we've currently got.
iTempOffset = OFFSET(pTempEntity->pev);
if (iBestOffset == -1 || iTempOffset < iBestOffset)
{
iBestOffset = iTempOffset;
pBestEntity = pTempEntity;
}
}
}
pEntity = UTIL_FindEntityByTargetname(pEntity,szValue);
}
return pBestEntity;
}
// for every info_group which has the given groupname, find the earliest entity which is referred to by its member
// with the given membername and which is later than pStartEntity.
CBaseEntity *UTIL_FollowGroupReference(CBaseEntity *pStartEntity, char* szGroupName, char* szMemberName)
{
CBaseEntity* pEntity;
CBaseEntity* pBestEntity = NULL; // the entity we're currently planning to return.
int iBestOffset = -1; // the offset of that entity.
CBaseEntity* pTempEntity;
int iTempOffset;
char szBuf[MAX_ALIASNAME_LEN];
char* szThisMember = szMemberName;
char* szTail = NULL;
int iszMemberValue;
int i;
// find the first '.' in the membername and if there is one, split the string at that point.
for (i = 0; szMemberName[i]; i++)
{
if (szMemberName[i] == '.')
{
// recursive member-reference
// FIXME: we should probably check that i < MAX_ALIASNAME_LEN.
strncpy(szBuf,szMemberName,i);
szBuf[i] = 0;
szTail = &(szMemberName[i+1]);
szThisMember = szBuf;
break;
}
}
pEntity = UTIL_FindEntityByTargetname(NULL,szGroupName);
while ( pEntity )
{
if (FStrEq(STRING(pEntity->pev->classname), "info_group"))
{
iszMemberValue = ((CInfoGroup*)pEntity)->GetMember(szThisMember);
// ALERT(at_console,"survived getMember\n");
// return NULL;
if (!FStringNull(iszMemberValue))
{
if (szTail) // do we have more references to follow?
pTempEntity = UTIL_FollowGroupReference(pStartEntity, (char*)STRING(iszMemberValue), szTail);
else
pTempEntity = UTIL_FindEntityByTargetname(pStartEntity,STRING(iszMemberValue));
if ( pTempEntity )
{
iTempOffset = OFFSET(pTempEntity->pev);
if (iBestOffset == -1 || iTempOffset < iBestOffset)
{
iBestOffset = iTempOffset;
pBestEntity = pTempEntity;
}
}
}
}
pEntity = UTIL_FindEntityByTargetname(pEntity,szGroupName);
}
if (pBestEntity)
{
// ALERT(at_console,"\"%s\".\"%s\" returns %s\n",szGroupName,szMemberName,STRING(pBestEntity->pev->targetname));
return pBestEntity;
}
return NULL;
}
// Returns the first entity which szName refers to and which is after pStartEntity.
CBaseEntity *UTIL_FollowReference( CBaseEntity *pStartEntity, const char* szName )
{
char szRoot[MAX_ALIASNAME_LEN+1]; // allow room for null-terminator
char* szMember;
int i;
CBaseEntity *pResult;
if (!szName || szName[0] == 0) return NULL;
// reference through an info_group?
for (i = 0; szName[i]; i++)
{
if (szName[i] == '.')
{
// yes, it looks like a reference through an info_group...
// FIXME: we should probably check that i < MAX_ALIASNAME_LEN.
strncpy(szRoot,szName,i);
szRoot[i] = 0;
szMember = (char*)&szName[i+1];
//ALERT(at_console,"Following reference- group %s with member %s\n",szRoot,szMember);
pResult = UTIL_FollowGroupReference(pStartEntity, szRoot, szMember);
// if (pResult)
// ALERT(at_console,"\"%s\".\"%s\" = %s\n",szRoot,szMember,STRING(pResult->pev->targetname));
return pResult;
}
}
// reference through an info_alias?
if ( szName[0] == '*' )
{
if (FStrEq(szName, "*player"))
{
CBaseEntity* pPlayer = UTIL_FindEntityByClassname(NULL, "player");
if (pPlayer && (pStartEntity == NULL || pPlayer->eoffset() > pStartEntity->eoffset()))
return pPlayer;
else
return NULL;
}
//ALERT(at_console,"Following alias %s\n",szName+1);
pResult = UTIL_FollowAliasReference( pStartEntity, szName+1 );
// if (pResult)
// ALERT(at_console,"alias \"%s\" = %s\n",szName+1,STRING(pResult->pev->targetname));
return pResult;
}
// not a reference
// ALERT(at_console,"%s is not a reference\n",szName);
return NULL;
}
CBaseEntity *UTIL_FindEntityByTargetname( CBaseEntity *pStartEntity, const char *szName )
{
CBaseEntity *pFound = UTIL_FollowReference( pStartEntity, szName );
if (pFound)
return pFound;
else
return UTIL_FindEntityByString( pStartEntity, "targetname", szName );
7 years ago
}
CBaseEntity *UTIL_FindEntityByTargetname( CBaseEntity *pStartEntity, const char *szName, CBaseEntity *pActivator )
{
if (FStrEq(szName, "*locus"))
{
if (pActivator && (pStartEntity == NULL || pActivator->eoffset() > pStartEntity->eoffset()))
return pActivator;
else
return NULL;
}
else
return UTIL_FindEntityByTargetname( pStartEntity, szName );
}
CBaseEntity *UTIL_FindEntityByTarget( CBaseEntity *pStartEntity, const char *szName )
{
return UTIL_FindEntityByString( pStartEntity, "target", szName );
}
CBaseEntity *UTIL_FindEntityGeneric( const char *szWhatever, Vector &vecSrc, float flRadius )
{
CBaseEntity *pEntity = NULL;
pEntity = UTIL_FindEntityByTargetname( NULL, szWhatever );
8 years ago
if( pEntity )
7 years ago
return pEntity;
CBaseEntity *pSearch = NULL;
float flMaxDist2 = flRadius * flRadius;
8 years ago
while( ( pSearch = UTIL_FindEntityByClassname( pSearch, szWhatever ) ) != NULL )
7 years ago
{
8 years ago
float flDist2 = ( pSearch->pev->origin - vecSrc ).Length();
7 years ago
flDist2 = flDist2 * flDist2;
8 years ago
if( flMaxDist2 > flDist2 )
7 years ago
{
pEntity = pSearch;
flMaxDist2 = flDist2;
}
}
return pEntity;
}
// returns a CBaseEntity pointer to a player by index. Only returns if the player is spawned and connected
// otherwise returns NULL
// Index is 1 based
8 years ago
CBaseEntity *UTIL_PlayerByIndex( int playerIndex )
7 years ago
{
CBaseEntity *pPlayer = NULL;
8 years ago
if( playerIndex > 0 && playerIndex <= gpGlobals->maxClients )
7 years ago
{
edict_t *pPlayerEdict = INDEXENT( playerIndex );
8 years ago
if( pPlayerEdict && !pPlayerEdict->free )
7 years ago
{
pPlayer = CBaseEntity::Instance( pPlayerEdict );
}
}
return pPlayer;
}
void UTIL_MakeVectors( const Vector &vecAngles )
{
MAKE_VECTORS( vecAngles );
}
void UTIL_MakeAimVectors( const Vector &vecAngles )
{
float rgflVec[3];
vecAngles.CopyToArray(rgflVec);
rgflVec[0] = -rgflVec[0];
8 years ago
MAKE_VECTORS( rgflVec );
7 years ago
}
8 years ago
#define SWAP( a, b, temp ) ( ( temp ) = ( a ), ( a ) = ( b ), ( b ) = ( temp ) )
7 years ago
void UTIL_MakeInvVectors( const Vector &vec, globalvars_t *pgv )
{
8 years ago
MAKE_VECTORS( vec );
7 years ago
float tmp;
pgv->v_right = pgv->v_right * -1;
8 years ago
SWAP( pgv->v_forward.y, pgv->v_right.x, tmp );
SWAP( pgv->v_forward.z, pgv->v_up.x, tmp );
SWAP( pgv->v_right.z, pgv->v_up.y, tmp );
7 years ago
}
void UTIL_EmitAmbientSound( edict_t *entity, const Vector &vecOrigin, const char *samp, float vol, float attenuation, int fFlags, int pitch )
{
float rgfl[3];
8 years ago
vecOrigin.CopyToArray( rgfl );
7 years ago
8 years ago
if( samp && *samp == '!' )
7 years ago
{
char name[32];
8 years ago
if( SENTENCEG_Lookup( samp, name ) >= 0 )
EMIT_AMBIENT_SOUND( entity, rgfl, name, vol, attenuation, fFlags, pitch );
7 years ago
}
else
8 years ago
EMIT_AMBIENT_SOUND( entity, rgfl, samp, vol, attenuation, fFlags, pitch );
7 years ago
}
static unsigned short FixedUnsigned16( float value, float scale )
{
int output;
output = (int)( value * scale );
8 years ago
if( output < 0 )
7 years ago
output = 0;
8 years ago
if( output > 0xFFFF )
7 years ago
output = 0xFFFF;
return (unsigned short)output;
}
static short FixedSigned16( float value, float scale )
{
int output;
output = (int)( value * scale );
7 years ago
8 years ago
if( output > 32767 )
7 years ago
output = 32767;
8 years ago
if( output < -32768 )
7 years ago
output = -32768;
return (short)output;
}
// Shake the screen of all clients within radius
// radius == 0, shake all clients
// UNDONE: Allow caller to shake clients not ONGROUND?
// UNDONE: Fix falloff model (disabled)?
// UNDONE: Affect user controls?
//LRC UNDONE: Work during trigger_camera?
void UTIL_ScreenShake( const Vector &center, float amplitude, float frequency, float duration, float radius )
{
8 years ago
int i;
7 years ago
float localAmplitude;
ScreenShake shake;
8 years ago
shake.duration = FixedUnsigned16( duration, 1 << 12 ); // 4.12 fixed
shake.frequency = FixedUnsigned16( frequency, 1 << 8 ); // 8.8 fixed
7 years ago
8 years ago
for( i = 1; i <= gpGlobals->maxClients; i++ )
7 years ago
{
CBaseEntity *pPlayer = UTIL_PlayerByIndex( i );
8 years ago
if( !pPlayer || !( pPlayer->pev->flags & FL_ONGROUND ) ) // Don't shake if not onground
7 years ago
continue;
localAmplitude = 0;
8 years ago
if( radius <= 0 )
7 years ago
localAmplitude = amplitude;
else
{
Vector delta = center - pPlayer->pev->origin;
float distance = delta.Length();
7 years ago
// Had to get rid of this falloff - it didn't work well
8 years ago
if( distance < radius )
7 years ago
localAmplitude = amplitude;//radius - distance;
}
8 years ago
if( localAmplitude )
7 years ago
{
8 years ago
shake.amplitude = FixedUnsigned16( localAmplitude, 1 << 12 ); // 4.12 fixed
7 years ago
MESSAGE_BEGIN( MSG_ONE, gmsgShake, NULL, pPlayer->edict() ); // use the magic #1 for "one client"
WRITE_SHORT( shake.amplitude ); // shake amount
WRITE_SHORT( shake.duration ); // shake lasts this long
WRITE_SHORT( shake.frequency ); // shake noise frequency
MESSAGE_END();
}
}
}
void UTIL_ScreenShakeAll( const Vector &center, float amplitude, float frequency, float duration )
{
UTIL_ScreenShake( center, amplitude, frequency, duration, 0 );
}
void UTIL_ScreenFadeBuild( ScreenFade &fade, const Vector &color, float fadeTime, float fadeHold, int alpha, int flags )
{
8 years ago
fade.duration = FixedUnsigned16( fadeTime, 1 << 12 ); // 4.12 fixed
fade.holdTime = FixedUnsigned16( fadeHold, 1 << 12 ); // 4.12 fixed
7 years ago
fade.r = (int)color.x;
fade.g = (int)color.y;
fade.b = (int)color.z;
fade.a = alpha;
fade.fadeFlags = flags;
}
void UTIL_ScreenFadeWrite( const ScreenFade &fade, CBaseEntity *pEntity )
{
8 years ago
if( !pEntity || !pEntity->IsNetClient() )
7 years ago
return;
MESSAGE_BEGIN( MSG_ONE, gmsgFade, NULL, pEntity->edict() ); // use the magic #1 for "one client"
WRITE_SHORT( fade.duration ); // fade lasts this long
WRITE_SHORT( fade.holdTime ); // fade lasts this long
WRITE_SHORT( fade.fadeFlags ); // fade type (in / out)
WRITE_BYTE( fade.r ); // fade red
WRITE_BYTE( fade.g ); // fade green
WRITE_BYTE( fade.b ); // fade blue
WRITE_BYTE( fade.a ); // fade blue
MESSAGE_END();
}
void UTIL_ScreenFadeAll( const Vector &color, float fadeTime, float fadeHold, int alpha, int flags )
{
8 years ago
int i;
ScreenFade fade;
7 years ago
UTIL_ScreenFadeBuild( fade, color, fadeTime, fadeHold, alpha, flags );
8 years ago
for( i = 1; i <= gpGlobals->maxClients; i++ )
7 years ago
{
CBaseEntity *pPlayer = UTIL_PlayerByIndex( i );
#ifdef XENWARRIOR
if (((CBasePlayer*)pPlayer)->FlashlightIsOn())
((CBasePlayer*)pPlayer)->FlashlightTurnOff();
#endif
UTIL_ScreenFadeWrite( fade, pPlayer );
}
}
void UTIL_ScreenFade( CBaseEntity *pEntity, const Vector &color, float fadeTime, float fadeHold, int alpha, int flags )
{
8 years ago
ScreenFade fade;
7 years ago
UTIL_ScreenFadeBuild( fade, color, fadeTime, fadeHold, alpha, flags );
UTIL_ScreenFadeWrite( fade, pEntity );
}
void UTIL_HudMessage( CBaseEntity *pEntity, const hudtextparms_t &textparms, const char *pMessage )
{
8 years ago
if( !pEntity || !pEntity->IsNetClient() )
7 years ago
return;
MESSAGE_BEGIN( MSG_ONE, SVC_TEMPENTITY, NULL, pEntity->edict() );
WRITE_BYTE( TE_TEXTMESSAGE );
WRITE_BYTE( textparms.channel & 0xFF );
8 years ago
WRITE_SHORT( FixedSigned16( textparms.x, 1 << 13 ) );
WRITE_SHORT( FixedSigned16( textparms.y, 1 << 13 ) );
7 years ago
WRITE_BYTE( textparms.effect );
WRITE_BYTE( textparms.r1 );
WRITE_BYTE( textparms.g1 );
WRITE_BYTE( textparms.b1 );
WRITE_BYTE( textparms.a1 );
WRITE_BYTE( textparms.r2 );
WRITE_BYTE( textparms.g2 );
WRITE_BYTE( textparms.b2 );
WRITE_BYTE( textparms.a2 );
8 years ago
WRITE_SHORT( FixedUnsigned16( textparms.fadeinTime, 1 << 8 ) );
WRITE_SHORT( FixedUnsigned16( textparms.fadeoutTime, 1 << 8 ) );
WRITE_SHORT( FixedUnsigned16( textparms.holdTime, 1 << 8 ) );
if( textparms.effect == 2 )
WRITE_SHORT( FixedUnsigned16( textparms.fxTime, 1 << 8 ) );
7 years ago
8 years ago
if( strlen( pMessage ) < 512 )
7 years ago
{
WRITE_STRING( pMessage );
}
else
{
char tmp[512];
strncpy( tmp, pMessage, 511 );
tmp[511] = 0;
WRITE_STRING( tmp );
}
MESSAGE_END();
}
void UTIL_HudMessageAll( const hudtextparms_t &textparms, const char *pMessage )
{
8 years ago
int i;
7 years ago
8 years ago
for( i = 1; i <= gpGlobals->maxClients; i++ )
7 years ago
{
CBaseEntity *pPlayer = UTIL_PlayerByIndex( i );
8 years ago
if( pPlayer )
7 years ago
UTIL_HudMessage( pPlayer, textparms, pMessage );
}
}
7 years ago
extern int gmsgTextMsg, gmsgSayText;
void UTIL_ClientPrintAll( int msg_dest, const char *msg_name, const char *param1, const char *param2, const char *param3, const char *param4 )
{
MESSAGE_BEGIN( MSG_ALL, gmsgTextMsg );
WRITE_BYTE( msg_dest );
WRITE_STRING( msg_name );
8 years ago
if( param1 )
7 years ago
WRITE_STRING( param1 );
8 years ago
if( param2 )
7 years ago
WRITE_STRING( param2 );
8 years ago
if( param3 )
7 years ago
WRITE_STRING( param3 );
8 years ago
if( param4 )
7 years ago
WRITE_STRING( param4 );
MESSAGE_END();
}
void ClientPrint( entvars_t *client, int msg_dest, const char *msg_name, const char *param1, const char *param2, const char *param3, const char *param4 )
{
MESSAGE_BEGIN( MSG_ONE, gmsgTextMsg, NULL, client );
WRITE_BYTE( msg_dest );
WRITE_STRING( msg_name );
8 years ago
if( param1 )
7 years ago
WRITE_STRING( param1 );
8 years ago
if( param2 )
7 years ago
WRITE_STRING( param2 );
8 years ago
if( param3 )
7 years ago
WRITE_STRING( param3 );
8 years ago
if( param4 )
7 years ago
WRITE_STRING( param4 );
MESSAGE_END();
}
void UTIL_SayText( const char *pText, CBaseEntity *pEntity )
{
8 years ago
if( !pEntity->IsNetClient() )
7 years ago
return;
MESSAGE_BEGIN( MSG_ONE, gmsgSayText, NULL, pEntity->edict() );
WRITE_BYTE( pEntity->entindex() );
WRITE_STRING( pText );
MESSAGE_END();
}
void UTIL_SayTextAll( const char *pText, CBaseEntity *pEntity )
{
MESSAGE_BEGIN( MSG_ALL, gmsgSayText, NULL );
WRITE_BYTE( pEntity->entindex() );
WRITE_STRING( pText );
MESSAGE_END();
}
char *UTIL_dtos1( int d )
{
static char buf[8];
sprintf( buf, "%d", d );
return buf;
}
char *UTIL_dtos2( int d )
{
static char buf[8];
sprintf( buf, "%d", d );
return buf;
}
char *UTIL_dtos3( int d )
{
static char buf[8];
sprintf( buf, "%d", d );
return buf;
}
char *UTIL_dtos4( int d )
{
static char buf[8];
sprintf( buf, "%d", d );
return buf;
}
void UTIL_ShowMessage( const char *pString, CBaseEntity *pEntity )
{
8 years ago
if( !pEntity || !pEntity->IsNetClient() )
7 years ago
return;
MESSAGE_BEGIN( MSG_ONE, gmsgHudText, NULL, pEntity->edict() );
WRITE_STRING( pString );
MESSAGE_END();
}
void UTIL_ShowMessageAll( const char *pString )
{
8 years ago
int i;
7 years ago
// loop through all players
8 years ago
for( i = 1; i <= gpGlobals->maxClients; i++ )
7 years ago
{
CBaseEntity *pPlayer = UTIL_PlayerByIndex( i );
8 years ago
if( pPlayer )
7 years ago
UTIL_ShowMessage( pString, pPlayer );
}
}
// Overloaded to add IGNORE_GLASS
void UTIL_TraceLine( const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, IGNORE_GLASS ignoreGlass, edict_t *pentIgnore, TraceResult *ptr )
{
8 years ago
TRACE_LINE( vecStart, vecEnd, ( igmon == ignore_monsters ? TRUE : FALSE ) | ( ignoreGlass ? 0x100 : 0 ), pentIgnore, ptr );
7 years ago
}
void UTIL_TraceLine( const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, edict_t *pentIgnore, TraceResult *ptr )
{
8 years ago
TRACE_LINE( vecStart, vecEnd, ( igmon == ignore_monsters ? TRUE : FALSE ), pentIgnore, ptr );
7 years ago
}
void UTIL_TraceHull( const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, int hullNumber, edict_t *pentIgnore, TraceResult *ptr )
{
8 years ago
TRACE_HULL( vecStart, vecEnd, ( igmon == ignore_monsters ? TRUE : FALSE ), hullNumber, pentIgnore, ptr );
7 years ago
}
void UTIL_TraceModel( const Vector &vecStart, const Vector &vecEnd, int hullNumber, edict_t *pentModel, TraceResult *ptr )
{
g_engfuncs.pfnTraceModel( vecStart, vecEnd, hullNumber, pentModel, ptr );
}
TraceResult UTIL_GetGlobalTrace( )
{
TraceResult tr;
tr.fAllSolid = (int)gpGlobals->trace_allsolid;
tr.fStartSolid = (int)gpGlobals->trace_startsolid;
tr.fInOpen = (int)gpGlobals->trace_inopen;
tr.fInWater = (int)gpGlobals->trace_inwater;
7 years ago
tr.flFraction = gpGlobals->trace_fraction;
tr.flPlaneDist = gpGlobals->trace_plane_dist;
tr.pHit = gpGlobals->trace_ent;
tr.vecEndPos = gpGlobals->trace_endpos;
tr.vecPlaneNormal = gpGlobals->trace_plane_normal;
tr.iHitgroup = gpGlobals->trace_hitgroup;
return tr;
}
void UTIL_SetSize( entvars_t *pev, const Vector &vecMin, const Vector &vecMax )
{
8 years ago
SET_SIZE( ENT( pev ), vecMin, vecMax );
7 years ago
}
float UTIL_VecToYaw( const Vector &vec )
{
8 years ago
return VEC_TO_YAW( vec );
7 years ago
}
void UTIL_SetEdictOrigin( edict_t *pEdict, const Vector &vecOrigin )
{
SET_ORIGIN(pEdict, vecOrigin );
}
// 'links' the entity into the world
void UTIL_SetOrigin( CBaseEntity *pEntity, const Vector &vecOrigin )
{
SET_ORIGIN(ENT(pEntity->pev), vecOrigin );
}
void UTIL_ParticleEffect( const Vector &vecOrigin, const Vector &vecDirection, ULONG ulColor, ULONG ulCount )
{
PARTICLE_EFFECT( vecOrigin, vecDirection, (float)ulColor, (float)ulCount );
}
float UTIL_Approach( float target, float value, float speed )
{
float delta = target - value;
8 years ago
if( delta > speed )
7 years ago
value += speed;
8 years ago
else if( delta < -speed )
7 years ago
value -= speed;
else
value = target;
return value;
}
float UTIL_ApproachAngle( float target, float value, float speed )
{
target = UTIL_AngleMod( target );
7 years ago
value = UTIL_AngleMod( value );
7 years ago
float delta = target - value;
// Speed is assumed to be positive
8 years ago
if( speed < 0 )
7 years ago
speed = -speed;
8 years ago
if( delta < -180 )
7 years ago
delta += 360;
8 years ago
else if( delta > 180 )
7 years ago
delta -= 360;
8 years ago
if( delta > speed )
7 years ago
value += speed;
8 years ago
else if( delta < -speed )
7 years ago
value -= speed;
else
value = target;
return value;
}
float UTIL_AngleDistance( float next, float cur )
{
float delta = next - cur;
// LRC- correct for deltas > 360
while ( delta < -180 )
delta += 360;
while ( delta > 180 )
delta -= 360;
return delta;
}
float UTIL_SplineFraction( float value, float scale )
{
value = scale * value;
float valueSquared = value * value;
// Nice little ease-in, ease-out spline-like curve
return 3 * valueSquared - 2 * valueSquared * value;
}
char *UTIL_VarArgs( const char *format, ... )
7 years ago
{
8 years ago
va_list argptr;
static char string[1024];
8 years ago
va_start( argptr, format );
vsprintf( string, format, argptr );
va_end( argptr );
7 years ago
8 years ago
return string;
7 years ago
}
7 years ago
Vector UTIL_GetAimVector( edict_t *pent, float flSpeed )
{
Vector tmp;
8 years ago
GET_AIM_VECTOR( pent, flSpeed, tmp );
7 years ago
return tmp;
}
BOOL UTIL_IsMasterTriggered(string_t iszMaster, CBaseEntity *pActivator)
{
int i, j, found = false;
const char *szMaster;
char szBuf[80];
CBaseEntity *pMaster;
int reverse = false;
if (iszMaster)
{
7 years ago
// ALERT(at_console, "IsMasterTriggered(%s, %s \"%s\")\n", STRING(iszMaster), STRING(pActivator->pev->classname), STRING(pActivator->pev->targetname));
szMaster = STRING(iszMaster);
if (szMaster[0] == '~') //inverse master
{
7 years ago
reverse = true;
szMaster++;
}
pMaster = UTIL_FindEntityByTargetname( NULL, szMaster );
if ( !pMaster )
{
for (i = 0; szMaster[i]; i++)
{
if (szMaster[i] == '(')
{
for (j = i+1; szMaster[j]; j++)
{
if (szMaster[j] == ')')
{
strncpy(szBuf, szMaster+i+1, (j-i)-1);
szBuf[(j-i)-1] = 0;
pActivator = UTIL_FindEntityByTargetname( NULL, szBuf );
found = true;
break;
}
}
if (!found) // no ) found
{
ALERT(at_error, "Missing ')' in master \"%s\"\n", szMaster);
return FALSE;
}
break;
}
}
if (!found) // no ( found
{
ALERT(at_console, "Master \"%s\" not found!\n",szMaster);
7 years ago
return TRUE;
}
strncpy(szBuf, szMaster, i);
szBuf[i] = 0;
pMaster = UTIL_FindEntityByTargetname( NULL, szBuf );
}
if (pMaster)
{
if (reverse)
return (pMaster->GetState( pActivator ) != STATE_ON);
else
return (pMaster->GetState( pActivator ) == STATE_ON);
}
}
// if the entity has no master (or the master is missing), just say yes.
return TRUE;
}
BOOL UTIL_ShouldShowBlood( int color )
{
8 years ago
if( color != DONT_BLEED )
7 years ago
{
8 years ago
if( color == BLOOD_COLOR_RED )
7 years ago
{
8 years ago
if( CVAR_GET_FLOAT( "violence_hblood" ) != 0 )
7 years ago
return TRUE;
}
else
{
8 years ago
if( CVAR_GET_FLOAT( "violence_ablood" ) != 0 )
7 years ago
return TRUE;
}
}
return FALSE;
}
int UTIL_PointContents( const Vector &vec )
{
return POINT_CONTENTS(vec);
}
void UTIL_BloodStream( const Vector &origin, const Vector &direction, int color, int amount )
{
8 years ago
if( !UTIL_ShouldShowBlood( color ) )
7 years ago
return;
8 years ago
if( g_Language == LANGUAGE_GERMAN && color == BLOOD_COLOR_RED )
7 years ago
color = 0;
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, origin );
WRITE_BYTE( TE_BLOODSTREAM );
WRITE_COORD( origin.x );
WRITE_COORD( origin.y );
WRITE_COORD( origin.z );
WRITE_COORD( direction.x );
WRITE_COORD( direction.y );
WRITE_COORD( direction.z );
WRITE_BYTE( color );
WRITE_BYTE( Q_min( amount, 255 ) );
7 years ago
MESSAGE_END();
}
void UTIL_BloodDrips( const Vector &origin, const Vector &direction, int color, int amount )
{
8 years ago
if( !UTIL_ShouldShowBlood( color ) )
7 years ago
return;
8 years ago
if( color == DONT_BLEED || amount == 0 )
7 years ago
return;
8 years ago
if( g_Language == LANGUAGE_GERMAN && color == BLOOD_COLOR_RED )
7 years ago
color = 0;
8 years ago
if( g_pGameRules->IsMultiplayer() )
7 years ago
{
// scale up blood effect in multiplayer for better visibility
amount *= 2;
}
8 years ago
if( amount > 255 )
7 years ago
amount = 255;
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, origin );
WRITE_BYTE( TE_BLOODSPRITE );
WRITE_COORD( origin.x); // pos
WRITE_COORD( origin.y);
WRITE_COORD( origin.z);
WRITE_SHORT( g_sModelIndexBloodSpray ); // initial sprite model
WRITE_SHORT( g_sModelIndexBloodDrop ); // droplet sprite models
WRITE_BYTE( color ); // color index into host_basepal
WRITE_BYTE( Q_min( Q_max( 3, amount / 10 ), 16 ) ); // size
7 years ago
MESSAGE_END();
}
Vector UTIL_RandomBloodVector( void )
{
Vector direction;
8 years ago
direction.x = RANDOM_FLOAT( -1, 1 );
direction.y = RANDOM_FLOAT( -1, 1 );
direction.z = RANDOM_FLOAT( 0, 1 );
7 years ago
return direction;
}
void UTIL_BloodDecalTrace( TraceResult *pTrace, int bloodColor )
{
8 years ago
if( UTIL_ShouldShowBlood( bloodColor ) )
7 years ago
{
8 years ago
if( bloodColor == BLOOD_COLOR_RED )
UTIL_DecalTrace( pTrace, DECAL_BLOOD1 + RANDOM_LONG( 0, 5 ) );
7 years ago
else
8 years ago
UTIL_DecalTrace( pTrace, DECAL_YBLOOD1 + RANDOM_LONG( 0, 5 ) );
7 years ago
}
}
void UTIL_DecalTrace( TraceResult *pTrace, int decalNumber )
{
short entityIndex;
int index;
int message;
8 years ago
if( decalNumber < 0 )
7 years ago
return;
8 years ago
index = gDecals[decalNumber].index;
7 years ago
8 years ago
if( index < 0 )
7 years ago
return;
if( pTrace->flFraction == 1.0f )
7 years ago
return;
// Only decal BSP models
8 years ago
if( pTrace->pHit )
7 years ago
{
CBaseEntity *pEntity = CBaseEntity::Instance( pTrace->pHit );
8 years ago
if( pEntity && !pEntity->IsBSPModel() )
7 years ago
return;
entityIndex = ENTINDEX( pTrace->pHit );
}
8 years ago
else
7 years ago
entityIndex = 0;
message = TE_DECAL;
8 years ago
if( entityIndex != 0 )
7 years ago
{
8 years ago
if( index > 255 )
7 years ago
{
message = TE_DECALHIGH;
index -= 256;
}
}
else
{
message = TE_WORLDDECAL;
8 years ago
if( index > 255 )
7 years ago
{
message = TE_WORLDDECALHIGH;
index -= 256;
}
}
8 years ago
7 years ago
MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
WRITE_BYTE( message );
WRITE_COORD( pTrace->vecEndPos.x );
WRITE_COORD( pTrace->vecEndPos.y );
WRITE_COORD( pTrace->vecEndPos.z );
WRITE_BYTE( index );
8 years ago
if( entityIndex )
7 years ago
WRITE_SHORT( entityIndex );
MESSAGE_END();
}
/*
==============
UTIL_PlayerDecalTrace
A player is trying to apply his custom decal for the spray can.
Tell connected clients to display it, or use the default spray can decal
if the custom can't be loaded.
==============
*/
void UTIL_PlayerDecalTrace( TraceResult *pTrace, int playernum, int decalNumber, BOOL bIsCustom )
{
int index;
8 years ago
if( !bIsCustom )
7 years ago
{
8 years ago
if( decalNumber < 0 )
7 years ago
return;
8 years ago
index = gDecals[decalNumber].index;
if( index < 0 )
7 years ago
return;
}
else
index = decalNumber;
if( pTrace->flFraction == 1.0f )
7 years ago
return;
MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
WRITE_BYTE( TE_PLAYERDECAL );
8 years ago
WRITE_BYTE( playernum );
7 years ago
WRITE_COORD( pTrace->vecEndPos.x );
WRITE_COORD( pTrace->vecEndPos.y );
WRITE_COORD( pTrace->vecEndPos.z );
8 years ago
WRITE_SHORT( (short)ENTINDEX( pTrace->pHit ) );
7 years ago
WRITE_BYTE( index );
MESSAGE_END();
}
void UTIL_GunshotDecalTrace( TraceResult *pTrace, int decalNumber )
{
8 years ago
if( decalNumber < 0 )
7 years ago
return;
8 years ago
int index = gDecals[decalNumber].index;
if( index < 0 )
7 years ago
return;
if( pTrace->flFraction == 1.0f )
7 years ago
return;
MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pTrace->vecEndPos );
WRITE_BYTE( TE_GUNSHOTDECAL );
WRITE_COORD( pTrace->vecEndPos.x );
WRITE_COORD( pTrace->vecEndPos.y );
WRITE_COORD( pTrace->vecEndPos.z );
8 years ago
WRITE_SHORT( (short)ENTINDEX( pTrace->pHit ) );
7 years ago
WRITE_BYTE( index );
MESSAGE_END();
}
void UTIL_Sparks( const Vector &position )
{
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, position );
WRITE_BYTE( TE_SPARKS );
WRITE_COORD( position.x );
WRITE_COORD( position.y );
WRITE_COORD( position.z );
MESSAGE_END();
}
void UTIL_Ricochet( const Vector &position, float scale )
{
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, position );
WRITE_BYTE( TE_ARMOR_RICOCHET );
WRITE_COORD( position.x );
WRITE_COORD( position.y );
WRITE_COORD( position.z );
WRITE_BYTE( (int)( scale * 10.0f ) );
7 years ago
MESSAGE_END();
}
BOOL UTIL_TeamsMatch( const char *pTeamName1, const char *pTeamName2 )
{
// Everyone matches unless it's teamplay
8 years ago
if( !g_pGameRules->IsTeamplay() )
7 years ago
return TRUE;
// Both on a team?
8 years ago
if( *pTeamName1 != 0 && *pTeamName2 != 0 )
7 years ago
{
8 years ago
if( !stricmp( pTeamName1, pTeamName2 ) ) // Same Team?
7 years ago
return TRUE;
}
return FALSE;
}
//LRC - moved here from barney.cpp
BOOL UTIL_IsFacing( entvars_t *pevTest, const Vector &reference )
{
Vector vecDir = (reference - pevTest->origin);
vecDir.z = 0;
vecDir = vecDir.Normalize();
Vector forward, angle;
angle = pevTest->v_angle;
angle.x = 0;
UTIL_MakeVectorsPrivate( angle, forward, NULL, NULL );
// He's facing me, he meant it
if( DotProduct( forward, vecDir ) > 0.96f ) // +/- 15 degrees or so
7 years ago
{
return TRUE;
}
return FALSE;
}
void UTIL_StringToVector( float *pVector, const char *pString )
{
char *pstr, *pfront, tempString[128];
8 years ago
int j;
7 years ago
strcpy( tempString, pString );
pstr = pfront = tempString;
8 years ago
for( j = 0; j < 3; j++ ) // lifted from pr_edict.c
7 years ago
{
pVector[j] = atof( pfront );
8 years ago
while( *pstr && *pstr != ' ' )
7 years ago
pstr++;
if( !( *pstr ) )
7 years ago
break;
pstr++;
pfront = pstr;
}
8 years ago
if( j < 2 )
7 years ago
{
/*
ALERT( at_error, "Bad field in entity!! %s:%s == \"%s\"\n",
pkvd->szClassName, pkvd->szKeyName, pkvd->szValue );
*/
8 years ago
for( j = j + 1;j < 3; j++ )
7 years ago
pVector[j] = 0;
}
}
//LRC - randomized vectors of the form "0 0 0 .. 1 0 0"
void UTIL_StringToRandomVector( float *pVector, const char *pString )
{
char *pstr, *pfront, tempString[128];
int j;
float pAltVec[3];
strcpy( tempString, pString );
pstr = pfront = tempString;
for ( j = 0; j < 3; j++ ) // lifted from pr_edict.c
{
pVector[j] = atof( pfront );
while ( *pstr && *pstr != ' ' ) pstr++;
if (!*pstr) break;
pstr++;
pfront = pstr;
}
if (j < 2)
{
/*
ALERT( at_error, "Bad field in entity!! %s:%s == \"%s\"\n",
pkvd->szClassName, pkvd->szKeyName, pkvd->szValue );
*/
for (j = j+1;j < 3; j++)
pVector[j] = 0;
}
else if (*pstr == '.')
{
pstr++;
if (*pstr != '.') return;
pstr++;
if (*pstr != ' ') return;
UTIL_StringToVector(pAltVec, pstr);
pVector[0] = RANDOM_FLOAT( pVector[0], pAltVec[0] );
pVector[1] = RANDOM_FLOAT( pVector[1], pAltVec[1] );
pVector[2] = RANDOM_FLOAT( pVector[2], pAltVec[2] );
}
}
void UTIL_StringToIntArray( int *pVector, int count, const char *pString )
{
char *pstr, *pfront, tempString[128];
8 years ago
int j;
7 years ago
strcpy( tempString, pString );
pstr = pfront = tempString;
8 years ago
for( j = 0; j < count; j++ ) // lifted from pr_edict.c
7 years ago
{
pVector[j] = atoi( pfront );
8 years ago
while( *pstr && *pstr != ' ' )
7 years ago
pstr++;
8 years ago
if( !(*pstr) )
7 years ago
break;
pstr++;
pfront = pstr;
}
8 years ago
for( j++; j < count; j++ )
7 years ago
{
pVector[j] = 0;
}
}
Vector UTIL_ClampVectorToBox( const Vector &input, const Vector &clampSize )
{
Vector sourceVector = input;
8 years ago
if( sourceVector.x > clampSize.x )
7 years ago
sourceVector.x -= clampSize.x;
8 years ago
else if( sourceVector.x < -clampSize.x )
7 years ago
sourceVector.x += clampSize.x;
else
sourceVector.x = 0;
8 years ago
if( sourceVector.y > clampSize.y )
7 years ago
sourceVector.y -= clampSize.y;
8 years ago
else if( sourceVector.y < -clampSize.y )
7 years ago
sourceVector.y += clampSize.y;
else
sourceVector.y = 0;
8 years ago
if( sourceVector.z > clampSize.z )
7 years ago
sourceVector.z -= clampSize.z;
8 years ago
else if( sourceVector.z < -clampSize.z )
7 years ago
sourceVector.z += clampSize.z;
else
sourceVector.z = 0;
return sourceVector.Normalize();
}
float UTIL_WaterLevel( const Vector &position, float minz, float maxz )
{
Vector midUp = position;
midUp.z = minz;
8 years ago
if( UTIL_PointContents( midUp ) != CONTENTS_WATER )
7 years ago
return minz;
midUp.z = maxz;
8 years ago
if( UTIL_PointContents( midUp ) == CONTENTS_WATER )
7 years ago
return maxz;
float diff = maxz - minz;
while( diff > 1.0f )
7 years ago
{
midUp.z = minz + diff / 2.0f;
8 years ago
if( UTIL_PointContents( midUp ) == CONTENTS_WATER )
7 years ago
{
minz = midUp.z;
}
else
{
maxz = midUp.z;
}
diff = maxz - minz;
}
return midUp.z;
}
8 years ago
extern DLL_GLOBAL short g_sModelIndexBubbles;// holds the index for the bubbles model
7 years ago
void UTIL_Bubbles( Vector mins, Vector maxs, int count )
{
Vector mid = ( mins + maxs ) * 0.5f;
7 years ago
8 years ago
float flHeight = UTIL_WaterLevel( mid, mid.z, mid.z + 1024 );
7 years ago
flHeight = flHeight - mins.z;
MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, mid );
WRITE_BYTE( TE_BUBBLES );
WRITE_COORD( mins.x ); // mins
WRITE_COORD( mins.y );
WRITE_COORD( mins.z );
WRITE_COORD( maxs.x ); // maxz
WRITE_COORD( maxs.y );
WRITE_COORD( maxs.z );
WRITE_COORD( flHeight ); // height
WRITE_SHORT( g_sModelIndexBubbles );
WRITE_BYTE( count ); // count
WRITE_COORD( 8 ); // speed
MESSAGE_END();
}
void UTIL_BubbleTrail( Vector from, Vector to, int count )
{
8 years ago
float flHeight = UTIL_WaterLevel( from, from.z, from.z + 256 );
7 years ago
flHeight = flHeight - from.z;
8 years ago
if( flHeight < 8 )
7 years ago
{
8 years ago
flHeight = UTIL_WaterLevel( to, to.z, to.z + 256 );
7 years ago
flHeight = flHeight - to.z;
8 years ago
if( flHeight < 8 )
7 years ago
return;
// UNDONE: do a ploink sound
flHeight = flHeight + to.z - from.z;
}
8 years ago
if( count > 255 )
7 years ago
count = 255;
MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
WRITE_BYTE( TE_BUBBLETRAIL );
WRITE_COORD( from.x ); // mins
WRITE_COORD( from.y );
WRITE_COORD( from.z );
WRITE_COORD( to.x ); // maxz
WRITE_COORD( to.y );
WRITE_COORD( to.z );
WRITE_COORD( flHeight ); // height
WRITE_SHORT( g_sModelIndexBubbles );
WRITE_BYTE( count ); // count
WRITE_COORD( 8 ); // speed
MESSAGE_END();
}
void UTIL_Remove( CBaseEntity *pEntity )
{
8 years ago
if( !pEntity )
7 years ago
return;
pEntity->UpdateOnRemove();
pEntity->pev->flags |= FL_KILLME;
pEntity->pev->targetname = 0;
}
BOOL UTIL_IsValidEntity( edict_t *pent )
{
8 years ago
if( !pent || pent->free || ( pent->v.flags & FL_KILLME ) )
7 years ago
return FALSE;
return TRUE;
}
void UTIL_PrecacheOther( const char *szClassname )
{
edict_t *pent;
pent = CREATE_NAMED_ENTITY( MAKE_STRING( szClassname ) );
8 years ago
if( FNullEnt( pent ) )
7 years ago
{
8 years ago
ALERT( at_console, "NULL Ent in UTIL_PrecacheOther\n" );
7 years ago
return;
}
8 years ago
CBaseEntity *pEntity = CBaseEntity::Instance( VARS( pent ) );
if( pEntity )
pEntity->Precache();
REMOVE_ENTITY( pent );
7 years ago
}
//=========================================================
// UTIL_LogPrintf - Prints a logged message to console.
// Preceded by LOG: ( timestamp ) < message >
//=========================================================
void UTIL_LogPrintf( const char *fmt, ... )
7 years ago
{
8 years ago
va_list argptr;
static char string[1024];
7 years ago
8 years ago
va_start( argptr, fmt );
vsprintf( string, fmt, argptr );
va_end( argptr );
7 years ago
// Print to server console
ALERT( at_logged, "%s", string );
}
//=========================================================
// UTIL_DotPoints - returns the dot product of a line from
// src to check and vecdir.
//=========================================================
8 years ago
float UTIL_DotPoints( const Vector &vecSrc, const Vector &vecCheck, const Vector &vecDir )
7 years ago
{
8 years ago
Vector2D vec2LOS;
7 years ago
vec2LOS = ( vecCheck - vecSrc ).Make2D();
vec2LOS = vec2LOS.Normalize();
8 years ago
return DotProduct( vec2LOS, ( vecDir.Make2D() ) );
7 years ago
}
//=========================================================
// UTIL_StripToken - for redundant keynames
//=========================================================
void UTIL_StripToken( const char *pKey, char *pDest )
{
int i = 0;
8 years ago
while( pKey[i] && pKey[i] != '#' )
7 years ago
{
pDest[i] = pKey[i];
i++;
}
pDest[i] = 0;
}
const char* GetStringForUseType( USE_TYPE useType )
7 years ago
{
switch(useType)
{
case USE_ON: return "USE_ON";
case USE_OFF: return "USE_OFF";
case USE_TOGGLE: return "USE_TOGGLE";
case USE_KILL: return "USE_KILL";
case USE_NOT: return "USE_NOT";
default:
return "USE_UNKNOWN!?";
}
}
const char *GetStringForState( STATE state )
7 years ago
{
switch(state)
{
case STATE_ON: return "ON";
case STATE_OFF: return "OFF";
case STATE_TURN_ON: return "TURN ON";
case STATE_TURN_OFF: return "TURN OFF";
case STATE_IN_USE: return "IN USE";
default:
return "STATE_UNKNOWN!?";
}
}
// --------------------------------------------------------------
//
// CSave
//
// --------------------------------------------------------------
static int gSizes[FIELD_TYPECOUNT] =
7 years ago
{
sizeof(float), // FIELD_FLOAT
sizeof(string_t), // FIELD_STRING
7 years ago
sizeof(void*), // FIELD_ENTITY
sizeof(void*), // FIELD_CLASSPTR
sizeof(void*), // FIELD_EHANDLE
sizeof(void*), // FIELD_entvars_t
sizeof(void*), // FIELD_EDICT
sizeof(float) * 3, // FIELD_VECTOR
sizeof(float) * 3, // FIELD_POSITION_VECTOR
sizeof(void *), // FIELD_POINTER
sizeof(int), // FIELD_INTEGER
4 years ago
#if GNUC
7 years ago
sizeof(void *) * 2, // FIELD_FUNCTION
#else
sizeof(void *), // FIELD_FUNCTION
#endif
sizeof(int), // FIELD_BOOLEAN
sizeof(short), // FIELD_SHORT
sizeof(char), // FIELD_CHARACTER
sizeof(float), // FIELD_TIME
sizeof(int), // FIELD_MODELNAME
sizeof(int), // FIELD_SOUNDNAME
};
// entities has different store size
static int gInputSizes[FIELD_TYPECOUNT] =
7 years ago
{
sizeof(float), // FIELD_FLOAT
sizeof(string_t), // FIELD_STRING
7 years ago
sizeof(int), // FIELD_ENTITY
sizeof(int), // FIELD_CLASSPTR
sizeof(int), // FIELD_EHANDLE
sizeof(int), // FIELD_entvars_t
sizeof(int), // FIELD_EDICT
8 years ago
sizeof(float) * 3, // FIELD_VECTOR
sizeof(float) * 3, // FIELD_POSITION_VECTOR
7 years ago
sizeof(void *), // FIELD_POINTER
7 years ago
sizeof(int), // FIELD_INTEGER
4 years ago
#if GNUC
7 years ago
sizeof(void *) * 2, // FIELD_FUNCTION
#else
7 years ago
sizeof(void *), // FIELD_FUNCTION
#endif
7 years ago
sizeof(int), // FIELD_BOOLEAN
sizeof(short), // FIELD_SHORT
sizeof(char), // FIELD_CHARACTER
sizeof(float), // FIELD_TIME
sizeof(int), // FIELD_MODELNAME
sizeof(int), // FIELD_SOUNDNAME
};
// Base class includes common SAVERESTOREDATA pointer, and manages the entity table
8 years ago
CSaveRestoreBuffer::CSaveRestoreBuffer( void )
7 years ago
{
m_pdata = NULL;
}
8 years ago
CSaveRestoreBuffer::CSaveRestoreBuffer( SAVERESTOREDATA *pdata )
7 years ago
{
m_pdata = pdata;
}
8 years ago
CSaveRestoreBuffer::~CSaveRestoreBuffer( void )
7 years ago
{
}
8 years ago
int CSaveRestoreBuffer::EntityIndex( CBaseEntity *pEntity )
7 years ago
{
8 years ago
if( pEntity == NULL )
7 years ago
return -1;
return EntityIndex( pEntity->pev );
}
8 years ago
int CSaveRestoreBuffer::EntityIndex( entvars_t *pevLookup )
7 years ago
{
8 years ago
if( pevLookup == NULL )
7 years ago
return -1;
return EntityIndex( ENT( pevLookup ) );
}
8 years ago
int CSaveRestoreBuffer::EntityIndex( EOFFSET eoLookup )
7 years ago
{
return EntityIndex( ENT( eoLookup ) );
}
8 years ago
int CSaveRestoreBuffer::EntityIndex( edict_t *pentLookup )
7 years ago
{
8 years ago
if( !m_pdata || pentLookup == NULL )
7 years ago
return -1;
int i;
ENTITYTABLE *pTable;
8 years ago
for( i = 0; i < m_pdata->tableCount; i++ )
7 years ago
{
pTable = m_pdata->pTable + i;
8 years ago
if( pTable->pent == pentLookup )
7 years ago
return i;
}
return -1;
}
8 years ago
edict_t *CSaveRestoreBuffer::EntityFromIndex( int entityIndex )
7 years ago
{
8 years ago
if( !m_pdata || entityIndex < 0 )
7 years ago
return NULL;
int i;
ENTITYTABLE *pTable;
8 years ago
for( i = 0; i < m_pdata->tableCount; i++ )
7 years ago
{
pTable = m_pdata->pTable + i;
8 years ago
if( pTable->id == entityIndex )
7 years ago
return pTable->pent;
}
return NULL;
}
8 years ago
int CSaveRestoreBuffer::EntityFlagsSet( int entityIndex, int flags )
7 years ago
{
8 years ago
if( !m_pdata || entityIndex < 0 )
7 years ago
return 0;
8 years ago
if( entityIndex > m_pdata->tableCount )
7 years ago
return 0;
8 years ago
m_pdata->pTable[entityIndex].flags |= flags;
7 years ago
8 years ago
return m_pdata->pTable[entityIndex].flags;
7 years ago
}
8 years ago
void CSaveRestoreBuffer::BufferRewind( int size )
7 years ago
{
8 years ago
if( !m_pdata )
7 years ago
return;
8 years ago
if( m_pdata->size < size )
7 years ago
size = m_pdata->size;
m_pdata->pCurrentData -= size;
m_pdata->size -= size;
}
3 years ago
#if !_WIN32 && !__WATCOMC__
7 years ago
extern "C" {
8 years ago
unsigned _rotr( unsigned val, int shift )
7 years ago
{
5 years ago
unsigned lobit; /* non-zero means lo bit set */
unsigned num = val; /* number to rotate */
7 years ago
shift &= 0x1f; /* modulo 32 -- this will also make
negative shifts work */
7 years ago
while( shift-- )
{
lobit = num & 1; /* get high bit */
num >>= 1; /* shift right one bit */
8 years ago
if( lobit )
num |= 0x80000000; /* set hi bit if lo bit was set */
}
7 years ago
return num;
7 years ago
}
}
#endif
8 years ago
unsigned int CSaveRestoreBuffer::HashString( const char *pszToken )
7 years ago
{
8 years ago
unsigned int hash = 0;
7 years ago
8 years ago
while( *pszToken )
7 years ago
hash = _rotr( hash, 4 ) ^ *pszToken++;
return hash;
}
8 years ago
unsigned short CSaveRestoreBuffer::TokenHash( const char *pszToken )
7 years ago
{
8 years ago
unsigned short hash = (unsigned short)( HashString( pszToken ) % (unsigned)m_pdata->tokenCount );
7 years ago
#if _DEBUG
static int tokensparsed = 0;
tokensparsed++;
8 years ago
if( !m_pdata->tokenCount || !m_pdata->pTokens )
7 years ago
ALERT( at_error, "No token table array in TokenHash()!" );
#endif
8 years ago
for( int i = 0; i < m_pdata->tokenCount; i++ )
7 years ago
{
#if _DEBUG
static qboolean beentheredonethat = FALSE;
8 years ago
if( i > 50 && !beentheredonethat )
7 years ago
{
beentheredonethat = TRUE;
ALERT( at_error, "CSaveRestoreBuffer :: TokenHash() is getting too full!" );
}
#endif
8 years ago
int index = hash + i;
if( index >= m_pdata->tokenCount )
7 years ago
index -= m_pdata->tokenCount;
8 years ago
if( !m_pdata->pTokens[index] || strcmp( pszToken, m_pdata->pTokens[index] ) == 0 )
7 years ago
{
m_pdata->pTokens[index] = (char *)pszToken;
return index;
}
}
8 years ago
7 years ago
// Token hash table full!!!
// [Consider doing overflow table(s) after the main table & limiting linear hash table search]
ALERT( at_error, "CSaveRestoreBuffer :: TokenHash() is COMPLETELY FULL!" );
return 0;
}
8 years ago
void CSave::WriteData( const char *pname, int size, const char *pdata )
7 years ago
{
BufferField( pname, size, pdata );
}
8 years ago
void CSave::WriteShort( const char *pname, const short *data, int count )
7 years ago
{
BufferField( pname, sizeof(short) * count, (const char *)data );
}
8 years ago
void CSave::WriteInt( const char *pname, const int *data, int count )
7 years ago
{
BufferField( pname, sizeof(int) * count, (const char *)data );
}
8 years ago
void CSave::WriteFloat( const char *pname, const float *data, int count )
7 years ago
{
BufferField( pname, sizeof(float) * count, (const char *)data );
}
8 years ago
void CSave::WriteTime( const char *pname, const float *data, int count )
7 years ago
{
int i;
8 years ago
//Vector tmp, input;
7 years ago
BufferHeader( pname, sizeof(float) * count );
8 years ago
for( i = 0; i < count; i++ )
7 years ago
{
float tmp = data[0];
// Always encode time as a delta from the current time so it can be re-based if loaded in a new level
// Times of 0 are never written to the file, so they will be restored as 0, not a relative time
8 years ago
if( m_pdata )
7 years ago
tmp -= m_pdata->time;
BufferData( (const char *)&tmp, sizeof(float) );
data ++;
}
}
8 years ago
void CSave::WriteString( const char *pname, const char *pdata )
7 years ago
{
4 years ago
#if TOKENIZE
8 years ago
short token = (short)TokenHash( pdata );
7 years ago
WriteShort( pname, &token, 1 );
#else
8 years ago
BufferField( pname, strlen( pdata ) + 1, pdata );
7 years ago
#endif
}
8 years ago
void CSave::WriteString( const char *pname, const int *stringId, int count )
7 years ago
{
int i, size;
4 years ago
#if TOKENIZE
8 years ago
short token = (short)TokenHash( STRING( *stringId ) );
7 years ago
WriteShort( pname, &token, 1 );
#else
#if 0
8 years ago
if( count != 1 )
7 years ago
ALERT( at_error, "No string arrays!\n" );
WriteString( pname, STRING( *stringId ) );
7 years ago
#endif
size = 0;
8 years ago
for( i = 0; i < count; i++ )
7 years ago
size += strlen( STRING( stringId[i] ) ) + 1;
BufferHeader( pname, size );
8 years ago
for( i = 0; i < count; i++ )
7 years ago
{
8 years ago
const char *pString = STRING( stringId[i] );
BufferData( pString, strlen( pString ) + 1 );
7 years ago
}
#endif
}
8 years ago
void CSave::WriteVector( const char *pname, const Vector &value )
7 years ago
{
WriteVector( pname, &value.x, 1 );
}
8 years ago
void CSave::WriteVector( const char *pname, const float *value, int count )
7 years ago
{
BufferHeader( pname, sizeof(float) * 3 * count );
BufferData( (const char *)value, sizeof(float) * 3 * count );
}
8 years ago
void CSave::WritePositionVector( const char *pname, const Vector &value )
7 years ago
{
8 years ago
if( m_pdata && m_pdata->fUseLandmark )
7 years ago
{
Vector tmp = value - m_pdata->vecLandmarkOffset;
WriteVector( pname, tmp );
}
WriteVector( pname, value );
}
8 years ago
void CSave::WritePositionVector( const char *pname, const float *value, int count )
7 years ago
{
int i;
8 years ago
//Vector tmp, input;
7 years ago
BufferHeader( pname, sizeof(float) * 3 * count );
8 years ago
for( i = 0; i < count; i++ )
7 years ago
{
Vector tmp( value[0], value[1], value[2] );
8 years ago
if( m_pdata && m_pdata->fUseLandmark )
7 years ago
tmp = tmp - m_pdata->vecLandmarkOffset;
BufferData( (const char *)&tmp.x, sizeof(float) * 3 );
value += 3;
}
}
void CSave :: WriteFunction( const char* cname, const char *pname, void **data, int count )
7 years ago
{
const char *functionName;
functionName = NAME_FOR_FUNCTION( *data );
8 years ago
if( functionName )
BufferField( pname, strlen( functionName ) + 1, functionName );
7 years ago
else
ALERT( at_error, "Member \"%s\" of \"%s\" contains an invalid function pointer %p!", pname, cname, *data );
}
void EntvarsKeyvalue( entvars_t *pev, KeyValueData *pkvd )
{
int i;
8 years ago
TYPEDESCRIPTION *pField;
7 years ago
for( i = 0; i < (int)ENTVARS_COUNT; i++ )
7 years ago
{
pField = &gEntvarsDescription[i];
8 years ago
if( !stricmp( pField->fieldName, pkvd->szKeyName ) )
7 years ago
{
switch( pField->fieldType )
{
case FIELD_MODELNAME:
case FIELD_SOUNDNAME:
case FIELD_STRING:
( *(string_t *)( (char *)pev + pField->fieldOffset ) ) = ALLOC_STRING( pkvd->szValue );
7 years ago
break;
case FIELD_TIME:
case FIELD_FLOAT:
8 years ago
( *(float *)( (char *)pev + pField->fieldOffset ) ) = atof( pkvd->szValue );
7 years ago
break;
case FIELD_INTEGER:
8 years ago
( *(int *)( (char *)pev + pField->fieldOffset ) ) = atoi( pkvd->szValue );
7 years ago
break;
case FIELD_POSITION_VECTOR:
case FIELD_VECTOR:
8 years ago
UTIL_StringToVector( (float *)( (char *)pev + pField->fieldOffset ), pkvd->szValue );
7 years ago
break;
default:
case FIELD_EVARS:
case FIELD_CLASSPTR:
case FIELD_EDICT:
case FIELD_ENTITY:
case FIELD_POINTER:
ALERT( at_error, "Bad field in entity!!\n" );
break;
}
pkvd->fHandled = TRUE;
return;
}
}
}
8 years ago
int CSave::WriteEntVars( const char *pname, entvars_t *pev )
7 years ago
{
if (pev->targetname)
return WriteFields( STRING(pev->targetname), pname, pev, gEntvarsDescription, ENTVARS_COUNT );
else
return WriteFields( STRING(pev->classname), pname, pev, gEntvarsDescription, ENTVARS_COUNT );
}
int CSave :: WriteFields( const char *cname, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount )
{
8 years ago
int i, j, actualCount, emptyCount;
7 years ago
TYPEDESCRIPTION *pTest;
8 years ago
int entityArray[MAX_ENTITYARRAY];
7 years ago
// Precalculate the number of empty fields
emptyCount = 0;
8 years ago
for( i = 0; i < fieldCount; i++ )
7 years ago
{
void *pOutputData;
8 years ago
pOutputData = ( (char *)pBaseData + pFields[i].fieldOffset );
if( DataEmpty( (const char *)pOutputData, pFields[i].fieldSize * gSizes[pFields[i].fieldType] ) )
7 years ago
emptyCount++;
}
// Empty fields will not be written, write out the actual number of fields to be written
actualCount = fieldCount - emptyCount;
WriteInt( pname, &actualCount, 1 );
8 years ago
for( i = 0; i < fieldCount; i++ )
7 years ago
{
void *pOutputData;
8 years ago
pTest = &pFields[i];
pOutputData = ( (char *)pBaseData + pTest->fieldOffset );
7 years ago
// UNDONE: Must we do this twice?
8 years ago
if( DataEmpty( (const char *)pOutputData, pTest->fieldSize * gSizes[pTest->fieldType] ) )
7 years ago
continue;
switch( pTest->fieldType )
{
case FIELD_FLOAT:
WriteFloat( pTest->fieldName, (float *)pOutputData, pTest->fieldSize );
break;
7 years ago
case FIELD_TIME:
WriteTime( pTest->fieldName, (float *)pOutputData, pTest->fieldSize );
break;
7 years ago
case FIELD_MODELNAME:
case FIELD_SOUNDNAME:
case FIELD_STRING:
WriteString( pTest->fieldName, (string_t *)pOutputData, pTest->fieldSize );
break;
7 years ago
case FIELD_CLASSPTR:
case FIELD_EVARS:
case FIELD_EDICT:
case FIELD_ENTITY:
case FIELD_EHANDLE:
8 years ago
if( pTest->fieldSize > MAX_ENTITYARRAY )
7 years ago
ALERT( at_error, "Can't save more than %d entities in an array!!!\n", MAX_ENTITYARRAY );
8 years ago
for( j = 0; j < pTest->fieldSize; j++ )
7 years ago
{
switch( pTest->fieldType )
{
case FIELD_EVARS:
8 years ago
entityArray[j] = EntityIndex( ( (entvars_t **)pOutputData )[j] );
break;
7 years ago
case FIELD_CLASSPTR:
8 years ago
entityArray[j] = EntityIndex( ( (CBaseEntity **)pOutputData )[j] );
break;
7 years ago
case FIELD_EDICT:
8 years ago
entityArray[j] = EntityIndex( ( (edict_t **)pOutputData )[j] );
break;
7 years ago
case FIELD_ENTITY:
8 years ago
entityArray[j] = EntityIndex( ( (EOFFSET *)pOutputData )[j] );
break;
7 years ago
case FIELD_EHANDLE:
8 years ago
entityArray[j] = EntityIndex( (CBaseEntity *)( ( (EHANDLE *)pOutputData)[j] ) );
break;
7 years ago
default:
break;
7 years ago
}
}
WriteInt( pTest->fieldName, entityArray, pTest->fieldSize );
break;
7 years ago
case FIELD_POSITION_VECTOR:
WritePositionVector( pTest->fieldName, (float *)pOutputData, pTest->fieldSize );
break;
7 years ago
case FIELD_VECTOR:
WriteVector( pTest->fieldName, (float *)pOutputData, pTest->fieldSize );
break;
7 years ago
case FIELD_BOOLEAN:
case FIELD_INTEGER:
WriteInt( pTest->fieldName, (int *)pOutputData, pTest->fieldSize );
break;
7 years ago
case FIELD_SHORT:
8 years ago
WriteData( pTest->fieldName, 2 * pTest->fieldSize, ( (char *)pOutputData ) );
break;
7 years ago
case FIELD_CHARACTER:
8 years ago
WriteData( pTest->fieldName, pTest->fieldSize, ( (char *)pOutputData ) );
break;
7 years ago
// For now, just write the address out, we're not going to change memory while doing this yet!
case FIELD_POINTER:
WriteInt( pTest->fieldName, (int *)(char *)pOutputData, pTest->fieldSize );
break;
7 years ago
case FIELD_FUNCTION:
WriteFunction( cname, pTest->fieldName, (void **)pOutputData, pTest->fieldSize );
break;
7 years ago
default:
ALERT( at_error, "Bad field type\n" );
}
}
return 1;
}
8 years ago
void CSave::BufferString( char *pdata, int len )
7 years ago
{
char c = 0;
BufferData( pdata, len ); // Write the string
BufferData( &c, 1 ); // Write a null terminator
}
8 years ago
int CSave::DataEmpty( const char *pdata, int size )
7 years ago
{
8 years ago
for( int i = 0; i < size; i++ )
7 years ago
{
8 years ago
if( pdata[i] )
7 years ago
return 0;
}
return 1;
}
8 years ago
void CSave::BufferField( const char *pname, int size, const char *pdata )
7 years ago
{
BufferHeader( pname, size );
BufferData( pdata, size );
}
8 years ago
void CSave::BufferHeader( const char *pname, int size )
7 years ago
{
8 years ago
short hashvalue = TokenHash( pname );
if( size > 1 << ( sizeof(short) * 8 ) )
7 years ago
ALERT( at_error, "CSave :: BufferHeader() size parameter exceeds 'short'!" );
BufferData( (const char *)&size, sizeof(short) );
BufferData( (const char *)&hashvalue, sizeof(short) );
}
8 years ago
void CSave::BufferData( const char *pdata, int size )
7 years ago
{
8 years ago
if( !m_pdata )
7 years ago
return;
8 years ago
if( m_pdata->size + size > m_pdata->bufferSize )
7 years ago
{
ALERT( at_error, "Save/Restore overflow!" );
m_pdata->size = m_pdata->bufferSize;
return;
}
memcpy( m_pdata->pCurrentData, pdata, size );
m_pdata->pCurrentData += size;
m_pdata->size += size;
}
// --------------------------------------------------------------
//
// CRestore
//
// --------------------------------------------------------------
int CRestore::ReadField( void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount, int startField, int size, char *pName, void *pData )
{
int i, j, stringCount, fieldNumber, entityIndex;
TYPEDESCRIPTION *pTest;
8 years ago
float time, timeData;
Vector position;
7 years ago
edict_t *pent;
8 years ago
char *pString;
7 years ago
time = 0;
8 years ago
position = Vector( 0, 0, 0 );
7 years ago
8 years ago
if( m_pdata )
7 years ago
{
time = m_pdata->time;
8 years ago
if( m_pdata->fUseLandmark )
7 years ago
position = m_pdata->vecLandmarkOffset;
}
8 years ago
for( i = 0; i < fieldCount; i++ )
7 years ago
{
8 years ago
fieldNumber = ( i + startField ) % fieldCount;
pTest = &pFields[fieldNumber];
if( !stricmp( pTest->fieldName, pName ) )
7 years ago
{
8 years ago
if( !m_global || !(pTest->flags & FTYPEDESC_GLOBAL ) )
7 years ago
{
8 years ago
for( j = 0; j < pTest->fieldSize; j++ )
7 years ago
{
8 years ago
void *pOutputData = ( (char *)pBaseData + pTest->fieldOffset + ( j * gSizes[pTest->fieldType] ) );
7 years ago
void *pInputData = (char *)pData + j * gInputSizes[pTest->fieldType];
7 years ago
switch( pTest->fieldType )
{
case FIELD_TIME:
4 years ago
#if __VFP_FP__
8 years ago
memcpy( &timeData, pInputData, 4 );
7 years ago
// Re-base time variables
timeData += time;
8 years ago
memcpy( pOutputData, &timeData, 4 );
7 years ago
#else
timeData = *(float *)pInputData;
// Re-base time variables
timeData += time;
8 years ago
*( (float *)pOutputData ) = timeData;
7 years ago
#endif
break;
7 years ago
case FIELD_FLOAT:
8 years ago
memcpy( pOutputData, pInputData, 4 );
break;
7 years ago
case FIELD_MODELNAME:
case FIELD_SOUNDNAME:
case FIELD_STRING:
// Skip over j strings
pString = (char *)pData;
8 years ago
for( stringCount = 0; stringCount < j; stringCount++ )
7 years ago
{
8 years ago
while( *pString )
7 years ago
pString++;
pString++;
}
pInputData = pString;
if( ( (char *)pInputData )[0] == '\0' )
*( (string_t *)pOutputData ) = 0;
7 years ago
else
{
string_t string;
7 years ago
string = ALLOC_STRING( (char *)pInputData );
*( (string_t *)pOutputData ) = string;
8 years ago
if( !FStringNull( string ) && m_precache )
7 years ago
{
8 years ago
if( pTest->fieldType == FIELD_MODELNAME )
PRECACHE_MODEL( STRING( string ) );
8 years ago
else if( pTest->fieldType == FIELD_SOUNDNAME )
PRECACHE_SOUND( STRING( string ) );
7 years ago
}
}
break;
7 years ago
case FIELD_EVARS:
entityIndex = *( int *)pInputData;
pent = EntityFromIndex( entityIndex );
8 years ago
if( pent )
*( (entvars_t **)pOutputData ) = VARS( pent );
7 years ago
else
8 years ago
*( (entvars_t **)pOutputData ) = NULL;
break;
7 years ago
case FIELD_CLASSPTR:
entityIndex = *( int *)pInputData;
pent = EntityFromIndex( entityIndex );
8 years ago
if( pent )
*( (CBaseEntity **)pOutputData ) = CBaseEntity::Instance( pent );
7 years ago
else
{
8 years ago
*( (CBaseEntity **)pOutputData ) = NULL;
7 years ago
if (entityIndex != -1) ALERT(at_console, "## Restore: invalid entitynum %d\n", entityIndex);
}
break;
7 years ago
case FIELD_EDICT:
8 years ago
entityIndex = *(int *)pInputData;
7 years ago
pent = EntityFromIndex( entityIndex );
8 years ago
*( (edict_t **)pOutputData ) = pent;
break;
7 years ago
case FIELD_EHANDLE:
// Input and Output sizes are different!
8 years ago
pOutputData = (char *)pOutputData + j * ( sizeof(EHANDLE) - gSizes[pTest->fieldType] );
entityIndex = *(int *)pInputData;
7 years ago
pent = EntityFromIndex( entityIndex );
8 years ago
if( pent )
*( (EHANDLE *)pOutputData ) = CBaseEntity::Instance( pent );
7 years ago
else
8 years ago
*( (EHANDLE *)pOutputData ) = NULL;
break;
7 years ago
case FIELD_ENTITY:
8 years ago
entityIndex = *(int *)pInputData;
7 years ago
pent = EntityFromIndex( entityIndex );
8 years ago
if( pent )
*( (EOFFSET *)pOutputData ) = OFFSET( pent );
7 years ago
else
8 years ago
*( (EOFFSET *)pOutputData ) = 0;
break;
7 years ago
case FIELD_VECTOR:
4 years ago
#if __VFP_FP__
memcpy( pOutputData, pInputData, sizeof( Vector ) );
#else
8 years ago
( (float *)pOutputData )[0] = ( (float *)pInputData )[0];
( (float *)pOutputData )[1] = ( (float *)pInputData )[1];
( (float *)pOutputData )[2] = ( (float *)pInputData )[2];
#endif
break;
7 years ago
case FIELD_POSITION_VECTOR:
4 years ago
#if __VFP_FP__
{
Vector tmp;
memcpy( &tmp, pInputData, sizeof( Vector ) );
8 years ago
tmp = tmp + position;
memcpy( pOutputData, &tmp, sizeof( Vector ) );
}
7 years ago
#else
8 years ago
( (float *)pOutputData )[0] = ( (float *)pInputData )[0] + position.x;
( (float *)pOutputData )[1] = ( (float *)pInputData )[1] + position.y;
( (float *)pOutputData )[2] = ( (float *)pInputData )[2] + position.z;
7 years ago
#endif
break;
7 years ago
case FIELD_BOOLEAN:
case FIELD_INTEGER:
8 years ago
*( (int *)pOutputData ) = *(int *)pInputData;
break;
7 years ago
case FIELD_SHORT:
8 years ago
*( (short *)pOutputData ) = *(short *)pInputData;
break;
7 years ago
case FIELD_CHARACTER:
8 years ago
*( (char *)pOutputData ) = *(char *)pInputData;
break;
7 years ago
case FIELD_POINTER:
8 years ago
*( (void**)pOutputData ) = *(void **)pInputData;
break;
7 years ago
case FIELD_FUNCTION:
if( ( (char *)pInputData )[0] == '\0' )
8 years ago
*( (void**)pOutputData ) = 0;
7 years ago
else
*( (void**)pOutputData ) = (void*)FUNCTION_FROM_NAME( (char *)pInputData );
break;
7 years ago
default:
ALERT( at_error, "Bad field type\n" );
}
}
}
#if 0
else
{
ALERT( at_console, "Skipping global field %s\n", pName );
7 years ago
}
#endif
return fieldNumber;
}
}
return -1;
}
int CRestore::ReadEntVars( const char *pname, entvars_t *pev )
{
return ReadFields( pname, pev, gEntvarsDescription, ENTVARS_COUNT );
}
int CRestore::ReadFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount )
{
8 years ago
unsigned short i, token;
int lastField, fileCount;
HEADER header;
7 years ago
i = ReadShort();
ASSERT( i == sizeof(int) ); // First entry should be an int
token = ReadShort();
// Check the struct name
8 years ago
if( token != TokenHash(pname) ) // Field Set marker
7 years ago
{
//ALERT( at_error, "Expected %s found %s!\n", pname, BufferPointer() );
8 years ago
BufferRewind( 2 * sizeof( short ) );
7 years ago
return 0;
}
// Skip over the struct name
fileCount = ReadInt(); // Read field count
lastField = 0; // Make searches faster, most data is read/written in the same order
// Clear out base data
8 years ago
for( i = 0; i < fieldCount; i++ )
7 years ago
{
// Don't clear global fields
8 years ago
if( !m_global || !( pFields[i].flags & FTYPEDESC_GLOBAL ) )
memset( ( (char *)pBaseData + pFields[i].fieldOffset ), 0, pFields[i].fieldSize * gSizes[pFields[i].fieldType] );
7 years ago
}
8 years ago
for( i = 0; i < fileCount; i++ )
7 years ago
{
BufferReadHeader( &header );
lastField = ReadField( pBaseData, pFields, fieldCount, lastField, header.size, m_pdata->pTokens[header.token], header.pData );
lastField++;
}
return 1;
}
void CRestore::BufferReadHeader( HEADER *pheader )
{
ASSERT( pheader!=NULL );
pheader->size = ReadShort(); // Read field size
pheader->token = ReadShort(); // Read field name token
pheader->pData = BufferPointer(); // Field Data is next
BufferSkipBytes( pheader->size ); // Advance to next field
}
short CRestore::ReadShort( void )
7 years ago
{
short tmp = 0;
BufferReadBytes( (char *)&tmp, sizeof(short) );
return tmp;
}
int CRestore::ReadInt( void )
7 years ago
{
int tmp = 0;
BufferReadBytes( (char *)&tmp, sizeof(int) );
return tmp;
}
int CRestore::ReadNamedInt( const char *pName )
{
HEADER header;
BufferReadHeader( &header );
8 years ago
return ( (int *)header.pData )[0];
7 years ago
}
char *CRestore::ReadNamedString( const char *pName )
{
HEADER header;
BufferReadHeader( &header );
4 years ago
#if TOKENIZE
8 years ago
return (char *)( m_pdata->pTokens[*(short *)header.pData] );
7 years ago
#else
return (char *)header.pData;
#endif
}
char *CRestore::BufferPointer( void )
{
8 years ago
if( !m_pdata )
7 years ago
return NULL;
return m_pdata->pCurrentData;
}
void CRestore::BufferReadBytes( char *pOutput, int size )
{
ASSERT( m_pdata !=NULL );
8 years ago
if( !m_pdata || Empty() )
7 years ago
return;
8 years ago
if( ( m_pdata->size + size ) > m_pdata->bufferSize )
7 years ago
{
ALERT( at_error, "Restore overflow!" );
m_pdata->size = m_pdata->bufferSize;
return;
}
8 years ago
if( pOutput )
7 years ago
memcpy( pOutput, m_pdata->pCurrentData, size );
m_pdata->pCurrentData += size;
m_pdata->size += size;
}
void CRestore::BufferSkipBytes( int bytes )
{
BufferReadBytes( NULL, bytes );
}
int CRestore::BufferSkipZString( void )
{
char *pszSearch;
8 years ago
int len;
7 years ago
8 years ago
if( !m_pdata )
7 years ago
return 0;
int maxLen = m_pdata->bufferSize - m_pdata->size;
len = 0;
pszSearch = m_pdata->pCurrentData;
8 years ago
while( *pszSearch++ && len < maxLen )
7 years ago
len++;
len++;
BufferSkipBytes( len );
return len;
}
int CRestore::BufferCheckZString( const char *string )
7 years ago
{
8 years ago
if( !m_pdata )
7 years ago
return 0;
int maxLen = m_pdata->bufferSize - m_pdata->size;
int len = strlen( string );
8 years ago
if( len <= maxLen )
7 years ago
{
8 years ago
if( !strncmp( string, m_pdata->pCurrentData, len ) )
7 years ago
return 1;
}
return 0;
}