This repository has been archived on 2022-06-27. You can view files and clone it, but cannot push or open issues or pull requests.
Xash3DArchive/engine/client/cl_game.c

985 lines
19 KiB
C
Raw Normal View History

2008-12-25 22:00:00 +01:00
//=======================================================================
// Copyright XashXT Group 2008 <20>
// cl_game.c - client dlls interaction
//=======================================================================
#include "common.h"
#include "client.h"
#include "byteorder.h"
#include "matrix_lib.h"
#include "com_library.h"
#include "const.h"
/*
====================
CL_GetClientEntity
Render callback for studio models
====================
*/
2009-01-03 22:00:00 +01:00
edict_t *CL_GetEdictByIndex( int index )
2008-12-25 22:00:00 +01:00
{
2009-01-03 22:00:00 +01:00
if( index < 0 || index > clgame.numEntities )
{
if( index == -1 ) return &cl.viewent;
MsgDev( D_ERROR, "CL_GetEntityByIndex: invalid entindex %i\n", index );
return NULL;
}
return EDICT_NUM( index );
2008-12-25 22:00:00 +01:00
}
/*
====================
CL_GetLocalPlayer
Render callback for studio models
====================
*/
2009-01-03 22:00:00 +01:00
edict_t *CL_GetLocalPlayer( void )
2008-12-25 22:00:00 +01:00
{
2009-01-03 22:00:00 +01:00
return EDICT_NUM( cl.playernum + 1 );
2008-12-25 22:00:00 +01:00
}
/*
====================
CL_GetMaxlients
Render callback for studio models
====================
*/
int CL_GetMaxClients( void )
{
return com.atoi( cl.configstrings[CS_MAXCLIENTS] );
}
/*
================
CL_FadeColor
================
*/
float *CL_FadeColor( float starttime, float endtime )
{
static vec4_t color;
float time, fade_time;
if( starttime == 0 ) return NULL;
time = (cls.realtime * 0.001f) - starttime;
if( time >= endtime ) return NULL;
// fade time is 1/4 of endtime
fade_time = endtime / 4;
fade_time = bound( 0.3f, fade_time, 10.0f );
// fade out
if((endtime - time) < fade_time)
color[3] = (endtime - time) * 1.0f / fade_time;
else color[3] = 1.0;
color[0] = color[1] = color[2] = 1.0f;
return color;
}
2008-12-26 22:00:00 +01:00
void CL_DrawHUD( int state )
2008-12-25 22:00:00 +01:00
{
2008-12-26 22:00:00 +01:00
cls.dllFuncs.pfnRedraw( cl.time * 0.001f, state );
2008-12-25 22:00:00 +01:00
}
void CL_CopyTraceResult( TraceResult *out, trace_t trace )
{
if( !out ) return;
out->fAllSolid = trace.allsolid;
out->fStartSolid = trace.startsolid;
out->fStartStuck = trace.startstuck;
out->flFraction = trace.fraction;
out->iStartContents = trace.startcontents;
out->iContents = trace.contents;
out->iHitgroup = trace.hitgroup;
out->flPlaneDist = trace.plane.dist;
VectorCopy( trace.endpos, out->vecEndPos );
VectorCopy( trace.plane.normal, out->vecPlaneNormal );
if( trace.surface )
out->pTexName = trace.surface->name;
else out->pTexName = NULL;
out->pHit = trace.ent;
}
2008-12-26 22:00:00 +01:00
static void CL_CreateUserMessage( int lastnum, const char *szMsgName, int svc_num, int iSize, pfnUserMsgHook pfn )
2008-12-25 22:00:00 +01:00
{
user_message_t *msg;
2008-12-26 22:00:00 +01:00
if( lastnum == clgame.numMessages )
2008-12-25 22:00:00 +01:00
{
2008-12-26 22:00:00 +01:00
if( clgame.numMessages == MAX_USER_MESSAGES )
{
MsgDev( D_ERROR, "CL_CreateUserMessage: user messages limit is out\n" );
return;
}
clgame.numMessages++;
2008-12-25 22:00:00 +01:00
}
2008-12-26 22:00:00 +01:00
msg = clgame.msg[lastnum];
2008-12-25 22:00:00 +01:00
// clear existing or allocate new one
if( msg ) Mem_Set( msg, 0, sizeof( *msg ));
2008-12-26 22:00:00 +01:00
else msg = clgame.msg[lastnum] = Mem_Alloc( cls.mempool, sizeof( *msg ));
com.strncpy( msg->name, szMsgName, CS_SIZE );
msg->number = svc_num;
msg->size = iSize;
msg->func = pfn;
}
2008-12-25 22:00:00 +01:00
2008-12-26 22:00:00 +01:00
void CL_LinkUserMessage( char *pszName, const int svc_num )
{
user_message_t *msg;
char *end;
char msgName[CS_SIZE];
int i, msgSize;
if( !pszName || !*pszName ) return; // ignore blank names
com.strncpy( msgName, pszName, CS_SIZE );
end = com.strchr( msgName, '@' );
2008-12-25 22:00:00 +01:00
if( !end )
{
2008-12-26 22:00:00 +01:00
MsgDev( D_ERROR, "CL_LinkUserMessage: can't register message %s\n", msgName );
2008-12-25 22:00:00 +01:00
return;
}
2008-12-26 22:00:00 +01:00
msgSize = com.atoi( end + 1 );
msgName[end-msgName] = '\0'; // remove size description from MsgName
2008-12-25 22:00:00 +01:00
2008-12-26 22:00:00 +01:00
// search message by name to link with
for( i = 0; i < clgame.numMessages; i++ )
{
msg = clgame.msg[i];
if( !msg ) continue;
if( !com.strcmp( msg->name, msgName ))
{
msg->number = svc_num;
msg->size = msgSize;
return;
}
}
// create an empty message
CL_CreateUserMessage( i, msgName, svc_num, msgSize, NULL );
}
void CL_SortUserMessages( void )
{
// FIXME: implement
2008-12-25 22:00:00 +01:00
}
void CL_ParseUserMessage( sizebuf_t *net_buffer, int svc_num )
{
user_message_t *msg;
2008-12-26 22:00:00 +01:00
int i, iSize;
2008-12-25 22:00:00 +01:00
byte *pbuf;
2008-12-26 22:00:00 +01:00
2008-12-25 22:00:00 +01:00
// NOTE: any user message parse on engine, not in client.dll
2008-12-26 22:00:00 +01:00
if( svc_num >= clgame.numMessages )
2008-12-25 22:00:00 +01:00
{
// unregister message can't be parsed
Host_Error( "CL_ParseUserMessage: illegible server message %d\n", svc_num );
return;
}
2008-12-26 22:00:00 +01:00
// search for svc_num
for( i = 0; i < clgame.numMessages; i++ )
2008-12-25 22:00:00 +01:00
{
2008-12-26 22:00:00 +01:00
msg = clgame.msg[i];
if( !msg ) continue;
if( msg->number == svc_num )
break;
}
2008-12-25 22:00:00 +01:00
2008-12-26 22:00:00 +01:00
if( i == clgame.numMessages || !msg )
{
// unregistered message ?
Host_Error( "CL_ParseUserMessage: illegible server message %d\n", svc_num );
return;
2008-12-25 22:00:00 +01:00
}
iSize = msg->size;
pbuf = NULL;
2008-12-26 22:00:00 +01:00
// message with variable sizes receive an actual size as first byte
2008-12-25 22:00:00 +01:00
if( iSize == -1 ) iSize = MSG_ReadByte( net_buffer );
if( iSize > 0 ) pbuf = Mem_Alloc( cls.private, iSize );
// parse user message into buffer
MSG_ReadData( net_buffer, pbuf, iSize );
if( msg->func ) msg->func( msg->name, iSize, pbuf );
2008-12-26 22:00:00 +01:00
else MsgDev( D_WARN, "CL_ParseUserMessage: %s not hooked\n", msg->name );
2008-12-25 22:00:00 +01:00
if( pbuf ) Mem_Free( pbuf );
}
void CL_InitEdict( edict_t *pEdict )
{
Com_Assert( pEdict == NULL );
2009-01-04 22:00:00 +01:00
Com_Assert( pEdict->pvClientData != NULL );
2008-12-25 22:00:00 +01:00
pEdict->v.pContainingEntity = pEdict; // make cross-links for consistency
2008-12-26 22:00:00 +01:00
pEdict->pvClientData = (cl_priv_t *)Mem_Alloc( cls.mempool, sizeof( cl_priv_t ));
2008-12-25 22:00:00 +01:00
pEdict->serialnumber = NUM_FOR_EDICT( pEdict ); // merged on first update
pEdict->free = false;
}
void CL_FreeEdict( edict_t *pEdict )
{
Com_Assert( pEdict == NULL );
Com_Assert( pEdict->free );
// unlink from world
// CL_UnlinkEdict( pEdict );
2008-12-26 22:00:00 +01:00
if( pEdict->pvClientData ) Mem_Free( pEdict->pvClientData );
2008-12-25 22:00:00 +01:00
Mem_Set( &pEdict->v, 0, sizeof( entvars_t ));
2008-12-26 22:00:00 +01:00
pEdict->pvClientData = NULL;
2008-12-25 22:00:00 +01:00
// mark edict as freed
pEdict->freetime = cl.time * 0.001f;
pEdict->serialnumber = 0;
pEdict->free = true;
}
edict_t *CL_AllocEdict( void )
{
edict_t *pEdict;
int i;
2008-12-26 22:00:00 +01:00
for( i = 0; i < clgame.numEntities; i++ )
2008-12-25 22:00:00 +01:00
{
pEdict = EDICT_NUM( i );
2009-01-04 22:00:00 +01:00
// the first couple seconds of client time can involve a lot of
2008-12-25 22:00:00 +01:00
// freeing and allocating, so relax the replacement policy
if( pEdict->free && ( pEdict->freetime < 2.0f || ((cl.time * 0.001f) - pEdict->freetime) > 0.5f ))
{
CL_InitEdict( pEdict );
return pEdict;
}
}
2008-12-26 22:00:00 +01:00
if( i == clgame.maxEntities )
2008-12-25 22:00:00 +01:00
Host_Error( "CL_AllocEdict: no free edicts\n" );
2008-12-26 22:00:00 +01:00
clgame.numEntities++;
2008-12-25 22:00:00 +01:00
pEdict = EDICT_NUM( i );
CL_InitEdict( pEdict );
return pEdict;
}
void CL_FreeEdicts( void )
{
int i;
edict_t *ent;
2008-12-26 22:00:00 +01:00
for( i = 0; i < clgame.numEntities; i++ )
2008-12-25 22:00:00 +01:00
{
ent = EDICT_NUM( i );
if( ent->free ) continue;
CL_FreeEdict( ent );
}
2009-01-02 22:00:00 +01:00
// clear globals
StringTable_Clear( clgame.hStringTable );
2008-12-26 22:00:00 +01:00
clgame.numEntities = 0;
2008-12-25 22:00:00 +01:00
}
/*
===============================================================================
CGame Builtin Functions
===============================================================================
*/
/*
=========
pfnMemAlloc
=========
*/
static void *pfnMemAlloc( size_t cb, const char *filename, const int fileline )
{
return com.malloc( cls.private, cb, filename, fileline );
}
/*
=========
pfnMemFree
=========
*/
static void pfnMemFree( void *mem, const char *filename, const int fileline )
{
com.free( mem, filename, fileline );
}
2008-12-26 22:00:00 +01:00
2008-12-25 22:00:00 +01:00
/*
=============
pfnLoadShader
=============
*/
shader_t pfnLoadShader( const char *szShaderName )
{
if( !re ) return 0; // render not initialized
if( !szShaderName || !*szShaderName )
{
MsgDev( D_ERROR, "CL_LoadShader: invalid shadername\n" );
return -1;
}
return re->RegisterShader( szShaderName, SHADER_NOMIP );
}
/*
=============
pfnFillRGBA
=============
*/
void pfnFillRGBA( int x, int y, int width, int height, const float *color, float alpha )
{
2008-12-29 22:00:00 +01:00
if( !re ) return;
re->SetColor( GetRGBA( color[0], color[1], color[2], alpha ));
re->DrawFill( x, y, width, height );
re->SetColor( NULL );
2008-12-25 22:00:00 +01:00
}
2008-12-29 22:00:00 +01:00
/*
=============
pfnDrawImageExt
=============
*/
2009-01-06 22:00:00 +01:00
void pfnDrawImageExt( HSPRITE shader, float x, float y, float w, float h, float s1, float t1, float s2, float t2 )
2008-12-29 22:00:00 +01:00
{
if( !re ) return;
re->DrawStretchPic( x, y, w, h, s1, t1, s2, t2, shader );
re->SetColor( NULL );
}
2008-12-25 22:00:00 +01:00
/*
=============
pfnSetColor
=============
*/
void pfnSetColor( float r, float g, float b, float a )
{
if( !re ) return; // render not initialized
re->SetColor( GetRGBA( r, g, b, a ));
}
/*
=============
pfnRegisterVariable
=============
*/
void pfnRegisterVariable( const char *szName, const char *szValue, int flags, const char *szDesc )
{
// FIXME: translate client.dll flags to real cvar flags
Cvar_Get( szName, szValue, flags, szDesc );
}
/*
=============
pfnCvarSetValue
=============
*/
void pfnCvarSetValue( const char *cvar, float value )
{
Cvar_SetValue( cvar, value );
}
/*
=============
pfnGetCvarFloat
=============
*/
float pfnGetCvarFloat( const char *szName )
{
return Cvar_VariableValue( szName );
}
/*
=============
pfnGetCvarString
=============
*/
char* pfnGetCvarString( const char *szName )
{
return Cvar_VariableString( szName );
}
/*
=============
pfnGetCvarString
=============
*/
void pfnAddCommand( const char *cmd_name, xcommand_t func, const char *cmd_desc )
{
// NOTE: if( func == NULL ) cmd will be forwarded to a server
Cmd_AddCommand( cmd_name, func, cmd_desc );
}
/*
=============
pfnHookUserMsg
=============
*/
2008-12-26 22:00:00 +01:00
void pfnHookUserMsg( const char *szMsgName, pfnUserMsgHook pfn )
2008-12-25 22:00:00 +01:00
{
user_message_t *msg;
int i;
// ignore blank names
if( !szMsgName || !*szMsgName ) return;
2008-12-26 22:00:00 +01:00
// duplicate call can change msgFunc
for( i = 0; i < clgame.numMessages; i++ )
2008-12-25 22:00:00 +01:00
{
2008-12-26 22:00:00 +01:00
msg = clgame.msg[i];
if( !msg ) continue;
2008-12-25 22:00:00 +01:00
if( !com.strcmp( szMsgName, msg->name ))
{
2008-12-26 22:00:00 +01:00
if( msg->func != pfn )
msg->func = pfn;
2008-12-25 22:00:00 +01:00
return;
}
}
2008-12-26 22:00:00 +01:00
// allocate a new one
CL_CreateUserMessage( i, szMsgName, 0, 0, pfn );
2008-12-25 22:00:00 +01:00
}
/*
=============
pfnServerCmd
=============
*/
void pfnServerCmd( const char *szCmdString )
{
// server command adding in cmds queue
Cbuf_AddText( va( "cmd %s", szCmdString ));
}
/*
=============
pfnClientCmd
=============
*/
void pfnClientCmd( const char *szCmdString )
{
// client command executes immediately
Cmd_ExecuteString( szCmdString );
}
2009-01-09 22:00:00 +01:00
/*
=============
pfnSetKeyDest
=============
*/
void pfnSetKeyDest( int key_dest )
{
switch( key_dest )
{
case key_game:
cls.key_dest = key_game;
break;
case key_hudmenu:
cls.key_dest = key_hudmenu;
break;
case key_menu:
cls.key_dest = key_menu;
break;
case key_message:
cls.key_dest = key_message;
break;
default:
MsgDev( D_ERROR, "CL_SetKeyDest: wrong destination %i!\n", key_dest );
break;
}
}
2008-12-25 22:00:00 +01:00
/*
=============
2009-01-03 22:00:00 +01:00
pfnGetPlayerInfo
2008-12-25 22:00:00 +01:00
=============
*/
void pfnGetPlayerInfo( int player_num, hud_player_info_t *pinfo )
{
// FIXME: implement
static hud_player_info_t null_info;
Mem_Copy( pinfo, &null_info, sizeof( null_info ));
}
/*
=============
2009-01-03 22:00:00 +01:00
pfnTextMessageGet
2008-12-25 22:00:00 +01:00
=============
*/
client_textmessage_t *pfnTextMessageGet( const char *pName )
{
2009-01-03 22:00:00 +01:00
// FIXME: implement or move to client.dll
2008-12-25 22:00:00 +01:00
static client_textmessage_t null_msg;
return &null_msg;
}
/*
=============
pfnCmdArgc
=============
*/
int pfnCmdArgc( void )
{
return Cmd_Argc();
}
/*
=============
pfnCmdArgv
=============
*/
char *pfnCmdArgv( int argc )
{
if( argc >= 0 && argc < Cmd_Argc())
return Cmd_Argv( argc );
return "";
}
/*
=============
pfnPlaySoundByName
=============
*/
2009-01-05 22:00:00 +01:00
void pfnPlaySoundByName( const char *szSound, float volume, int pitch, const float *org )
2008-12-25 22:00:00 +01:00
{
2009-01-05 22:00:00 +01:00
S_StartLocalSound( szSound, volume, pitch, org );
2008-12-25 22:00:00 +01:00
}
/*
=============
pfnPlaySoundByIndex
=============
*/
2009-01-05 22:00:00 +01:00
void pfnPlaySoundByIndex( int iSound, float volume, int pitch, const float *org )
2008-12-25 22:00:00 +01:00
{
// make sure what we in-bounds
iSound = bound( 0, iSound, MAX_SOUNDS );
if( cl.sound_precache[iSound] == 0 )
{
MsgDev( D_ERROR, "CL_PlaySoundByIndex: invalid sound handle %i\n", iSound );
return;
}
2009-01-05 22:00:00 +01:00
S_StartSound( org, cl.playernum + 1, CHAN_AUTO, cl.sound_precache[iSound], volume, ATTN_NORM, pitch );
2008-12-25 22:00:00 +01:00
}
/*
=============
pfnDrawCenterPrint
called each frame
=============
*/
void pfnDrawCenterPrint( void )
{
char *start;
int l, x, y, w;
float *color;
if( !cl.centerPrintTime ) return;
color = CL_FadeColor( cl.centerPrintTime * 0.001f, scr_centertime->value );
if( !color )
{
cl.centerPrintTime = 0;
return;
}
re->SetColor( color );
start = cl.centerPrint;
y = cl.centerPrintY - cl.centerPrintLines * BIGCHAR_HEIGHT / 2;
while( 1 )
{
char linebuffer[1024];
for ( l = 0; l < 50; l++ )
{
if ( !start[l] || start[l] == '\n' )
break;
linebuffer[l] = start[l];
}
linebuffer[l] = 0;
w = cl.centerPrintCharWidth * com.cstrlen( linebuffer );
x = ( SCREEN_WIDTH - w )>>1;
SCR_DrawStringExt( x, y, cl.centerPrintCharWidth, BIGCHAR_HEIGHT, linebuffer, color, false );
y += cl.centerPrintCharWidth * 1.5;
while( *start && ( *start != '\n' )) start++;
if( !*start ) break;
start++;
}
if( re ) re->SetColor( NULL );
}
/*
=============
pfnCenterPrint
called once from message
=============
*/
void pfnCenterPrint( const char *text, int y, int charWidth )
{
char *s;
com.strncpy( cl.centerPrint, text, sizeof( cl.centerPrint ));
cl.centerPrintTime = cls.realtime;
cl.centerPrintY = y;
cl.centerPrintCharWidth = charWidth;
// count the number of lines for centering
cl.centerPrintLines = 1;
s = cl.centerPrint;
while( *s )
{
if( *s == '\n' )
cl.centerPrintLines++;
s++;
}
}
/*
=============
pfnDrawString
=============
*/
void pfnDrawString( int x, int y, int width, int height, const char *text )
{
if( !text || !*text )
{
MsgDev( D_ERROR, "SCR_DrawStringExt: passed null string!\n" );
return;
}
SCR_DrawStringExt( x, y, width, height, text, g_color_table[7], false );
if( re ) re->SetColor( NULL );
}
2008-12-28 22:00:00 +01:00
/*
=============
pfnGetImageSize
=============
*/
2009-01-04 22:00:00 +01:00
void pfnGetDrawParms( int *w, int *h, int *f, int frame, shader_t shader )
2008-12-25 22:00:00 +01:00
{
2009-01-04 22:00:00 +01:00
if( re ) re->GetParms( w, h, f, frame, shader );
2008-12-25 22:00:00 +01:00
else
{
2008-12-28 22:00:00 +01:00
if( w ) *w = 0;
if( h ) *h = 0;
2009-01-04 22:00:00 +01:00
if( f ) *f = 1;
2008-12-25 22:00:00 +01:00
}
}
2008-12-28 22:00:00 +01:00
/*
=============
pfnSetDrawParms
=============
*/
void pfnSetDrawParms( shader_t handle, kRenderMode_t rendermode, int frame )
{
if( re ) re->SetParms( handle, rendermode, frame );
}
2008-12-25 22:00:00 +01:00
/*
=============
pfnGetViewAngles
return interpolated angles from previous frame
=============
*/
void pfnGetViewAngles( float *angles )
{
if( angles == NULL ) return;
VectorCopy( cl.refdef.viewangles, angles );
}
/*
=============
pfnIsSpectateOnly
=============
*/
int pfnIsSpectateOnly( void )
{
// FIXME: implement
return 0;
}
/*
=============
pfnGetClientTime
=============
*/
float pfnGetClientTime( void )
{
return cl.time * 0.001f;
}
/*
=============
pfnGetMaxClients
=============
*/
int pfnGetMaxClients( void )
{
return com.atoi( cl.configstrings[CS_MAXCLIENTS] );
}
/*
=============
pfnGetViewModel
can return NULL
=============
*/
edict_t* pfnGetViewModel( void )
{
2009-01-03 22:00:00 +01:00
return &cl.viewent;
2008-12-25 22:00:00 +01:00
}
2008-12-26 22:00:00 +01:00
/*
=============
pfnMakeLevelShot
force to make levelshot
=============
*/
void pfnMakeLevelShot( void )
{
if( !cl.need_levelshot ) return;
Con_ClearNotify();
// make levelshot at nextframe()
Cbuf_ExecuteText( EXEC_APPEND, "levelshot\n" );
}
2008-12-25 22:00:00 +01:00
/*
=============
pfnPointContents
=============
*/
static int pfnPointContents( const float *rgflVector )
{
return CL_PointContents( rgflVector );
}
/*
=============
pfnTraceLine
=============
*/
static void pfnTraceLine( const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr )
{
trace_t trace;
int move;
move = (fNoMonsters) ? MOVE_NOMONSTERS : MOVE_NORMAL;
if( IS_NAN(v1[0]) || IS_NAN(v1[1]) || IS_NAN(v1[2]) || IS_NAN(v2[0]) || IS_NAN(v1[2]) || IS_NAN(v2[2] ))
Host_Error( "CL_Trace: NAN errors detected ('%f %f %f', '%f %f %f'\n", v1[0], v1[1], v1[2], v2[0], v2[1], v2[2] );
trace = CL_Trace( v1, vec3_origin, vec3_origin, v2, move, pentToSkip, CL_ContentsMask( pentToSkip ));
CL_CopyTraceResult( ptr, trace );
}
2008-12-26 22:00:00 +01:00
/*
=============
CL_AllocString
=============
*/
string_t CL_AllocString( const char *szValue )
{
return StringTable_SetString( clgame.hStringTable, szValue );
}
/*
=============
CL_GetString
=============
*/
const char *CL_GetString( string_t iString )
{
return StringTable_GetString( clgame.hStringTable, iString );
}
2008-12-25 22:00:00 +01:00
static triapi_t gTriApi =
{
sizeof( triapi_t ),
};
// engine callbacks
static cl_enginefuncs_t gEngfuncs =
{
sizeof( cl_enginefuncs_t ),
pfnMemAlloc,
pfnMemFree,
pfnLoadShader,
pfnFillRGBA,
2008-12-29 22:00:00 +01:00
pfnDrawImageExt,
2008-12-25 22:00:00 +01:00
pfnSetColor,
pfnRegisterVariable,
pfnCvarSetValue,
pfnGetCvarFloat,
pfnGetCvarString,
pfnAddCommand,
pfnHookUserMsg,
pfnServerCmd,
pfnClientCmd,
2009-01-09 22:00:00 +01:00
pfnSetKeyDest,
2008-12-25 22:00:00 +01:00
pfnGetPlayerInfo,
pfnTextMessageGet,
pfnCmdArgc,
pfnCmdArgv,
pfnAlertMessage,
pfnPlaySoundByName,
pfnPlaySoundByIndex,
AngleVectors,
pfnDrawCenterPrint,
pfnCenterPrint,
pfnDrawString,
2009-01-04 22:00:00 +01:00
pfnGetDrawParms,
2008-12-28 22:00:00 +01:00
pfnSetDrawParms,
2008-12-25 22:00:00 +01:00
pfnGetViewAngles,
2009-01-03 22:00:00 +01:00
CL_GetEdictByIndex,
CL_GetLocalPlayer,
2008-12-25 22:00:00 +01:00
pfnIsSpectateOnly,
pfnGetClientTime,
pfnGetMaxClients,
2008-12-26 22:00:00 +01:00
pfnGetViewModel,
pfnMakeLevelShot,
2008-12-25 22:00:00 +01:00
pfnPointContents,
pfnTraceLine,
pfnRandomLong,
pfnRandomFloat,
pfnLoadFile,
2009-01-01 22:00:00 +01:00
pfnFileExists,
2008-12-25 22:00:00 +01:00
pfnGetGameDir,
Host_Error,
&gTriApi
};
/*
====================
StudioEvent
Event callback for studio models
====================
*/
2009-01-03 22:00:00 +01:00
void CL_StudioEvent( dstudioevent_t *event, edict_t *pEdict )
2008-12-25 22:00:00 +01:00
{
cls.dllFuncs.pfnStudioEvent( event, pEdict );
}
void CL_UnloadProgs( void )
{
// initialize game
cls.dllFuncs.pfnShutdown();
2008-12-26 22:00:00 +01:00
StringTable_Delete( clgame.hStringTable );
2008-12-25 22:00:00 +01:00
Com_FreeLibrary( cls.game );
Mem_FreePool( &cls.mempool );
Mem_FreePool( &cls.private );
}
bool CL_LoadProgs( const char *name )
{
static CLIENTAPI GetClientAPI;
string libname;
edict_t *e;
int i;
if( cls.game ) CL_UnloadProgs();
// fill it in
com.snprintf( libname, MAX_STRING, "bin/%s.dll", name );
cls.mempool = Mem_AllocPool( "Client Edicts Zone" );
cls.private = Mem_AllocPool( "Client Private Zone" );
cls.game = Com_LoadLibrary( libname );
if( !cls.game ) return false;
GetClientAPI = (CLIENTAPI)Com_GetProcAddress( cls.game, "CreateAPI" );
if( !GetClientAPI )
{
MsgDev( D_ERROR, "CL_LoadProgs: failed to get address of CreateAPI proc\n" );
return false;
}
if( !GetClientAPI( &cls.dllFuncs, &gEngfuncs, INTERFACE_VERSION ))
{
MsgDev( D_ERROR, "CL_LoadProgs: can't init client API\n" );
return false;
}
// 65535 unique strings should be enough ...
2009-01-02 22:00:00 +01:00
clgame.hStringTable = StringTable_Create( "Client", 0x10000 );
2008-12-26 22:00:00 +01:00
clgame.maxEntities = host.max_edicts; // FIXME: must come from CS_MAXENTITIES
clgame.maxClients = Host_MaxClients();
cls.edicts = Mem_Alloc( cls.mempool, sizeof( edict_t ) * clgame.maxEntities );
// register svc_bad message
pfnHookUserMsg( "bad", NULL );
CL_LinkUserMessage( "bad@0", svc_bad );
for( i = 0, e = EDICT_NUM( 0 ); i < clgame.maxEntities; i++, e++ )
2008-12-25 22:00:00 +01:00
e->free = true; // mark all edicts as freed
// initialize game
cls.dllFuncs.pfnInit();
return true;
}