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

2467 lines
48 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 "const.h"
2010-08-04 22:00:00 +02:00
#include "protocol.h"
2009-01-11 22:00:00 +01:00
#include "triangle_api.h"
#include "effects_api.h"
2010-08-07 22:00:00 +02:00
#include "event_flags.h"
2009-11-26 22:00:00 +01:00
#include "pm_defs.h"
2008-12-25 22:00:00 +01:00
/*
====================
2010-08-07 22:00:00 +02:00
CL_GetEntityByIndex
2008-12-25 22:00:00 +01:00
Render callback for studio models
====================
*/
2010-08-07 22:00:00 +02:00
cl_entity_t *CL_GetEntityByIndex( int index )
2008-12-25 22:00:00 +01:00
{
2010-08-07 22:00:00 +02:00
if( !clgame.entities )
return NULL;
2009-10-18 22:00:00 +02:00
2009-09-28 22:00:00 +02:00
if( index < 0 || index > clgame.globals->numEntities )
2009-01-03 22:00:00 +01:00
{
2010-08-07 22:00:00 +02:00
if( index == -1 )
return NULL;
MsgDev( D_ERROR, "CL_GetEntityByIndex: invalid entindex %i\n", index );
2009-01-03 22:00:00 +01:00
return NULL;
}
2008-12-25 22:00:00 +01:00
2010-08-07 22:00:00 +02:00
if( EDICT_NUM( index )->index == -1 )
2010-04-21 22:00:00 +02:00
return NULL;
2010-08-07 22:00:00 +02:00
return EDICT_NUM( index );
2010-04-21 22:00:00 +02:00
}
2009-10-02 22:00:00 +02:00
/*
====================
CL_GetServerTime
don't clamped time that come from server
====================
*/
2010-06-24 22:00:00 +02:00
float CL_GetServerTime( void )
2009-10-02 22:00:00 +02:00
{
2010-07-23 22:00:00 +02:00
return sv_time();
2009-10-02 22:00:00 +02:00
}
2010-08-07 22:00:00 +02:00
/*
====================
CL_GetPlayerInfo
get player info by render request
====================
*/
player_info_t *CL_GetPlayerInfo( int playerIndex )
{
if( playerIndex < 0 || playerIndex >= clgame.globals->maxClients )
return NULL;
return &cl.players[playerIndex];
}
2009-09-17 22:00:00 +02:00
/*
====================
StudioEvent
Event callback for studio models
====================
*/
2010-08-07 22:00:00 +02:00
void CL_StudioEvent( mstudioevent_t *event, cl_entity_t *pEdict )
2009-09-17 22:00:00 +02:00
{
clgame.dllFuncs.pfnStudioEvent( event, pEdict );
}
2009-09-03 22:00:00 +02:00
/*
====================
Studio_FxTransform
2009-09-17 22:00:00 +02:00
apply fxtransforms for each studio bone
2009-09-03 22:00:00 +02:00
====================
*/
2010-08-07 22:00:00 +02:00
void CL_StudioFxTransform( cl_entity_t *ent, float transform[4][4] )
2009-09-03 22:00:00 +02:00
{
2009-09-17 22:00:00 +02:00
clgame.dllFuncs.pfnStudioFxTransform( ent, transform );
2009-09-03 22:00:00 +02:00
}
2009-12-05 22:00:00 +01:00
/*
=============
CL_GetLerpFrac
=============
*/
float CL_GetLerpFrac( void )
{
return cl.lerpFrac;
}
2009-12-04 22:00:00 +01:00
/*
================
CL_FadeAlpha
================
*/
void CL_FadeAlpha( int starttime, int endtime, rgba_t color )
{
int time, fade_time;
if( starttime == 0 )
{
MakeRGBA( color, 255, 255, 255, 255 );
return;
}
2010-07-23 22:00:00 +02:00
time = cls.realtime - starttime;
2009-12-04 22:00:00 +01:00
if( time >= endtime )
{
MakeRGBA( color, 255, 255, 255, 0 );
return;
}
// fade time is 1/4 of endtime
fade_time = endtime / 4;
fade_time = bound( 300, fade_time, 10000 );
color[0] = color[1] = color[2] = 255;
// fade out
if(( endtime - time ) < fade_time )
2010-07-23 22:00:00 +02:00
color[3] = bound( 0, (( endtime - time ) * ( 1.0f / fade_time )) * 255, 255 );
2009-12-04 22:00:00 +01:00
else color[3] = 255;
}
/*
=============
2010-07-19 22:00:00 +02:00
CL_AdjustXPos
2009-12-04 22:00:00 +01:00
2010-07-19 22:00:00 +02:00
adjust text by x pos
2009-12-04 22:00:00 +01:00
=============
*/
2010-07-19 22:00:00 +02:00
static int CL_AdjustXPos( float x, int width, int totalWidth )
2009-12-04 22:00:00 +01:00
{
2010-07-19 22:00:00 +02:00
int xPos;
2009-12-04 22:00:00 +01:00
2010-07-19 22:00:00 +02:00
if( x == -1 )
2009-12-04 22:00:00 +01:00
{
2010-07-19 22:00:00 +02:00
xPos = ( clgame.scrInfo.iWidth - width ) * 0.5f;
2009-12-04 22:00:00 +01:00
}
2010-07-19 22:00:00 +02:00
else
2009-12-04 22:00:00 +01:00
{
2010-07-19 22:00:00 +02:00
if ( x < 0 )
xPos = (1.0 + x) * clgame.scrInfo.iWidth - totalWidth; // Alight right
else // align left
xPos = x * clgame.scrInfo.iWidth;
}
2009-12-04 22:00:00 +01:00
2010-07-19 22:00:00 +02:00
if( xPos + width > clgame.scrInfo.iWidth )
xPos = clgame.scrInfo.iWidth - width;
else if( xPos < 0 )
xPos = 0;
2009-12-04 22:00:00 +01:00
2010-07-19 22:00:00 +02:00
return xPos;
}
2009-12-04 22:00:00 +01:00
2010-07-19 22:00:00 +02:00
/*
=============
CL_AdjustYPos
adjust text by y pos
=============
*/
static int CL_AdjustYPos( float y, int height )
{
int yPos;
2009-12-04 22:00:00 +01:00
2010-07-19 22:00:00 +02:00
if( y == -1 ) // centered?
{
yPos = ( clgame.scrInfo.iHeight - height ) * 0.5f;
2009-12-04 22:00:00 +01:00
}
2010-07-19 22:00:00 +02:00
else
{
// Alight bottom?
if( y < 0 )
yPos = (1.0 + y) * clgame.scrInfo.iHeight - height; // Alight bottom
else // align top
yPos = y * clgame.scrInfo.iHeight;
}
if( yPos + height > clgame.scrInfo.iHeight )
yPos = clgame.scrInfo.iHeight - height;
else if( yPos < 0 )
yPos = 0;
return yPos;
2009-12-04 22:00:00 +01:00
}
/*
=============
CL_CenterPrint
print centerscreen message
=============
*/
2010-07-19 22:00:00 +02:00
void CL_CenterPrint( const char *text, float y )
2009-12-04 22:00:00 +01:00
{
char *s;
2010-07-19 22:00:00 +02:00
int width = 0;
int length = 0;
2009-12-04 22:00:00 +01:00
2010-07-19 22:00:00 +02:00
clgame.centerPrint.lines = 1;
clgame.centerPrint.totalWidth = 0;
2010-07-23 22:00:00 +02:00
clgame.centerPrint.time = cl.frame.servertime; // allow pause for centerprint
2010-07-19 22:00:00 +02:00
com.strncpy( clgame.centerPrint.message, text, sizeof( clgame.centerPrint.message ));
s = clgame.centerPrint.message;
2009-12-04 22:00:00 +01:00
// count the number of lines for centering
while( *s )
{
if( *s == '\n' )
2010-07-19 22:00:00 +02:00
{
clgame.centerPrint.lines++;
if( width > clgame.centerPrint.totalWidth )
clgame.centerPrint.totalWidth = width;
width = 0;
}
else width += clgame.scrInfo.charWidths[*s];
2009-12-04 22:00:00 +01:00
s++;
2010-07-19 22:00:00 +02:00
length++;
2009-12-04 22:00:00 +01:00
}
2010-07-19 22:00:00 +02:00
clgame.centerPrint.totalHeight = ( clgame.centerPrint.lines * clgame.scrInfo.iCharHeight );
clgame.centerPrint.y = CL_AdjustYPos( y, clgame.centerPrint.totalHeight );
2009-12-04 22:00:00 +01:00
}
2009-12-03 22:00:00 +01:00
/*
====================
SPR_AdjustSize
draw hudsprite routine
====================
*/
static void SPR_AdjustSize( float *x, float *y, float *w, float *h )
{
float xscale, yscale;
if( !x && !y && !w && !h ) return;
// scale for screen sizes
xscale = clgame.scrInfo.iRealWidth / (float)clgame.scrInfo.iWidth;
yscale = clgame.scrInfo.iRealHeight / (float)clgame.scrInfo.iHeight;
if( x ) *x *= xscale;
if( y ) *y *= yscale;
if( w ) *w *= xscale;
if( h ) *h *= yscale;
}
static bool SPR_Scissor( float *x, float *y, float *width, float *height, float *u0, float *v0, float *u1, float *v1 )
{
float dudx, dvdy;
// clip sub rect to sprite
if(( width == 0 ) || ( height == 0 ))
return false;
if( *x + *width <= clgame.ds.scissor_x )
return false;
if( *x >= clgame.ds.scissor_x + clgame.ds.scissor_width )
return false;
if( *y + *height <= clgame.ds.scissor_y )
return false;
if( *y >= clgame.ds.scissor_y + clgame.ds.scissor_height )
return false;
dudx = (*u1 - *u0) / *width;
dvdy = (*v1 - *v0) / *height;
if( *x < clgame.ds.scissor_x )
{
*u0 += (clgame.ds.scissor_x - *x) * dudx;
*width -= clgame.ds.scissor_x - *x;
*x = clgame.ds.scissor_x;
}
if( *x + *width > clgame.ds.scissor_x + clgame.ds.scissor_width )
{
*u1 -= (*x + *width - (clgame.ds.scissor_x + clgame.ds.scissor_width)) * dudx;
*width = clgame.ds.scissor_x + clgame.ds.scissor_width - *x;
}
if( *y < clgame.ds.scissor_y )
{
*v0 += (clgame.ds.scissor_y - *y) * dvdy;
*height -= clgame.ds.scissor_y - *y;
*y = clgame.ds.scissor_y;
}
if( *y + *height > clgame.ds.scissor_y + clgame.ds.scissor_height )
{
*v1 -= (*y + *height - (clgame.ds.scissor_y + clgame.ds.scissor_height)) * dvdy;
*height = clgame.ds.scissor_y + clgame.ds.scissor_height - *y;
}
return true;
}
/*
====================
SPR_DrawGeneric
draw hudsprite routine
====================
*/
static void SPR_DrawGeneric( int frame, float x, float y, float width, float height, const wrect_t *prc )
{
float s1, s2, t1, t2;
if( !re ) return;
if( width == -1 && height == -1 )
{
int w, h;
2010-07-17 22:00:00 +02:00
// assume we get sizes from image
2009-12-03 22:00:00 +01:00
re->GetParms( &w, &h, NULL, frame, clgame.ds.hSprite );
width = w;
height = h;
}
if( prc )
{
2010-07-20 22:00:00 +02:00
// calc user-defined rectangle
s1 = (float)prc->left / width;
t1 = (float)prc->top / height;
s2 = (float)prc->right / width;
t2 = (float)prc->bottom / height;
width = prc->right - prc->left;
height = prc->bottom - prc->top;
2009-12-03 22:00:00 +01:00
}
else
{
s1 = t1 = 0.0f;
s2 = t2 = 1.0f;
}
// pass scissor test if supposed
if( clgame.ds.scissor_test && !SPR_Scissor( &x, &y, &width, &height, &s1, &t1, &s2, &t2 ))
return;
// scale for screen sizes
SPR_AdjustSize( &x, &y, &width, &height );
re->DrawStretchPic( x, y, width, height, s1, t1, s2, t2, clgame.ds.hSprite );
re->SetColor( NULL );
}
2010-07-19 22:00:00 +02:00
/*
=============
CL_DrawCenterPrint
called each frame
=============
*/
static void CL_DrawCenterPrint( void )
{
char *pText;
int i, j, x, y;
int width, lineLength;
byte line[80];
rgba_t color;
if( !clgame.centerPrint.time )
return;
CL_FadeAlpha( clgame.centerPrint.time, scr_centertime->value * 1000, color );
if( *(int *)color == 0x00FFFFFF )
{
// faded out
clgame.centerPrint.time = 0;
return;
}
pText = clgame.centerPrint.message;
y = clgame.centerPrint.y; // start y
for( i = 0; i < clgame.centerPrint.lines; i++ )
{
lineLength = 0;
width = 0;
while( *pText && *pText != '\n' )
{
byte c = *pText;
line[lineLength] = c;
width += clgame.scrInfo.charWidths[c];
lineLength++;
pText++;
}
pText++; // Skip LineFeed
line[lineLength] = 0;
x = CL_AdjustXPos( -1, width, clgame.centerPrint.totalWidth );
for( j = 0; j < lineLength; j++ )
{
int ch = line[j];
int next = x + clgame.scrInfo.charWidths[ch];
if( x >= 0 && y >= 0 && next <= clgame.scrInfo.iWidth )
{
re->SetColor( color );
2010-07-20 22:00:00 +02:00
clgame.ds.hSprite = cls.creditsFont.hFontTexture;
2010-07-19 22:00:00 +02:00
re->SetParms( clgame.ds.hSprite, kRenderTransAdd, 0 );
2010-07-20 22:00:00 +02:00
SPR_DrawGeneric( 0, x, y, -1, -1, &cls.creditsFont.fontRc[ch] );
2010-07-19 22:00:00 +02:00
}
x = next;
}
y += clgame.scrInfo.iCharHeight;
}
}
2009-10-23 22:00:00 +02:00
/*
====================
CL_InitTitles
parse all messages that declared in titles.txt
and hold them into permament memory pool
====================
*/
static void CL_InitTitles( const char *filename )
{
2010-03-28 22:00:00 +02:00
size_t fileSize;
byte *pMemFile;
2009-10-23 22:00:00 +02:00
2010-03-28 22:00:00 +02:00
// clear out any old data that's sitting around.
if( clgame.titles ) Mem_Free( clgame.titles );
2009-10-23 22:00:00 +02:00
2010-03-28 22:00:00 +02:00
clgame.titles = NULL;
clgame.numTitles = 0;
2009-10-23 22:00:00 +02:00
2010-03-28 22:00:00 +02:00
pMemFile = FS_LoadFile( filename, &fileSize );
if( !pMemFile ) return;
2009-10-23 22:00:00 +02:00
2010-03-28 22:00:00 +02:00
CL_TextMessageParse( pMemFile, fileSize );
Mem_Free( pMemFile );
2009-10-23 22:00:00 +02:00
}
2010-06-22 22:00:00 +02:00
/*
====================
CL_BadMessage
Default method to invoke host error
====================
*/
int CL_BadMessage( const char *pszName, int iSize, void *pbuf )
{
Host_Error( "svc_bad\n" );
return 0;
}
2008-12-25 22:00:00 +01:00
/*
====================
CL_GetLocalPlayer
Render callback for studio models
====================
*/
2010-08-07 22:00:00 +02:00
cl_entity_t *CL_GetLocalPlayer( void )
2008-12-25 22:00:00 +01:00
{
2009-10-13 22:00:00 +02:00
if( cls.state == ca_active )
2009-11-26 22:00:00 +01:00
{
2010-08-07 22:00:00 +02:00
cl_entity_t *player = EDICT_NUM( cl.playernum + 1 );
if( player ) return player;
2009-11-26 22:00:00 +01:00
Host_Error( "CL_GetLocalPlayer: invalid edict\n" );
}
2009-10-13 22:00:00 +02:00
return NULL;
2008-12-25 22:00:00 +01:00
}
/*
====================
CL_GetMaxlients
Render callback for studio models
====================
*/
int CL_GetMaxClients( void )
{
2009-11-27 22:00:00 +01:00
return clgame.globals->maxClients;
2008-12-25 22:00:00 +01:00
}
2009-12-03 22:00:00 +01:00
void CL_DrawCrosshair( void )
{
2010-08-07 22:00:00 +02:00
int x, y, width, height;
cl_entity_t *pPlayer;
2009-12-03 22:00:00 +01:00
if( !re || clgame.ds.hCrosshair <= 0 || cl.refdef.crosshairangle[2] || !cl_crosshair->integer )
return;
2009-12-04 22:00:00 +01:00
pPlayer = CL_GetLocalPlayer();
2009-12-03 22:00:00 +01:00
2010-08-15 22:00:00 +02:00
if( cl.frame.cd.deadflag != DEAD_NO || cl.frame.cd.flags & FL_FROZEN )
2009-12-04 22:00:00 +01:00
return;
2009-12-03 22:00:00 +01:00
2010-05-04 22:00:00 +02:00
// any camera on
2010-08-07 22:00:00 +02:00
if( cl.refdef.viewentity != pPlayer->index )
2009-12-04 22:00:00 +01:00
return;
2009-12-03 22:00:00 +01:00
2009-12-04 22:00:00 +01:00
// get crosshair dimension
width = clgame.ds.rcCrosshair.right - clgame.ds.rcCrosshair.left;
height = clgame.ds.rcCrosshair.bottom - clgame.ds.rcCrosshair.top;
2009-12-03 22:00:00 +01:00
2010-03-09 22:00:00 +01:00
x = clgame.scrInfo.iWidth / 2;
y = clgame.scrInfo.iHeight / 2;
2009-12-04 22:00:00 +01:00
// g-cont - cl.refdef.crosshairangle is the autoaim angle.
2010-03-09 22:00:00 +01:00
// if we're not using autoaim, just draw in the middle of the screen
2009-12-04 22:00:00 +01:00
if( !VectorIsNull( cl.refdef.crosshairangle ))
{
vec3_t angles;
vec3_t forward;
vec3_t point, screen;
2009-12-03 22:00:00 +01:00
2010-03-09 22:00:00 +01:00
VectorAdd( cl.refdef.viewangles, cl.refdef.crosshairangle, angles );
2009-12-04 22:00:00 +01:00
AngleVectors( angles, forward, NULL, NULL );
VectorAdd( cl.refdef.vieworg, forward, point );
re->WorldToScreen( point, screen );
2009-12-03 22:00:00 +01:00
2010-03-09 22:00:00 +01:00
x += 0.5f * screen[0] * clgame.scrInfo.iRealWidth + 0.5f;
y += 0.5f * screen[1] * clgame.scrInfo.iRealHeight + 0.5f;
2009-12-04 22:00:00 +01:00
}
2009-12-03 22:00:00 +01:00
clgame.ds.hSprite = clgame.ds.hCrosshair;
re->SetColor( clgame.ds.rgbaCrosshair );
re->SetParms( clgame.ds.hSprite, kRenderTransAlpha, 0 );
2009-12-04 22:00:00 +01:00
SPR_DrawGeneric( 0, x - 0.5f * width, y - 0.5f * height, -1, -1, &clgame.ds.rcCrosshair );
2009-12-03 22:00:00 +01:00
}
2010-07-08 22:00:00 +02:00
/*
=============
CL_DrawLoading
draw loading progress bar
=============
*/
2010-07-19 22:00:00 +02:00
static void CL_DrawLoading( float percent )
2010-07-08 22:00:00 +02:00
{
int x, y, width, height, right;
float xscale, yscale, step, s2;
rgba_t color;
re->GetParms( &width, &height, NULL, 0, cls.loadingBar );
2010-07-20 22:00:00 +02:00
x = ( 640 - width ) >> 1;
y = ( 480 - height) >> 1;
2010-07-08 22:00:00 +02:00
xscale = scr_width->integer / 640.0f;
yscale = scr_height->integer / 480.0f;
x *= xscale;
y *= yscale;
width *= xscale;
height *= yscale;
MakeRGBA( color, 128, 128, 128, 255 );
re->SetColor( color );
2010-07-21 22:00:00 +02:00
re->SetParms( cls.loadingBar, kRenderTransTexture, 0 );
2010-07-08 22:00:00 +02:00
re->DrawStretchPic( x, y, width, height, 0, 0, 1, 1, cls.loadingBar );
step = (float)width / 100.0f;
right = (int)ceil( percent * step );
s2 = (float)right / width;
width = right;
MakeRGBA( color, 208, 152, 0, 255 );
re->SetColor( color );
2010-07-13 22:00:00 +02:00
re->SetParms( cls.loadingBar, kRenderTransTexture, 0 );
2010-07-08 22:00:00 +02:00
re->DrawStretchPic( x, y, width, height, 0, 0, s2, 1, cls.loadingBar );
re->SetColor( NULL );
}
/*
=============
CL_DrawPause
draw pause sign
=============
*/
2010-07-19 22:00:00 +02:00
static void CL_DrawPause( void )
2010-07-08 22:00:00 +02:00
{
2010-07-19 22:00:00 +02:00
int x, y, width, height;
float xscale, yscale;
if( !re ) return;
2010-07-08 22:00:00 +02:00
2010-07-19 22:00:00 +02:00
re->GetParms( &width, &height, NULL, 0, cls.pauseIcon );
2010-07-20 22:00:00 +02:00
x = ( 640 - width ) >> 1;
y = ( 480 - height) >> 1;
2010-07-19 22:00:00 +02:00
xscale = scr_width->integer / 640.0f;
yscale = scr_height->integer / 480.0f;
x *= xscale;
y *= yscale;
width *= xscale;
height *= yscale;
re->SetColor( NULL );
re->SetParms( cls.pauseIcon, kRenderTransTexture, 0 );
re->DrawStretchPic( x, y, width, height, 0, 0, 1, 1, cls.pauseIcon );
2010-07-08 22:00:00 +02:00
}
2008-12-26 22:00:00 +01:00
void CL_DrawHUD( int state )
2008-12-25 22:00:00 +01:00
{
2009-01-25 22:00:00 +01:00
if( state == CL_ACTIVE && !cl.video_prepped )
state = CL_LOADING;
2009-11-10 22:00:00 +01:00
if( state == CL_ACTIVE && cl.refdef.paused )
2009-01-25 22:00:00 +01:00
state = CL_PAUSED;
2010-08-15 22:00:00 +02:00
if( state == CL_ACTIVE )
{
clgame.dllFuncs.pfnRedraw( cl_time(), false );
}
2009-01-22 22:00:00 +01:00
2010-07-08 22:00:00 +02:00
switch( state )
2009-12-04 22:00:00 +01:00
{
2010-07-08 22:00:00 +02:00
case CL_PAUSED:
CL_DrawPause();
// intentionally fallthrough
case CL_ACTIVE:
2009-12-04 22:00:00 +01:00
CL_DrawCrosshair ();
CL_DrawCenterPrint ();
2010-07-08 22:00:00 +02:00
break;
case CL_LOADING:
CL_DrawLoading( scr_loading->value );
break;
case CL_CHANGELEVEL:
CL_DrawLoading( 100.0f );
break;
2009-12-04 22:00:00 +01:00
}
2008-12-25 22:00:00 +01:00
}
2010-06-22 22:00:00 +02:00
void CL_LinkUserMessage( char *pszName, const int svc_num, int iSize )
2008-12-25 22:00:00 +01:00
{
2010-08-16 22:00:00 +02:00
int i;
2008-12-25 22:00:00 +01:00
2010-06-22 22:00:00 +02:00
if( !pszName || !*pszName )
2010-08-16 22:00:00 +02:00
Host_Error( "CL_LinkUserMessage: bad message name\n" );
if( svc_num < svc_lastmsg )
Host_Error( "CL_LinkUserMessage: tired to hook a system message \"%s\"\n", svc_strings[svc_num] );
2008-12-26 22:00:00 +01:00
2010-06-22 22:00:00 +02:00
// see if already hooked
for( i = 0; i < MAX_USER_MESSAGES && clgame.msg[i].name[0]; i++ )
2008-12-26 22:00:00 +01:00
{
2010-08-16 22:00:00 +02:00
// NOTE: no check for DispatchFunc, check only name
if( !com.strcmp( clgame.msg[i].name, pszName ))
{
clgame.msg[i].number = svc_num;
clgame.msg[i].size = iSize;
2008-12-26 22:00:00 +01:00
return;
2010-08-16 22:00:00 +02:00
}
2009-12-03 22:00:00 +01:00
}
2010-06-22 22:00:00 +02:00
if( i == MAX_USER_MESSAGES )
2008-12-25 22:00:00 +01:00
{
2010-08-16 22:00:00 +02:00
Host_Error( "CL_LinkUserMessage: MAX_USER_MESSAGES hit!\n" );
2008-12-25 22:00:00 +01:00
return;
}
2010-08-16 22:00:00 +02:00
// register new message without DispatchFunc, so we should parse it properly
2010-06-22 22:00:00 +02:00
com.strncpy( clgame.msg[i].name, pszName, sizeof( clgame.msg[i].name ));
clgame.msg[i].number = svc_num;
clgame.msg[i].size = iSize;
2008-12-25 22:00:00 +01:00
}
2009-12-02 22:00:00 +01:00
static void CL_RegisterEvent( int lastnum, const char *szEvName, pfnEventHook func )
{
user_event_t *ev;
if( lastnum == MAX_EVENTS )
{
2010-08-16 22:00:00 +02:00
MsgDev( D_ERROR, "CL_RegisterEvent: MAX_EVENTS hit!\n" );
2009-12-02 22:00:00 +01:00
return;
}
ev = clgame.events[lastnum];
// clear existing or allocate new one
if( ev ) Mem_Set( ev, 0, sizeof( *ev ));
else ev = clgame.events[lastnum] = Mem_Alloc( cls.mempool, sizeof( *ev ));
com.strncpy( ev->name, szEvName, CS_SIZE );
ev->func = func;
// ev->index will be set later
}
void CL_SetEventIndex( const char *szEvName, int ev_index )
{
user_event_t *ev;
int i;
if( !szEvName || !*szEvName ) return; // ignore blank names
// search event by name to link with
for( i = 0; i < MAX_EVENTS; i++ )
{
ev = clgame.events[i];
if( !ev ) break;
if( !com.strcmp( ev->name, szEvName ))
{
ev->index = ev_index;
return;
}
}
}
2010-08-07 22:00:00 +02:00
void CL_InitEntity( cl_entity_t *pEdict )
2008-12-25 22:00:00 +01:00
{
2010-07-29 22:00:00 +02:00
ASSERT( pEdict );
2008-12-25 22:00:00 +01:00
2010-08-07 22:00:00 +02:00
pEdict->index = NUM_FOR_EDICT( pEdict );
2008-12-25 22:00:00 +01:00
}
2010-08-07 22:00:00 +02:00
void CL_FreeEntity( cl_entity_t *pEdict )
2008-12-25 22:00:00 +01:00
{
2010-07-29 22:00:00 +02:00
ASSERT( pEdict );
2008-12-25 22:00:00 +01:00
2010-08-07 22:00:00 +02:00
// already freed ?
if( pEdict->index == -1 )
return;
clgame.dllFuncs.pfnUpdateOnRemove( pEdict );
pEdict->index = -1; // freed
2008-12-25 22:00:00 +01:00
}
2009-11-27 22:00:00 +01:00
void CL_InitWorld( void )
2009-09-25 22:00:00 +02:00
{
2010-08-07 22:00:00 +02:00
cl_entity_t *ent;
2009-09-25 22:00:00 +02:00
2009-11-26 22:00:00 +01:00
ent = EDICT_NUM( 0 );
2010-08-07 22:00:00 +02:00
ent->index = NUM_FOR_EDICT( ent );
ent->curstate.modelindex = 1; // world model
ent->curstate.solid = SOLID_BSP;
ent->curstate.movetype = MOVETYPE_PUSH;
2009-11-26 22:00:00 +01:00
clgame.globals->numEntities = 1;
2009-10-18 22:00:00 +02:00
2010-08-18 22:00:00 +02:00
// clear physics interaction links
CL_ClearWorld ();
2009-09-25 22:00:00 +02:00
}
2009-11-27 22:00:00 +01:00
void CL_InitEdicts( void )
{
2010-08-07 22:00:00 +02:00
cl_entity_t *e;
2009-11-27 22:00:00 +01:00
int i;
2010-08-07 22:00:00 +02:00
ASSERT( clgame.entities == NULL );
2009-11-28 22:00:00 +01:00
2010-04-02 22:00:00 +02:00
CL_UPDATE_BACKUP = ( clgame.globals->maxClients == 1 ) ? SINGLEPLAYER_BACKUP : MULTIPLAYER_BACKUP;
cl.frames = Mem_Alloc( clgame.mempool, sizeof( frame_t ) * CL_UPDATE_BACKUP );
2010-08-07 22:00:00 +02:00
clgame.entities = Mem_Alloc( clgame.mempool, sizeof( cl_entity_t ) * clgame.globals->maxEntities );
for( i = 0, e = clgame.entities; i < clgame.globals->maxEntities; i++, e++ )
e->index = -1; // mark all entities as freed
2009-11-27 22:00:00 +01:00
}
2008-12-25 22:00:00 +01:00
void CL_FreeEdicts( void )
{
int i;
2010-08-07 22:00:00 +02:00
cl_entity_t *ent;
2008-12-25 22:00:00 +01:00
2010-08-07 22:00:00 +02:00
if( clgame.entities )
2008-12-25 22:00:00 +01:00
{
2009-11-27 22:00:00 +01:00
for( i = 0; i < clgame.globals->maxEntities; i++ )
{
ent = EDICT_NUM( i );
2010-08-07 22:00:00 +02:00
if( ent->index <= 0 ) continue;
CL_FreeEntity( ent );
2009-11-27 22:00:00 +01:00
}
2010-08-07 22:00:00 +02:00
Mem_Free( clgame.entities );
2008-12-25 22:00:00 +01:00
}
2009-01-02 22:00:00 +01:00
2010-04-02 22:00:00 +02:00
if( cl.frames ) Mem_Free( cl.frames );
2009-09-28 22:00:00 +02:00
clgame.globals->numEntities = 0;
2010-08-07 22:00:00 +02:00
clgame.entities = NULL;
2010-04-02 22:00:00 +02:00
cl.frames = NULL;
2008-12-25 22:00:00 +01:00
}
/*
===============================================================================
CGame Builtin Functions
===============================================================================
*/
2009-12-03 22:00:00 +01:00
/*
=========
pfnSPR_Load
=========
*/
2009-12-04 22:00:00 +01:00
static HSPRITE pfnSPR_Load( const char *szPicName )
2009-12-03 22:00:00 +01:00
{
if( !re ) return 0; // render not initialized
if( !szPicName || !*szPicName )
{
2010-07-08 22:00:00 +02:00
MsgDev( D_ERROR, "CL_LoadSprite: bad name!\n" );
return 0;
2009-12-03 22:00:00 +01:00
}
2010-07-08 22:00:00 +02:00
return re->RegisterShader( szPicName, SHADER_SPRITE );
2009-12-03 22:00:00 +01:00
}
/*
=========
2010-07-18 22:00:00 +02:00
pfnSPR_Frames
2009-12-03 22:00:00 +01:00
=========
*/
static int pfnSPR_Frames( HSPRITE hPic )
{
int numFrames;
if( !re ) return 1;
re->GetParms( NULL, NULL, &numFrames, 0, hPic );
return numFrames;
}
/*
=========
2010-07-18 22:00:00 +02:00
pfnSPR_Height
2009-12-03 22:00:00 +01:00
=========
*/
static int pfnSPR_Height( HSPRITE hPic, int frame )
{
int sprHeight;
if( !re ) return 0;
re->GetParms( NULL, &sprHeight, NULL, frame, hPic );
return sprHeight;
}
/*
=========
2010-07-18 22:00:00 +02:00
pfnSPR_Width
2009-12-03 22:00:00 +01:00
=========
*/
static int pfnSPR_Width( HSPRITE hPic, int frame )
{
int sprWidth;
if( !re ) return 0;
re->GetParms( &sprWidth, NULL, NULL, frame, hPic );
return sprWidth;
}
/*
=========
2010-07-18 22:00:00 +02:00
pfnSPR_Set
2009-12-03 22:00:00 +01:00
=========
*/
static void pfnSPR_Set( HSPRITE hPic, int r, int g, int b, int a )
{
rgba_t color;
if( !re ) return; // render not initialized
clgame.ds.hSprite = hPic;
MakeRGBA( color, r, g, b, a );
re->SetColor( color );
}
/*
=========
pfnSPR_Draw
=========
*/
static void pfnSPR_Draw( int frame, int x, int y, int width, int height, const wrect_t *prc )
{
if( !re ) return; // render not initialized
re->SetParms( clgame.ds.hSprite, kRenderNormal, frame );
SPR_DrawGeneric( frame, x, y, width, height, prc );
}
/*
=========
pfnSPR_DrawTrans
=========
*/
static void pfnSPR_DrawTrans( int frame, int x, int y, int width, int height, const wrect_t *prc )
{
if( !re ) return; // render not initialized
re->SetParms( clgame.ds.hSprite, kRenderTransColor, frame );
SPR_DrawGeneric( frame, x, y, width, height, prc );
}
/*
=========
pfnSPR_DrawHoles
=========
*/
static void pfnSPR_DrawHoles( int frame, int x, int y, int width, int height, const wrect_t *prc )
{
if( !re ) return; // render not initialized
re->SetParms( clgame.ds.hSprite, kRenderTransAlpha, frame );
SPR_DrawGeneric( frame, x, y, width, height, prc );
}
/*
=========
pfnSPR_DrawAdditive
=========
*/
static void pfnSPR_DrawAdditive( int frame, int x, int y, int width, int height, const wrect_t *prc )
{
if( !re ) return; // render not initialized
re->SetParms( clgame.ds.hSprite, kRenderTransAdd, frame );
SPR_DrawGeneric( frame, x, y, width, height, prc );
}
/*
=========
pfnSPR_EnableScissor
=========
*/
static void pfnSPR_EnableScissor( int x, int y, int width, int height )
{
// check bounds
x = bound( 0, x, clgame.scrInfo.iWidth );
y = bound( 0, y, clgame.scrInfo.iHeight );
width = bound( 0, width, clgame.scrInfo.iWidth - x );
height = bound( 0, height, clgame.scrInfo.iHeight - y );
clgame.ds.scissor_x = x;
clgame.ds.scissor_width = width;
clgame.ds.scissor_y = y;
clgame.ds.scissor_height = height;
clgame.ds.scissor_test = true;
}
/*
=========
pfnSPR_DisableScissor
=========
*/
static void pfnSPR_DisableScissor( void )
{
clgame.ds.scissor_x = 0;
clgame.ds.scissor_width = 0;
clgame.ds.scissor_y = 0;
clgame.ds.scissor_height = 0;
clgame.ds.scissor_test = false;
}
/*
=========
pfnSPR_GetList
2010-03-30 22:00:00 +02:00
for parsing half-life scripts - hud.txt etc
2009-12-03 22:00:00 +01:00
=========
*/
static client_sprite_t *pfnSPR_GetList( char *psz, int *piCount )
{
2010-03-30 22:00:00 +02:00
client_sprite_t *pList;
2010-07-08 22:00:00 +02:00
int numSprites = 0;
2010-03-30 22:00:00 +02:00
int index, iTemp;
script_t *script;
token_t token;
if( piCount ) *piCount = 0;
2010-07-08 22:00:00 +02:00
if( !clgame.itemspath[0] )
FS_ExtractFilePath( psz, clgame.itemspath );
2010-03-30 22:00:00 +02:00
script = Com_OpenScript( psz, NULL, 0 );
if( !script ) return NULL;
2010-07-08 22:00:00 +02:00
Com_ReadUlong( script, SC_ALLOW_NEWLINES, &numSprites );
2010-03-30 22:00:00 +02:00
// name, res, pic, x, y, w, h
pList = Mem_Alloc( clgame.mempool, sizeof( *pList ) * numSprites );
for( index = 0; index < numSprites; index++ )
{
2010-07-08 22:00:00 +02:00
if( !Com_ReadToken( script, SC_ALLOW_NEWLINES|SC_PARSE_GENERIC, &token ))
2010-03-30 22:00:00 +02:00
break;
com.strncpy( pList[index].szName, token.string, sizeof( pList[index].szName ));
// read resolution
Com_ReadUlong( script, false, &iTemp );
pList[index].iRes = iTemp;
// read spritename
2010-07-08 22:00:00 +02:00
Com_ReadToken( script, SC_PARSE_GENERIC, &token );
2010-03-30 22:00:00 +02:00
com.strncpy( pList[index].szSprite, token.string, sizeof( pList[index].szSprite ));
// parse rectangle
Com_ReadUlong( script, false, &iTemp );
pList[index].rc.left = iTemp;
Com_ReadUlong( script, false, &iTemp );
pList[index].rc.top = iTemp;
Com_ReadUlong( script, false, &iTemp );
pList[index].rc.right = pList[index].rc.left + iTemp;
Com_ReadUlong( script, false, &iTemp );
pList[index].rc.bottom = pList[index].rc.top + iTemp;
if( piCount ) (*piCount)++;
}
if( index < numSprites )
2010-07-13 22:00:00 +02:00
MsgDev( D_WARN, "SPR_GetList: unexpected end of %s (%i should be %i)\n", psz, index, numSprites );
2010-03-30 22:00:00 +02:00
Com_CloseScript( script );
return pList;
2009-12-03 22:00:00 +01:00
}
/*
=============
pfnFillRGBA
=============
*/
static void pfnFillRGBA( int x, int y, int width, int height, int r, int g, int b, int a )
{
rgba_t color;
if( !re ) return;
MakeRGBA( color, r, g, b, a );
re->SetColor( color );
SPR_AdjustSize( (float *)&x, (float *)&y, (float *)&width, (float *)&height );
2010-07-19 22:00:00 +02:00
re->SetParms( cls.fillShader, kRenderTransTexture, 0 );
2009-12-03 22:00:00 +01:00
re->DrawStretchPic( x, y, width, height, 0, 0, 1, 1, cls.fillShader );
re->SetColor( NULL );
}
/*
=============
pfnGetScreenInfo
get actual screen info
=============
*/
static int pfnGetScreenInfo( SCREENINFO *pscrinfo )
{
// setup screen info
clgame.scrInfo.iRealWidth = scr_width->integer;
clgame.scrInfo.iRealHeight = scr_height->integer;
if( pscrinfo && pscrinfo->iFlags & SCRINFO_VIRTUALSPACE )
{
// virtual screen space 640x480
2010-07-20 22:00:00 +02:00
clgame.scrInfo.iWidth = 640;
clgame.scrInfo.iHeight = 480;
2009-12-04 22:00:00 +01:00
clgame.scrInfo.iFlags |= SCRINFO_VIRTUALSPACE;
2009-12-03 22:00:00 +01:00
}
else
{
clgame.scrInfo.iWidth = scr_width->integer;
clgame.scrInfo.iHeight = scr_height->integer;
2009-12-04 22:00:00 +01:00
clgame.scrInfo.iFlags &= ~SCRINFO_VIRTUALSPACE;
2009-12-03 22:00:00 +01:00
}
if( !pscrinfo ) return 0;
*pscrinfo = clgame.scrInfo; // copy screeninfo out
return 1;
}
/*
=============
pfnSetCrosshair
setup auto-aim crosshair
=============
*/
static void pfnSetCrosshair( HSPRITE hspr, wrect_t rc, int r, int g, int b )
{
clgame.ds.rgbaCrosshair[0] = (byte)r;
clgame.ds.rgbaCrosshair[1] = (byte)g;
clgame.ds.rgbaCrosshair[2] = (byte)b;
clgame.ds.rgbaCrosshair[3] = (byte)0xFF;
clgame.ds.hCrosshair = hspr;
clgame.ds.rcCrosshair = rc;
}
2008-12-25 22:00:00 +01:00
/*
=============
pfnHookUserMsg
=============
*/
2010-06-22 22:00:00 +02:00
static void pfnHookUserMsg( const char *pszName, pfnUserMsgHook pfn )
2008-12-25 22:00:00 +01:00
{
2010-06-22 22:00:00 +02:00
int i;
2008-12-25 22:00:00 +01:00
2010-08-16 22:00:00 +02:00
// ignore blank names or invalid callbacks
if( !pszName || !*pszName || !pfn )
2010-06-22 22:00:00 +02:00
return;
2008-12-26 22:00:00 +01:00
2010-08-16 22:00:00 +02:00
for( i = 0; i < MAX_USER_MESSAGES && clgame.msg[i].name[0]; i++ )
2008-12-25 22:00:00 +01:00
{
2010-06-22 22:00:00 +02:00
// see if already hooked
2010-08-16 22:00:00 +02:00
if( !com.strcmp( clgame.msg[i].name, pszName ))
2008-12-25 22:00:00 +01:00
return;
}
2010-06-22 22:00:00 +02:00
if( i == MAX_USER_MESSAGES )
{
2010-08-16 22:00:00 +02:00
Host_Error( "HookUserMsg: MAX_USER_MESSAGES hit!\n" );
2010-06-22 22:00:00 +02:00
return;
}
// hook new message
2010-08-16 22:00:00 +02:00
com.strncpy( clgame.msg[i].name, pszName, sizeof( clgame.msg[i].name ));
clgame.msg[i].func = pfn;
2008-12-25 22:00:00 +01:00
}
/*
=============
pfnServerCmd
=============
*/
2009-12-04 22:00:00 +01:00
static void pfnServerCmd( const char *szCmdString )
2008-12-25 22:00:00 +01:00
{
// server command adding in cmds queue
Cbuf_AddText( va( "cmd %s", szCmdString ));
}
/*
=============
pfnClientCmd
=============
*/
2009-12-04 22:00:00 +01:00
static void pfnClientCmd( const char *szCmdString )
2008-12-25 22:00:00 +01:00
{
// client command executes immediately
2010-02-02 22:00:00 +01:00
Cbuf_AddText( szCmdString );
2008-12-25 22:00:00 +01:00
}
2009-01-09 22:00:00 +01:00
/*
=============
2009-12-04 22:00:00 +01:00
pfnGetPlayerInfo
2009-01-09 22:00:00 +01:00
=============
*/
2009-12-04 22:00:00 +01:00
static void pfnGetPlayerInfo( int ent_num, hud_player_info_t *pinfo )
2009-01-09 22:00:00 +01:00
{
2009-12-04 22:00:00 +01:00
player_info_t *player;
ent_num -= 1; // player list if offset by 1 from ents
if( ent_num >= clgame.globals->maxClients || ent_num < 0 || !cl.players[ent_num].name[0] )
2009-01-09 22:00:00 +01:00
{
2009-12-04 22:00:00 +01:00
Mem_Set( pinfo, 0, sizeof( *pinfo ));
return;
2009-01-09 22:00:00 +01:00
}
2009-12-04 22:00:00 +01:00
player = &cl.players[ent_num];
pinfo->thisplayer = ( ent_num == cl.playernum ) ? true : false;
pinfo->name = player->name;
pinfo->model = player->model;
pinfo->ping = com.atoi( Info_ValueForKey( player->userinfo, "ping" ));
pinfo->spectator = com.atoi( Info_ValueForKey( player->userinfo, "spectator" ));
pinfo->packetloss = com.atoi( Info_ValueForKey( player->userinfo, "loss" ));
pinfo->topcolor = com.atoi( Info_ValueForKey( player->userinfo, "topcolor" ));
pinfo->bottomcolor = com.atoi( Info_ValueForKey( player->userinfo, "bottomcolor" ));
2009-01-09 22:00:00 +01:00
}
2009-12-04 22:00:00 +01:00
2008-12-25 22:00:00 +01:00
/*
=============
2009-12-04 22:00:00 +01:00
pfnPlaySoundByName
2008-12-25 22:00:00 +01:00
=============
*/
2009-12-04 22:00:00 +01:00
static void pfnPlaySoundByName( const char *szSound, float volume, int pitch, const float *org )
2008-12-25 22:00:00 +01:00
{
2010-06-28 22:00:00 +02:00
S_StartSound( org, cl.refdef.viewentity, CHAN_AUTO, S_RegisterSound( szSound ), volume, ATTN_NORM, pitch, 0 );
2009-12-04 22:00:00 +01:00
}
2008-12-25 22:00:00 +01:00
2009-12-04 22:00:00 +01:00
/*
=============
pfnPlaySoundByIndex
=============
*/
static void pfnPlaySoundByIndex( int iSound, float volume, int pitch, const float *org )
{
// 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;
}
S_StartSound( org, cl.refdef.viewentity, CHAN_AUTO, cl.sound_precache[iSound], volume, ATTN_NORM, pitch, 0 );
2008-12-25 22:00:00 +01:00
}
/*
=============
2009-01-03 22:00:00 +01:00
pfnTextMessageGet
2008-12-25 22:00:00 +01:00
2009-12-04 22:00:00 +01:00
returns specified message from titles.txt
2008-12-25 22:00:00 +01:00
=============
*/
2009-12-04 22:00:00 +01:00
static client_textmessage_t *pfnTextMessageGet( const char *pName )
2008-12-25 22:00:00 +01:00
{
2009-10-23 22:00:00 +02:00
int i;
2008-12-25 22:00:00 +01:00
2009-10-23 22:00:00 +02:00
// find desired message
for( i = 0; i < clgame.numTitles; i++ )
{
if( !com.strcmp( pName, clgame.titles[i].pName ))
return clgame.titles + i;
}
return NULL; // found nothing
2008-12-25 22:00:00 +01:00
}
/*
=============
2009-12-04 22:00:00 +01:00
pfnDrawCharacter
2008-12-25 22:00:00 +01:00
2009-12-04 22:00:00 +01:00
returns drawed chachter width (in real screen pixels)
2008-12-25 22:00:00 +01:00
=============
*/
2009-12-04 22:00:00 +01:00
static int pfnDrawCharacter( int x, int y, int number, int r, int g, int b )
2008-12-25 22:00:00 +01:00
{
2009-12-04 22:00:00 +01:00
number &= 255;
2010-07-20 22:00:00 +02:00
if( !cls.creditsFont.valid )
return 0;
2010-07-08 22:00:00 +02:00
if( number < 32 ) return 0;
2009-12-04 22:00:00 +01:00
if( y < -clgame.scrInfo.iCharHeight )
return 0;
2010-07-20 22:00:00 +02:00
pfnSPR_Set( cls.creditsFont.hFontTexture, r, g, b, 255 );
pfnSPR_DrawAdditive( 0, x, y, -1, -1, &cls.creditsFont.fontRc[number] );
2009-12-04 22:00:00 +01:00
return clgame.scrInfo.charWidths[number];
2008-12-25 22:00:00 +01:00
}
/*
=============
2009-12-04 22:00:00 +01:00
pfnDrawConsoleString
2008-12-25 22:00:00 +01:00
2009-12-04 22:00:00 +01:00
drawing string like a console string
2008-12-25 22:00:00 +01:00
=============
2009-12-04 22:00:00 +01:00
*/
static int pfnDrawConsoleString( int x, int y, char *string )
2008-12-25 22:00:00 +01:00
{
2010-07-20 22:00:00 +02:00
int drawLen;
2009-12-04 22:00:00 +01:00
if( !string || !*string ) return 0; // silent ignore
2010-07-20 22:00:00 +02:00
drawLen = Con_DrawString( x, y, string, clgame.ds.textColor );
MakeRGBA( clgame.ds.textColor, 255, 255, 255, 255 );
return drawLen; // exclude color prexfixes
2008-12-25 22:00:00 +01:00
}
/*
=============
2009-12-04 22:00:00 +01:00
pfnDrawSetTextColor
2008-12-25 22:00:00 +01:00
2009-12-04 22:00:00 +01:00
set color for anything
2008-12-25 22:00:00 +01:00
=============
*/
2009-12-04 22:00:00 +01:00
static void pfnDrawSetTextColor( float r, float g, float b )
2008-12-25 22:00:00 +01:00
{
2009-12-04 22:00:00 +01:00
// bound color and convert to byte
2010-07-20 22:00:00 +02:00
clgame.ds.textColor[0] = (byte)bound( 0, r * 255, 255 );
clgame.ds.textColor[1] = (byte)bound( 0, g * 255, 255 );
clgame.ds.textColor[2] = (byte)bound( 0, b * 255, 255 );
clgame.ds.textColor[3] = (byte)0xFF;
2008-12-25 22:00:00 +01:00
}
/*
=============
2009-12-04 22:00:00 +01:00
pfnConsolePrint
2008-12-25 22:00:00 +01:00
2009-12-04 22:00:00 +01:00
prints dirctly into console (can skip notify)
2008-12-25 22:00:00 +01:00
=============
*/
2009-12-04 22:00:00 +01:00
static void pfnConsolePrint( const char *string )
2008-12-25 22:00:00 +01:00
{
2009-12-04 22:00:00 +01:00
if( !string || !*string ) return;
2010-02-02 22:00:00 +01:00
if( *string != 1 ) Con_Print( string ); // show notify
else Con_Print( va( "[skipnotify]%s", string + 1 )); // skip notify
2009-12-04 22:00:00 +01:00
}
2008-12-25 22:00:00 +01:00
2009-12-04 22:00:00 +01:00
/*
=============
pfnCenterPrint
2008-12-25 22:00:00 +01:00
2009-12-04 22:00:00 +01:00
holds and fade message at center of screen
like trigger_multiple message in q1
=============
*/
static void pfnCenterPrint( const char *string )
{
if( !string || !*string ) return; // someone stupid joke
2010-07-19 22:00:00 +02:00
CL_CenterPrint( string, -1 );
2009-12-04 22:00:00 +01:00
}
2009-12-05 22:00:00 +01:00
2009-12-04 22:00:00 +01:00
/*
=========
pfnMemAlloc
2008-12-25 22:00:00 +01:00
2009-12-04 22:00:00 +01:00
=========
*/
static void *pfnMemAlloc( size_t cb, const char *filename, const int fileline )
{
return com.malloc( clgame.private, cb, filename, fileline );
}
2008-12-25 22:00:00 +01:00
2009-12-04 22:00:00 +01:00
/*
=========
pfnMemFree
2008-12-25 22:00:00 +01:00
2009-12-04 22:00:00 +01:00
=========
*/
static void pfnMemFree( void *mem, const char *filename, const int fileline )
{
com.free( mem, filename, fileline );
2008-12-25 22:00:00 +01:00
}
/*
=============
2009-12-05 22:00:00 +01:00
pfnGetViewAngles
2008-12-25 22:00:00 +01:00
2009-12-05 22:00:00 +01:00
return interpolated angles from previous frame
2008-12-25 22:00:00 +01:00
=============
*/
2009-12-05 22:00:00 +01:00
static void pfnGetViewAngles( float *angles )
2008-12-25 22:00:00 +01:00
{
2010-06-28 22:00:00 +02:00
if( angles ) VectorCopy( cl.refdef.cl_viewangles, angles );
2008-12-25 22:00:00 +01:00
}
/*
=============
2009-12-05 22:00:00 +01:00
pfnSetViewAngles
2008-12-25 22:00:00 +01:00
2009-12-05 22:00:00 +01:00
return interpolated angles from previous frame
2008-12-25 22:00:00 +01:00
=============
*/
2009-12-05 22:00:00 +01:00
static void pfnSetViewAngles( float *angles )
2008-12-25 22:00:00 +01:00
{
2010-06-28 22:00:00 +02:00
if( angles ) VectorCopy( angles, cl.refdef.cl_viewangles );
2008-12-25 22:00:00 +01:00
}
2009-12-04 22:00:00 +01:00
/*
=============
2009-12-05 22:00:00 +01:00
pfnPhysInfo_ValueForKey
2009-12-04 22:00:00 +01:00
=============
2009-12-05 22:00:00 +01:00
*/
static const char* pfnPhysInfo_ValueForKey( const char *key )
2009-12-04 22:00:00 +01:00
{
2010-08-05 22:00:00 +02:00
return Info_ValueForKey( cl.frame.cd.physinfo, key );
2008-12-28 22:00:00 +01:00
}
2008-12-25 22:00:00 +01:00
/*
=============
2009-12-05 22:00:00 +01:00
pfnServerInfo_ValueForKey
2008-12-25 22:00:00 +01:00
=============
*/
2009-12-05 22:00:00 +01:00
static const char* pfnServerInfo_ValueForKey( const char *key )
2008-12-25 22:00:00 +01:00
{
2010-03-30 22:00:00 +02:00
return Info_ValueForKey( cl.serverinfo, key );
2008-12-25 22:00:00 +01:00
}
/*
=============
2009-12-05 22:00:00 +01:00
pfnGetClientMaxspeed
2008-12-25 22:00:00 +01:00
2009-12-05 22:00:00 +01:00
value that come from server
2008-12-25 22:00:00 +01:00
=============
*/
2009-12-05 22:00:00 +01:00
static float pfnGetClientMaxspeed( void )
2008-12-25 22:00:00 +01:00
{
2010-08-07 22:00:00 +02:00
return cl.frame.cd.maxspeed;
2008-12-25 22:00:00 +01:00
}
/*
=============
2009-12-05 22:00:00 +01:00
pfnGetModelPtr
2008-12-25 22:00:00 +01:00
2009-12-05 22:00:00 +01:00
returns pointer to a studiomodel
2008-12-25 22:00:00 +01:00
=============
*/
2010-08-07 22:00:00 +02:00
static void *pfnGetModelPtr( cl_entity_t *pEdict )
2008-12-25 22:00:00 +01:00
{
2010-08-07 22:00:00 +02:00
if( !pEdict || pEdict->index == -1 )
2009-12-05 22:00:00 +01:00
return NULL;
2010-08-07 22:00:00 +02:00
return Mod_Extradata( pEdict->curstate.modelindex );
2008-12-25 22:00:00 +01:00
}
/*
=============
2009-12-05 22:00:00 +01:00
pfnGetViewModel
2008-12-25 22:00:00 +01:00
2009-12-05 22:00:00 +01:00
can return NULL
2008-12-25 22:00:00 +01:00
=============
*/
2010-08-07 22:00:00 +02:00
static cl_entity_t* pfnGetViewModel( void )
2008-12-25 22:00:00 +01:00
{
2009-12-05 22:00:00 +01:00
return &clgame.viewent;
2008-12-25 22:00:00 +01:00
}
/*
=============
2009-12-05 22:00:00 +01:00
pfnGetClientTime
2008-12-25 22:00:00 +01:00
=============
*/
2009-12-05 22:00:00 +01:00
static float pfnGetClientTime( void )
2008-12-25 22:00:00 +01:00
{
2010-07-23 22:00:00 +02:00
return cl_time();
2008-12-25 22:00:00 +01:00
}
2009-01-22 22:00:00 +01:00
/*
=============
2009-12-05 22:00:00 +01:00
pfnIsSpectateOnly
2009-01-22 22:00:00 +01:00
=============
*/
2009-12-05 22:00:00 +01:00
static int pfnIsSpectateOnly( void )
2009-01-22 22:00:00 +01:00
{
2009-12-05 22:00:00 +01:00
return com.atoi( Info_ValueForKey( Cvar_Userinfo(), "spectator" )) ? true : false;
2009-01-22 22:00:00 +01:00
}
2008-12-25 22:00:00 +01:00
/*
=============
pfnPointContents
=============
*/
2010-08-18 22:00:00 +02:00
static int pfnPointContents( const float *p, int *truecontents )
2008-12-25 22:00:00 +01:00
{
2010-08-18 22:00:00 +02:00
int cont, truecont;
truecont = cont = CL_TruePointContents( p );
if( truecontents ) *truecontents = truecont;
if( cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN )
cont = CONTENTS_WATER;
return cont;
2008-12-25 22:00:00 +01:00
}
2009-12-05 22:00:00 +01:00
/*
=============
pfnWaterEntity
=============
*/
2010-08-07 22:00:00 +02:00
static cl_entity_t *pfnWaterEntity( const float *rgflPos )
2009-12-05 22:00:00 +01:00
{
2010-08-07 22:00:00 +02:00
cl_entity_t *pWater, *touch[MAX_EDICTS];
2010-08-18 22:00:00 +02:00
int i, num;
2009-12-05 22:00:00 +01:00
if( !rgflPos ) return NULL;
2010-05-04 22:00:00 +02:00
// grab contents from all the water entities
2010-08-18 22:00:00 +02:00
num = CL_AreaEdicts( rgflPos, rgflPos, touch, MAX_EDICTS, AREA_CUSTOM );
2009-12-05 22:00:00 +01:00
2010-05-04 22:00:00 +02:00
for( i = 0; i < num; i++ )
2009-12-05 22:00:00 +01:00
{
2010-05-04 22:00:00 +02:00
pWater = touch[i];
2009-12-05 22:00:00 +01:00
2010-08-07 22:00:00 +02:00
if( !pWater || pWater->index == -1 )
2010-05-04 22:00:00 +02:00
continue;
2010-08-07 22:00:00 +02:00
if( pWater->curstate.solid != SOLID_NOT || pWater->curstate.skin == CONTENTS_NONE )
2010-05-04 22:00:00 +02:00
continue; // invalid water ?
// return first valid water entity
return pWater;
2009-12-05 22:00:00 +01:00
}
return NULL;
}
2008-12-25 22:00:00 +01:00
/*
=============
pfnTraceLine
=============
*/
2010-08-12 22:00:00 +02:00
static pmtrace_t *pfnTraceLine( const float *start, const float *end, int flags, int usehull, int ignore_pe )
2009-01-11 22:00:00 +01:00
{
2010-08-12 22:00:00 +02:00
static pmtrace_t trace;
2009-01-11 22:00:00 +01:00
2010-08-12 22:00:00 +02:00
// FIXME: implement traceline
Mem_Set( &trace, 0, sizeof( pmtrace_t ));
VectorCopy( end, trace.endpos );
trace.fraction = 1.0f;
trace.allsolid = true;
trace.hitgroup = -1;
2009-01-11 22:00:00 +01:00
2010-08-12 22:00:00 +02:00
return &trace;
2009-01-11 22:00:00 +01:00
}
/*
=============
pfnPrecacheEvent
=============
*/
static word pfnPrecacheEvent( int type, const char* psz )
{
2009-12-02 22:00:00 +01:00
return CL_PrecacheEvent( psz );
2009-01-11 22:00:00 +01:00
}
2009-12-05 22:00:00 +01:00
/*
=============
pfnHookEvent
=============
*/
static void pfnHookEvent( const char *name, pfnEventHook pfn )
{
word event_index = CL_PrecacheEvent( name );
user_event_t *ev;
int i;
// ignore blank names
if( !name || !*name ) return;
// second call can change EventFunc
for( i = 0; i < MAX_EVENTS; i++ )
{
ev = clgame.events[i];
if( !ev ) break;
if( !com.strcmp( name, ev->name ))
{
if( ev->func != pfn )
ev->func = pfn;
return;
}
}
CL_RegisterEvent( i, name, pfn );
}
2009-01-11 22:00:00 +01:00
/*
=============
pfnKillEvent
=============
*/
2009-12-05 22:00:00 +01:00
static void pfnKillEvents( int entnum, const char *eventname )
{
int i;
event_state_t *es;
event_info_t *ei;
int eventIndex = CL_PrecacheEvent( eventname );
if( eventIndex < 0 || eventIndex >= MAX_EVENTS )
return;
if( entnum < 0 || entnum > clgame.globals->maxEntities )
return;
es = &cl.events;
// find all events with specified index and kill it
for( i = 0; i < MAX_EVENT_QUEUE; i++ )
{
ei = &es->ei[i];
if( ei->index != eventIndex || ei->entity_index != entnum )
continue;
CL_ResetEvent( ei );
}
}
2009-12-08 22:00:00 +01:00
/*
=============
pfnPlaySound
=============
*/
2010-08-12 22:00:00 +02:00
void pfnPlaySound( int ent, float *org, int chan, const char *samp, float vol, float attn, int flags, int pitch )
2009-12-08 22:00:00 +01:00
{
2010-08-12 22:00:00 +02:00
S_StartSound( org, ent, chan, S_RegisterSound( samp ), vol, attn, pitch, flags );
2009-12-08 22:00:00 +01:00
}
/*
=============
pfnStopSound
=============
*/
void pfnStopSound( int ent, int channel, const char *sample )
{
2010-04-24 22:00:00 +02:00
S_StopSound( ent, channel, sample );
2009-12-08 22:00:00 +01:00
}
/*
=============
pfnFindModelIndex
=============
*/
int pfnFindModelIndex( const char *model )
{
int i;
if( !model || !*model ) return 0;
for( i = 1; i < MAX_MODELS; i++ )
{
if( !com.strcmp( model, cl.configstrings[CS_MODELS+i] ))
return i;
}
return 0;
}
/*
=============
pfnIsLocal
=============
*/
int pfnIsLocal( int playernum )
{
if( playernum == cl.playernum )
return true;
return false;
}
2010-08-12 22:00:00 +02:00
/*
=============
pfnLocalPlayerDucking
=============
*/
int pfnLocalPlayerDucking( void )
{
return cl.frame.cd.bInDuck;
}
2009-12-08 22:00:00 +01:00
/*
=============
pfnLocalPlayerViewheight
=============
*/
void pfnLocalPlayerViewheight( float *view_ofs )
{
// predicted or smoothed
if( view_ofs ) VectorCopy( cl.predicted_viewofs, view_ofs );
}
/*
=============
2010-08-12 22:00:00 +02:00
pfnLocalPlayerBounds
2009-12-08 22:00:00 +01:00
=============
*/
2010-08-12 22:00:00 +02:00
void pfnLocalPlayerBounds( int hull, float *mins, float *maxs )
2009-12-08 22:00:00 +01:00
{
2010-08-12 22:00:00 +02:00
if( hull >= 0 && hull < 4 )
{
if( mins ) VectorCopy( clgame.pmove->player_mins[hull], mins );
if( maxs ) VectorCopy( clgame.pmove->player_maxs[hull], maxs );
}
2009-12-08 22:00:00 +01:00
}
2010-03-06 22:00:00 +01:00
/*
=============
2010-08-12 22:00:00 +02:00
pfnIndexFromTrace
2010-03-06 22:00:00 +01:00
=============
*/
2010-08-12 22:00:00 +02:00
int pfnIndexFromTrace( struct pmtrace_s *pTrace )
2010-03-06 22:00:00 +01:00
{
2010-08-12 22:00:00 +02:00
// FIXME: implement
return -1;
2010-03-06 22:00:00 +01:00
}
/*
=============
2010-08-12 22:00:00 +02:00
pfnGetPhysent
2010-03-06 22:00:00 +01:00
=============
*/
2010-08-12 22:00:00 +02:00
physent_t *pfnGetPhysent( int idx )
2010-03-06 22:00:00 +01:00
{
2010-08-12 22:00:00 +02:00
// FIXME: implement
return NULL;
}
2010-03-06 22:00:00 +01:00
2010-08-12 22:00:00 +02:00
/*
=============
pfnSetUpPlayerPrediction
=============
*/
void pfnSetUpPlayerPrediction( int dopred, int bIncludeLocalClient )
{
// FIXME: implement
}
/*
=============
pfnPushPMStates
=============
*/
void pfnPushPMStates( void )
{
// FIXME: implement
2010-03-06 22:00:00 +01:00
}
2010-03-17 22:00:00 +01:00
/*
=============
2010-08-12 22:00:00 +02:00
pfnPopPMStates
2010-03-17 22:00:00 +01:00
=============
*/
2010-08-12 22:00:00 +02:00
void pfnPopPMStates( void )
2010-03-17 22:00:00 +01:00
{
2010-08-12 22:00:00 +02:00
// FIXME: implement
}
/*
=============
pfnSetSolidPlayers
=============
*/
void pfnSetSolidPlayers( int playernum )
{
// FIXME: implement
}
/*
=============
pfnSetTraceHull
=============
*/
void pfnSetTraceHull( int hull )
{
// FIXME: implement
}
/*
=============
pfnPlayerTrace
=============
*/
static void pfnPlayerTrace( float *start, float *end, int traceFlags, int ignore_pe, pmtrace_t *tr )
{
// FIXME: implement
}
/*
=============
pfnTraceTexture
=============
*/
static const char *pfnTraceTexture( int ground, const float *v1, const float *v2 )
{
// FIXME: implement
return NULL;
}
/*
=============
pfnStopAllSounds
=============
*/
void pfnStopAllSounds( int ent, int entchannel )
{
S_StopSound( ent, entchannel, NULL );
}
/*
=============
pfnBoxVisible
=============
*/
static bool pfnBoxVisible( const vec3_t mins, const vec3_t maxs )
{
if( !re ) return false;
return CM_BoxVisible( mins, maxs, re->GetCurrentVis());
}
/*
=============
pfnGetModFrames
=============
*/
int pfnGetModFrames( int modelIndex )
{
int numFrames = 1;
Mod_GetFrames( modelIndex, &numFrames );
return numFrames;
2010-03-17 22:00:00 +01:00
}
2009-12-08 22:00:00 +01:00
2009-12-05 22:00:00 +01:00
/*
=============
VGui_GetPanel
=============
*/
void *VGui_GetPanel( void )
2009-01-11 22:00:00 +01:00
{
2010-03-30 22:00:00 +02:00
// UNDONE: wait for version 0.75
2009-12-05 22:00:00 +01:00
return NULL;
2009-01-11 22:00:00 +01:00
}
2008-12-26 22:00:00 +01:00
/*
=============
2009-12-05 22:00:00 +01:00
VGui_ViewportPaintBackground
2008-12-26 22:00:00 +01:00
=============
*/
2009-12-05 22:00:00 +01:00
void VGui_ViewportPaintBackground( int extents[4] )
2008-12-26 22:00:00 +01:00
{
2010-03-30 22:00:00 +02:00
// UNDONE: wait for version 0.75
2009-12-05 22:00:00 +01:00
}
2008-12-26 22:00:00 +01:00
2009-12-05 22:00:00 +01:00
/*
2010-03-17 22:00:00 +01:00
=============
pfnIsInGame
2009-01-15 22:00:00 +01:00
2010-03-17 22:00:00 +01:00
=============
2009-01-15 22:00:00 +01:00
*/
2010-03-17 22:00:00 +01:00
int pfnIsInGame( void )
2009-01-15 22:00:00 +01:00
{
2010-03-17 22:00:00 +01:00
return ( cls.key_dest == key_game ) ? true : false;
2009-01-15 22:00:00 +01:00
}
2010-03-17 22:00:00 +01:00
/*
===============================================================================
EffectsAPI Builtin Functions
===============================================================================
*/
2009-01-16 22:00:00 +01:00
/*
=================
pfnDecalIndexFromName
=================
*/
2010-07-01 22:00:00 +02:00
int pfnDecalIndexFromName( const char *szDecalName )
2009-01-16 22:00:00 +01:00
{
int i;
// look through the loaded sprite name list for SpriteName
2010-06-29 22:00:00 +02:00
for( i = 0; i < MAX_DECALNAMES && cl.configstrings[CS_DECALS+i+1][0]; i++ )
2009-01-16 22:00:00 +01:00
{
2010-03-16 22:00:00 +01:00
if( !com.stricmp( szDecalName, cl.configstrings[CS_DECALS+i+1] ))
2009-01-16 22:00:00 +01:00
return cl.decal_shaders[i+1];
}
2010-06-30 22:00:00 +02:00
return 0; // invalid decal
2009-01-16 22:00:00 +01:00
}
/*
=================
pfnDecalIndex
=================
*/
static int pfnDecalIndex( int id )
{
2010-06-29 22:00:00 +02:00
id = bound( 0, id, MAX_DECALNAMES - 1 );
2009-01-16 22:00:00 +01:00
return cl.decal_shaders[id];
}
2010-03-26 22:00:00 +01:00
/*
=================
pfnCullBox
=================
*/
2010-03-06 22:00:00 +01:00
static int pfnCullBox( const vec3_t mins, const vec3_t maxs )
{
if( !re ) return false;
return re->CullBox( mins, maxs );
}
2010-03-26 22:00:00 +01:00
/*
=================
pfnEnvShot
=================
*/
static void pfnEnvShot( const float *vieworg, const char *name, int skyshot )
{
static vec3_t viewPoint;
if( !name )
{
MsgDev( D_ERROR, "R_%sShot: bad name\n", skyshot ? "Sky" : "Env" );
return;
}
if( cls.scrshot_action != scrshot_inactive )
{
if( cls.scrshot_action != scrshot_skyshot && cls.scrshot_action != scrshot_envshot )
MsgDev( D_ERROR, "R_%sShot: subsystem is busy, try later.\n", skyshot ? "Sky" : "Env" );
return;
}
cls.envshot_vieworg = NULL; // use client view
com.strncpy( cls.shotname, name, sizeof( cls.shotname ));
if( vieworg )
{
// make sure what viewpoint don't temporare
VectorCopy( vieworg, viewPoint );
cls.envshot_vieworg = viewPoint;
}
// make request for envshot
if( skyshot ) cls.scrshot_action = scrshot_skyshot;
else cls.scrshot_action = scrshot_envshot;
}
2010-07-13 22:00:00 +02:00
/*
=================
pfnGetPaletteColor
=================
*/
static void pfnGetPaletteColor( int colorIndex, vec3_t outColor )
{
if( !outColor ) return;
colorIndex = bound( 0, colorIndex, 255 );
VectorCopy( clgame.palette[colorIndex], outColor );
}
2009-01-22 22:00:00 +01:00
/*
=================
TriApi implementation
=================
*/
2009-12-07 22:00:00 +01:00
/*
=================
Tri_DrawTriangles
2009-10-20 22:00:00 +02:00
2009-12-07 22:00:00 +01:00
callback from renderer
=================
*/
void Tri_DrawTriangles( int fTrans )
2009-10-20 22:00:00 +02:00
{
2009-12-07 22:00:00 +01:00
clgame.dllFuncs.pfnDrawTriangles( fTrans );
2009-10-20 22:00:00 +02:00
}
2009-12-06 22:00:00 +01:00
/*
=============
TriLoadShader
=============
*/
shader_t TriLoadShader( const char *szShaderName, int fShaderNoMip )
{
if( !re ) return 0; // render not initialized
if( !szShaderName || !*szShaderName )
{
2009-12-07 22:00:00 +01:00
MsgDev( D_ERROR, "Tri_LoadShader: invalid shadername (%s)\n", fShaderNoMip ? "nomip" : "generic" );
2009-12-06 22:00:00 +01:00
return -1;
}
if( fShaderNoMip )
return re->RegisterShader( szShaderName, SHADER_NOMIP );
return re->RegisterShader( szShaderName, SHADER_GENERIC );
}
2009-12-07 22:00:00 +01:00
/*
=============
TriRenderMode
=============
*/
2009-01-22 22:00:00 +01:00
void TriRenderMode( kRenderMode_t mode )
{
2009-10-20 22:00:00 +02:00
if( !re ) return;
2009-12-07 22:00:00 +01:00
re->RenderMode( mode );
2009-01-22 22:00:00 +01:00
}
2010-03-06 22:00:00 +01:00
shader_t TriGetSpriteFrame( int spriteIndex, int spriteFrame )
{
if( !re ) return 0;
return re->GetSpriteTexture( spriteIndex, spriteFrame );
}
2010-07-13 22:00:00 +02:00
2009-12-07 22:00:00 +01:00
/*
=============
TriBind
bind current shader
=============
*/
2009-10-20 22:00:00 +02:00
void TriBind( shader_t shader, int frame )
2009-01-22 22:00:00 +01:00
{
2009-12-07 22:00:00 +01:00
if( !re ) return;
re->Bind( shader, frame );
2009-01-22 22:00:00 +01:00
}
2009-12-07 22:00:00 +01:00
/*
=============
TriBegin
begin triangle sequence
=============
*/
2009-01-22 22:00:00 +01:00
void TriBegin( TRI_DRAW mode )
{
2009-12-07 22:00:00 +01:00
if( re ) re->Begin( mode );
2009-01-22 22:00:00 +01:00
}
2009-12-07 22:00:00 +01:00
/*
=============
TriEnd
draw triangle sequence
=============
*/
2009-01-22 22:00:00 +01:00
void TriEnd( void )
{
2009-12-07 22:00:00 +01:00
if( re ) re->End();
2009-01-22 22:00:00 +01:00
}
2009-12-07 22:00:00 +01:00
/*
=============
TriEnable
=============
*/
2009-01-22 22:00:00 +01:00
void TriEnable( int cap )
{
2009-12-07 22:00:00 +01:00
if( !re ) return;
re->Enable( cap );
2009-01-22 22:00:00 +01:00
}
2009-12-07 22:00:00 +01:00
/*
=============
TriDisable
=============
*/
2009-01-22 22:00:00 +01:00
void TriDisable( int cap )
{
2009-12-07 22:00:00 +01:00
if( !re ) return;
re->Disable( cap );
2009-01-22 22:00:00 +01:00
}
2009-12-07 22:00:00 +01:00
/*
=============
TriVertex3f
=============
*/
2009-01-22 22:00:00 +01:00
void TriVertex3f( float x, float y, float z )
{
2009-12-07 22:00:00 +01:00
if( !re ) return;
re->Vertex3f( x, y, z );
2009-01-22 22:00:00 +01:00
}
2009-12-07 22:00:00 +01:00
/*
=============
TriVertex3fv
=============
*/
2009-10-20 22:00:00 +02:00
void TriVertex3fv( const float *v )
2009-01-22 22:00:00 +01:00
{
2009-12-07 22:00:00 +01:00
if( !re || !v ) return;
re->Vertex3f( v[0], v[1], v[2] );
2009-01-22 22:00:00 +01:00
}
2009-12-07 22:00:00 +01:00
/*
=============
TriNormal3f
=============
*/
2009-10-20 22:00:00 +02:00
void TriNormal3f( float x, float y, float z )
2009-01-22 22:00:00 +01:00
{
2009-12-07 22:00:00 +01:00
if( !re ) return;
re->Normal3f( x, y, z );
2009-01-22 22:00:00 +01:00
}
2009-12-07 22:00:00 +01:00
/*
=============
TriNormal3fv
=============
*/
2009-10-20 22:00:00 +02:00
void TriNormal3fv( const float *v )
2009-01-22 22:00:00 +01:00
{
2009-12-07 22:00:00 +01:00
if( !re || !v ) return;
re->Normal3f( v[0], v[1], v[2] );
2009-01-22 22:00:00 +01:00
}
2009-12-07 22:00:00 +01:00
/*
=============
TriColor4f
=============
*/
2009-01-22 22:00:00 +01:00
void TriColor4f( float r, float g, float b, float a )
{
2009-12-07 22:00:00 +01:00
rgba_t rgba;
if( !re ) return;
2010-03-09 22:00:00 +01:00
rgba[0] = (byte)bound( 0, (r * 255.0f), 255 );
rgba[1] = (byte)bound( 0, (g * 255.0f), 255 );
rgba[2] = (byte)bound( 0, (b * 255.0f), 255 );
rgba[3] = (byte)bound( 0, (a * 255.0f), 255 );
2009-12-07 22:00:00 +01:00
re->Color4ub( rgba[0], rgba[1], rgba[2], rgba[3] );
2009-01-22 22:00:00 +01:00
}
2009-12-07 22:00:00 +01:00
/*
=============
TriColor4ub
=============
*/
2009-01-22 22:00:00 +01:00
void TriColor4ub( byte r, byte g, byte b, byte a )
{
2009-12-07 22:00:00 +01:00
if( !re ) return;
re->Color4ub( r, g, b, a );
2009-01-22 22:00:00 +01:00
}
2009-12-07 22:00:00 +01:00
/*
=============
TriTexCoord2f
=============
*/
2009-01-22 22:00:00 +01:00
void TriTexCoord2f( float u, float v )
{
2009-12-07 22:00:00 +01:00
if( !re ) return;
re->TexCoord2f( u, v );
2009-01-22 22:00:00 +01:00
}
2009-12-07 22:00:00 +01:00
/*
=============
TriCullFace
=============
*/
2009-01-22 22:00:00 +01:00
void TriCullFace( TRI_CULL mode )
{
2009-12-07 22:00:00 +01:00
if( !re ) return;
re->CullFace( mode );
2009-01-22 22:00:00 +01:00
}
2009-12-07 22:00:00 +01:00
/*
=============
TriScreenToWorld
convert screen coordinates (x,y) into world (x, y, z)
=============
*/
2009-01-22 22:00:00 +01:00
void TriScreenToWorld( float *screen, float *world )
{
2009-10-20 22:00:00 +02:00
if( !re ) return;
re->ScreenToWorld( screen, world );
2009-01-22 22:00:00 +01:00
}
2009-12-07 22:00:00 +01:00
/*
=============
TriWorldToScreen
convert world coordinates (x,y,z) into screen (x, y)
=============
*/
2009-01-22 22:00:00 +01:00
int TriWorldToScreen( float *world, float *screen )
{
2010-03-09 22:00:00 +01:00
int retval = 0;
if( !re || !world || !screen )
return retval;
retval = re->WorldToScreen( world, screen );
2010-03-10 22:00:00 +01:00
screen[0] = 0.5f * screen[0] * (float)cl.refdef.viewport[2];
screen[1] = -0.5f * screen[1] * (float)cl.refdef.viewport[3];
screen[0] += 0.5f * (float)cl.refdef.viewport[2];
screen[1] += 0.5f * (float)cl.refdef.viewport[3];
2010-03-09 22:00:00 +01:00
return retval;
2009-01-22 22:00:00 +01:00
}
2009-12-07 22:00:00 +01:00
/*
=============
TriFog
enables global fog on the level
=============
*/
2009-01-22 22:00:00 +01:00
void TriFog( float flFogColor[3], float flStart, float flEnd, int bOn )
{
2009-12-07 22:00:00 +01:00
if( re ) re->Fog( flFogColor, flStart, flEnd, bOn );
2009-01-22 22:00:00 +01:00
}
2008-12-25 22:00:00 +01:00
static triapi_t gTriApi =
{
2010-06-23 22:00:00 +02:00
TRI_API_VERSION,
2009-12-06 22:00:00 +01:00
TriLoadShader,
2010-03-06 22:00:00 +01:00
TriGetSpriteFrame,
2009-01-22 22:00:00 +01:00
TriRenderMode,
TriBegin,
TriEnd,
TriEnable,
TriDisable,
TriVertex3f,
TriVertex3fv,
2009-10-20 22:00:00 +02:00
TriNormal3f,
TriNormal3fv,
2009-01-22 22:00:00 +01:00
TriColor4f,
TriColor4ub,
TriTexCoord2f,
2009-10-20 22:00:00 +02:00
TriBind,
2009-01-22 22:00:00 +01:00
TriCullFace,
TriScreenToWorld,
TriWorldToScreen,
TriFog
2008-12-25 22:00:00 +01:00
};
2009-01-11 22:00:00 +01:00
static efxapi_t gEfxApi =
{
2010-07-13 22:00:00 +02:00
pfnGetPaletteColor,
2010-02-23 22:00:00 +01:00
pfnDecalIndex,
pfnDecalIndexFromName,
2010-06-28 22:00:00 +02:00
CL_DecalShoot,
2010-06-30 22:00:00 +02:00
CL_PlayerDecal,
2010-06-28 22:00:00 +02:00
CL_AllocDlight,
CL_AllocElight,
2010-03-15 22:00:00 +01:00
CL_LightForPoint,
2010-08-12 22:00:00 +02:00
pfnBoxVisible,
2010-03-06 22:00:00 +01:00
pfnCullBox,
2010-03-14 22:00:00 +01:00
CL_AddEntity,
2010-03-26 22:00:00 +01:00
pfnEnvShot,
2009-01-11 22:00:00 +01:00
};
2009-12-05 22:00:00 +01:00
static event_api_t gEventApi =
{
2010-06-23 22:00:00 +02:00
EVENT_API_VERSION,
2009-12-08 22:00:00 +01:00
pfnPlaySound,
pfnStopSound,
pfnFindModelIndex,
pfnIsLocal,
2010-08-12 22:00:00 +02:00
pfnLocalPlayerDucking,
2010-06-28 22:00:00 +02:00
pfnLocalPlayerViewheight,
2010-08-12 22:00:00 +02:00
pfnLocalPlayerBounds,
pfnIndexFromTrace,
pfnGetPhysent,
pfnSetUpPlayerPrediction,
pfnPushPMStates,
pfnPopPMStates,
pfnSetSolidPlayers,
pfnSetTraceHull,
pfnPlayerTrace,
2010-08-07 22:00:00 +02:00
CL_WeaponAnim,
2010-06-28 22:00:00 +02:00
pfnPrecacheEvent,
2010-08-16 22:00:00 +02:00
CL_PlaybackEvent,
2010-06-28 22:00:00 +02:00
pfnTraceTexture,
pfnStopAllSounds,
pfnKillEvents,
2009-12-05 22:00:00 +01:00
};
2010-03-06 22:00:00 +01:00
2008-12-25 22:00:00 +01:00
// engine callbacks
static cl_enginefuncs_t gEngfuncs =
{
2009-12-03 22:00:00 +01:00
pfnSPR_Load,
pfnSPR_Frames,
pfnSPR_Height,
pfnSPR_Width,
pfnSPR_Set,
pfnSPR_Draw,
pfnSPR_DrawHoles,
pfnSPR_DrawTrans,
pfnSPR_DrawAdditive,
pfnSPR_EnableScissor,
pfnSPR_DisableScissor,
pfnSPR_GetList,
pfnFillRGBA,
pfnGetScreenInfo,
pfnSetCrosshair,
2009-01-22 22:00:00 +01:00
pfnCVarRegister,
2009-12-04 22:00:00 +01:00
pfnCVarGetValue,
pfnCVarGetString,
2008-12-25 22:00:00 +01:00
pfnAddCommand,
pfnHookUserMsg,
pfnServerCmd,
pfnClientCmd,
pfnGetPlayerInfo,
2009-12-04 22:00:00 +01:00
pfnPlaySoundByName,
pfnPlaySoundByIndex,
AngleVectors,
2008-12-25 22:00:00 +01:00
pfnTextMessageGet,
2009-12-04 22:00:00 +01:00
pfnDrawCharacter,
pfnDrawConsoleString,
pfnDrawSetTextColor,
2010-07-20 22:00:00 +02:00
Con_DrawStringLen,
2009-12-04 22:00:00 +01:00
pfnConsolePrint,
pfnCenterPrint,
pfnMemAlloc,
pfnMemFree,
2009-12-05 22:00:00 +01:00
pfnGetViewAngles,
pfnSetViewAngles,
2009-12-04 22:00:00 +01:00
pfnCVarSetString,
pfnCVarSetValue,
2009-12-05 22:00:00 +01:00
pfnCmd_Argc,
pfnCmd_Argv,
pfnCmd_Args,
CL_GetLerpFrac,
2009-12-04 22:00:00 +01:00
pfnDelCommand,
2010-08-15 22:00:00 +02:00
pfnCon_Printf,
pfnCon_DPrintf,
2009-12-05 22:00:00 +01:00
pfnPhysInfo_ValueForKey,
pfnServerInfo_ValueForKey,
pfnGetClientMaxspeed,
pfnGetModelPtr,
2010-06-28 22:00:00 +02:00
CL_GetLocalPlayer,
2009-12-05 22:00:00 +01:00
pfnGetViewModel,
2010-08-07 22:00:00 +02:00
CL_GetEntityByIndex,
2008-12-25 22:00:00 +01:00
pfnGetClientTime,
2010-06-28 22:00:00 +02:00
S_FadeClientVolume,
2008-12-25 22:00:00 +01:00
pfnPointContents,
2009-12-05 22:00:00 +01:00
pfnWaterEntity,
2008-12-25 22:00:00 +01:00
pfnTraceLine,
2010-08-12 22:00:00 +02:00
CM_GetModelType,
Mod_GetBounds,
pfnGetModFrames,
2010-06-23 22:00:00 +02:00
pfnPrecacheEvent,
2010-08-16 22:00:00 +02:00
CL_PlaybackEvent,
2010-08-07 22:00:00 +02:00
CL_WeaponAnim,
2010-06-23 22:00:00 +02:00
pfnRandomFloat,
pfnRandomLong,
pfnHookEvent,
Con_Visible,
2009-11-23 22:00:00 +01:00
pfnLoadLibrary,
pfnGetProcAddress,
2009-12-05 22:00:00 +01:00
pfnFreeLibrary,
2008-12-25 22:00:00 +01:00
Host_Error,
2009-12-05 22:00:00 +01:00
pfnFileExists,
2010-04-09 22:00:00 +02:00
pfnGetGameDir,
2009-12-05 22:00:00 +01:00
VGui_GetPanel,
VGui_ViewportPaintBackground,
pfnLoadFile,
pfnParseToken,
pfnFreeFile,
2009-01-11 22:00:00 +01:00
&gTriApi,
2009-12-05 22:00:00 +01:00
&gEfxApi,
2010-03-17 22:00:00 +01:00
&gEventApi,
2010-06-28 22:00:00 +02:00
pfnIsSpectateOnly,
2010-03-17 22:00:00 +01:00
pfnIsInGame
2008-12-25 22:00:00 +01:00
};
void CL_UnloadProgs( void )
{
2010-06-08 22:00:00 +02:00
if( !clgame.hInstance ) return;
2009-10-18 22:00:00 +02:00
CL_FreeEdicts();
2010-03-14 22:00:00 +01:00
// deinitialize game
clgame.dllFuncs.pfnShutdown();
2010-03-30 22:00:00 +02:00
2010-03-27 22:00:00 +01:00
FS_FreeLibrary( clgame.hInstance );
2008-12-25 22:00:00 +01:00
Mem_FreePool( &cls.mempool );
2009-11-27 22:00:00 +01:00
Mem_FreePool( &clgame.mempool );
2009-06-24 22:00:00 +02:00
Mem_FreePool( &clgame.private );
2010-03-27 22:00:00 +01:00
Mem_Set( &clgame, 0, sizeof( clgame ));
2008-12-25 22:00:00 +01:00
}
bool CL_LoadProgs( const char *name )
{
static CLIENTAPI GetClientAPI;
2009-09-28 22:00:00 +02:00
static cl_globalvars_t gpGlobals;
2009-11-26 22:00:00 +01:00
static playermove_t gpMove;
2008-12-25 22:00:00 +01:00
2009-06-24 22:00:00 +02:00
if( clgame.hInstance ) CL_UnloadProgs();
2008-12-25 22:00:00 +01:00
2009-10-20 22:00:00 +02:00
// setup globals
2009-09-28 22:00:00 +02:00
clgame.globals = &gpGlobals;
2010-03-07 22:00:00 +01:00
cl.refdef.movevars = &clgame.movevars;
clgame.globals->pViewParms = &cl.refdef;
2009-10-20 22:00:00 +02:00
2010-08-12 22:00:00 +02:00
// initialize PlayerMove
2009-11-26 22:00:00 +01:00
clgame.pmove = &gpMove;
2009-12-07 22:00:00 +01:00
2009-11-27 22:00:00 +01:00
cls.mempool = Mem_AllocPool( "Client Static Pool" );
clgame.mempool = Mem_AllocPool( "Client Edicts Zone" );
2009-06-24 22:00:00 +02:00
clgame.private = Mem_AllocPool( "Client Private Zone" );
2010-08-07 22:00:00 +02:00
clgame.entities = NULL;
2008-12-25 22:00:00 +01:00
2010-03-27 22:00:00 +01:00
clgame.hInstance = FS_LoadLibrary( name, false );
2009-06-24 22:00:00 +02:00
if( !clgame.hInstance ) return false;
2008-12-25 22:00:00 +01:00
2010-03-27 22:00:00 +01:00
GetClientAPI = (CLIENTAPI)FS_GetProcAddress( clgame.hInstance, "CreateAPI" );
2008-12-25 22:00:00 +01:00
if( !GetClientAPI )
{
2010-03-28 22:00:00 +02:00
FS_FreeLibrary( clgame.hInstance );
MsgDev( D_NOTE, "CL_LoadProgs: failed to get address of CreateAPI proc\n" );
clgame.hInstance = NULL;
2008-12-25 22:00:00 +01:00
return false;
}
2009-09-28 22:00:00 +02:00
if( !GetClientAPI( &clgame.dllFuncs, &gEngfuncs, clgame.globals ))
2008-12-25 22:00:00 +01:00
{
2010-03-28 22:00:00 +02:00
FS_FreeLibrary( clgame.hInstance );
MsgDev( D_NOTE, "CL_LoadProgs: can't init client API\n" );
clgame.hInstance = NULL;
2008-12-25 22:00:00 +01:00
return false;
}
2009-11-27 22:00:00 +01:00
clgame.globals->maxEntities = GI->max_edicts; // merge during loading
2010-07-02 22:00:00 +02:00
CL_InitTitles( "titles.txt" );
2009-10-23 22:00:00 +02:00
2008-12-25 22:00:00 +01:00
// initialize game
2009-06-24 22:00:00 +02:00
clgame.dllFuncs.pfnInit();
2008-12-25 22:00:00 +01:00
2009-12-05 22:00:00 +01:00
// initialize pm_shared
CL_InitClientMove();
2008-12-25 22:00:00 +01:00
return true;
}