2013-03-31 04:21:08 +00:00
# include "quakedef.h"
2004-08-23 00:15:46 +00:00
# define Q2NUM_FOR_EDICT(ent) (((char *)ent - (char *)ge->edicts) / ge->edict_size)
# ifndef Q2SERVER
qboolean SVQ2_InitGameProgs ( void )
{
return false ;
}
# else
game_export_t * ge ;
2011-04-20 03:34:32 +00:00
int svq2_maxclients ;
2004-08-23 00:15:46 +00:00
2013-05-11 14:02:55 +00:00
dllhandle_t * q2gamedll ;
void SVQ2_UnloadGame ( void )
{
if ( q2gamedll )
Sys_CloseLibrary ( q2gamedll ) ;
q2gamedll = NULL ;
}
void * SVQ2_GetGameAPI ( void * parms )
{
void * ( VARGS * GetGameAPI ) ( void * ) ;
dllfunction_t funcs [ ] =
{
{ ( void * * ) & GetGameAPI , " GetGameAPI " } ,
{ NULL , NULL }
} ;
char name [ MAX_OSPATH ] ;
2014-09-20 04:11:39 +00:00
char syspath [ MAX_OSPATH ] ;
char gamepath [ MAX_OSPATH ] ;
2013-06-21 08:23:42 +00:00
void * iterator ;
2013-05-11 14:02:55 +00:00
int o ;
const char * gamename [ ] = {
2014-09-20 04:11:39 +00:00
" " ,
" " ,
2013-05-11 14:02:55 +00:00
# ifdef _DEBUG
" debug/game " ARCH_CPU_POSTFIX ARCH_DL_POSTFIX ,
# endif
# if defined(__linux__) && defined(__i386__)
" game " " i386 " ARCH_DL_POSTFIX , //compat is often better than consistancy
# endif
" game " ARCH_CPU_POSTFIX ARCH_DL_POSTFIX ,
" game " ARCH_DL_POSTFIX ,
NULL
} ;
void * ret ;
2004-08-23 00:15:46 +00:00
2013-07-14 12:22:51 +00:00
# ifdef _DEBUG
2014-09-20 04:11:39 +00:00
Con_DPrintf ( " Searching for %s \n " , gamename [ 3 ] ) ;
2013-07-14 12:22:51 +00:00
# else
2014-09-20 04:11:39 +00:00
Con_DPrintf ( " Searching for %s \n " , gamename [ 2 ] ) ;
2013-07-14 12:22:51 +00:00
# endif
2013-05-11 14:02:55 +00:00
2013-06-21 08:23:42 +00:00
iterator = NULL ;
2014-09-20 04:11:39 +00:00
while ( COM_IteratePaths ( & iterator , syspath , sizeof ( syspath ) , gamepath , sizeof ( gamepath ) ) )
2013-05-11 14:02:55 +00:00
{
for ( o = 0 ; gamename [ o ] ; o + + )
{
2014-09-20 04:11:39 +00:00
if ( o = = 0 )
{ //nice and specific
if ( ! host_parms . binarydir )
continue ;
Q_snprintfz ( name , sizeof ( name ) , " %sq2game " ARCH_CPU_POSTFIX " _%s " ARCH_DL_POSTFIX , host_parms . binarydir , gamepath ) ;
}
else if ( o = = 1 )
{ //because some people don't like knowing what cpu arch they're compiling for
if ( ! host_parms . binarydir )
continue ;
Q_snprintfz ( name , sizeof ( name ) , " %slibgame_%s " ARCH_DL_POSTFIX , host_parms . binarydir , gamepath ) ;
}
else
2015-03-03 00:14:43 +00:00
{ //gamedir paths as specified above.
2014-09-20 04:11:39 +00:00
if ( com_nogamedirnativecode . ival )
continue ;
Q_snprintfz ( name , sizeof ( name ) , " %s%s " , syspath , gamename [ o ] ) ;
}
2013-05-11 14:02:55 +00:00
q2gamedll = Sys_LoadLibrary ( name , funcs ) ;
2013-06-23 03:59:48 +00:00
if ( q2gamedll )
2013-05-11 14:02:55 +00:00
{
ret = GetGameAPI ( parms ) ;
if ( ret )
{
return ret ;
}
Sys_CloseLibrary ( q2gamedll ) ;
q2gamedll = 0 ;
}
}
}
2015-01-02 05:20:56 +00:00
# ifdef _WIN64
//if we found 32bit q2 gamecode that cannot be loaded, print out a warning about it.
//this should make it a little obvious when people try using 64bit builds to run q2.
if ( COM_FCheckExists ( " gamex86.dll " ) )
Con_Printf ( CON_ERROR " WARNING: 32bit q2 gamecode found, but it cannot be used in a 64bit process. \n If you wish to run this q2 mod, you will need to use a 32bit engine build. \n " ) ;
# endif
2013-05-11 14:02:55 +00:00
return NULL ;
}
2004-11-17 17:31:21 +00:00
2004-08-23 00:15:46 +00:00
/*
= = = = = = = = = = = = = = =
PF_Unicast
Sends the contents of the mutlicast buffer to a single client
= = = = = = = = = = = = = = =
*/
2005-03-18 06:13:11 +00:00
static void VARGS PFQ2_Unicast ( q2edict_t * ent , qboolean reliable )
2004-08-23 00:15:46 +00:00
{
int p ;
client_t * client ;
if ( ! ent )
return ;
p = Q2NUM_FOR_EDICT ( ent ) ;
2013-12-02 14:30:30 +00:00
if ( p < 1 | | p > svs . allocated_client_slots )
2004-08-23 00:15:46 +00:00
return ;
client = svs . clients + ( p - 1 ) ;
if ( client - > state < cs_connected )
return ;
if ( reliable )
2005-07-14 01:57:34 +00:00
SZ_Write ( & client - > netchan . message , sv . q2multicast . data , sv . q2multicast . cursize ) ;
2004-08-23 00:15:46 +00:00
else
2005-07-14 01:57:34 +00:00
SZ_Write ( & client - > datagram , sv . q2multicast . data , sv . q2multicast . cursize ) ;
2004-08-23 00:15:46 +00:00
2005-07-14 01:57:34 +00:00
SZ_Clear ( & sv . q2multicast ) ;
2004-08-23 00:15:46 +00:00
}
/*
= = = = = = = = = = = = = = =
PF_dprintf
Debug print to server console
= = = = = = = = = = = = = = =
*/
static void VARGS PFQ2_dprintf ( char * fmt , . . . )
{
char msg [ 1024 ] ;
va_list argptr ;
va_start ( argptr , fmt ) ;
2011-07-22 15:11:35 +00:00
vsnprintf ( msg , sizeof ( msg ) , fmt , argptr ) ;
2004-08-23 00:15:46 +00:00
va_end ( argptr ) ;
Con_Printf ( " %s " , msg ) ;
}
/*
= = = = = = = = = = = = = = =
PF_cprintf
Print to a single client
= = = = = = = = = = = = = = =
*/
static void VARGS PFQ2_cprintf ( q2edict_t * ent , int level , char * fmt , . . . )
{
char msg [ 1024 ] ;
va_list argptr ;
int n = 0 ;
if ( ent )
{
n = Q2NUM_FOR_EDICT ( ent ) ;
2013-12-02 14:30:30 +00:00
if ( n < 1 | | n > svs . allocated_client_slots )
2004-08-23 00:15:46 +00:00
{
Sys_Error ( " cprintf to a non-client " ) ;
return ;
}
if ( svs . clients [ n - 1 ] . state < cs_connected )
{
Sys_Error ( " cprintf to a disconnected client " ) ;
return ;
}
}
va_start ( argptr , fmt ) ;
2011-07-22 15:11:35 +00:00
vsnprintf ( msg , sizeof ( msg ) , fmt , argptr ) ;
2004-08-23 00:15:46 +00:00
va_end ( argptr ) ;
if ( ent )
SV_ClientPrintf ( svs . clients + ( n - 1 ) , level , " %s " , msg ) ;
else
Con_Printf ( " %s " , msg ) ;
}
/*
= = = = = = = = = = = = = = =
PF_centerprintf
centerprint to a single client
= = = = = = = = = = = = = = =
*/
static void VARGS PFQ2_centerprintf ( q2edict_t * ent , char * fmt , . . . )
{
char msg [ 1024 ] ;
va_list argptr ;
int n ;
n = Q2NUM_FOR_EDICT ( ent ) ;
2013-12-02 14:30:30 +00:00
if ( n < 1 | | n > svs . allocated_client_slots )
2004-08-23 00:15:46 +00:00
return ; // Com_Error (ERR_DROP, "centerprintf to a non-client");
if ( svs . clients [ n - 1 ] . state < cs_connected )
return ;
va_start ( argptr , fmt ) ;
vsprintf ( msg , fmt , argptr ) ;
va_end ( argptr ) ;
2005-07-14 01:57:34 +00:00
MSG_WriteByte ( & sv . q2multicast , svcq2_centerprint ) ;
MSG_WriteString ( & sv . q2multicast , msg ) ;
2004-08-23 00:15:46 +00:00
PFQ2_Unicast ( ent , true ) ;
}
/*
= = = = = = = = = = = = = = =
PF_error
Abort the server with a game error
= = = = = = = = = = = = = = =
*/
static void VARGS PFQ2_error ( char * fmt , . . . )
{
char msg [ 1024 ] ;
va_list argptr ;
va_start ( argptr , fmt ) ;
2011-07-22 15:11:35 +00:00
vsnprintf ( msg , sizeof ( msg ) , fmt , argptr ) ;
2004-08-23 00:15:46 +00:00
va_end ( argptr ) ;
2005-01-07 02:34:59 +00:00
SV_Error ( " Game Error: %s " , msg ) ;
2004-08-23 00:15:46 +00:00
}
/*
= = = = = = = = = = = = = = =
PF_Configstring
= = = = = = = = = = = = = = =
*/
2005-03-18 06:13:11 +00:00
static void VARGS PFQ2_Configstring ( int i , char * val )
2004-08-23 00:15:46 +00:00
{
if ( i < 0 | | i > = Q2MAX_CONFIGSTRINGS )
Sys_Error ( " configstring: bad index %i \n " , i ) ;
if ( ! val )
val = " " ;
2006-02-17 02:51:59 +00:00
strcpy ( sv . strings . configstring [ i ] , val ) ;
2005-03-20 02:57:11 +00:00
if ( i = = Q2CS_NAME )
Q_strncpyz ( sv . mapname , val , sizeof ( sv . name ) ) ;
/*
2004-08-23 00:15:46 +00:00
//work out range
if ( i > = Q2CS_LIGHTS & & i < Q2CS_LIGHTS + Q2MAX_LIGHTSTYLES )
{
j = i - Q2CS_LIGHTS ;
if ( j < MAX_LIGHTSTYLES )
{
if ( sv . lightstyles [ j ] )
Z_Free ( sv . lightstyles [ j ] ) ;
sv . lightstyles [ j ] = Z_Malloc ( strlen ( val ) + 1 ) ;
strcpy ( sv . lightstyles [ j ] , val ) ;
}
}
else if ( i > = Q2CS_MODELS & & i < Q2CS_MODELS + Q2MAX_MODELS )
{
Q_strncpyS ( sv . model_precache [ i - Q2CS_MODELS ] , val , MAX_QPATH - 1 ) ;
}
else if ( i > = Q2CS_SOUNDS & & i < Q2CS_SOUNDS + Q2MAX_SOUNDS )
{
Q_strncpyS ( sv . sound_precache [ i - Q2CS_SOUNDS ] , val , MAX_QPATH - 1 ) ;
}
else if ( i > = Q2CS_IMAGES & & i < Q2CS_IMAGES + Q2MAX_IMAGES )
{
Q_strncpyS ( sv . image_precache [ i - Q2CS_IMAGES ] , val , MAX_QPATH - 1 ) ;
}
else if ( i = = Q2CS_STATUSBAR )
{
if ( sv . statusbar )
Z_Free ( sv . statusbar ) ;
sv . statusbar = Z_Malloc ( strlen ( val ) + 1 ) ;
strcpy ( sv . statusbar , val ) ;
}
else if ( i = = Q2CS_NAME )
{
2005-01-07 02:34:59 +00:00
Q_strncpyz ( sv . mapname , val , sizeof ( sv . name ) ) ;
2004-08-23 00:15:46 +00:00
}
else
{
Con_Printf ( " Ignoring configstring %i \n " , i ) ;
}
2005-03-20 02:57:11 +00:00
*/
2004-08-23 00:15:46 +00:00
if ( sv . state ! = ss_loading )
{ // send the update to everyone
2005-07-14 01:57:34 +00:00
SZ_Clear ( & sv . q2multicast ) ;
MSG_WriteChar ( & sv . q2multicast , svcq2_configstring ) ;
MSG_WriteShort ( & sv . q2multicast , i ) ;
MSG_WriteString ( & sv . q2multicast , val ) ;
2004-08-23 00:15:46 +00:00
SV_Multicast ( vec3_origin , MULTICAST_ALL_R ) ;
}
}
2005-03-20 02:57:11 +00:00
static int SVQ2_FindIndex ( char * name , int start , int max , qboolean create )
2004-08-23 00:15:46 +00:00
{
int i ;
2005-03-20 02:57:11 +00:00
int stringlength = MAX_QPATH ;
2006-02-17 02:51:59 +00:00
char * strings = sv . strings . configstring [ start ] ;
2005-03-20 02:57:11 +00:00
strings + = stringlength ;
2004-08-23 00:15:46 +00:00
if ( ! name | | ! name [ 0 ] )
return 0 ;
for ( i = 1 ; i < max & & strings [ 0 ] ; i + + , strings + = stringlength )
if ( ! strcmp ( strings , name ) )
return i ;
if ( ! create )
return 0 ;
if ( i = = max )
Sys_Error ( " *Index: overflow " ) ;
PFQ2_Configstring ( start + i , name ) ;
return i ;
}
2005-03-18 06:13:11 +00:00
static int VARGS SVQ2_ModelIndex ( char * name )
2004-08-23 00:15:46 +00:00
{
2005-03-20 02:57:11 +00:00
return SVQ2_FindIndex ( name , Q2CS_MODELS , Q2MAX_MODELS , true ) ;
2004-08-23 00:15:46 +00:00
}
2005-03-18 06:13:11 +00:00
static int VARGS SVQ2_SoundIndex ( char * name )
2004-08-23 00:15:46 +00:00
{
2005-03-20 02:57:11 +00:00
return SVQ2_FindIndex ( name , Q2CS_SOUNDS , Q2MAX_SOUNDS , true ) ;
2004-08-23 00:15:46 +00:00
}
2005-03-18 06:13:11 +00:00
static int VARGS SVQ2_ImageIndex ( char * name )
2004-08-23 00:15:46 +00:00
{
2005-03-20 02:57:11 +00:00
return SVQ2_FindIndex ( name , Q2CS_IMAGES , Q2MAX_IMAGES , true ) ;
2004-08-23 00:15:46 +00:00
}
/*
= = = = = = = = = = = = = = = = =
PF_setmodel
Also sets mins and maxs for inline bmodels
= = = = = = = = = = = = = = = = =
*/
2005-03-18 06:13:11 +00:00
static void VARGS PFQ2_setmodel ( q2edict_t * ent , char * name )
2004-08-23 00:15:46 +00:00
{
int i ;
model_t * mod ;
if ( ! name )
2006-07-21 23:38:24 +00:00
{
2007-09-23 15:28:06 +00:00
Con_Printf ( CON_ERROR " ERROR: PF_setmodel: NULL \n " ) ;
2006-07-21 23:38:24 +00:00
ent - > s . modelindex = 0 ;
return ;
}
2004-08-23 00:15:46 +00:00
i = SVQ2_ModelIndex ( name ) ;
// ent->model = name;
ent - > s . modelindex = i ;
// if it is an inline model, get the size information for it
if ( name [ 0 ] = = ' * ' )
{
2014-10-05 20:04:11 +00:00
mod = Mod_FindName ( Mod_FixName ( name , sv . modelname ) ) ;
if ( mod - > loadstate = = MLS_LOADING )
COM_WorkerPartialSync ( mod , & mod - > loadstate , MLS_LOADING ) ; //wait for it if needed
2004-08-23 00:15:46 +00:00
VectorCopy ( mod - > mins , ent - > mins ) ;
VectorCopy ( mod - > maxs , ent - > maxs ) ;
2009-11-04 21:16:50 +00:00
WorldQ2_LinkEdict ( & sv . world , ent ) ;
2004-08-23 00:15:46 +00:00
}
}
/*
static qboolean PFQ2_Q1BSP_AreasConnected ( int area1 , int area2 )
{
return true ;
}
static qboolean CMQ2_Q1BSP_SetAreaPortalState ( int portalnum , qboolean open )
{
return true ;
} */
2014-03-30 08:55:06 +00:00
static void VARGS PFQ2_WriteChar ( int c ) { MSG_WriteChar ( & sv . q2multicast , c & 0xff ) ; }
static void VARGS PFQ2_WriteByte ( int c ) { MSG_WriteByte ( & sv . q2multicast , c & 0xff ) ; }
static void VARGS PFQ2_WriteShort ( int c ) { MSG_WriteShort ( & sv . q2multicast , c & 0xffff ) ; }
2005-07-14 01:57:34 +00:00
static void VARGS PFQ2_WriteLong ( int c ) { MSG_WriteLong ( & sv . q2multicast , c ) ; }
static void VARGS PFQ2_WriteFloat ( float f ) { MSG_WriteFloat ( & sv . q2multicast , f ) ; }
static void VARGS PFQ2_WriteString ( char * s ) { MSG_WriteString ( & sv . q2multicast , s ) ; }
static void VARGS PFQ2_WriteAngle ( float f ) { MSG_WriteAngle ( & sv . q2multicast , f ) ; }
static void VARGS PFQ2_WritePos ( vec3_t pos ) { MSG_WriteCoord ( & sv . q2multicast , pos [ 0 ] ) ;
MSG_WriteCoord ( & sv . q2multicast , pos [ 1 ] ) ;
MSG_WriteCoord ( & sv . q2multicast , pos [ 2 ] ) ;
2004-08-23 00:15:46 +00:00
}
2005-07-14 01:57:34 +00:00
static void VARGS PFQ2_WriteDir ( vec3_t dir ) { MSG_WriteDir ( & sv . q2multicast , dir ) ; }
2004-08-23 00:15:46 +00:00
/*
= = = = = = = = = = = = = = = = =
PF_inPVS
Also checks portalareas so that doors block sight
= = = = = = = = = = = = = = = = =
*/
2005-03-18 06:13:11 +00:00
static qboolean VARGS PFQ2_inPVS ( vec3_t p1 , vec3_t p2 )
2004-08-23 00:15:46 +00:00
{
int leafnum ;
int cluster ;
int area1 , area2 ;
qbyte * mask ;
2012-02-27 12:23:15 +00:00
//FIXME: requires q2/q3 bsp
2009-11-04 21:16:50 +00:00
leafnum = CM_PointLeafnum ( sv . world . worldmodel , p1 ) ;
cluster = CM_LeafCluster ( sv . world . worldmodel , leafnum ) ;
area1 = CM_LeafArea ( sv . world . worldmodel , leafnum ) ;
mask = CM_ClusterPVS ( sv . world . worldmodel , cluster , NULL , 0 ) ;
2005-08-26 22:56:51 +00:00
2009-11-04 21:16:50 +00:00
leafnum = CM_PointLeafnum ( sv . world . worldmodel , p2 ) ;
cluster = CM_LeafCluster ( sv . world . worldmodel , leafnum ) ;
area2 = CM_LeafArea ( sv . world . worldmodel , leafnum ) ;
2004-08-23 00:15:46 +00:00
if ( mask & & ( ! ( mask [ cluster > > 3 ] & ( 1 < < ( cluster & 7 ) ) ) ) )
return false ;
2009-11-04 21:16:50 +00:00
if ( ! CM_AreasConnected ( sv . world . worldmodel , area1 , area2 ) )
2004-08-23 00:15:46 +00:00
return false ; // a door blocks sight
return true ;
}
/*
= = = = = = = = = = = = = = = = =
PF_inPHS
Also checks portalareas so that doors block sound
= = = = = = = = = = = = = = = = =
*/
2005-03-18 06:13:11 +00:00
static qboolean VARGS PFQ2_inPHS ( vec3_t p1 , vec3_t p2 )
2004-08-23 00:15:46 +00:00
{
int leafnum ;
int cluster ;
int area1 , area2 ;
qbyte * mask ;
2012-02-27 12:23:15 +00:00
//FIXME: requires q2/q3 bsp
2009-11-04 21:16:50 +00:00
leafnum = CM_PointLeafnum ( sv . world . worldmodel , p1 ) ;
cluster = CM_LeafCluster ( sv . world . worldmodel , leafnum ) ;
area1 = CM_LeafArea ( sv . world . worldmodel , leafnum ) ;
mask = CM_ClusterPHS ( sv . world . worldmodel , cluster ) ;
2004-08-23 00:15:46 +00:00
2009-11-04 21:16:50 +00:00
leafnum = CM_PointLeafnum ( sv . world . worldmodel , p2 ) ;
cluster = CM_LeafCluster ( sv . world . worldmodel , leafnum ) ;
area2 = CM_LeafArea ( sv . world . worldmodel , leafnum ) ;
2004-08-23 00:15:46 +00:00
if ( mask & & ( ! ( mask [ cluster > > 3 ] & ( 1 < < ( cluster & 7 ) ) ) ) )
return false ; // more than one bounce away
2009-11-04 21:16:50 +00:00
if ( ! CM_AreasConnected ( sv . world . worldmodel , area1 , area2 ) )
2004-08-23 00:15:46 +00:00
return false ; // a door blocks hearing
return true ;
}
2014-06-02 16:50:40 +00:00
qboolean VARGS PFQ2_AreasConnected ( unsigned int area1 , unsigned int area2 )
2005-08-26 22:56:51 +00:00
{
2012-02-27 12:23:15 +00:00
//FIXME: requires q2/q3 bsp
2009-11-04 21:16:50 +00:00
return CM_AreasConnected ( sv . world . worldmodel , area1 , area2 ) ;
2005-08-26 22:56:51 +00:00
}
2004-08-23 00:15:46 +00:00
# define Q2SND_VOLUME (1<<0) // a byte
# define Q2SND_ATTENUATION (1<<1) // a byte
# define Q2SND_POS (1<<2) // three coordinates
# define Q2SND_ENT (1<<3) // a short 0-2: channel, 3-12: entity
# define Q2SND_OFFSET (1<<4) // a byte, msec offset from frame start
# define Q2DEFAULT_SOUND_PACKET_VOLUME 1.0
# define Q2DEFAULT_SOUND_PACKET_ATTENUATION 1.0
# define Q2ATTN_NONE 0 // full volume the entire level
# define Q2ATTN_NORM 1 / *
# define Q2CHAN_AUTO 0
# define Q2CHAN_WEAPON 1
# define Q2CHAN_VOICE 2
# define Q2CHAN_ITEM 3
# define Q2CHAN_BODY 4* /
2005-09-07 14:55:25 +00:00
# define Q2CHAN_NO_PHS_ADD 8
2004-08-23 00:15:46 +00:00
# define Q2CHAN_RELIABLE 16
2005-03-18 06:13:11 +00:00
void VARGS SVQ2_StartSound ( vec3_t origin , q2edict_t * entity , int channel ,
2004-08-23 00:15:46 +00:00
int soundindex , float volume ,
float attenuation , float timeofs )
{
int sendchan ;
int flags ;
int i ;
int ent ;
vec3_t origin_v ;
qboolean use_phs ;
if ( volume < 0 | | volume > 1.0 )
Sys_Error ( " SV_StartSound: volume = %f " , volume ) ;
if ( attenuation < 0 | | attenuation > 4 )
Sys_Error ( " SV_StartSound: attenuation = %f " , attenuation ) ;
// if (channel < 0 || channel > 15)
// Sys_Error ("SV_StartSound: channel = %i", channel);
if ( timeofs < 0 | | timeofs > 0.255 )
Sys_Error ( " SV_StartSound: timeofs = %f " , timeofs ) ;
ent = Q2NUM_FOR_EDICT ( entity ) ;
2005-09-07 14:55:25 +00:00
if ( channel & Q2CHAN_NO_PHS_ADD ) // no PHS flag
2004-08-23 00:15:46 +00:00
use_phs = false ;
else
use_phs = true ;
sendchan = ( ent < < 3 ) | ( channel & 7 ) ;
flags = 0 ;
if ( volume ! = Q2DEFAULT_SOUND_PACKET_VOLUME )
flags | = Q2SND_VOLUME ;
if ( attenuation ! = Q2DEFAULT_SOUND_PACKET_ATTENUATION )
flags | = Q2SND_ATTENUATION ;
// the client doesn't know that bmodels have weird origins
// the origin can also be explicitly set
if ( ( entity - > svflags & SVF_NOCLIENT )
| | ( entity - > solid = = Q2SOLID_BSP )
| | origin )
flags | = Q2SND_POS ;
// always send the entity number for channel overrides
flags | = Q2SND_ENT ;
if ( timeofs )
flags | = Q2SND_OFFSET ;
// use the entity origin unless it is a bmodel or explicitly specified
if ( ! origin )
{
origin = origin_v ;
if ( entity - > solid = = Q2SOLID_BSP )
{
for ( i = 0 ; i < 3 ; i + + )
origin_v [ i ] = entity - > s . origin [ i ] + 0.5 * ( entity - > mins [ i ] + entity - > maxs [ i ] ) ;
}
else
{
VectorCopy ( entity - > s . origin , origin_v ) ;
}
}
2005-07-14 01:57:34 +00:00
MSG_WriteByte ( & sv . q2multicast , svcq2_sound ) ;
MSG_WriteByte ( & sv . q2multicast , flags ) ;
MSG_WriteByte ( & sv . q2multicast , soundindex ) ;
2004-08-23 00:15:46 +00:00
if ( flags & Q2SND_VOLUME )
2005-07-14 01:57:34 +00:00
MSG_WriteByte ( & sv . q2multicast , volume * 255 ) ;
2004-08-23 00:15:46 +00:00
if ( flags & Q2SND_ATTENUATION )
2005-07-14 01:57:34 +00:00
MSG_WriteByte ( & sv . q2multicast , attenuation * 64 ) ;
2004-08-23 00:15:46 +00:00
if ( flags & Q2SND_OFFSET )
2005-07-14 01:57:34 +00:00
MSG_WriteByte ( & sv . q2multicast , timeofs * 1000 ) ;
2004-08-23 00:15:46 +00:00
if ( flags & Q2SND_ENT )
2005-07-14 01:57:34 +00:00
MSG_WriteShort ( & sv . q2multicast , sendchan ) ;
2004-08-23 00:15:46 +00:00
if ( flags & Q2SND_POS )
{
2005-07-14 01:57:34 +00:00
MSG_WriteCoord ( & sv . q2multicast , origin [ 0 ] ) ;
MSG_WriteCoord ( & sv . q2multicast , origin [ 1 ] ) ;
MSG_WriteCoord ( & sv . q2multicast , origin [ 2 ] ) ;
2004-08-23 00:15:46 +00:00
}
// if the sound doesn't attenuate,send it to everyone
// (global radio chatter, voiceovers, etc)
if ( attenuation = = Q2ATTN_NONE )
use_phs = false ;
if ( channel & Q2CHAN_RELIABLE )
{
if ( use_phs )
SV_Multicast ( origin , MULTICAST_PHS_R ) ;
else
SV_Multicast ( origin , MULTICAST_ALL_R ) ;
}
else
{
if ( use_phs )
SV_Multicast ( origin , MULTICAST_PHS ) ;
else
SV_Multicast ( origin , MULTICAST_ALL ) ;
}
}
2005-03-18 06:13:11 +00:00
static void VARGS PFQ2_StartSound ( q2edict_t * entity , int channel , int sound_num , float volume ,
2004-08-23 00:15:46 +00:00
float attenuation , float timeofs )
{
if ( ! entity )
return ;
SVQ2_StartSound ( NULL , entity , channel , sound_num , volume , attenuation , timeofs ) ;
}
2005-03-18 06:13:11 +00:00
static q2trace_t VARGS SVQ2_Trace ( vec3_t start , vec3_t mins , vec3_t maxs , vec3_t end , q2edict_t * passedict , int contentmask )
2004-08-23 00:15:46 +00:00
{
q2trace_t ret ;
trace_t tr ;
if ( ! mins )
2012-02-27 12:23:15 +00:00
mins = vec3_origin ;
2004-08-23 00:15:46 +00:00
if ( ! maxs )
2012-02-27 12:23:15 +00:00
maxs = vec3_origin ;
2009-11-04 21:16:50 +00:00
tr = WorldQ2_Move ( & sv . world , start , mins , maxs , end , contentmask , passedict ) ;
2012-02-27 12:23:15 +00:00
ret . allsolid = tr . allsolid ;
ret . startsolid = tr . startsolid ;
ret . contents = tr . contents ;
ret . surface = tr . surface ;
ret . fraction = tr . fraction ;
VectorCopy ( tr . endpos , ret . endpos ) ;
2013-03-12 22:47:42 +00:00
memset ( & ret . plane , 0 , sizeof ( ret . plane ) ) ;
2012-02-27 12:23:15 +00:00
VectorCopy ( tr . plane . normal , ret . plane . normal ) ;
ret . plane . dist = tr . plane . dist ;
2012-04-24 07:59:11 +00:00
ret . ent = tr . ent ;
2004-08-23 00:15:46 +00:00
return ret ;
}
2005-03-18 06:13:11 +00:00
static int VARGS SVQ2_PointContents ( vec3_t p )
2004-08-23 00:15:46 +00:00
{
2012-02-27 12:23:15 +00:00
q2trace_t tr = SVQ2_Trace ( p , vec3_origin , vec3_origin , p , NULL , ~ 0 ) ;
2004-08-23 00:15:46 +00:00
return tr . contents ;
// return CM_PointContents(p, 0);
}
2005-03-18 06:13:11 +00:00
static cvar_t * VARGS Q2Cvar_Get ( char * var_name , char * value , int flags )
2004-08-23 00:15:46 +00:00
{
2014-02-11 17:51:29 +00:00
cvar_t * var = Cvar_Get ( var_name , value , flags , " Quake2 game variables " ) ;
if ( ! var )
{
Con_Printf ( " Q2Cvar_Get: variable %s not creatable \n " , var_name ) ;
return NULL ;
}
return var ;
2004-08-23 00:15:46 +00:00
}
2005-03-18 06:13:11 +00:00
cvar_t * VARGS Q2Cvar_Set ( char * var_name , char * value )
2004-08-23 00:15:46 +00:00
{
cvar_t * var = Cvar_FindVar ( var_name ) ;
if ( ! var )
{
Con_Printf ( " Q2Cvar_Set: variable %s not found \n " , var_name ) ;
return NULL ;
}
return Cvar_Set ( var , value ) ;
}
2005-03-18 06:13:11 +00:00
cvar_t * VARGS Q2Cvar_ForceSet ( char * var_name , char * value )
2004-08-23 00:15:46 +00:00
{
cvar_t * var = Cvar_FindVar ( var_name ) ;
if ( ! var )
{
2009-10-06 00:37:47 +00:00
Con_Printf ( " Q2Cvar_Set: variable %s not found \n " , var_name ) ;
2004-08-23 00:15:46 +00:00
return NULL ;
}
return Cvar_ForceSet ( var , value ) ;
}
//==============================================
/*
= = = = = = = = = = = = = = =
SV_ShutdownGameProgs
Called when either the entire server is being killed , or
it is changing to a different game directory .
= = = = = = = = = = = = = = =
*/
2005-03-18 06:13:11 +00:00
void VARGS SVQ2_ShutdownGameProgs ( void )
2004-08-23 00:15:46 +00:00
{
if ( ! ge )
return ;
ge - > Shutdown ( ) ;
2013-05-11 14:02:55 +00:00
SVQ2_UnloadGame ( ) ;
2004-08-23 00:15:46 +00:00
ge = NULL ;
}
2005-03-18 06:13:11 +00:00
static void VARGS AddCommandString ( char * command )
2004-08-23 00:15:46 +00:00
{
Cbuf_AddText ( command , RESTRICT_LOCAL ) ;
}
/*
= = = = = = = = = = = = = = =
SV_InitGameProgs
Init the game subsystem for a new map
= = = = = = = = = = = = = = =
*/
2005-03-18 06:13:11 +00:00
void VARGS Q2SCR_DebugGraph ( float value , int color )
2004-08-23 00:15:46 +00:00
{ return ; }
2009-11-04 21:16:50 +00:00
static void VARGS SVQ2_LinkEdict ( q2edict_t * ent )
{
WorldQ2_LinkEdict ( & sv . world , ent ) ;
}
static void VARGS SVQ2_UnlinkEdict ( q2edict_t * ent )
{
WorldQ2_UnlinkEdict ( & sv . world , ent ) ;
}
static int VARGS SVQ2_AreaEdicts ( vec3_t mins , vec3_t maxs , q2edict_t * * list , int maxcount , int areatype )
{
return WorldQ2_AreaEdicts ( & sv . world , mins , maxs , list , maxcount , areatype ) ;
}
2010-07-11 02:22:39 +00:00
static model_t * SVQ2_GetCModel ( world_t * w , int modelindex )
{
2014-09-17 03:04:08 +00:00
if ( ( unsigned int ) modelindex < MAX_PRECACHE_MODELS )
2010-07-11 02:22:39 +00:00
return sv . models [ modelindex ] ;
else
return NULL ;
}
void SVQ2_InitWorld ( void )
{
2011-10-27 16:16:29 +00:00
sv . world . Get_CModel = SVQ2_GetCModel ;
2010-07-11 02:22:39 +00:00
}
2015-02-02 08:01:53 +00:00
static void QDECL PFQ2_SetAreaPortalState ( unsigned int p , qboolean s )
{
CMQ2_SetAreaPortalState ( sv . world . worldmodel , p , s ) ;
}
2004-08-23 00:15:46 +00:00
qboolean SVQ2_InitGameProgs ( void )
{
2011-04-20 03:34:32 +00:00
extern cvar_t maxclients ;
2005-03-18 06:13:11 +00:00
volatile static game_import_t import ; //volatile because msvc sucks
2004-08-23 00:15:46 +00:00
if ( COM_CheckParm ( " -noq2dll " ) )
{
SVQ2_ShutdownGameProgs ( ) ;
return false ;
}
// unload anything we have now
2013-12-08 20:06:55 +00:00
if ( sv . world . worldmodel & & ( sv . world . worldmodel - > fromgame = = fg_quake | | sv . world . worldmodel - > fromgame = = fg_halflife ) ) //we don't support q1 or hl maps yet... If ever.
2004-08-23 00:15:46 +00:00
{
SVQ2_ShutdownGameProgs ( ) ;
return false ;
}
if ( ge )
2010-07-11 02:22:39 +00:00
{
SVQ2_InitWorld ( ) ;
2004-08-23 00:15:46 +00:00
return true ;
2010-07-11 02:22:39 +00:00
}
2004-08-23 00:15:46 +00:00
// calc the imports.
import . multicast = SV_Multicast ;
import . unicast = PFQ2_Unicast ;
import . bprintf = SV_BroadcastPrintf ;
import . dprintf = PFQ2_dprintf ;
import . cprintf = PFQ2_cprintf ;
import . centerprintf = PFQ2_centerprintf ;
import . error = PFQ2_error ;
import . linkentity = SVQ2_LinkEdict ;
import . unlinkentity = SVQ2_UnlinkEdict ;
import . BoxEdicts = SVQ2_AreaEdicts ;
import . trace = SVQ2_Trace ;
import . pointcontents = SVQ2_PointContents ;
import . setmodel = PFQ2_setmodel ;
import . inPVS = PFQ2_inPVS ;
import . inPHS = PFQ2_inPHS ;
import . Pmove = Q2_Pmove ;
import . modelindex = SVQ2_ModelIndex ;
import . soundindex = SVQ2_SoundIndex ;
import . imageindex = SVQ2_ImageIndex ;
import . configstring = PFQ2_Configstring ;
import . sound = PFQ2_StartSound ;
import . positioned_sound = SVQ2_StartSound ;
import . WriteChar = PFQ2_WriteChar ;
import . WriteByte = PFQ2_WriteByte ;
import . WriteShort = PFQ2_WriteShort ;
import . WriteLong = PFQ2_WriteLong ;
import . WriteFloat = PFQ2_WriteFloat ;
import . WriteString = PFQ2_WriteString ;
import . WritePosition = PFQ2_WritePos ;
import . WriteDir = PFQ2_WriteDir ;
import . WriteAngle = PFQ2_WriteAngle ;
import . TagMalloc = Z_TagMalloc ;
2008-05-09 14:22:37 +00:00
import . TagFree = Z_TagFree ;
2004-08-23 00:15:46 +00:00
import . FreeTags = Z_FreeTags ;
import . cvar = Q2Cvar_Get ;
import . cvar_set = Q2Cvar_Set ;
import . cvar_forceset = Q2Cvar_ForceSet ;
import . argc = Cmd_Argc ;
import . argv = Cmd_Argv ;
import . args = Cmd_Args ;
import . AddCommandString = AddCommandString ;
import . DebugGraph = Q2SCR_DebugGraph ;
2015-02-02 08:01:53 +00:00
import . SetAreaPortalState = PFQ2_SetAreaPortalState ;
2005-08-26 22:56:51 +00:00
import . AreasConnected = PFQ2_AreasConnected ;
2004-08-23 00:15:46 +00:00
2013-12-08 20:06:55 +00:00
if ( sv . world . worldmodel & & ( sv . world . worldmodel - > fromgame = = fg_quake | | sv . world . worldmodel - > fromgame = = fg_halflife ) )
2004-08-23 00:15:46 +00:00
{
return false ;
}
2013-05-11 14:02:55 +00:00
ge = ( game_export_t * ) SVQ2_GetGameAPI ( ( game_import_t * ) & import ) ;
2004-08-23 00:15:46 +00:00
if ( ! ge )
return false ;
2005-03-07 08:58:26 +00:00
if ( ge - > apiversion ! = Q2GAME_API_VERSION )
2004-08-23 00:15:46 +00:00
{
2005-03-07 08:58:26 +00:00
Con_Printf ( " game is version %i, not %i " , ge - > apiversion , Q2GAME_API_VERSION ) ;
2013-05-11 14:02:55 +00:00
SVQ2_UnloadGame ( ) ;
2004-08-23 00:15:46 +00:00
return false ;
}
2014-05-10 13:42:13 +00:00
//stop q2 from crashing.
2011-04-23 20:37:20 +00:00
if ( ! deathmatch . value & & ! coop . value )
maxclients . value = 1 ;
2014-05-10 13:42:13 +00:00
else
maxclients . value = maxclients . ival ;
2011-04-20 03:34:32 +00:00
if ( maxclients . value > MAX_CLIENTS )
Cvar_SetValue ( & maxclients , MAX_CLIENTS ) ;
svq2_maxclients = maxclients . value ;
maxclients . flags | = CVAR_LATCH ;
deathmatch . flags | = CVAR_LATCH ;
coop . flags | = CVAR_LATCH ;
2010-07-11 02:22:39 +00:00
SVQ2_InitWorld ( ) ;
2004-08-23 00:15:46 +00:00
ge - > Init ( ) ;
return true ;
}
# endif