26 Feb 2018
This commit is contained in:
parent
209d2aabca
commit
64609ae475
|
@ -267,7 +267,7 @@ void CL_ProcessEntityUpdate( cl_entity_t *ent )
|
||||||
{
|
{
|
||||||
qboolean parametric;
|
qboolean parametric;
|
||||||
|
|
||||||
ent->model = Mod_Handle( ent->curstate.modelindex );
|
ent->model = CL_ModelHandle( ent->curstate.modelindex );
|
||||||
ent->index = ent->curstate.number;
|
ent->index = ent->curstate.number;
|
||||||
|
|
||||||
// g-cont. make sure what it's no broke XashXT physics
|
// g-cont. make sure what it's no broke XashXT physics
|
||||||
|
|
|
@ -114,6 +114,20 @@ cl_entity_t *CL_GetEntityByIndex( int index )
|
||||||
return CL_EDICT_NUM( index );
|
return CL_EDICT_NUM( index );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
CL_ModelHandle
|
||||||
|
|
||||||
|
get model handle by index
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
model_t *CL_ModelHandle( int modelindex )
|
||||||
|
{
|
||||||
|
if( modelindex < 0 || modelindex >= MAX_MODELS )
|
||||||
|
return NULL;
|
||||||
|
return cl.models[modelindex];
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
====================
|
====================
|
||||||
CL_IsThirdPerson
|
CL_IsThirdPerson
|
||||||
|
@ -2217,9 +2231,12 @@ int CL_FindModelIndex( const char *m )
|
||||||
if( !m || !m[0] )
|
if( !m || !m[0] )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for( i = 1; i < MAX_MODELS && cl.model_precache[i][0]; i++ )
|
for( i = 1; i < cl.nummodels; i++ )
|
||||||
{
|
{
|
||||||
if( !Q_stricmp( cl.model_precache[i], m ))
|
if( !cl.models[i] )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if( !Q_stricmp( cl.models[i]->name, m ))
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2431,13 +2448,16 @@ CL_LoadModel
|
||||||
*/
|
*/
|
||||||
model_t *CL_LoadModel( const char *modelname, int *index )
|
model_t *CL_LoadModel( const char *modelname, int *index )
|
||||||
{
|
{
|
||||||
int idx;
|
int i;
|
||||||
|
|
||||||
idx = CL_FindModelIndex( modelname );
|
if( index ) *index = -1;
|
||||||
if( !idx ) return NULL;
|
|
||||||
if( index ) *index = idx;
|
|
||||||
|
|
||||||
return Mod_Handle( idx );
|
if(( i = CL_FindModelIndex( modelname )) == 0 )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if( index ) *index = i;
|
||||||
|
|
||||||
|
return CL_ModelHandle( i );
|
||||||
}
|
}
|
||||||
|
|
||||||
int CL_AddEntity( int entityType, cl_entity_t *pEnt )
|
int CL_AddEntity( int entityType, cl_entity_t *pEnt )
|
||||||
|
|
|
@ -656,9 +656,8 @@ for drawing playermodel previews
|
||||||
*/
|
*/
|
||||||
static void pfnSetPlayerModel( cl_entity_t *ent, const char *path )
|
static void pfnSetPlayerModel( cl_entity_t *ent, const char *path )
|
||||||
{
|
{
|
||||||
Mod_RegisterModel( path, MAX_MODELS - 1 );
|
ent->model = Mod_ForName( path, false, false );
|
||||||
ent->curstate.modelindex = MAX_MODELS - 1;
|
ent->curstate.modelindex = MAX_MODELS; // unreachable index
|
||||||
ent->model = Mod_Handle( MAX_MODELS - 1 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -864,18 +863,6 @@ static void pfnChangeInstance( const char *newInstance, const char *szFinalMessa
|
||||||
Host_NewInstance( newInstance, szFinalMessage );
|
Host_NewInstance( newInstance, szFinalMessage );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
=========
|
|
||||||
pfnHostNewGame
|
|
||||||
|
|
||||||
=========
|
|
||||||
*/
|
|
||||||
static void pfnHostNewGame( const char *mapName )
|
|
||||||
{
|
|
||||||
if( !mapName || !*mapName ) return;
|
|
||||||
Host_NewGame( mapName, false );
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=========
|
=========
|
||||||
pfnHostEndGame
|
pfnHostEndGame
|
||||||
|
@ -885,7 +872,7 @@ pfnHostEndGame
|
||||||
static void pfnHostEndGame( const char *szFinalMessage )
|
static void pfnHostEndGame( const char *szFinalMessage )
|
||||||
{
|
{
|
||||||
if( !szFinalMessage ) szFinalMessage = "";
|
if( !szFinalMessage ) szFinalMessage = "";
|
||||||
Host_EndGame( szFinalMessage );
|
Host_EndGame( true, szFinalMessage );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1306,18 +1306,18 @@ void CL_Disconnect( void )
|
||||||
void CL_Disconnect_f( void )
|
void CL_Disconnect_f( void )
|
||||||
{
|
{
|
||||||
if( Host_IsLocalClient( ))
|
if( Host_IsLocalClient( ))
|
||||||
Host_EndGame( "disconnected from server\n" );
|
Host_EndGame( true, "disconnected from server\n" );
|
||||||
else CL_Disconnect();
|
else CL_Disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CL_Crashed( void )
|
void CL_Crashed( void )
|
||||||
{
|
{
|
||||||
// already freed
|
// already freed
|
||||||
if( host.state == HOST_CRASHED ) return;
|
if( host.status == HOST_CRASHED ) return;
|
||||||
if( host.type != HOST_NORMAL ) return;
|
if( host.type != HOST_NORMAL ) return;
|
||||||
if( !cls.initialized ) return;
|
if( !cls.initialized ) return;
|
||||||
|
|
||||||
host.state = HOST_CRASHED;
|
host.status = HOST_CRASHED;
|
||||||
|
|
||||||
CL_Stop_f(); // stop any demos
|
CL_Stop_f(); // stop any demos
|
||||||
|
|
||||||
|
@ -1704,31 +1704,26 @@ Call before entering a new level, or after changing dlls
|
||||||
*/
|
*/
|
||||||
void CL_PrepVideo( void )
|
void CL_PrepVideo( void )
|
||||||
{
|
{
|
||||||
string name, mapname;
|
int i;
|
||||||
int i, mdlcount;
|
|
||||||
|
|
||||||
if( !cl.model_precache[1][0] )
|
if( !cl.models[WORLD_INDEX] )
|
||||||
return; // no map loaded
|
return; // no map loaded
|
||||||
|
|
||||||
Cvar_SetValue( "scr_loading", 0.0f ); // reset progress bar
|
Cvar_SetValue( "scr_loading", 0.0f ); // reset progress bar
|
||||||
MsgDev( D_NOTE, "CL_PrepVideo: %s\n", clgame.mapname );
|
MsgDev( D_NOTE, "CL_PrepVideo: %s\n", clgame.mapname );
|
||||||
|
|
||||||
// let the render dll load the map
|
// let the render dll load the map
|
||||||
Q_strncpy( mapname, cl.model_precache[1], MAX_STRING );
|
world.loading = true;
|
||||||
Mod_LoadWorld( mapname, NS_CLIENT );
|
cl.worldmodel = Mod_LoadModel( cl.models[WORLD_INDEX], true );
|
||||||
cl.worldmodel = Mod_Handle( 1 ); // get world pointer
|
world.loading = false;
|
||||||
Cvar_SetValue( "scr_loading", 25.0f );
|
Cvar_SetValue( "scr_loading", 25.0f );
|
||||||
|
|
||||||
SCR_UpdateScreen();
|
SCR_UpdateScreen();
|
||||||
|
|
||||||
for( i = 0, mdlcount = 0; i < MAX_MODELS && cl.model_precache[i+1][0]; i++ )
|
for( i = WORLD_INDEX; i < cl.nummodels - 1; i++ )
|
||||||
mdlcount++; // total num models
|
|
||||||
|
|
||||||
for( i = 0; i < MAX_MODELS && cl.model_precache[i+1][0]; i++ )
|
|
||||||
{
|
{
|
||||||
Q_strncpy( name, cl.model_precache[i+1], MAX_STRING );
|
Mod_LoadModel( cl.models[i+1], false );
|
||||||
Mod_RegisterModel( name, i+1 );
|
Cvar_SetValue( "scr_loading", scr_loading->value + 75.0f / cl.nummodels );
|
||||||
Cvar_SetValue( "scr_loading", scr_loading->value + 75.0f / mdlcount );
|
|
||||||
if( cl_allow_levelshots->value || host.developer > 3 || cl.background )
|
if( cl_allow_levelshots->value || host.developer > 3 || cl.background )
|
||||||
SCR_UpdateScreen();
|
SCR_UpdateScreen();
|
||||||
}
|
}
|
||||||
|
@ -2185,7 +2180,7 @@ void CL_Precache_f( void )
|
||||||
CL_PrepVideo();
|
CL_PrepVideo();
|
||||||
|
|
||||||
MSG_BeginClientCmd( &cls.netchan.message, clc_stringcmd );
|
MSG_BeginClientCmd( &cls.netchan.message, clc_stringcmd );
|
||||||
MSG_WriteString( &cls.netchan.message, va( "begin %i\n", spawncount ));
|
MSG_WriteString( &cls.netchan.message, va( "spawn %i\n", spawncount ));
|
||||||
}
|
}
|
||||||
|
|
||||||
qboolean CL_PrecacheResources( void )
|
qboolean CL_PrecacheResources( void )
|
||||||
|
@ -2229,12 +2224,19 @@ qboolean CL_PrecacheResources( void )
|
||||||
case t_skin:
|
case t_skin:
|
||||||
break;
|
break;
|
||||||
case t_model:
|
case t_model:
|
||||||
|
if( pResource->nIndex >= cl.nummodels )
|
||||||
|
{
|
||||||
|
cl.nummodels = pResource->nIndex + 1;
|
||||||
|
cl.nummodels = Q_min( cl.nummodels, MAX_MODELS );
|
||||||
|
}
|
||||||
|
|
||||||
if( pResource->szFileName[0] != '*' )
|
if( pResource->szFileName[0] != '*' )
|
||||||
{
|
{
|
||||||
Q_strncpy( cl.model_precache[pResource->nIndex], pResource->szFileName, sizeof( cl.model_precache[0] ));
|
if( pResource->nIndex == WORLD_INDEX )
|
||||||
Mod_RegisterModel( pResource->szFileName, pResource->nIndex );
|
cl.models[pResource->nIndex] = Mod_LoadWorld( pResource->szFileName, true );
|
||||||
|
else cl.models[pResource->nIndex] = Mod_ForName( pResource->szFileName, false, true );
|
||||||
|
|
||||||
if( !Mod_Handle( pResource->nIndex ))
|
if( cl.models[pResource->nIndex] == NULL )
|
||||||
{
|
{
|
||||||
if( pResource->ucFlags != 0 )
|
if( pResource->ucFlags != 0 )
|
||||||
MsgDev( D_WARN, "model %s not found and not available\n", pResource->szFileName );
|
MsgDev( D_WARN, "model %s not found and not available\n", pResource->szFileName );
|
||||||
|
|
|
@ -559,7 +559,7 @@ void CL_ParseStaticEntity( sizebuf_t *msg )
|
||||||
// setup the new static entity
|
// setup the new static entity
|
||||||
VectorCopy( ent->curstate.origin, ent->origin );
|
VectorCopy( ent->curstate.origin, ent->origin );
|
||||||
VectorCopy( ent->curstate.angles, ent->angles );
|
VectorCopy( ent->curstate.angles, ent->angles );
|
||||||
ent->model = Mod_Handle( state.modelindex );
|
ent->model = CL_ModelHandle( state.modelindex );
|
||||||
ent->curstate.framerate = 1.0f;
|
ent->curstate.framerate = 1.0f;
|
||||||
CL_ResetLatchedVars( ent, true );
|
CL_ResetLatchedVars( ent, true );
|
||||||
|
|
||||||
|
@ -1267,19 +1267,24 @@ prceache model from server
|
||||||
*/
|
*/
|
||||||
void CL_PrecacheModel( sizebuf_t *msg )
|
void CL_PrecacheModel( sizebuf_t *msg )
|
||||||
{
|
{
|
||||||
int modelIndex;
|
const char *s;
|
||||||
|
int i;
|
||||||
|
|
||||||
modelIndex = MSG_ReadUBitLong( msg, MAX_MODEL_BITS );
|
i = MSG_ReadUBitLong( msg, MAX_MODEL_BITS );
|
||||||
|
s = MSG_ReadString( msg );
|
||||||
|
|
||||||
if( modelIndex < 0 || modelIndex >= MAX_MODELS )
|
if( i < 0 || i >= MAX_MODELS )
|
||||||
Host_Error( "CL_PrecacheModel: bad modelindex %i\n", modelIndex );
|
Host_Error( "CL_PrecacheModel: bad modelindex %i\n", i );
|
||||||
|
|
||||||
Q_strncpy( cl.model_precache[modelIndex], MSG_ReadString( msg ), sizeof( cl.model_precache[0] ));
|
if( i == WORLD_INDEX )
|
||||||
|
cl.models[i] = Mod_LoadWorld( s, false );
|
||||||
|
else cl.models[i] = Mod_FindName( s, false );
|
||||||
|
|
||||||
// when we loading map all resources is precached sequentially
|
if( i >= cl.nummodels )
|
||||||
if( !cl.video_prepped ) return;
|
{
|
||||||
|
cl.nummodels = i + 1;
|
||||||
Mod_RegisterModel( cl.model_precache[modelIndex], modelIndex );
|
cl.nummodels = Q_min( cl.nummodels, MAX_MODELS );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1370,12 +1375,9 @@ void CL_PrecacheBSPModels( const char *pfilename )
|
||||||
|
|
||||||
if( p->type == t_model && p->szFileName[0] == '*' )
|
if( p->type == t_model && p->szFileName[0] == '*' )
|
||||||
{
|
{
|
||||||
Q_strncpy( cl.model_precache[p->nIndex], p->szFileName, sizeof( cl.model_precache[0] ));
|
cl.models[p->nIndex] = Mod_ForName( p->szFileName, false, false );
|
||||||
|
|
||||||
// when we loading map all resources is precached sequentially
|
if( cl.models[p->nIndex] == NULL )
|
||||||
if( cl.video_prepped ) Mod_RegisterModel( cl.model_precache[p->nIndex], p->nIndex );
|
|
||||||
|
|
||||||
if( !Mod_Handle( p->nIndex ))
|
|
||||||
{
|
{
|
||||||
MsgDev( D_ERROR, "model %s not found\n", p->szFileName );
|
MsgDev( D_ERROR, "model %s not found\n", p->szFileName );
|
||||||
|
|
||||||
|
@ -1481,12 +1483,11 @@ void CL_RegisterResources ( sizebuf_t *msg )
|
||||||
CL_SendConsistencyInfo( msg );
|
CL_SendConsistencyInfo( msg );
|
||||||
|
|
||||||
// All done precaching.
|
// All done precaching.
|
||||||
cl.worldmodel = Mod_Handle( 1 ); // get world pointer
|
cl.worldmodel = CL_ModelHandle( 1 ); // get world pointer
|
||||||
cl.video_prepped = true;
|
|
||||||
cl.audio_prepped = true;
|
|
||||||
|
|
||||||
if( cl.worldmodel && cl.maxclients > 0 )
|
if( cl.worldmodel && cl.maxclients > 0 )
|
||||||
{
|
{
|
||||||
|
ASSERT( clgame.entities != NULL );
|
||||||
clgame.entities->model = cl.worldmodel;
|
clgame.entities->model = cl.worldmodel;
|
||||||
CL_PrecacheBSPModels( cl.worldmodel->name );
|
CL_PrecacheBSPModels( cl.worldmodel->name );
|
||||||
|
|
||||||
|
@ -1499,6 +1500,8 @@ void CL_RegisterResources ( sizebuf_t *msg )
|
||||||
|
|
||||||
// invalidate all decal indexes
|
// invalidate all decal indexes
|
||||||
memset( cl.decal_index, 0, sizeof( cl.decal_index ));
|
memset( cl.decal_index, 0, sizeof( cl.decal_index ));
|
||||||
|
cl.video_prepped = true;
|
||||||
|
cl.audio_prepped = true;
|
||||||
|
|
||||||
CL_ClearWorld ();
|
CL_ClearWorld ();
|
||||||
|
|
||||||
|
@ -1942,7 +1945,7 @@ void CL_ParseStudioDecal( sizebuf_t *msg )
|
||||||
cl_entity_t *ent = CL_GetEntityByIndex( entityIndex );
|
cl_entity_t *ent = CL_GetEntityByIndex( entityIndex );
|
||||||
|
|
||||||
if( ent && !ent->model && modelIndex != 0 )
|
if( ent && !ent->model && modelIndex != 0 )
|
||||||
ent->model = Mod_Handle( modelIndex );
|
ent->model = CL_ModelHandle( modelIndex );
|
||||||
|
|
||||||
clgame.drawFuncs.R_StudioDecalShoot( decalTexture, ent, start, pos, flags, &state );
|
clgame.drawFuncs.R_StudioDecalShoot( decalTexture, ent, start, pos, flags, &state );
|
||||||
}
|
}
|
||||||
|
|
|
@ -329,7 +329,7 @@ void CL_ClipPMoveToEntity( physent_t *pe, const vec3_t start, vec3_t mins, vec3_
|
||||||
|
|
||||||
static void CL_CopyEntityToPhysEnt( physent_t *pe, entity_state_t *state, qboolean visent )
|
static void CL_CopyEntityToPhysEnt( physent_t *pe, entity_state_t *state, qboolean visent )
|
||||||
{
|
{
|
||||||
model_t *mod = Mod_Handle( state->modelindex );
|
model_t *mod = CL_ModelHandle( state->modelindex );
|
||||||
|
|
||||||
pe->player = 0;
|
pe->player = 0;
|
||||||
|
|
||||||
|
@ -359,7 +359,7 @@ static void CL_CopyEntityToPhysEnt( physent_t *pe, entity_state_t *state, qboole
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if( pe->solid != SOLID_BSP && Mod_GetType( state->modelindex ) == mod_studio )
|
if( pe->solid != SOLID_BSP && ( mod != NULL ) && ( mod->type == mod_studio ))
|
||||||
pe->studiomodel = mod;
|
pe->studiomodel = mod;
|
||||||
else pe->model = mod;
|
else pe->model = mod;
|
||||||
}
|
}
|
||||||
|
@ -432,7 +432,7 @@ void CL_AddLinksToPmove( frame_t *frame )
|
||||||
if( !state->modelindex )
|
if( !state->modelindex )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
model = Mod_Handle( state->modelindex );
|
model = CL_ModelHandle( state->modelindex );
|
||||||
if( !model ) continue;
|
if( !model ) continue;
|
||||||
|
|
||||||
if(( state->owner != 0 ) && ( state->owner == cl.playernum + 1 ))
|
if(( state->owner != 0 ) && ( state->owner == cl.playernum + 1 ))
|
||||||
|
|
|
@ -257,7 +257,7 @@ void CL_PrepareTEnt( TEMPENTITY *pTemp, model_t *pmodel )
|
||||||
pTemp->flags = FTENT_NONE;
|
pTemp->flags = FTENT_NONE;
|
||||||
pTemp->die = cl.time + 0.75f;
|
pTemp->die = cl.time + 0.75f;
|
||||||
|
|
||||||
if( pmodel ) frameCount = Mod_FrameCount( pmodel );
|
if( pmodel ) frameCount = pmodel->numframes;
|
||||||
else pTemp->flags |= FTENT_NOMODEL;
|
else pTemp->flags |= FTENT_NOMODEL;
|
||||||
|
|
||||||
pTemp->entity.curstate.modelindex = modelIndex;
|
pTemp->entity.curstate.modelindex = modelIndex;
|
||||||
|
@ -580,25 +580,24 @@ Create a fizz effect
|
||||||
void R_FizzEffect( cl_entity_t *pent, int modelIndex, int density )
|
void R_FizzEffect( cl_entity_t *pent, int modelIndex, int density )
|
||||||
{
|
{
|
||||||
TEMPENTITY *pTemp;
|
TEMPENTITY *pTemp;
|
||||||
int i, width, depth, count, frameCount;
|
int i, width, depth, count;
|
||||||
float angle, maxHeight, speed;
|
float angle, maxHeight, speed;
|
||||||
float xspeed, yspeed, zspeed;
|
float xspeed, yspeed, zspeed;
|
||||||
vec3_t origin, mins, maxs;
|
vec3_t origin;
|
||||||
|
model_t *mod;
|
||||||
|
|
||||||
if( !pent || Mod_GetType( modelIndex ) == mod_bad )
|
if( !pent || pent->curstate.modelindex <= 0 )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if( pent->curstate.modelindex <= 0 )
|
if(( mod = CL_ModelHandle( pent->curstate.modelindex )) == NULL )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
count = density + 1;
|
count = density + 1;
|
||||||
density = count * 3 + 6;
|
density = count * 3 + 6;
|
||||||
|
maxHeight = mod->maxs[2] - mod->mins[2];
|
||||||
|
width = mod->maxs[0] - mod->mins[0];
|
||||||
|
depth = mod->maxs[1] - mod->mins[1];
|
||||||
|
|
||||||
Mod_GetBounds( pent->curstate.modelindex, mins, maxs );
|
|
||||||
|
|
||||||
maxHeight = maxs[2] - mins[2];
|
|
||||||
width = maxs[0] - mins[0];
|
|
||||||
depth = maxs[1] - mins[1];
|
|
||||||
speed = ( pent->curstate.rendercolor.r<<8 | pent->curstate.rendercolor.g );
|
speed = ( pent->curstate.rendercolor.r<<8 | pent->curstate.rendercolor.g );
|
||||||
if( pent->curstate.rendercolor.b )
|
if( pent->curstate.rendercolor.b )
|
||||||
speed = -speed;
|
speed = -speed;
|
||||||
|
@ -609,14 +608,12 @@ void R_FizzEffect( cl_entity_t *pent, int modelIndex, int density )
|
||||||
xspeed *= speed;
|
xspeed *= speed;
|
||||||
yspeed *= speed;
|
yspeed *= speed;
|
||||||
|
|
||||||
Mod_GetFrames( modelIndex, &frameCount );
|
|
||||||
|
|
||||||
for( i = 0; i < count; i++ )
|
for( i = 0; i < count; i++ )
|
||||||
{
|
{
|
||||||
origin[0] = mins[0] + COM_RandomLong( 0, width - 1 );
|
origin[0] = mod->mins[0] + COM_RandomLong( 0, width - 1 );
|
||||||
origin[1] = mins[1] + COM_RandomLong( 0, depth - 1 );
|
origin[1] = mod->mins[1] + COM_RandomLong( 0, depth - 1 );
|
||||||
origin[2] = mins[2];
|
origin[2] = mod->mins[2];
|
||||||
pTemp = CL_TempEntAlloc( origin, Mod_Handle( modelIndex ));
|
pTemp = CL_TempEntAlloc( origin, mod );
|
||||||
|
|
||||||
if ( !pTemp ) return;
|
if ( !pTemp ) return;
|
||||||
|
|
||||||
|
@ -628,7 +625,7 @@ void R_FizzEffect( cl_entity_t *pent, int modelIndex, int density )
|
||||||
zspeed = COM_RandomLong( 80, 140 );
|
zspeed = COM_RandomLong( 80, 140 );
|
||||||
VectorSet( pTemp->entity.baseline.origin, xspeed, yspeed, zspeed );
|
VectorSet( pTemp->entity.baseline.origin, xspeed, yspeed, zspeed );
|
||||||
pTemp->die = cl.time + ( maxHeight / zspeed ) - 0.1f;
|
pTemp->die = cl.time + ( maxHeight / zspeed ) - 0.1f;
|
||||||
pTemp->entity.curstate.frame = COM_RandomLong( 0, frameCount - 1 );
|
pTemp->entity.curstate.frame = COM_RandomLong( 0, pTemp->frameMax );
|
||||||
// Set sprite scale
|
// Set sprite scale
|
||||||
pTemp->entity.curstate.scale = 1.0f / COM_RandomFloat( 2.0f, 5.0f );
|
pTemp->entity.curstate.scale = 1.0f / COM_RandomFloat( 2.0f, 5.0f );
|
||||||
pTemp->entity.curstate.rendermode = kRenderTransAlpha;
|
pTemp->entity.curstate.rendermode = kRenderTransAlpha;
|
||||||
|
@ -646,22 +643,21 @@ Create bubbles
|
||||||
void R_Bubbles( const vec3_t mins, const vec3_t maxs, float height, int modelIndex, int count, float speed )
|
void R_Bubbles( const vec3_t mins, const vec3_t maxs, float height, int modelIndex, int count, float speed )
|
||||||
{
|
{
|
||||||
TEMPENTITY *pTemp;
|
TEMPENTITY *pTemp;
|
||||||
int i, frameCount;
|
|
||||||
float sine, cosine;
|
float sine, cosine;
|
||||||
float angle, zspeed;
|
float angle, zspeed;
|
||||||
vec3_t origin;
|
vec3_t origin;
|
||||||
|
model_t *mod;
|
||||||
|
int i;
|
||||||
|
|
||||||
if( Mod_GetType( modelIndex ) == mod_bad )
|
if(( mod = CL_ModelHandle( modelIndex )) == NULL )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Mod_GetFrames( modelIndex, &frameCount );
|
|
||||||
|
|
||||||
for ( i = 0; i < count; i++ )
|
for ( i = 0; i < count; i++ )
|
||||||
{
|
{
|
||||||
origin[0] = COM_RandomLong( mins[0], maxs[0] );
|
origin[0] = COM_RandomLong( mins[0], maxs[0] );
|
||||||
origin[1] = COM_RandomLong( mins[1], maxs[1] );
|
origin[1] = COM_RandomLong( mins[1], maxs[1] );
|
||||||
origin[2] = COM_RandomLong( mins[2], maxs[2] );
|
origin[2] = COM_RandomLong( mins[2], maxs[2] );
|
||||||
pTemp = CL_TempEntAlloc( origin, Mod_Handle( modelIndex ));
|
pTemp = CL_TempEntAlloc( origin, mod );
|
||||||
if( !pTemp ) return;
|
if( !pTemp ) return;
|
||||||
|
|
||||||
pTemp->flags |= FTENT_SINEWAVE;
|
pTemp->flags |= FTENT_SINEWAVE;
|
||||||
|
@ -674,7 +670,7 @@ void R_Bubbles( const vec3_t mins, const vec3_t maxs, float height, int modelInd
|
||||||
zspeed = COM_RandomLong( 80, 140 );
|
zspeed = COM_RandomLong( 80, 140 );
|
||||||
VectorSet( pTemp->entity.baseline.origin, speed * cosine, speed * sine, zspeed );
|
VectorSet( pTemp->entity.baseline.origin, speed * cosine, speed * sine, zspeed );
|
||||||
pTemp->die = cl.time + ((height - (origin[2] - mins[2])) / zspeed) - 0.1f;
|
pTemp->die = cl.time + ((height - (origin[2] - mins[2])) / zspeed) - 0.1f;
|
||||||
pTemp->entity.curstate.frame = COM_RandomLong( 0, frameCount - 1 );
|
pTemp->entity.curstate.frame = COM_RandomLong( 0, pTemp->frameMax );
|
||||||
|
|
||||||
// Set sprite scale
|
// Set sprite scale
|
||||||
pTemp->entity.curstate.scale = 1.0f / COM_RandomFloat( 2.0f, 5.0f );
|
pTemp->entity.curstate.scale = 1.0f / COM_RandomFloat( 2.0f, 5.0f );
|
||||||
|
@ -693,21 +689,20 @@ Create bubble trail
|
||||||
void R_BubbleTrail( const vec3_t start, const vec3_t end, float height, int modelIndex, int count, float speed )
|
void R_BubbleTrail( const vec3_t start, const vec3_t end, float height, int modelIndex, int count, float speed )
|
||||||
{
|
{
|
||||||
TEMPENTITY *pTemp;
|
TEMPENTITY *pTemp;
|
||||||
int i, frameCount;
|
|
||||||
float sine, cosine, zspeed;
|
float sine, cosine, zspeed;
|
||||||
float dist, angle;
|
float dist, angle;
|
||||||
vec3_t origin;
|
vec3_t origin;
|
||||||
|
model_t *mod;
|
||||||
|
int i;
|
||||||
|
|
||||||
if( Mod_GetType( modelIndex ) == mod_bad )
|
if(( mod = CL_ModelHandle( modelIndex )) == NULL )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Mod_GetFrames( modelIndex, &frameCount );
|
|
||||||
|
|
||||||
for( i = 0; i < count; i++ )
|
for( i = 0; i < count; i++ )
|
||||||
{
|
{
|
||||||
dist = COM_RandomFloat( 0, 1.0 );
|
dist = COM_RandomFloat( 0, 1.0 );
|
||||||
VectorLerp( start, dist, end, origin );
|
VectorLerp( start, dist, end, origin );
|
||||||
pTemp = CL_TempEntAlloc( origin, Mod_Handle( modelIndex ));
|
pTemp = CL_TempEntAlloc( origin, mod );
|
||||||
if( !pTemp ) return;
|
if( !pTemp ) return;
|
||||||
|
|
||||||
pTemp->flags |= FTENT_SINEWAVE;
|
pTemp->flags |= FTENT_SINEWAVE;
|
||||||
|
@ -720,7 +715,7 @@ void R_BubbleTrail( const vec3_t start, const vec3_t end, float height, int mode
|
||||||
zspeed = COM_RandomLong( 80, 140 );
|
zspeed = COM_RandomLong( 80, 140 );
|
||||||
VectorSet( pTemp->entity.baseline.origin, speed * cosine, speed * sine, zspeed );
|
VectorSet( pTemp->entity.baseline.origin, speed * cosine, speed * sine, zspeed );
|
||||||
pTemp->die = cl.time + ((height - (origin[2] - start[2])) / zspeed) - 0.1f;
|
pTemp->die = cl.time + ((height - (origin[2] - start[2])) / zspeed) - 0.1f;
|
||||||
pTemp->entity.curstate.frame = COM_RandomLong( 0, frameCount - 1 );
|
pTemp->entity.curstate.frame = COM_RandomLong( 0, pTemp->frameMax );
|
||||||
|
|
||||||
// Set sprite scale
|
// Set sprite scale
|
||||||
pTemp->entity.curstate.scale = 1.0f / COM_RandomFloat( 2.0f, 5.0f );
|
pTemp->entity.curstate.scale = 1.0f / COM_RandomFloat( 2.0f, 5.0f );
|
||||||
|
@ -741,6 +736,7 @@ void R_AttachTentToPlayer( int client, int modelIndex, float zoffset, float life
|
||||||
TEMPENTITY *pTemp;
|
TEMPENTITY *pTemp;
|
||||||
vec3_t position;
|
vec3_t position;
|
||||||
cl_entity_t *pClient;
|
cl_entity_t *pClient;
|
||||||
|
model_t *pModel;
|
||||||
|
|
||||||
if( client <= 0 || client > cl.maxclients )
|
if( client <= 0 || client > cl.maxclients )
|
||||||
{
|
{
|
||||||
|
@ -753,10 +749,13 @@ void R_AttachTentToPlayer( int client, int modelIndex, float zoffset, float life
|
||||||
if( !pClient || pClient->curstate.messagenum != cl.parsecount )
|
if( !pClient || pClient->curstate.messagenum != cl.parsecount )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if(( pModel = CL_ModelHandle( modelIndex )) == NULL )
|
||||||
|
return;
|
||||||
|
|
||||||
VectorCopy( pClient->origin, position );
|
VectorCopy( pClient->origin, position );
|
||||||
position[2] += zoffset;
|
position[2] += zoffset;
|
||||||
|
|
||||||
pTemp = CL_TempEntAllocHigh( position, Mod_Handle( modelIndex ));
|
pTemp = CL_TempEntAllocHigh( position, pModel );
|
||||||
if( !pTemp ) return;
|
if( !pTemp ) return;
|
||||||
|
|
||||||
pTemp->entity.curstate.renderfx = kRenderFxNoDissipation;
|
pTemp->entity.curstate.renderfx = kRenderFxNoDissipation;
|
||||||
|
@ -770,7 +769,7 @@ void R_AttachTentToPlayer( int client, int modelIndex, float zoffset, float life
|
||||||
pTemp->flags |= FTENT_PLYRATTACHMENT|FTENT_PERSIST;
|
pTemp->flags |= FTENT_PLYRATTACHMENT|FTENT_PERSIST;
|
||||||
|
|
||||||
// is the model a sprite?
|
// is the model a sprite?
|
||||||
if( Mod_GetType( pTemp->entity.curstate.modelindex ) == mod_sprite )
|
if( pModel->type == mod_sprite )
|
||||||
{
|
{
|
||||||
pTemp->flags |= FTENT_SPRANIMATE|FTENT_SPRANIMATELOOP;
|
pTemp->flags |= FTENT_SPRANIMATE|FTENT_SPRANIMATELOOP;
|
||||||
pTemp->entity.curstate.framerate = 10;
|
pTemp->entity.curstate.framerate = 10;
|
||||||
|
@ -918,10 +917,11 @@ and some blood drops. This is high-priority tent
|
||||||
*/
|
*/
|
||||||
void R_BloodSprite( const vec3_t org, int colorIndex, int modelIndex, int modelIndex2, float size )
|
void R_BloodSprite( const vec3_t org, int colorIndex, int modelIndex, int modelIndex2, float size )
|
||||||
{
|
{
|
||||||
TEMPENTITY *pTemp;
|
model_t *pModel, *pModel2;
|
||||||
int impactindex;
|
int impactindex;
|
||||||
int spatterindex;
|
int spatterindex;
|
||||||
int i, splatter;
|
int i, splatter;
|
||||||
|
TEMPENTITY *pTemp;
|
||||||
vec3_t pos;
|
vec3_t pos;
|
||||||
|
|
||||||
colorIndex += COM_RandomLong( 1, 3 );
|
colorIndex += COM_RandomLong( 1, 3 );
|
||||||
|
@ -929,13 +929,13 @@ void R_BloodSprite( const vec3_t org, int colorIndex, int modelIndex, int modelI
|
||||||
spatterindex = colorIndex - 1;
|
spatterindex = colorIndex - 1;
|
||||||
|
|
||||||
// validate the model first
|
// validate the model first
|
||||||
if( modelIndex && ( Mod_GetType( modelIndex ) != mod_bad ))
|
if(( pModel = CL_ModelHandle( modelIndex )) != NULL )
|
||||||
{
|
{
|
||||||
VectorCopy( org, pos );
|
VectorCopy( org, pos );
|
||||||
pos[2] += COM_RandomFloat( 2.0f, 4.0f ); // make offset from ground (snarks issues)
|
pos[2] += COM_RandomFloat( 2.0f, 4.0f ); // make offset from ground (snarks issues)
|
||||||
|
|
||||||
// large, single blood sprite is a high-priority tent
|
// large, single blood sprite is a high-priority tent
|
||||||
if(( pTemp = CL_TempEntAllocHigh( pos, Mod_Handle( modelIndex ))) != NULL )
|
if(( pTemp = CL_TempEntAllocHigh( pos, pModel )) != NULL )
|
||||||
{
|
{
|
||||||
pTemp->entity.curstate.rendermode = kRenderTransTexture;
|
pTemp->entity.curstate.rendermode = kRenderTransTexture;
|
||||||
pTemp->entity.curstate.renderfx = kRenderFxClampMinScale;
|
pTemp->entity.curstate.renderfx = kRenderFxClampMinScale;
|
||||||
|
@ -955,14 +955,14 @@ void R_BloodSprite( const vec3_t org, int colorIndex, int modelIndex, int modelI
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate the model first
|
// validate the model first
|
||||||
if( modelIndex2 && ( Mod_GetType( modelIndex2 ) != mod_bad ))
|
if(( pModel2 = CL_ModelHandle( modelIndex2 )) != NULL )
|
||||||
{
|
{
|
||||||
splatter = size + ( COM_RandomLong( 1, 8 ) + COM_RandomLong( 1, 8 ));
|
splatter = size + ( COM_RandomLong( 1, 8 ) + COM_RandomLong( 1, 8 ));
|
||||||
|
|
||||||
for( i = 0; i < splatter; i++ )
|
for( i = 0; i < splatter; i++ )
|
||||||
{
|
{
|
||||||
// create blood drips
|
// create blood drips
|
||||||
if(( pTemp = CL_TempEntAlloc( org, Mod_Handle( modelIndex2 ))) != NULL )
|
if(( pTemp = CL_TempEntAlloc( org, pModel2 )) != NULL )
|
||||||
{
|
{
|
||||||
pTemp->entity.curstate.rendermode = kRenderTransTexture;
|
pTemp->entity.curstate.rendermode = kRenderTransTexture;
|
||||||
pTemp->entity.curstate.renderfx = kRenderFxClampMinScale;
|
pTemp->entity.curstate.renderfx = kRenderFxClampMinScale;
|
||||||
|
@ -1004,15 +1004,15 @@ Create a shards
|
||||||
void R_BreakModel( const vec3_t pos, const vec3_t size, const vec3_t dir, float random, float life, int count, int modelIndex, char flags )
|
void R_BreakModel( const vec3_t pos, const vec3_t size, const vec3_t dir, float random, float life, int count, int modelIndex, char flags )
|
||||||
{
|
{
|
||||||
TEMPENTITY *pTemp;
|
TEMPENTITY *pTemp;
|
||||||
|
model_t *pmodel;
|
||||||
char type;
|
char type;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
if( !modelIndex ) return;
|
if(( pmodel = CL_ModelHandle( modelIndex )) == NULL )
|
||||||
type = flags & BREAK_TYPEMASK;
|
|
||||||
|
|
||||||
if( Mod_GetType( modelIndex ) == mod_bad )
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
type = flags & BREAK_TYPEMASK;
|
||||||
|
|
||||||
if( count == 0 )
|
if( count == 0 )
|
||||||
{
|
{
|
||||||
// assume surface (not volume)
|
// assume surface (not volume)
|
||||||
|
@ -1039,15 +1039,15 @@ void R_BreakModel( const vec3_t pos, const vec3_t size, const vec3_t dir, float
|
||||||
|
|
||||||
if( j == 32 ) continue; // a piece completely stuck in the wall, ignore it
|
if( j == 32 ) continue; // a piece completely stuck in the wall, ignore it
|
||||||
|
|
||||||
pTemp = CL_TempEntAlloc( vecSpot, Mod_Handle( modelIndex ));
|
pTemp = CL_TempEntAlloc( vecSpot, pmodel );
|
||||||
if( !pTemp ) return;
|
if( !pTemp ) return;
|
||||||
|
|
||||||
// keep track of break_type, so we know how to play sound on collision
|
// keep track of break_type, so we know how to play sound on collision
|
||||||
pTemp->hitSound = type;
|
pTemp->hitSound = type;
|
||||||
|
|
||||||
if( Mod_GetType( modelIndex ) == mod_sprite )
|
if( pmodel->type == mod_sprite )
|
||||||
pTemp->entity.curstate.frame = COM_RandomLong( 0, pTemp->frameMax );
|
pTemp->entity.curstate.frame = COM_RandomLong( 0, pTemp->frameMax );
|
||||||
else if( Mod_GetType( modelIndex ) == mod_studio )
|
else if( pmodel->type == mod_studio )
|
||||||
pTemp->entity.curstate.body = COM_RandomLong( 0, pTemp->frameMax );
|
pTemp->entity.curstate.body = COM_RandomLong( 0, pTemp->frameMax );
|
||||||
|
|
||||||
pTemp->flags |= FTENT_COLLIDEWORLD | FTENT_FADEOUT | FTENT_SLOWGRAVITY;
|
pTemp->flags |= FTENT_COLLIDEWORLD | FTENT_FADEOUT | FTENT_SLOWGRAVITY;
|
||||||
|
@ -1093,8 +1093,12 @@ TEMPENTITY *R_TempModel( const vec3_t pos, const vec3_t dir, const vec3_t angles
|
||||||
{
|
{
|
||||||
// alloc a new tempent
|
// alloc a new tempent
|
||||||
TEMPENTITY *pTemp;
|
TEMPENTITY *pTemp;
|
||||||
|
model_t *pmodel;
|
||||||
|
|
||||||
pTemp = CL_TempEntAlloc( pos, Mod_Handle( modelIndex ));
|
if(( pmodel = CL_ModelHandle( modelIndex )) == NULL )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
pTemp = CL_TempEntAlloc( pos, pmodel );
|
||||||
if( !pTemp ) return NULL;
|
if( !pTemp ) return NULL;
|
||||||
|
|
||||||
pTemp->flags = (FTENT_COLLIDEWORLD|FTENT_GRAVITY);
|
pTemp->flags = (FTENT_COLLIDEWORLD|FTENT_GRAVITY);
|
||||||
|
@ -1120,7 +1124,7 @@ TEMPENTITY *R_TempModel( const vec3_t pos, const vec3_t dir, const vec3_t angles
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( Mod_GetType( modelIndex ) == mod_sprite )
|
if( pmodel->type == mod_sprite )
|
||||||
pTemp->entity.curstate.frame = COM_RandomLong( 0, pTemp->frameMax );
|
pTemp->entity.curstate.frame = COM_RandomLong( 0, pTemp->frameMax );
|
||||||
else pTemp->entity.curstate.body = COM_RandomLong( 0, pTemp->frameMax );
|
else pTemp->entity.curstate.body = COM_RandomLong( 0, pTemp->frameMax );
|
||||||
|
|
||||||
|
@ -1139,18 +1143,19 @@ Create an animated sprite
|
||||||
TEMPENTITY *R_DefaultSprite( const vec3_t pos, int spriteIndex, float framerate )
|
TEMPENTITY *R_DefaultSprite( const vec3_t pos, int spriteIndex, float framerate )
|
||||||
{
|
{
|
||||||
TEMPENTITY *pTemp;
|
TEMPENTITY *pTemp;
|
||||||
|
model_t *psprite;
|
||||||
|
|
||||||
// don't spawn while paused
|
// don't spawn while paused
|
||||||
if( cl.time == cl.oldtime )
|
if( cl.time == cl.oldtime )
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if( !spriteIndex || Mod_GetType( spriteIndex ) != mod_sprite )
|
if(( psprite = CL_ModelHandle( spriteIndex )) == NULL || psprite->type != mod_sprite )
|
||||||
{
|
{
|
||||||
MsgDev( D_INFO, "No Sprite %d!\n", spriteIndex );
|
MsgDev( D_INFO, "No Sprite %d!\n", spriteIndex );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pTemp = CL_TempEntAlloc( pos, Mod_Handle( spriteIndex ));
|
pTemp = CL_TempEntAlloc( pos, psprite );
|
||||||
if( !pTemp ) return NULL;
|
if( !pTemp ) return NULL;
|
||||||
|
|
||||||
pTemp->entity.curstate.scale = 1.0f;
|
pTemp->entity.curstate.scale = 1.0f;
|
||||||
|
@ -1199,17 +1204,15 @@ Create an animated moving sprite
|
||||||
TEMPENTITY *R_TempSprite( vec3_t pos, const vec3_t dir, float scale, int modelIndex, int rendermode, int renderfx, float a, float life, int flags )
|
TEMPENTITY *R_TempSprite( vec3_t pos, const vec3_t dir, float scale, int modelIndex, int rendermode, int renderfx, float a, float life, int flags )
|
||||||
{
|
{
|
||||||
TEMPENTITY *pTemp;
|
TEMPENTITY *pTemp;
|
||||||
|
model_t *pmodel;
|
||||||
|
|
||||||
if( !modelIndex )
|
if(( pmodel = CL_ModelHandle( modelIndex )) == NULL )
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if( Mod_GetType( modelIndex ) == mod_bad )
|
|
||||||
{
|
{
|
||||||
MsgDev( D_ERROR, "No model %d!\n", modelIndex );
|
MsgDev( D_ERROR, "No model %d!\n", modelIndex );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pTemp = CL_TempEntAlloc( pos, Mod_Handle( modelIndex ));
|
pTemp = CL_TempEntAlloc( pos, pmodel );
|
||||||
if( !pTemp ) return NULL;
|
if( !pTemp ) return NULL;
|
||||||
|
|
||||||
pTemp->entity.curstate.framerate = 10;
|
pTemp->entity.curstate.framerate = 10;
|
||||||
|
@ -1307,22 +1310,23 @@ void R_Spray( const vec3_t pos, const vec3_t dir, int modelIndex, int count, int
|
||||||
TEMPENTITY *pTemp;
|
TEMPENTITY *pTemp;
|
||||||
float noise;
|
float noise;
|
||||||
float znoise;
|
float znoise;
|
||||||
|
model_t *pmodel;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if(( pmodel = CL_ModelHandle( modelIndex )) == NULL )
|
||||||
|
{
|
||||||
|
MsgDev( D_INFO, "No model %d!\n", modelIndex );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
noise = (float)spread / 100.0f;
|
noise = (float)spread / 100.0f;
|
||||||
|
|
||||||
// more vertical displacement
|
// more vertical displacement
|
||||||
znoise = Q_min( 1.0f, noise * 1.5f );
|
znoise = Q_min( 1.0f, noise * 1.5f );
|
||||||
|
|
||||||
if( Mod_GetType( modelIndex ) == mod_bad )
|
|
||||||
{
|
|
||||||
MsgDev( D_INFO, "No model %d!\n", modelIndex );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for( i = 0; i < count; i++ )
|
for( i = 0; i < count; i++ )
|
||||||
{
|
{
|
||||||
pTemp = CL_TempEntAlloc( pos, Mod_Handle( modelIndex ));
|
pTemp = CL_TempEntAlloc( pos, pmodel );
|
||||||
if( !pTemp ) return;
|
if( !pTemp ) return;
|
||||||
|
|
||||||
pTemp->entity.curstate.rendermode = rendermode;
|
pTemp->entity.curstate.rendermode = rendermode;
|
||||||
|
@ -1384,9 +1388,10 @@ void R_Sprite_Trail( int type, vec3_t start, vec3_t end, int modelIndex, int cou
|
||||||
{
|
{
|
||||||
TEMPENTITY *pTemp;
|
TEMPENTITY *pTemp;
|
||||||
vec3_t delta, dir;
|
vec3_t delta, dir;
|
||||||
|
model_t *pmodel;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if( Mod_GetType( modelIndex ) == mod_bad )
|
if(( pmodel = CL_ModelHandle( modelIndex )) == NULL )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
VectorSubtract( end, start, delta );
|
VectorSubtract( end, start, delta );
|
||||||
|
@ -1402,7 +1407,7 @@ void R_Sprite_Trail( int type, vec3_t start, vec3_t end, int modelIndex, int cou
|
||||||
if( i == 0 ) VectorCopy( start, pos );
|
if( i == 0 ) VectorCopy( start, pos );
|
||||||
else VectorMA( start, ( i / ( count - 1.0f )), delta, pos );
|
else VectorMA( start, ( i / ( count - 1.0f )), delta, pos );
|
||||||
|
|
||||||
pTemp = CL_TempEntAlloc( pos, Mod_Handle( modelIndex ));
|
pTemp = CL_TempEntAlloc( pos, pmodel );
|
||||||
if( !pTemp ) return;
|
if( !pTemp ) return;
|
||||||
|
|
||||||
pTemp->flags = (FTENT_COLLIDEWORLD|FTENT_SPRCYCLE|FTENT_FADEOUT|FTENT_SLOWGRAVITY);
|
pTemp->flags = (FTENT_COLLIDEWORLD|FTENT_SPRCYCLE|FTENT_FADEOUT|FTENT_SLOWGRAVITY);
|
||||||
|
@ -1434,21 +1439,14 @@ Create a funnel effect with custom sprite
|
||||||
void R_FunnelSprite( const vec3_t org, int modelIndex, int reverse )
|
void R_FunnelSprite( const vec3_t org, int modelIndex, int reverse )
|
||||||
{
|
{
|
||||||
TEMPENTITY *pTemp;
|
TEMPENTITY *pTemp;
|
||||||
model_t *model;
|
|
||||||
vec3_t dir, dest;
|
vec3_t dir, dest;
|
||||||
float dist, vel;
|
float dist, vel;
|
||||||
|
model_t *pmodel;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
if( !modelIndex )
|
if(( pmodel = CL_ModelHandle( modelIndex )) == NULL )
|
||||||
{
|
{
|
||||||
MsgDev( D_ERROR, "no modelindex for funnel!\n" );
|
MsgDev( D_ERROR, "no model %d!\n", modelIndex );
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
model = Mod_Handle( modelIndex );
|
|
||||||
if( !model )
|
|
||||||
{
|
|
||||||
MsgDev( D_ERROR, "No model %d!\n", modelIndex );
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1456,7 +1454,7 @@ void R_FunnelSprite( const vec3_t org, int modelIndex, int reverse )
|
||||||
{
|
{
|
||||||
for( j = -8; j < 8; j++ )
|
for( j = -8; j < 8; j++ )
|
||||||
{
|
{
|
||||||
pTemp = CL_TempEntAlloc( org, model );
|
pTemp = CL_TempEntAlloc( org, pmodel );
|
||||||
if( !pTemp ) return;
|
if( !pTemp ) return;
|
||||||
|
|
||||||
dest[0] = (i * 32.0f) + org[0];
|
dest[0] = (i * 32.0f) + org[0];
|
||||||
|
@ -1535,22 +1533,25 @@ Create an projectile entity
|
||||||
*/
|
*/
|
||||||
void R_Projectile( const vec3_t origin, const vec3_t velocity, int modelIndex, int life, int owner, void (*hitcallback)( TEMPENTITY*, pmtrace_t* ))
|
void R_Projectile( const vec3_t origin, const vec3_t velocity, int modelIndex, int life, int owner, void (*hitcallback)( TEMPENTITY*, pmtrace_t* ))
|
||||||
{
|
{
|
||||||
// alloc a new tempent
|
|
||||||
TEMPENTITY *pTemp;
|
TEMPENTITY *pTemp;
|
||||||
|
model_t *pmodel;
|
||||||
vec3_t dir;
|
vec3_t dir;
|
||||||
|
|
||||||
pTemp = CL_TempEntAllocHigh( origin, Mod_Handle( modelIndex ));
|
if(( pmodel = CL_ModelHandle( modelIndex )) == NULL )
|
||||||
|
return;
|
||||||
|
|
||||||
|
pTemp = CL_TempEntAllocHigh( origin, pmodel );
|
||||||
if( !pTemp ) return;
|
if( !pTemp ) return;
|
||||||
|
|
||||||
VectorCopy( velocity, pTemp->entity.baseline.origin );
|
VectorCopy( velocity, pTemp->entity.baseline.origin );
|
||||||
|
|
||||||
if( Mod_GetType( modelIndex ) == mod_sprite )
|
if( pmodel->type == mod_sprite )
|
||||||
{
|
{
|
||||||
pTemp->flags |= FTENT_SPRANIMATE;
|
SetBits( pTemp->flags, FTENT_SPRANIMATE );
|
||||||
|
|
||||||
if( pTemp->frameMax < 10 )
|
if( pTemp->frameMax < 10 )
|
||||||
{
|
{
|
||||||
pTemp->flags |= FTENT_SPRANIMATE | FTENT_SPRANIMATELOOP;
|
SetBits( pTemp->flags, FTENT_SPRANIMATE|FTENT_SPRANIMATELOOP );
|
||||||
pTemp->entity.curstate.framerate = 10;
|
pTemp->entity.curstate.framerate = 10;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1587,7 +1588,7 @@ void R_TempSphereModel( const vec3_t pos, float speed, float life, int count, in
|
||||||
// create temp models
|
// create temp models
|
||||||
for( i = 0; i < count; i++ )
|
for( i = 0; i < count; i++ )
|
||||||
{
|
{
|
||||||
pTemp = CL_TempEntAlloc( pos, Mod_Handle( modelIndex ));
|
pTemp = CL_TempEntAlloc( pos, CL_ModelHandle( modelIndex ));
|
||||||
if( !pTemp ) return;
|
if( !pTemp ) return;
|
||||||
|
|
||||||
pTemp->entity.curstate.body = COM_RandomLong( 0, pTemp->frameMax );
|
pTemp->entity.curstate.body = COM_RandomLong( 0, pTemp->frameMax );
|
||||||
|
@ -1705,7 +1706,7 @@ void R_PlayerSprites( int client, int modelIndex, int count, int size )
|
||||||
position[1] += COM_RandomFloat( -10.0f, 10.0f );
|
position[1] += COM_RandomFloat( -10.0f, 10.0f );
|
||||||
position[2] += COM_RandomFloat( -20.0f, 36.0f );
|
position[2] += COM_RandomFloat( -20.0f, 36.0f );
|
||||||
|
|
||||||
pTemp = CL_TempEntAlloc( position, Mod_Handle( modelIndex ));
|
pTemp = CL_TempEntAlloc( position, CL_ModelHandle( modelIndex ));
|
||||||
if( !pTemp ) return;
|
if( !pTemp ) return;
|
||||||
|
|
||||||
VectorSubtract( pTemp->entity.origin, pEnt->origin, pTemp->tentOffset );
|
VectorSubtract( pTemp->entity.origin, pEnt->origin, pTemp->tentOffset );
|
||||||
|
@ -1750,11 +1751,12 @@ Makes a field of fire
|
||||||
void R_FireField( float *org, int radius, int modelIndex, int count, int flags, float life )
|
void R_FireField( float *org, int radius, int modelIndex, int count, int flags, float life )
|
||||||
{
|
{
|
||||||
TEMPENTITY *pTemp;
|
TEMPENTITY *pTemp;
|
||||||
|
model_t *pmodel;
|
||||||
float time;
|
float time;
|
||||||
vec3_t pos;
|
vec3_t pos;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if( Mod_GetType( modelIndex ) == mod_bad )
|
if(( pmodel = CL_ModelHandle( modelIndex )) == NULL )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for( i = 0; i < count; i++ )
|
for( i = 0; i < count; i++ )
|
||||||
|
@ -1766,7 +1768,7 @@ void R_FireField( float *org, int radius, int modelIndex, int count, int flags,
|
||||||
if( !FBitSet( flags, TEFIRE_FLAG_PLANAR ))
|
if( !FBitSet( flags, TEFIRE_FLAG_PLANAR ))
|
||||||
pos[2] += COM_RandomFloat( -radius, radius );
|
pos[2] += COM_RandomFloat( -radius, radius );
|
||||||
|
|
||||||
pTemp = CL_TempEntAlloc( pos, Mod_Handle( modelIndex ));
|
pTemp = CL_TempEntAlloc( pos, pmodel );
|
||||||
if( !pTemp ) return;
|
if( !pTemp ) return;
|
||||||
|
|
||||||
if( FBitSet( flags, TEFIRE_FLAG_ALPHA ))
|
if( FBitSet( flags, TEFIRE_FLAG_ALPHA ))
|
||||||
|
|
|
@ -89,7 +89,7 @@ void V_SetupViewModel( void )
|
||||||
view->curstate.colormap = (info->topcolor & 0xFFFF)|((info->bottomcolor << 8) & 0xFFFF);
|
view->curstate.colormap = (info->topcolor & 0xFFFF)|((info->bottomcolor << 8) & 0xFFFF);
|
||||||
view->curstate.number = cl.playernum + 1;
|
view->curstate.number = cl.playernum + 1;
|
||||||
view->index = cl.playernum + 1;
|
view->index = cl.playernum + 1;
|
||||||
view->model = Mod_Handle( cl.local.viewmodel );
|
view->model = CL_ModelHandle( cl.local.viewmodel );
|
||||||
view->curstate.modelindex = cl.local.viewmodel;
|
view->curstate.modelindex = cl.local.viewmodel;
|
||||||
view->curstate.sequence = cl.local.weaponsequence;
|
view->curstate.sequence = cl.local.weaponsequence;
|
||||||
view->curstate.rendermode = kRenderNormal;
|
view->curstate.rendermode = kRenderNormal;
|
||||||
|
@ -271,10 +271,10 @@ qboolean V_PreRender( void )
|
||||||
if( !glw_state.initialized )
|
if( !glw_state.initialized )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if( host.state == HOST_NOFOCUS )
|
if( host.status == HOST_NOFOCUS )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if( host.state == HOST_SLEEP )
|
if( host.status == HOST_SLEEP )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// if the screen is disabled (loading plaque is up)
|
// if the screen is disabled (loading plaque is up)
|
||||||
|
|
|
@ -267,10 +267,11 @@ typedef struct
|
||||||
entity_state_t instanced_baseline[MAX_CUSTOM_BASELINES];
|
entity_state_t instanced_baseline[MAX_CUSTOM_BASELINES];
|
||||||
int instanced_baseline_count;
|
int instanced_baseline_count;
|
||||||
|
|
||||||
char model_precache[MAX_MODELS][MAX_QPATH];
|
|
||||||
char sound_precache[MAX_SOUNDS][MAX_QPATH];
|
char sound_precache[MAX_SOUNDS][MAX_QPATH];
|
||||||
char event_precache[MAX_EVENTS][MAX_QPATH];
|
char event_precache[MAX_EVENTS][MAX_QPATH];
|
||||||
lightstyle_t lightstyles[MAX_LIGHTSTYLES];
|
lightstyle_t lightstyles[MAX_LIGHTSTYLES];
|
||||||
|
model_t *models[MAX_MODELS+1]; // precached models (plus one slot for menu preview)
|
||||||
|
int nummodels;
|
||||||
|
|
||||||
consistency_t consistency_list[MAX_MODELS];
|
consistency_t consistency_list[MAX_MODELS];
|
||||||
int num_consistency;
|
int num_consistency;
|
||||||
|
@ -807,10 +808,12 @@ void CL_TextMessageParse( byte *pMemFile, int fileSize );
|
||||||
client_textmessage_t *CL_TextMessageGet( const char *pName );
|
client_textmessage_t *CL_TextMessageGet( const char *pName );
|
||||||
int pfnDecalIndexFromName( const char *szDecalName );
|
int pfnDecalIndexFromName( const char *szDecalName );
|
||||||
int pfnIndexFromTrace( struct pmtrace_s *pTrace );
|
int pfnIndexFromTrace( struct pmtrace_s *pTrace );
|
||||||
|
model_t *CL_ModelHandle( int modelindex );
|
||||||
void NetAPI_CancelAllRequests( void );
|
void NetAPI_CancelAllRequests( void );
|
||||||
int CL_FindModelIndex( const char *m );
|
int CL_FindModelIndex( const char *m );
|
||||||
cl_entity_t *CL_GetLocalPlayer( void );
|
cl_entity_t *CL_GetLocalPlayer( void );
|
||||||
model_t *CL_LoadClientSprite( const char *filename );
|
model_t *CL_LoadClientSprite( const char *filename );
|
||||||
|
model_t *CL_LoadModel( const char *modelname, int *index );
|
||||||
HSPRITE pfnSPR_Load( const char *szPicName );
|
HSPRITE pfnSPR_Load( const char *szPicName );
|
||||||
HSPRITE pfnSPR_LoadExt( const char *szPicName, uint texFlags );
|
HSPRITE pfnSPR_LoadExt( const char *szPicName, uint texFlags );
|
||||||
void PicAdjustSize( float *x, float *y, float *w, float *h );
|
void PicAdjustSize( float *x, float *y, float *w, float *h );
|
||||||
|
|
|
@ -164,7 +164,7 @@ passed through this
|
||||||
*/
|
*/
|
||||||
void R_BeamSetup( BEAM *pbeam, vec3_t start, vec3_t end, int modelIndex, float life, float width, float amplitude, float brightness, float speed )
|
void R_BeamSetup( BEAM *pbeam, vec3_t start, vec3_t end, int modelIndex, float life, float width, float amplitude, float brightness, float speed )
|
||||||
{
|
{
|
||||||
model_t *sprite = Mod_Handle( modelIndex );
|
model_t *sprite = CL_ModelHandle( modelIndex );
|
||||||
|
|
||||||
if( !sprite ) return;
|
if( !sprite ) return;
|
||||||
|
|
||||||
|
@ -172,7 +172,7 @@ void R_BeamSetup( BEAM *pbeam, vec3_t start, vec3_t end, int modelIndex, float l
|
||||||
pbeam->modelIndex = modelIndex;
|
pbeam->modelIndex = modelIndex;
|
||||||
pbeam->frame = 0;
|
pbeam->frame = 0;
|
||||||
pbeam->frameRate = 0;
|
pbeam->frameRate = 0;
|
||||||
pbeam->frameCount = Mod_FrameCount( sprite );
|
pbeam->frameCount = sprite->numframes;
|
||||||
|
|
||||||
VectorCopy( start, pbeam->source );
|
VectorCopy( start, pbeam->source );
|
||||||
VectorCopy( end, pbeam->target );
|
VectorCopy( end, pbeam->target );
|
||||||
|
@ -1065,21 +1065,19 @@ Update beam vars and draw it
|
||||||
*/
|
*/
|
||||||
void R_BeamDraw( BEAM *pbeam, float frametime )
|
void R_BeamDraw( BEAM *pbeam, float frametime )
|
||||||
{
|
{
|
||||||
model_t *sprite;
|
model_t *model;
|
||||||
vec3_t delta;
|
vec3_t delta;
|
||||||
|
|
||||||
|
model = CL_ModelHandle( pbeam->modelIndex );
|
||||||
SetBits( pbeam->flags, FBEAM_ISACTIVE );
|
SetBits( pbeam->flags, FBEAM_ISACTIVE );
|
||||||
|
|
||||||
if( Mod_GetType( pbeam->modelIndex ) != mod_sprite )
|
if( !model || model->type != mod_sprite )
|
||||||
{
|
{
|
||||||
pbeam->flags &= ~FBEAM_ISACTIVE; // force to ignore
|
pbeam->flags &= ~FBEAM_ISACTIVE; // force to ignore
|
||||||
pbeam->die = cl.time;
|
pbeam->die = cl.time;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sprite = Mod_Handle( pbeam->modelIndex );
|
|
||||||
if( !sprite ) return;
|
|
||||||
|
|
||||||
// update frequency
|
// update frequency
|
||||||
pbeam->freq += frametime;
|
pbeam->freq += frametime;
|
||||||
|
|
||||||
|
@ -1182,7 +1180,7 @@ void R_BeamDraw( BEAM *pbeam, float frametime )
|
||||||
|
|
||||||
TriRenderMode( FBitSet( pbeam->flags, FBEAM_SOLID ) ? kRenderNormal : kRenderTransAdd );
|
TriRenderMode( FBitSet( pbeam->flags, FBEAM_SOLID ) ? kRenderNormal : kRenderTransAdd );
|
||||||
|
|
||||||
if( !TriSpriteTexture( sprite, (int)(pbeam->frame + pbeam->frameRate * cl.time) % pbeam->frameCount ))
|
if( !TriSpriteTexture( model, (int)(pbeam->frame + pbeam->frameRate * cl.time) % pbeam->frameCount ))
|
||||||
{
|
{
|
||||||
ClearBits( pbeam->flags, FBEAM_ISACTIVE );
|
ClearBits( pbeam->flags, FBEAM_ISACTIVE );
|
||||||
return;
|
return;
|
||||||
|
@ -1590,9 +1588,12 @@ BEAM *R_BeamEnts( int startEnt, int endEnt, int modelIndex, float life, float wi
|
||||||
{
|
{
|
||||||
cl_entity_t *start, *end;
|
cl_entity_t *start, *end;
|
||||||
BEAM *pbeam;
|
BEAM *pbeam;
|
||||||
|
model_t *mod;
|
||||||
|
|
||||||
|
mod = CL_ModelHandle( modelIndex );
|
||||||
|
|
||||||
// need a valid model.
|
// need a valid model.
|
||||||
if( Mod_GetType( modelIndex ) != mod_sprite )
|
if( !mod || mod->type != mod_sprite )
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
start = R_BeamGetEntity( startEnt );
|
start = R_BeamGetEntity( startEnt );
|
||||||
|
@ -1960,7 +1961,8 @@ void CL_ReadLineFile_f( void )
|
||||||
char *afile, *pfile;
|
char *afile, *pfile;
|
||||||
vec3_t p1, p2;
|
vec3_t p1, p2;
|
||||||
int count, modelIndex;
|
int count, modelIndex;
|
||||||
char filename[64];
|
char filename[MAX_QPATH];
|
||||||
|
model_t *model;
|
||||||
string token;
|
string token;
|
||||||
|
|
||||||
Q_snprintf( filename, sizeof( filename ), "maps/%s.lin", clgame.mapname );
|
Q_snprintf( filename, sizeof( filename ), "maps/%s.lin", clgame.mapname );
|
||||||
|
@ -1976,7 +1978,7 @@ void CL_ReadLineFile_f( void )
|
||||||
|
|
||||||
count = 0;
|
count = 0;
|
||||||
pfile = afile;
|
pfile = afile;
|
||||||
modelIndex = CL_FindModelIndex( "sprites/laserbeam.spr" );
|
model = CL_LoadModel( "sprites/laserbeam.spr", &modelIndex );
|
||||||
|
|
||||||
while( 1 )
|
while( 1 )
|
||||||
{
|
{
|
||||||
|
@ -2017,8 +2019,8 @@ void CL_ReadLineFile_f( void )
|
||||||
|
|
||||||
if( !R_BeamPoints( p1, p2, modelIndex, 99999, 2, 0, 255, 0, 0, 0, 255.0f, 0.0f, 0.0f ))
|
if( !R_BeamPoints( p1, p2, modelIndex, 99999, 2, 0, 255, 0, 0, 0, 255.0f, 0.0f, 0.0f ))
|
||||||
{
|
{
|
||||||
if( Mod_GetType( modelIndex ) != mod_sprite )
|
if( !model || model->type != mod_sprite )
|
||||||
MsgDev( D_ERROR, "CL_ReadLineFile: failed to load sprites/laserbeam.spr!\n" );
|
MsgDev( D_ERROR, "CL_ReadLineFile: failed to load \"sprites/laserbeam.spr\"!\n" );
|
||||||
else MsgDev( D_ERROR, "CL_ReadLineFile: not enough free beams!\n" );
|
else MsgDev( D_ERROR, "CL_ReadLineFile: not enough free beams!\n" );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -749,12 +749,12 @@ void R_DecalShoot( int textureIndex, int entityIndex, int modelIndex, vec3_t pos
|
||||||
{
|
{
|
||||||
ent = CL_GetEntityByIndex( entityIndex );
|
ent = CL_GetEntityByIndex( entityIndex );
|
||||||
|
|
||||||
if( modelIndex > 0 ) model = Mod_Handle( modelIndex );
|
if( modelIndex > 0 ) model = CL_ModelHandle( modelIndex );
|
||||||
else if( ent != NULL ) model = Mod_Handle( ent->curstate.modelindex );
|
else if( ent != NULL ) model = CL_ModelHandle( ent->curstate.modelindex );
|
||||||
else return;
|
else return;
|
||||||
}
|
}
|
||||||
else if( modelIndex > 0 )
|
else if( modelIndex > 0 )
|
||||||
model = Mod_Handle( modelIndex );
|
model = CL_ModelHandle( modelIndex );
|
||||||
else model = cl.worldmodel;
|
else model = cl.worldmodel;
|
||||||
|
|
||||||
if( !model ) return;
|
if( !model ) return;
|
||||||
|
|
|
@ -1460,7 +1460,7 @@ static render_api_t gRenderAPI =
|
||||||
pfnFileBufferCRC32,
|
pfnFileBufferCRC32,
|
||||||
COM_CompareFileTime,
|
COM_CompareFileTime,
|
||||||
Host_Error,
|
Host_Error,
|
||||||
Mod_Handle,
|
CL_ModelHandle,
|
||||||
pfnTime,
|
pfnTime,
|
||||||
Cvar_Set,
|
Cvar_Set,
|
||||||
S_FadeMusicVolume,
|
S_FadeMusicVolume,
|
||||||
|
|
|
@ -2058,9 +2058,9 @@ void GL_RebuildLightmaps( void )
|
||||||
|
|
||||||
LM_InitBlock();
|
LM_InitBlock();
|
||||||
|
|
||||||
for( i = 1; i < MAX_MODELS; i++ )
|
for( i = 1; i < cl.nummodels; i++ )
|
||||||
{
|
{
|
||||||
if(( m = Mod_Handle( i )) == NULL )
|
if(( m = CL_ModelHandle( i )) == NULL )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( m->name[0] == '*' || m->type != mod_brush )
|
if( m->name[0] == '*' || m->type != mod_brush )
|
||||||
|
@ -2121,9 +2121,9 @@ void GL_BuildLightmaps( void )
|
||||||
|
|
||||||
LM_InitBlock();
|
LM_InitBlock();
|
||||||
|
|
||||||
for( i = 1; i < MAX_MODELS; i++ )
|
for( i = 1; i < cl.nummodels; i++ )
|
||||||
{
|
{
|
||||||
if(( m = Mod_Handle( i )) == NULL )
|
if(( m = CL_ModelHandle( i )) == NULL )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( m->name[0] == '*' || m->type != mod_brush )
|
if( m->name[0] == '*' || m->type != mod_brush )
|
||||||
|
|
|
@ -439,6 +439,17 @@ static player_info_t *pfnPlayerInfo( int index )
|
||||||
return &cl.players[index];
|
return &cl.players[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
===============
|
||||||
|
pfnMod_ForName
|
||||||
|
|
||||||
|
===============
|
||||||
|
*/
|
||||||
|
static model_t *pfnMod_ForName( const char *model, int crash )
|
||||||
|
{
|
||||||
|
return Mod_ForName( model, crash, false );
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
===============
|
===============
|
||||||
pfnGetPlayerState
|
pfnGetPlayerState
|
||||||
|
@ -2180,7 +2191,7 @@ void R_StudioRenderShadow( int iSprite, float *p1, float *p2, float *p3, float *
|
||||||
if( !p1 || !p2 || !p3 || !p4 )
|
if( !p1 || !p2 || !p3 || !p4 )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if( TriSpriteTexture( Mod_Handle( iSprite ), 0 ))
|
if( TriSpriteTexture( CL_ModelHandle( iSprite ), 0 ))
|
||||||
{
|
{
|
||||||
TriRenderMode( kRenderTransAlpha );
|
TriRenderMode( kRenderTransAlpha );
|
||||||
TriColor4f( 0.0f, 0.0f, 0.0f, 1.0f );
|
TriColor4f( 0.0f, 0.0f, 0.0f, 1.0f );
|
||||||
|
@ -2747,7 +2758,8 @@ static model_t *R_StudioSetupPlayerModel( int index )
|
||||||
|
|
||||||
state = &cl.player_models[index];
|
state = &cl.player_models[index];
|
||||||
|
|
||||||
if(( host.developer || !Host_IsLocalGame( )) && info->model[0] )
|
// g-cont: force for "dev-mode", non-local games and menu preview
|
||||||
|
if(( host.developer || !Host_IsLocalGame( ) || !RI.drawWorld ) && info->model[0] )
|
||||||
{
|
{
|
||||||
if( Q_strcmp( state->name, info->model ))
|
if( Q_strcmp( state->name, info->model ))
|
||||||
{
|
{
|
||||||
|
@ -2757,7 +2769,7 @@ static model_t *R_StudioSetupPlayerModel( int index )
|
||||||
Q_snprintf( state->modelname, sizeof( state->modelname ), "models/player/%s/%s.mdl", info->model, info->model );
|
Q_snprintf( state->modelname, sizeof( state->modelname ), "models/player/%s/%s.mdl", info->model, info->model );
|
||||||
|
|
||||||
if( FS_FileExists( state->modelname, false ))
|
if( FS_FileExists( state->modelname, false ))
|
||||||
state->model = Mod_ForName( state->modelname, false );
|
state->model = Mod_ForName( state->modelname, false, true );
|
||||||
else state->model = NULL;
|
else state->model = NULL;
|
||||||
|
|
||||||
if( !state->model )
|
if( !state->model )
|
||||||
|
@ -3452,7 +3464,7 @@ static int R_StudioDrawPlayer( int flags, entity_state_t *pplayer )
|
||||||
if( pplayer->weaponmodel )
|
if( pplayer->weaponmodel )
|
||||||
{
|
{
|
||||||
cl_entity_t saveent = *RI.currententity;
|
cl_entity_t saveent = *RI.currententity;
|
||||||
model_t *pweaponmodel = Mod_Handle( pplayer->weaponmodel );
|
model_t *pweaponmodel = CL_ModelHandle( pplayer->weaponmodel );
|
||||||
|
|
||||||
m_pStudioHeader = (studiohdr_t *)Mod_StudioExtradata( pweaponmodel );
|
m_pStudioHeader = (studiohdr_t *)Mod_StudioExtradata( pweaponmodel );
|
||||||
|
|
||||||
|
@ -4003,9 +4015,9 @@ static engine_studio_api_t gStudioAPI =
|
||||||
Mod_Calloc,
|
Mod_Calloc,
|
||||||
Mod_CacheCheck,
|
Mod_CacheCheck,
|
||||||
Mod_LoadCacheFile,
|
Mod_LoadCacheFile,
|
||||||
Mod_ForName,
|
pfnMod_ForName,
|
||||||
Mod_StudioExtradata,
|
Mod_StudioExtradata,
|
||||||
Mod_Handle,
|
CL_ModelHandle,
|
||||||
pfnGetCurrentEntity,
|
pfnGetCurrentEntity,
|
||||||
pfnPlayerInfo,
|
pfnPlayerInfo,
|
||||||
R_StudioGetPlayerState,
|
R_StudioGetPlayerState,
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
com_strings.h - all paths to external resources that hardcoded into engine
|
||||||
|
Copyright (C) 2018 Uncle Mike
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef COM_STRINGS_H
|
||||||
|
#define COM_STRINGS_H
|
||||||
|
|
||||||
|
// end game final default message
|
||||||
|
#define DEFAULT_ENDGAME_MESSAGE "The End"
|
||||||
|
|
||||||
|
// path to the hash-pak that contain custom player decals
|
||||||
|
#define CUSTOM_RES_PATH "custom.hpk"
|
||||||
|
|
||||||
|
// path to default playermodel in GoldSrc
|
||||||
|
#define DEFAULT_PLAYER_PATH_HALFLIFE "models/player.mdl"
|
||||||
|
|
||||||
|
// path to default playermodel in Quake
|
||||||
|
#define DEFAULT_PLAYER_PATH_QUAKE "progs/player.mdl"
|
||||||
|
|
||||||
|
#endif//COM_STRINGS_H
|
|
@ -312,6 +312,19 @@ qboolean COM_ParseVector( char **pfile, float *v, size_t size )
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
COM_CheckString
|
||||||
|
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
int COM_CheckString( const char *string )
|
||||||
|
{
|
||||||
|
if( !string || (byte)*string <= ' ' )
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=============
|
=============
|
||||||
COM_FileSize
|
COM_FileSize
|
||||||
|
@ -673,7 +686,6 @@ void pfnGetModelBounds( model_t *mod, float *mins, float *maxs )
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MsgDev( D_ERROR, "Mod_GetBounds: NULL model\n" );
|
|
||||||
if( mins ) VectorClear( mins );
|
if( mins ) VectorClear( mins );
|
||||||
if( maxs ) VectorClear( maxs );
|
if( maxs ) VectorClear( maxs );
|
||||||
}
|
}
|
||||||
|
@ -881,7 +893,7 @@ qboolean COM_IsSafeFileToDownload( const char *filename )
|
||||||
const char *ext;
|
const char *ext;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if( !filename )
|
if( !COM_CheckString( filename ))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if( !Q_strncmp( filename, "!MD5", 4 ))
|
if( !Q_strncmp( filename, "!MD5", 4 ))
|
||||||
|
|
|
@ -105,6 +105,7 @@ typedef enum
|
||||||
|
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "com_model.h"
|
#include "com_model.h"
|
||||||
|
#include "com_strings.h"
|
||||||
#include "crtlib.h"
|
#include "crtlib.h"
|
||||||
#include "cvar.h"
|
#include "cvar.h"
|
||||||
|
|
||||||
|
@ -127,8 +128,6 @@ typedef enum
|
||||||
#define CIN_MAIN 0
|
#define CIN_MAIN 0
|
||||||
#define CIN_LOGO 1
|
#define CIN_LOGO 1
|
||||||
|
|
||||||
#define CUSTOM_RES_PATH "custom.hpk"
|
|
||||||
|
|
||||||
#define MAX_NUM_ARGVS 128
|
#define MAX_NUM_ARGVS 128
|
||||||
|
|
||||||
// config strings are a general means of communication from
|
// config strings are a general means of communication from
|
||||||
|
@ -150,6 +149,7 @@ typedef enum
|
||||||
#define GI SI.GameInfo
|
#define GI SI.GameInfo
|
||||||
#define FS_Gamedir() SI.GameInfo->gamedir
|
#define FS_Gamedir() SI.GameInfo->gamedir
|
||||||
#define FS_Title() SI.GameInfo->title
|
#define FS_Title() SI.GameInfo->title
|
||||||
|
#define GameState (&host.game)
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
void DBG_AssertFunction( qboolean fExpr, const char* szExpr, const char* szFile, int szLine, const char* szMessage );
|
void DBG_AssertFunction( qboolean fExpr, const char* szExpr, const char* szFile, int szLine, const char* szMessage );
|
||||||
|
@ -162,6 +162,7 @@ extern convar_t *gl_vsync;
|
||||||
extern convar_t *scr_loading;
|
extern convar_t *scr_loading;
|
||||||
extern convar_t *scr_download;
|
extern convar_t *scr_download;
|
||||||
extern convar_t *cmd_scripting;
|
extern convar_t *cmd_scripting;
|
||||||
|
extern convar_t *sv_maxclients;
|
||||||
extern convar_t *cl_allow_levelshots;
|
extern convar_t *cl_allow_levelshots;
|
||||||
extern convar_t *vid_displayfrequency;
|
extern convar_t *vid_displayfrequency;
|
||||||
extern convar_t *host_limitlocal;
|
extern convar_t *host_limitlocal;
|
||||||
|
@ -243,7 +244,27 @@ typedef enum
|
||||||
HOST_SLEEP, // sleeped by different reason, e.g. minimize window
|
HOST_SLEEP, // sleeped by different reason, e.g. minimize window
|
||||||
HOST_NOFOCUS, // same as HOST_FRAME, but disable mouse
|
HOST_NOFOCUS, // same as HOST_FRAME, but disable mouse
|
||||||
HOST_CRASHED // an exception handler called
|
HOST_CRASHED // an exception handler called
|
||||||
} host_state;
|
} host_status_t;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
STATE_RUNFRAME = 0,
|
||||||
|
STATE_LOAD_LEVEL,
|
||||||
|
STATE_LOAD_GAME,
|
||||||
|
STATE_CHANGELEVEL,
|
||||||
|
STATE_GAME_SHUTDOWN,
|
||||||
|
} host_state_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
host_state_t curstate;
|
||||||
|
host_state_t nextstate;
|
||||||
|
char levelName[MAX_QPATH];
|
||||||
|
char landmarkName[MAX_QPATH];
|
||||||
|
qboolean backgroundMap;
|
||||||
|
qboolean loadGame;
|
||||||
|
qboolean newGame; // unload the server.dll before start a new map
|
||||||
|
} game_status_t;
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
|
@ -309,7 +330,8 @@ typedef struct host_parm_s
|
||||||
HANDLE hMutex;
|
HANDLE hMutex;
|
||||||
LPTOP_LEVEL_EXCEPTION_FILTER oldFilter;
|
LPTOP_LEVEL_EXCEPTION_FILTER oldFilter;
|
||||||
|
|
||||||
host_state state; // global host state
|
host_status_t status; // global host state
|
||||||
|
game_status_t game; // game manager
|
||||||
uint type; // running at
|
uint type; // running at
|
||||||
jmp_buf abortframe; // abort current frame
|
jmp_buf abortframe; // abort current frame
|
||||||
dword errorframe; // to prevent multiple host error
|
dword errorframe; // to prevent multiple host error
|
||||||
|
@ -404,6 +426,7 @@ void COM_NormalizeAngles( vec3_t angles );
|
||||||
int COM_FileSize( const char *filename );
|
int COM_FileSize( const char *filename );
|
||||||
void COM_FixSlashes( char *pname );
|
void COM_FixSlashes( char *pname );
|
||||||
void COM_FreeFile( void *buffer );
|
void COM_FreeFile( void *buffer );
|
||||||
|
int COM_CheckString( const char *string );
|
||||||
int COM_CompareFileTime( const char *filename1, const char *filename2, int *iCompare );
|
int COM_CompareFileTime( const char *filename1, const char *filename2, int *iCompare );
|
||||||
search_t *FS_Search( const char *pattern, int caseinsensitive, int gamedironly );
|
search_t *FS_Search( const char *pattern, int caseinsensitive, int gamedironly );
|
||||||
file_t *FS_Open( const char *filepath, const char *mode, qboolean gamedironly );
|
file_t *FS_Open( const char *filepath, const char *mode, qboolean gamedironly );
|
||||||
|
@ -652,8 +675,7 @@ void Host_SetServerState( int state );
|
||||||
int Host_ServerState( void );
|
int Host_ServerState( void );
|
||||||
int Host_CompareFileTime( long ft1, long ft2 );
|
int Host_CompareFileTime( long ft1, long ft2 );
|
||||||
void Host_NewInstance( const char *name, const char *finalmsg );
|
void Host_NewInstance( const char *name, const char *finalmsg );
|
||||||
qboolean Host_NewGame( const char *mapName, qboolean loadGame );
|
void Host_EndGame( qboolean abort, const char *message, ... );
|
||||||
void Host_EndGame( const char *message, ... );
|
|
||||||
void Host_AbortCurrentFrame( void );
|
void Host_AbortCurrentFrame( void );
|
||||||
void Host_RestartAmbientSounds( void );
|
void Host_RestartAmbientSounds( void );
|
||||||
void Host_RestartDecals( void );
|
void Host_RestartDecals( void );
|
||||||
|
@ -667,9 +689,20 @@ void Host_ShutdownServer( void );
|
||||||
void Host_Print( const char *txt );
|
void Host_Print( const char *txt );
|
||||||
void Host_Error( const char *error, ... );
|
void Host_Error( const char *error, ... );
|
||||||
void Host_PrintEngineFeatures( void );
|
void Host_PrintEngineFeatures( void );
|
||||||
|
void Host_Frame( float time );
|
||||||
void Host_InitDecals( void );
|
void Host_InitDecals( void );
|
||||||
void Host_Credits( void );
|
void Host_Credits( void );
|
||||||
|
|
||||||
|
//
|
||||||
|
// host_state.c
|
||||||
|
//
|
||||||
|
void COM_InitHostState( void );
|
||||||
|
void COM_NewGame( char const *pMapName );
|
||||||
|
void COM_LoadLevel( char const *pMapName, qboolean background );
|
||||||
|
void COM_LoadGame( char const *pSaveFileName );
|
||||||
|
void COM_ChangeLevel( char const *pNewLevel, char const *pLandmarkName );
|
||||||
|
void COM_Frame( float time );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
==============================================================
|
==============================================================
|
||||||
|
|
||||||
|
@ -840,6 +873,7 @@ int flags, struct modelstate_s *state );
|
||||||
void Log_Printf( const char *fmt, ... );
|
void Log_Printf( const char *fmt, ... );
|
||||||
struct sizebuf_s *SV_GetReliableDatagram( void );
|
struct sizebuf_s *SV_GetReliableDatagram( void );
|
||||||
void SV_BroadcastCommand( const char *fmt, ... );
|
void SV_BroadcastCommand( const char *fmt, ... );
|
||||||
|
void SV_ChangeLevel( qboolean loadfromsavedgame, const char *mapname, const char *start );
|
||||||
qboolean SV_RestoreCustomDecal( struct decallist_s *entry, edict_t *pEdict, qboolean adjacent );
|
qboolean SV_RestoreCustomDecal( struct decallist_s *entry, edict_t *pEdict, qboolean adjacent );
|
||||||
void SV_BroadcastPrintf( struct sv_client_s *ignore, int level, char *fmt, ... );
|
void SV_BroadcastPrintf( struct sv_client_s *ignore, int level, char *fmt, ... );
|
||||||
int R_CreateDecalList( struct decallist_s *pList, qboolean changelevel );
|
int R_CreateDecalList( struct decallist_s *pList, qboolean changelevel );
|
||||||
|
@ -850,6 +884,8 @@ qboolean S_StreamGetCurrentState( char *currentTrack, char *loopTrack, int *posi
|
||||||
struct cl_entity_s *CL_GetEntityByIndex( int index );
|
struct cl_entity_s *CL_GetEntityByIndex( int index );
|
||||||
struct player_info_s *CL_GetPlayerInfo( int playerIndex );
|
struct player_info_s *CL_GetPlayerInfo( int playerIndex );
|
||||||
void CL_ServerCommand( qboolean reliable, char *fmt, ... );
|
void CL_ServerCommand( qboolean reliable, char *fmt, ... );
|
||||||
|
void SV_ActivateServer( void );
|
||||||
|
void SV_DeactivateServer( void );
|
||||||
const char *CL_MsgInfo( int cmd );
|
const char *CL_MsgInfo( int cmd );
|
||||||
void SV_DrawDebugTriangles( void );
|
void SV_DrawDebugTriangles( void );
|
||||||
void SV_DrawOrthoTriangles( void );
|
void SV_DrawOrthoTriangles( void );
|
||||||
|
@ -868,10 +904,13 @@ qboolean SV_NewGame( const char *mapName, qboolean loadGame );
|
||||||
void SV_ClipPMoveToEntity( struct physent_s *pe, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, struct pmtrace_s *tr );
|
void SV_ClipPMoveToEntity( struct physent_s *pe, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, struct pmtrace_s *tr );
|
||||||
void CL_ClipPMoveToEntity( struct physent_s *pe, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, struct pmtrace_s *tr );
|
void CL_ClipPMoveToEntity( struct physent_s *pe, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, struct pmtrace_s *tr );
|
||||||
void CL_Particle( const vec3_t origin, int color, float life, int zpos, int zvel ); // debug thing
|
void CL_Particle( const vec3_t origin, int color, float life, int zpos, int zvel ); // debug thing
|
||||||
|
void SV_LevelInit( const char *pMapName, char const *pOldLevel, char const *pLandmarkName, qboolean loadGame );
|
||||||
|
qboolean SV_SpawnServer( const char *mapname, const char *startspot, qboolean background );
|
||||||
void SV_SysError( const char *error_string );
|
void SV_SysError( const char *error_string );
|
||||||
|
qboolean SV_LoadGame( const char *pName );
|
||||||
|
void SV_ClearSaveDir( void );
|
||||||
void SV_InitGameProgs( void );
|
void SV_InitGameProgs( void );
|
||||||
void SV_FreeGameProgs( void );
|
void SV_FreeGameProgs( void );
|
||||||
void SV_ForceError( void );
|
|
||||||
void CL_WriteMessageHistory( void );
|
void CL_WriteMessageHistory( void );
|
||||||
void CL_SendCmd( void );
|
void CL_SendCmd( void );
|
||||||
void CL_Disconnect( void );
|
void CL_Disconnect( void );
|
||||||
|
|
|
@ -2083,8 +2083,9 @@ void Con_DrawConsole( void )
|
||||||
Key_SetKeyDest( key_console );
|
Key_SetKeyDest( key_console );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ca_connected:
|
|
||||||
case ca_connecting:
|
case ca_connecting:
|
||||||
|
case ca_connected:
|
||||||
|
case ca_validate:
|
||||||
// force to show console always for -dev 3 and higher
|
// force to show console always for -dev 3 and higher
|
||||||
if( con.vislines )
|
if( con.vislines )
|
||||||
{
|
{
|
||||||
|
@ -2174,7 +2175,7 @@ void Con_RunConsole( void )
|
||||||
}
|
}
|
||||||
else con.showlines = 0; // none visible
|
else con.showlines = 0; // none visible
|
||||||
|
|
||||||
if( cls.state == ca_connecting || cls.state == ca_connected || cl.first_frame )
|
if( cls.state == ca_connecting || cls.state == ca_connected || cls.state == ca_validate || cl.first_frame )
|
||||||
host.realframetime = 0.000001f; // don't accumulate frametime
|
host.realframetime = 0.000001f; // don't accumulate frametime
|
||||||
|
|
||||||
lines_per_frame = fabs( scr_conspeed->value ) * host.realframetime;
|
lines_per_frame = fabs( scr_conspeed->value ) * host.realframetime;
|
||||||
|
|
|
@ -90,26 +90,12 @@ void Host_PrintEngineFeatures( void )
|
||||||
MsgDev( D_REPORT, "^3EXT:^7 runnung server at constant fps\n" );
|
MsgDev( D_REPORT, "^3EXT:^7 runnung server at constant fps\n" );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
================
|
|
||||||
Host_NewGame
|
|
||||||
================
|
|
||||||
*/
|
|
||||||
qboolean Host_NewGame( const char *mapName, qboolean loadGame )
|
|
||||||
{
|
|
||||||
qboolean iRet;
|
|
||||||
|
|
||||||
iRet = SV_NewGame( mapName, loadGame );
|
|
||||||
|
|
||||||
return iRet;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
================
|
================
|
||||||
Host_EndGame
|
Host_EndGame
|
||||||
================
|
================
|
||||||
*/
|
*/
|
||||||
void Host_EndGame( const char *message, ... )
|
void Host_EndGame( qboolean abort, const char *message, ... )
|
||||||
{
|
{
|
||||||
va_list argptr;
|
va_list argptr;
|
||||||
static char string[MAX_SYSPATH];
|
static char string[MAX_SYSPATH];
|
||||||
|
@ -132,9 +118,9 @@ void Host_EndGame( const char *message, ... )
|
||||||
CL_ClearEdicts ();
|
CL_ClearEdicts ();
|
||||||
|
|
||||||
// release all models
|
// release all models
|
||||||
Mod_ClearAll( true );
|
Mod_FreeAll();
|
||||||
|
|
||||||
Host_AbortCurrentFrame ();
|
if( abort ) Host_AbortCurrentFrame ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -173,13 +159,13 @@ void Host_CheckSleep( void )
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if( host.state == HOST_NOFOCUS )
|
if( host.status == HOST_NOFOCUS )
|
||||||
{
|
{
|
||||||
if( Host_ServerState() && CL_IsInGame( ))
|
if( Host_ServerState() && CL_IsInGame( ))
|
||||||
Sys_Sleep( 1 ); // listenserver
|
Sys_Sleep( 1 ); // listenserver
|
||||||
else Sys_Sleep( 20 ); // sleep 20 ms otherwise
|
else Sys_Sleep( 20 ); // sleep 20 ms otherwise
|
||||||
}
|
}
|
||||||
else if( host.state == HOST_SLEEP )
|
else if( host.status == HOST_SLEEP )
|
||||||
{
|
{
|
||||||
// completely sleep in minimized state
|
// completely sleep in minimized state
|
||||||
Sys_Sleep( 20 );
|
Sys_Sleep( 20 );
|
||||||
|
@ -687,7 +673,7 @@ void Host_Error( const char *error, ... )
|
||||||
}
|
}
|
||||||
|
|
||||||
// host is shutting down. don't invoke infinite loop
|
// host is shutting down. don't invoke infinite loop
|
||||||
if( host.state == HOST_SHUTDOWN ) return;
|
if( host.status == HOST_SHUTDOWN ) return;
|
||||||
|
|
||||||
if( recursive )
|
if( recursive )
|
||||||
{
|
{
|
||||||
|
@ -711,7 +697,7 @@ void Host_Error( const char *error, ... )
|
||||||
CL_ClearEdicts ();
|
CL_ClearEdicts ();
|
||||||
|
|
||||||
// release all models
|
// release all models
|
||||||
Mod_ClearAll( false );
|
Mod_FreeAll();
|
||||||
|
|
||||||
recursive = false;
|
recursive = false;
|
||||||
Host_AbortCurrentFrame();
|
Host_AbortCurrentFrame();
|
||||||
|
@ -733,12 +719,6 @@ void Sys_Error_f( void )
|
||||||
Sys_Error( "%s\n", error );
|
Sys_Error( "%s\n", error );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Net_Error_f( void )
|
|
||||||
{
|
|
||||||
Q_strncpy( host.finalmsg, Cmd_Argv( 1 ), sizeof( host.finalmsg ));
|
|
||||||
SV_ForceError();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=================
|
=================
|
||||||
Host_Crash_f
|
Host_Crash_f
|
||||||
|
@ -777,7 +757,7 @@ void Host_InitCommon( const char *hostname, qboolean bChangeGame )
|
||||||
host.oldFilter = SetUnhandledExceptionFilter( Sys_Crash );
|
host.oldFilter = SetUnhandledExceptionFilter( Sys_Crash );
|
||||||
host.hInst = GetModuleHandle( NULL );
|
host.hInst = GetModuleHandle( NULL );
|
||||||
host.change_game = bChangeGame;
|
host.change_game = bChangeGame;
|
||||||
host.state = HOST_INIT; // initialzation started
|
host.status = HOST_INIT; // initialzation started
|
||||||
host.developer = host.old_developer = 0;
|
host.developer = host.old_developer = 0;
|
||||||
host.config_executed = false;
|
host.config_executed = false;
|
||||||
|
|
||||||
|
@ -886,6 +866,9 @@ void Host_InitCommon( const char *hostname, qboolean bChangeGame )
|
||||||
// get default screen res
|
// get default screen res
|
||||||
VID_InitDefaultResolution();
|
VID_InitDefaultResolution();
|
||||||
|
|
||||||
|
// init host state machine
|
||||||
|
COM_InitHostState();
|
||||||
|
|
||||||
// startup cmds and cvars subsystem
|
// startup cmds and cvars subsystem
|
||||||
Cmd_Init();
|
Cmd_Init();
|
||||||
Cvar_Init();
|
Cvar_Init();
|
||||||
|
@ -947,7 +930,6 @@ int EXPORT Host_Main( const char *progname, int bChangeGame, pfnChangeGame func
|
||||||
Cmd_AddCommand ( "sys_error", Sys_Error_f, "just throw a fatal error to test shutdown procedures");
|
Cmd_AddCommand ( "sys_error", Sys_Error_f, "just throw a fatal error to test shutdown procedures");
|
||||||
Cmd_AddCommand ( "host_error", Host_Error_f, "just throw a host error to test shutdown procedures");
|
Cmd_AddCommand ( "host_error", Host_Error_f, "just throw a host error to test shutdown procedures");
|
||||||
Cmd_AddCommand ( "crash", Host_Crash_f, "a way to force a bus error for development reasons");
|
Cmd_AddCommand ( "crash", Host_Crash_f, "a way to force a bus error for development reasons");
|
||||||
Cmd_AddCommand ( "net_error", Net_Error_f, "send network bad message from random place");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
host_maxfps = Cvar_Get( "fps_max", "72", FCVAR_ARCHIVE, "host fps upper limit" );
|
host_maxfps = Cvar_Get( "fps_max", "72", FCVAR_ARCHIVE, "host fps upper limit" );
|
||||||
|
@ -1024,7 +1006,7 @@ int EXPORT Host_Main( const char *progname, int bChangeGame, pfnChangeGame func
|
||||||
while( !host.crashed )
|
while( !host.crashed )
|
||||||
{
|
{
|
||||||
newtime = Sys_DoubleTime ();
|
newtime = Sys_DoubleTime ();
|
||||||
Host_Frame( newtime - oldtime );
|
COM_Frame( newtime - oldtime );
|
||||||
oldtime = newtime;
|
oldtime = newtime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1042,7 +1024,7 @@ void EXPORT Host_Shutdown( void )
|
||||||
if( host.shutdown_issued ) return;
|
if( host.shutdown_issued ) return;
|
||||||
host.shutdown_issued = true;
|
host.shutdown_issued = true;
|
||||||
|
|
||||||
if( host.state != HOST_ERR_FATAL ) host.state = HOST_SHUTDOWN; // prepare host to normal shutdown
|
if( host.status != HOST_ERR_FATAL ) host.status = HOST_SHUTDOWN; // prepare host to normal shutdown
|
||||||
if( !host.change_game ) Q_strncpy( host.finalmsg, "Server shutdown", sizeof( host.finalmsg ));
|
if( !host.change_game ) Q_strncpy( host.finalmsg, "Server shutdown", sizeof( host.finalmsg ));
|
||||||
|
|
||||||
if( host.type == HOST_NORMAL )
|
if( host.type == HOST_NORMAL )
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
/*
|
|
||||||
host_cmd.c - dedicated and normal host
|
|
||||||
Copyright (C) 2017 Uncle Mike
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "netchan.h"
|
|
||||||
#include "protocol.h"
|
|
||||||
#include "mod_local.h"
|
|
||||||
#include "mathlib.h"
|
|
||||||
#include "input.h"
|
|
||||||
#include "features.h"
|
|
||||||
#include "render_api.h" // decallist_t
|
|
|
@ -0,0 +1,210 @@
|
||||||
|
/*
|
||||||
|
host_cmd.c - dedicated and normal host
|
||||||
|
Copyright (C) 2017 Uncle Mike
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "netchan.h"
|
||||||
|
#include "protocol.h"
|
||||||
|
#include "mod_local.h"
|
||||||
|
#include "mathlib.h"
|
||||||
|
#include "input.h"
|
||||||
|
#include "features.h"
|
||||||
|
#include "render_api.h" // decallist_t
|
||||||
|
|
||||||
|
void COM_InitHostState( void )
|
||||||
|
{
|
||||||
|
memset( GameState, 0, sizeof( game_status_t ));
|
||||||
|
GameState->curstate = STATE_RUNFRAME;
|
||||||
|
GameState->nextstate = STATE_RUNFRAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void HostState_SetState( host_state_t newState, qboolean clearNext )
|
||||||
|
{
|
||||||
|
if( clearNext )
|
||||||
|
GameState->nextstate = newState;
|
||||||
|
GameState->curstate = newState;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void HostState_SetNextState( host_state_t nextState )
|
||||||
|
{
|
||||||
|
ASSERT( GameState->curstate == STATE_RUNFRAME );
|
||||||
|
GameState->nextstate = nextState;
|
||||||
|
}
|
||||||
|
|
||||||
|
void COM_NewGame( char const *pMapName )
|
||||||
|
{
|
||||||
|
Q_strncpy( GameState->levelName, pMapName, sizeof( GameState->levelName ));
|
||||||
|
HostState_SetNextState( STATE_LOAD_LEVEL );
|
||||||
|
|
||||||
|
GameState->backgroundMap = false;
|
||||||
|
GameState->landmarkName[0] = 0;
|
||||||
|
GameState->newGame = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void COM_LoadLevel( char const *pMapName, qboolean background )
|
||||||
|
{
|
||||||
|
Q_strncpy( GameState->levelName, pMapName, sizeof( GameState->levelName ));
|
||||||
|
HostState_SetNextState( STATE_LOAD_LEVEL );
|
||||||
|
|
||||||
|
GameState->backgroundMap = background;
|
||||||
|
GameState->landmarkName[0] = 0;
|
||||||
|
GameState->newGame = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void COM_LoadGame( char const *pMapName )
|
||||||
|
{
|
||||||
|
Q_strncpy( GameState->levelName, pMapName, sizeof( GameState->levelName ));
|
||||||
|
HostState_SetNextState( STATE_LOAD_GAME );
|
||||||
|
GameState->backgroundMap = false;
|
||||||
|
GameState->newGame = false;
|
||||||
|
GameState->loadGame = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void COM_ChangeLevel( char const *pNewLevel, char const *pLandmarkName )
|
||||||
|
{
|
||||||
|
Q_strncpy( GameState->levelName, pNewLevel, sizeof( GameState->levelName ));
|
||||||
|
|
||||||
|
if( COM_CheckString( pLandmarkName ))
|
||||||
|
{
|
||||||
|
Q_strncpy( GameState->landmarkName, pLandmarkName, sizeof( GameState->landmarkName ));
|
||||||
|
GameState->loadGame = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GameState->landmarkName[0] = 0;
|
||||||
|
GameState->loadGame = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
HostState_SetNextState( STATE_CHANGELEVEL );
|
||||||
|
GameState->newGame = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HostState_LoadLevel( void )
|
||||||
|
{
|
||||||
|
if( SV_SpawnServer( GameState->levelName, NULL, GameState->backgroundMap ))
|
||||||
|
{
|
||||||
|
SV_LevelInit( GameState->levelName, NULL, NULL, false );
|
||||||
|
SV_ActivateServer ();
|
||||||
|
}
|
||||||
|
|
||||||
|
HostState_SetState( STATE_RUNFRAME, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
void HostState_LoadGame( void )
|
||||||
|
{
|
||||||
|
if( SV_SpawnServer( GameState->levelName, NULL, false ))
|
||||||
|
{
|
||||||
|
SV_LevelInit( GameState->levelName, NULL, NULL, true );
|
||||||
|
SV_ActivateServer ();
|
||||||
|
}
|
||||||
|
|
||||||
|
HostState_SetState( STATE_RUNFRAME, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
void HostState_ChangeLevel( void )
|
||||||
|
{
|
||||||
|
SV_ChangeLevel( GameState->loadGame, GameState->levelName, GameState->landmarkName );
|
||||||
|
HostState_SetState( STATE_RUNFRAME, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
void HostState_ShutdownGame( void )
|
||||||
|
{
|
||||||
|
if( !GameState->loadGame )
|
||||||
|
SV_ClearSaveDir();
|
||||||
|
|
||||||
|
S_StopBackgroundTrack();
|
||||||
|
|
||||||
|
if( GameState->newGame )
|
||||||
|
{
|
||||||
|
Host_EndGame( false, DEFAULT_ENDGAME_MESSAGE );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
S_StopAllSounds( true );
|
||||||
|
SV_DeactivateServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
switch( GameState->nextstate )
|
||||||
|
{
|
||||||
|
case STATE_LOAD_GAME:
|
||||||
|
case STATE_LOAD_LEVEL:
|
||||||
|
HostState_SetState( GameState->nextstate, true );
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
HostState_SetState( STATE_RUNFRAME, true );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HostState_Run( float time )
|
||||||
|
{
|
||||||
|
// engine main frame
|
||||||
|
Host_Frame( time );
|
||||||
|
|
||||||
|
switch( GameState->nextstate )
|
||||||
|
{
|
||||||
|
case STATE_RUNFRAME:
|
||||||
|
break;
|
||||||
|
case STATE_LOAD_GAME:
|
||||||
|
case STATE_LOAD_LEVEL:
|
||||||
|
SCR_BeginLoadingPlaque( GameState->backgroundMap );
|
||||||
|
// intentionally fallthrough
|
||||||
|
case STATE_GAME_SHUTDOWN:
|
||||||
|
HostState_SetState( STATE_GAME_SHUTDOWN, false );
|
||||||
|
break;
|
||||||
|
case STATE_CHANGELEVEL:
|
||||||
|
SCR_BeginLoadingPlaque( false );
|
||||||
|
HostState_SetState( GameState->nextstate, true );
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
HostState_SetState( STATE_RUNFRAME, true );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void COM_Frame( float time )
|
||||||
|
{
|
||||||
|
int loopCount = 0;
|
||||||
|
|
||||||
|
while( 1 )
|
||||||
|
{
|
||||||
|
int oldState = GameState->curstate;
|
||||||
|
|
||||||
|
// execute the current state (and transition to the next state if not in HS_RUN)
|
||||||
|
switch( GameState->curstate )
|
||||||
|
{
|
||||||
|
case STATE_LOAD_LEVEL:
|
||||||
|
HostState_LoadLevel();
|
||||||
|
break;
|
||||||
|
case STATE_LOAD_GAME:
|
||||||
|
HostState_LoadGame();
|
||||||
|
break;
|
||||||
|
case STATE_CHANGELEVEL:
|
||||||
|
HostState_ChangeLevel();
|
||||||
|
break;
|
||||||
|
case STATE_RUNFRAME:
|
||||||
|
HostState_Run( time );
|
||||||
|
break;
|
||||||
|
case STATE_GAME_SHUTDOWN:
|
||||||
|
HostState_ShutdownGame();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( oldState == STATE_RUNFRAME )
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(( GameState->curstate == oldState ) || ( ++loopCount > 8 ))
|
||||||
|
Sys_Error( "state infinity loop!\n" );
|
||||||
|
}
|
||||||
|
}
|
|
@ -382,7 +382,7 @@ void Host_InputFrame( void )
|
||||||
if( !in_mouseinitialized )
|
if( !in_mouseinitialized )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if( host.state != HOST_FRAME )
|
if( host.status != HOST_FRAME )
|
||||||
{
|
{
|
||||||
IN_DeactivateMouse();
|
IN_DeactivateMouse();
|
||||||
return;
|
return;
|
||||||
|
@ -451,21 +451,21 @@ LONG IN_WndProc( HWND hWnd, UINT uMsg, UINT wParam, LONG lParam )
|
||||||
Sys_Quit();
|
Sys_Quit();
|
||||||
break;
|
break;
|
||||||
case WM_ACTIVATE:
|
case WM_ACTIVATE:
|
||||||
if( host.state == HOST_SHUTDOWN )
|
if( host.status == HOST_SHUTDOWN )
|
||||||
break; // no need to activate
|
break; // no need to activate
|
||||||
if( HIWORD( wParam ))
|
if( HIWORD( wParam ))
|
||||||
host.state = HOST_SLEEP;
|
host.status = HOST_SLEEP;
|
||||||
else if( LOWORD( wParam ) == WA_INACTIVE )
|
else if( LOWORD( wParam ) == WA_INACTIVE )
|
||||||
host.state = HOST_NOFOCUS;
|
host.status = HOST_NOFOCUS;
|
||||||
else host.state = HOST_FRAME;
|
else host.status = HOST_FRAME;
|
||||||
fActivate = (host.state == HOST_FRAME) ? true : false;
|
fActivate = (host.status == HOST_FRAME) ? true : false;
|
||||||
wnd_caption = GetSystemMetrics( SM_CYCAPTION ) + WND_BORDER;
|
wnd_caption = GetSystemMetrics( SM_CYCAPTION ) + WND_BORDER;
|
||||||
|
|
||||||
S_Activate( fActivate, host.hWnd );
|
S_Activate( fActivate, host.hWnd );
|
||||||
IN_ActivateMouse( fActivate );
|
IN_ActivateMouse( fActivate );
|
||||||
Key_ClearStates();
|
Key_ClearStates();
|
||||||
|
|
||||||
if( host.state == HOST_FRAME )
|
if( host.status == HOST_FRAME )
|
||||||
{
|
{
|
||||||
SetForegroundWindow( hWnd );
|
SetForegroundWindow( hWnd );
|
||||||
ShowWindow( hWnd, SW_RESTORE );
|
ShowWindow( hWnd, SW_RESTORE );
|
||||||
|
@ -512,7 +512,7 @@ LONG IN_WndProc( HWND hWnd, UINT uMsg, UINT wParam, LONG lParam )
|
||||||
break;
|
break;
|
||||||
case WM_SYSCOMMAND:
|
case WM_SYSCOMMAND:
|
||||||
// never turn screensaver while Xash is active
|
// never turn screensaver while Xash is active
|
||||||
if( wParam == SC_SCREENSAVE && host.state != HOST_SLEEP )
|
if( wParam == SC_SCREENSAVE && host.status != HOST_SLEEP )
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
case WM_SYSKEYDOWN:
|
case WM_SYSKEYDOWN:
|
||||||
|
|
|
@ -833,7 +833,7 @@ void Com_FreeLibrary( void *hInstance )
|
||||||
if( !hInst || !hInst->hInstance )
|
if( !hInst || !hInst->hInstance )
|
||||||
return; // already freed
|
return; // already freed
|
||||||
|
|
||||||
if( host.state == HOST_CRASHED )
|
if( host.status == HOST_CRASHED )
|
||||||
{
|
{
|
||||||
// we need to hold down all modules, while MSVC can find error
|
// we need to hold down all modules, while MSVC can find error
|
||||||
MsgDev( D_NOTE, "Sys_FreeLibrary: hold %s for debugging\n", hInst->dllName );
|
MsgDev( D_NOTE, "Sys_FreeLibrary: hold %s for debugging\n", hInst->dllName );
|
||||||
|
|
|
@ -524,7 +524,7 @@ byte *Mod_GetPVSForPoint( const vec3_t p )
|
||||||
mnode_t *node;
|
mnode_t *node;
|
||||||
mleaf_t *leaf = NULL;
|
mleaf_t *leaf = NULL;
|
||||||
|
|
||||||
Assert( worldmodel != NULL );
|
ASSERT( worldmodel != NULL );
|
||||||
|
|
||||||
node = worldmodel->nodes;
|
node = worldmodel->nodes;
|
||||||
|
|
||||||
|
@ -589,9 +589,12 @@ within radius pixels of the given point.
|
||||||
*/
|
*/
|
||||||
int Mod_FatPVS( const vec3_t org, float radius, byte *visbuffer, int visbytes, qboolean merge, qboolean fullvis )
|
int Mod_FatPVS( const vec3_t org, float radius, byte *visbuffer, int visbytes, qboolean merge, qboolean fullvis )
|
||||||
{
|
{
|
||||||
mleaf_t *leaf = Mod_PointInLeaf( org, worldmodel->nodes );
|
|
||||||
int bytes = world.visbytes;
|
int bytes = world.visbytes;
|
||||||
|
mleaf_t *leaf = NULL;
|
||||||
|
|
||||||
|
ASSERT( worldmodel != NULL );
|
||||||
|
|
||||||
|
leaf = Mod_PointInLeaf( org, worldmodel->nodes );
|
||||||
bytes = Q_min( bytes, visbytes );
|
bytes = Q_min( bytes, visbytes );
|
||||||
|
|
||||||
// enable full visibility for some reasons
|
// enable full visibility for some reasons
|
||||||
|
@ -1856,6 +1859,7 @@ static void Mod_LoadTextures( dbspmodel_t *bmod )
|
||||||
// if texture is completely missed
|
// if texture is completely missed
|
||||||
if( !tx->gl_texturenum )
|
if( !tx->gl_texturenum )
|
||||||
{
|
{
|
||||||
|
if( host.type != HOST_DEDICATED )
|
||||||
MsgDev( D_ERROR, "couldn't load %s.mip\n", mt->name );
|
MsgDev( D_ERROR, "couldn't load %s.mip\n", mt->name );
|
||||||
tx->gl_texturenum = tr.defaultTexture;
|
tx->gl_texturenum = tr.defaultTexture;
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,8 @@ GNU General Public License for more details.
|
||||||
#define FATPVS_RADIUS 8.0f // FatPVS use radius smaller than the FatPHS
|
#define FATPVS_RADIUS 8.0f // FatPVS use radius smaller than the FatPHS
|
||||||
#define FATPHS_RADIUS 16.0f
|
#define FATPHS_RADIUS 16.0f
|
||||||
|
|
||||||
|
#define WORLD_INDEX (1) // world index is always 1
|
||||||
|
|
||||||
// model flags (stored in model_t->flags)
|
// model flags (stored in model_t->flags)
|
||||||
#define MODEL_CONVEYOR BIT( 0 )
|
#define MODEL_CONVEYOR BIT( 0 )
|
||||||
#define MODEL_HAS_ORIGIN BIT( 1 )
|
#define MODEL_HAS_ORIGIN BIT( 1 )
|
||||||
|
@ -89,10 +91,9 @@ typedef struct
|
||||||
} model_info_t;
|
} model_info_t;
|
||||||
|
|
||||||
// values for model_t's needload
|
// values for model_t's needload
|
||||||
#define NL_PRESENT 0
|
#define NL_UNREFERENCED 0 // this model can be freed after sequence precaching is done
|
||||||
#define NL_NEEDS_LOADED 1
|
#define NL_NEEDS_LOADED 1
|
||||||
#define NL_UNREFERENCED 2 // this model can be freed after sequence precaching is done
|
#define NL_PRESENT 2
|
||||||
#define NL_CLIENT 3 // client-side models are static
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
@ -131,27 +132,23 @@ extern convar_t *r_wadtextures;
|
||||||
// model.c
|
// model.c
|
||||||
//
|
//
|
||||||
void Mod_Init( void );
|
void Mod_Init( void );
|
||||||
void Mod_ClearAll( qboolean keep_playermodel );
|
void Mod_FreeAll( void );
|
||||||
void Mod_Shutdown( void );
|
void Mod_Shutdown( void );
|
||||||
void Mod_ClearUserData( void );
|
void Mod_ClearUserData( void );
|
||||||
void Mod_GetBounds( int handle, vec3_t mins, vec3_t maxs );
|
model_t *Mod_LoadWorld( const char *name, qboolean preload );
|
||||||
void Mod_GetFrames( int handle, int *numFrames );
|
|
||||||
void Mod_LoadWorld( const char *name, netsrc_t type );
|
|
||||||
int Mod_FrameCount( model_t *mod );
|
|
||||||
void *Mod_Calloc( int number, size_t size );
|
void *Mod_Calloc( int number, size_t size );
|
||||||
void *Mod_CacheCheck( struct cache_user_s *c );
|
void *Mod_CacheCheck( struct cache_user_s *c );
|
||||||
void Mod_LoadCacheFile( const char *path, struct cache_user_s *cu );
|
void Mod_LoadCacheFile( const char *path, struct cache_user_s *cu );
|
||||||
void *Mod_AliasExtradata( model_t *mod );
|
void *Mod_AliasExtradata( model_t *mod );
|
||||||
void *Mod_StudioExtradata( model_t *mod );
|
void *Mod_StudioExtradata( model_t *mod );
|
||||||
model_t *Mod_FindName( const char *name, qboolean create );
|
model_t *Mod_FindName( const char *name, qboolean trackCRC );
|
||||||
model_t *Mod_LoadModel( model_t *mod, qboolean world );
|
model_t *Mod_LoadModel( model_t *mod, qboolean crash );
|
||||||
model_t *Mod_ForName( const char *name, qboolean world );
|
model_t *Mod_ForName( const char *name, qboolean crash, qboolean trackCRC );
|
||||||
qboolean Mod_RegisterModel( const char *name, int index );
|
|
||||||
qboolean Mod_ValidateCRC( const char *name, CRC32_t crc );
|
qboolean Mod_ValidateCRC( const char *name, CRC32_t crc );
|
||||||
void Mod_NeedCRC( const char *name, qboolean needCRC );
|
void Mod_NeedCRC( const char *name, qboolean needCRC );
|
||||||
modtype_t Mod_GetType( int handle );
|
void Mod_PurgeStudioCache( void );
|
||||||
model_t *Mod_Handle( int handle );
|
|
||||||
void Mod_FreeUnused( void );
|
void Mod_FreeUnused( void );
|
||||||
|
void Mod_ClearAll( void );
|
||||||
|
|
||||||
//
|
//
|
||||||
// mod_bmodel.c
|
// mod_bmodel.c
|
||||||
|
@ -187,5 +184,6 @@ void R_StudioCalcBonePosition( int frame, float s, void *pbone, void *panim, vec
|
||||||
void *R_StudioGetAnim( void *m_pStudioHeader, void *m_pSubModel, void *pseqdesc );
|
void *R_StudioGetAnim( void *m_pStudioHeader, void *m_pSubModel, void *pseqdesc );
|
||||||
void Mod_StudioComputeBounds( void *buffer, vec3_t mins, vec3_t maxs, qboolean ignore_sequences );
|
void Mod_StudioComputeBounds( void *buffer, vec3_t mins, vec3_t maxs, qboolean ignore_sequences );
|
||||||
int Mod_HitgroupForStudioHull( int index );
|
int Mod_HitgroupForStudioHull( int index );
|
||||||
|
void Mod_ClearStudioCache( void );
|
||||||
|
|
||||||
#endif//MOD_LOCAL_H
|
#endif//MOD_LOCAL_H
|
|
@ -509,7 +509,7 @@ void Mod_StudioGetAttachment( const edict_t *e, int iAtt, float *origin, float *
|
||||||
vec3_t angles2;
|
vec3_t angles2;
|
||||||
model_t *mod;
|
model_t *mod;
|
||||||
|
|
||||||
mod = Mod_Handle( e->v.modelindex );
|
mod = SV_ModelHandle( e->v.modelindex );
|
||||||
mod_studiohdr = (studiohdr_t *)Mod_StudioExtradata( mod );
|
mod_studiohdr = (studiohdr_t *)Mod_StudioExtradata( mod );
|
||||||
if( !mod_studiohdr ) return;
|
if( !mod_studiohdr ) return;
|
||||||
|
|
||||||
|
@ -558,7 +558,7 @@ void Mod_GetBonePosition( const edict_t *e, int iBone, float *origin, float *ang
|
||||||
{
|
{
|
||||||
model_t *mod;
|
model_t *mod;
|
||||||
|
|
||||||
mod = Mod_Handle( e->v.modelindex );
|
mod = SV_ModelHandle( e->v.modelindex );
|
||||||
mod_studiohdr = (studiohdr_t *)Mod_StudioExtradata( mod );
|
mod_studiohdr = (studiohdr_t *)Mod_StudioExtradata( mod );
|
||||||
if( !mod_studiohdr ) return;
|
if( !mod_studiohdr ) return;
|
||||||
|
|
||||||
|
|
|
@ -25,10 +25,9 @@ GNU General Public License for more details.
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "server.h" // LUMP_ error codes
|
#include "server.h" // LUMP_ error codes
|
||||||
|
|
||||||
static model_t *com_models[MAX_MODELS]; // shared replacement modeltable
|
static model_info_t mod_crcinfo[MAX_MODELS];
|
||||||
static model_info_t cm_modinfo[MAX_MODELS];
|
static model_t mod_known[MAX_MODELS];
|
||||||
static model_t cm_models[MAX_MODELS];
|
static int mod_numknown = 0;
|
||||||
static int cm_nummodels = 0;
|
|
||||||
byte *com_studiocache; // cache for submodels
|
byte *com_studiocache; // cache for submodels
|
||||||
convar_t *mod_studiocache;
|
convar_t *mod_studiocache;
|
||||||
convar_t *r_wadtextures;
|
convar_t *r_wadtextures;
|
||||||
|
@ -54,7 +53,7 @@ static void Mod_Modellist_f( void )
|
||||||
Msg( "\n" );
|
Msg( "\n" );
|
||||||
Msg( "-----------------------------------\n" );
|
Msg( "-----------------------------------\n" );
|
||||||
|
|
||||||
for( i = nummodels = 0, mod = cm_models; i < cm_nummodels; i++, mod++ )
|
for( i = nummodels = 0, mod = mod_known; i < mod_numknown; i++, mod++ )
|
||||||
{
|
{
|
||||||
if( !mod->name[0] )
|
if( !mod->name[0] )
|
||||||
continue; // free slot
|
continue; // free slot
|
||||||
|
@ -75,8 +74,8 @@ Mod_FreeUserData
|
||||||
*/
|
*/
|
||||||
static void Mod_FreeUserData( model_t *mod )
|
static void Mod_FreeUserData( model_t *mod )
|
||||||
{
|
{
|
||||||
// already freed?
|
// ignore submodels and freed models
|
||||||
if( !mod || !mod->name[0] )
|
if( !mod->name[0] || mod->name[0] == '*' )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if( host.type == HOST_DEDICATED )
|
if( host.type == HOST_DEDICATED )
|
||||||
|
@ -108,6 +107,7 @@ static void Mod_FreeModel( model_t *mod )
|
||||||
if( !mod || !mod->name[0] )
|
if( !mod || !mod->name[0] )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
Msg( "release %s\n", mod->name );
|
||||||
Mod_FreeUserData( mod );
|
Mod_FreeUserData( mod );
|
||||||
|
|
||||||
// select the properly unloader
|
// select the properly unloader
|
||||||
|
@ -126,6 +126,8 @@ static void Mod_FreeModel( model_t *mod )
|
||||||
Mod_UnloadAliasModel( mod );
|
Mod_UnloadAliasModel( mod );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memset( mod, 0, sizeof( *mod ));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -148,36 +150,59 @@ void Mod_Init( void )
|
||||||
Mod_InitStudioHull ();
|
Mod_InitStudioHull ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mod_ClearAll( qboolean keep_playermodel )
|
/*
|
||||||
|
================
|
||||||
|
Mod_FreeAll
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void Mod_FreeAll( void )
|
||||||
{
|
{
|
||||||
model_t *plr = com_models[MAX_MODELS-1];
|
|
||||||
model_t *mod;
|
model_t *mod;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for( i = 0, mod = cm_models; i < cm_nummodels; i++, mod++ )
|
for( i = 0, mod = mod_known; i < mod_numknown; i++, mod++ )
|
||||||
{
|
|
||||||
if( keep_playermodel && mod == plr )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Mod_FreeModel( mod );
|
Mod_FreeModel( mod );
|
||||||
memset( mod, 0, sizeof( *mod ));
|
mod_numknown = 0;
|
||||||
}
|
|
||||||
|
|
||||||
// g-cont. may be just leave unchanged?
|
|
||||||
if( !keep_playermodel ) cm_nummodels = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
Mod_ClearAll
|
||||||
|
|
||||||
|
clear all models as unreferenced
|
||||||
|
but don't touch the real data
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void Mod_ClearAll( void )
|
||||||
|
{
|
||||||
|
model_t *mod;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for( i = 0, mod = mod_known; i < mod_numknown; i++, mod++ )
|
||||||
|
mod->needload = NL_UNREFERENCED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
Mod_ClearUserData
|
||||||
|
================
|
||||||
|
*/
|
||||||
void Mod_ClearUserData( void )
|
void Mod_ClearUserData( void )
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for( i = 0; i < cm_nummodels; i++ )
|
for( i = 0; i < mod_numknown; i++ )
|
||||||
Mod_FreeUserData( &cm_models[i] );
|
Mod_FreeUserData( &mod_known[i] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
Mod_Shutdown
|
||||||
|
================
|
||||||
|
*/
|
||||||
void Mod_Shutdown( void )
|
void Mod_Shutdown( void )
|
||||||
{
|
{
|
||||||
Mod_ClearAll( false );
|
Mod_FreeAll();
|
||||||
Mem_FreePool( &com_studiocache );
|
Mem_FreePool( &com_studiocache );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,48 +219,46 @@ Mod_FindName
|
||||||
|
|
||||||
==================
|
==================
|
||||||
*/
|
*/
|
||||||
model_t *Mod_FindName( const char *filename, qboolean create )
|
model_t *Mod_FindName( const char *filename, qboolean trackCRC )
|
||||||
{
|
{
|
||||||
|
char modname[MAX_QPATH];
|
||||||
model_t *mod;
|
model_t *mod;
|
||||||
char name[64];
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if( !filename || !filename[0] )
|
if( !COM_CheckString( filename ))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if( *filename == '!' ) filename++;
|
Q_strncpy( modname, filename, sizeof( modname ));
|
||||||
Q_strncpy( name, filename, sizeof( name ));
|
|
||||||
COM_FixSlashes( name );
|
|
||||||
|
|
||||||
// search the currently loaded models
|
// search the currently loaded models
|
||||||
for( i = 0, mod = cm_models; i < cm_nummodels; i++, mod++ )
|
for( i = 0, mod = mod_known; i < mod_numknown; i++, mod++ )
|
||||||
{
|
{
|
||||||
if( !mod->name[0] ) continue;
|
if( !Q_stricmp( mod->name, modname ))
|
||||||
if( !Q_stricmp( mod->name, name ))
|
|
||||||
{
|
{
|
||||||
// prolonge registration
|
if( mod->mempool )
|
||||||
mod->needload = world.load_sequence;
|
mod->needload = NL_PRESENT;
|
||||||
|
else mod->needload = NL_NEEDS_LOADED;
|
||||||
|
|
||||||
return mod;
|
return mod;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !create ) return NULL;
|
|
||||||
|
|
||||||
// find a free model slot spot
|
// find a free model slot spot
|
||||||
for( i = 0, mod = cm_models; i < cm_nummodels; i++, mod++ )
|
for( i = 0, mod = mod_known; i < mod_numknown; i++, mod++ )
|
||||||
if( !mod->name[0] ) break; // this is a valid spot
|
if( !mod->name[0] ) break; // this is a valid spot
|
||||||
|
|
||||||
if( i == cm_nummodels )
|
if( i == mod_numknown )
|
||||||
{
|
{
|
||||||
if( cm_nummodels == MAX_MODELS )
|
if( mod_numknown == MAX_MODELS )
|
||||||
Host_Error( "Mod_ForName: MAX_MODELS limit exceeded\n" );
|
Host_Error( "Mod_ForName: MAX_MODELS limit exceeded\n" );
|
||||||
cm_nummodels++;
|
mod_numknown++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy name, so model loader can find model file
|
// copy name, so model loader can find model file
|
||||||
Q_strncpy( mod->name, name, sizeof( mod->name ));
|
Q_strncpy( mod->name, modname, sizeof( mod->name ));
|
||||||
cm_modinfo[i].initialCRC = 0;
|
if( trackCRC ) mod_crcinfo[i].flags = FCRC_SHOULD_CHECKSUM;
|
||||||
cm_modinfo[i].flags = 0;
|
else mod_crcinfo[i].flags = 0;
|
||||||
|
mod_crcinfo[i].initialCRC = 0;
|
||||||
|
|
||||||
return mod;
|
return mod;
|
||||||
}
|
}
|
||||||
|
@ -264,7 +287,10 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
|
||||||
|
|
||||||
// check if already loaded (or inline bmodel)
|
// check if already loaded (or inline bmodel)
|
||||||
if( mod->mempool || mod->name[0] == '*' )
|
if( mod->mempool || mod->name[0] == '*' )
|
||||||
|
{
|
||||||
|
mod->needload = NL_PRESENT;
|
||||||
return mod;
|
return mod;
|
||||||
|
}
|
||||||
|
|
||||||
// store modelname to show error
|
// store modelname to show error
|
||||||
Q_strncpy( tempname, mod->name, sizeof( tempname ));
|
Q_strncpy( tempname, mod->name, sizeof( tempname ));
|
||||||
|
@ -341,7 +367,8 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p = &cm_modinfo[mod - cm_models];
|
p = &mod_crcinfo[mod - mod_known];
|
||||||
|
mod->needload = NL_PRESENT;
|
||||||
|
|
||||||
if( FBitSet( p->flags, FCRC_SHOULD_CHECKSUM ))
|
if( FBitSet( p->flags, FCRC_SHOULD_CHECKSUM ))
|
||||||
{
|
{
|
||||||
|
@ -374,14 +401,37 @@ Mod_ForName
|
||||||
Loads in a model for the given name
|
Loads in a model for the given name
|
||||||
==================
|
==================
|
||||||
*/
|
*/
|
||||||
model_t *Mod_ForName( const char *name, qboolean crash )
|
model_t *Mod_ForName( const char *name, qboolean crash, qboolean trackCRC )
|
||||||
{
|
{
|
||||||
model_t *mod;
|
model_t *mod = Mod_FindName( name, trackCRC );
|
||||||
|
|
||||||
mod = Mod_FindName( name, true );
|
|
||||||
return Mod_LoadModel( mod, crash );
|
return Mod_LoadModel( mod, crash );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
==================
|
||||||
|
Mod_PurgeStudioCache
|
||||||
|
|
||||||
|
free studio cache on change level
|
||||||
|
==================
|
||||||
|
*/
|
||||||
|
void Mod_PurgeStudioCache( void )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// we should release all the world submodels
|
||||||
|
// and clear studio sequences
|
||||||
|
for( i = 1; i < mod_numknown; i++ )
|
||||||
|
{
|
||||||
|
if( mod_known[i].type == mod_studio )
|
||||||
|
mod_known[i].submodels = NULL;
|
||||||
|
if( mod_known[i].name[0] == '*' )
|
||||||
|
Mod_FreeModel( &mod_known[i] );
|
||||||
|
}
|
||||||
|
|
||||||
|
Mem_EmptyPool( com_studiocache );
|
||||||
|
Mod_ClearStudioCache();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
==================
|
==================
|
||||||
Mod_LoadWorld
|
Mod_LoadWorld
|
||||||
|
@ -389,37 +439,32 @@ Mod_LoadWorld
|
||||||
Loads in the map and all submodels
|
Loads in the map and all submodels
|
||||||
==================
|
==================
|
||||||
*/
|
*/
|
||||||
void Mod_LoadWorld( const char *name, netsrc_t source )
|
model_t *Mod_LoadWorld( const char *name, qboolean preload )
|
||||||
{
|
{
|
||||||
int i;
|
model_t *pworld;
|
||||||
|
|
||||||
// invalidate representation table
|
// already loaded?
|
||||||
if( source == NS_SERVER || !Host_ServerState())
|
if( !Q_stricmp( mod_known->name, name ))
|
||||||
memset( com_models, 0, sizeof( com_models ));
|
return mod_known;
|
||||||
|
|
||||||
if( !Q_stricmp( cm_models[0].name, name ))
|
// free sequence files on studiomodels
|
||||||
{
|
Mod_PurgeStudioCache();
|
||||||
// map already loaded
|
|
||||||
com_models[1] = cm_models;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// clear all studio submodels on restart
|
// release previois map
|
||||||
for( i = 1; i < cm_nummodels; i++ )
|
Mod_FreeModel( mod_known ); // world is stuck on slot #0 always
|
||||||
{
|
|
||||||
if( cm_models[i].type == mod_studio )
|
|
||||||
cm_models[i].submodels = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// purge all submodels
|
|
||||||
Mod_FreeModel( &cm_models[0] ); // unload the previois map
|
|
||||||
Mem_EmptyPool( com_studiocache ); // purge studio cache
|
|
||||||
world.load_sequence++; // now all models are invalid
|
world.load_sequence++; // now all models are invalid
|
||||||
|
Mod_ClearAll();
|
||||||
|
|
||||||
// load the newmap
|
// load the newmap
|
||||||
world.loading = true;
|
world.loading = true;
|
||||||
com_models[1] = Mod_ForName( name, true );
|
pworld = Mod_FindName( name, false );
|
||||||
|
if( preload ) Mod_LoadModel( pworld, true );
|
||||||
world.loading = false;
|
world.loading = false;
|
||||||
|
|
||||||
|
ASSERT( pworld == mod_known );
|
||||||
|
|
||||||
|
return pworld;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -434,10 +479,11 @@ void Mod_FreeUnused( void )
|
||||||
model_t *mod;
|
model_t *mod;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for( i = 0, mod = cm_models; i < cm_nummodels; i++, mod++ )
|
Msg( "Mod_FreeUnused()\n" );
|
||||||
|
|
||||||
|
for( i = 0, mod = mod_known; i < mod_numknown; i++, mod++ )
|
||||||
{
|
{
|
||||||
if( !mod->name[0] ) continue;
|
if( mod->needload == NL_UNREFERENCED )
|
||||||
if( mod->needload != world.load_sequence )
|
|
||||||
Mod_FreeModel( mod );
|
Mod_FreeModel( mod );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -449,80 +495,6 @@ void Mod_FreeUnused( void )
|
||||||
|
|
||||||
===============================================================================
|
===============================================================================
|
||||||
*/
|
*/
|
||||||
/*
|
|
||||||
===================
|
|
||||||
Mod_GetType
|
|
||||||
===================
|
|
||||||
*/
|
|
||||||
modtype_t Mod_GetType( int handle )
|
|
||||||
{
|
|
||||||
model_t *mod = Mod_Handle( handle );
|
|
||||||
|
|
||||||
if( !mod ) return mod_bad;
|
|
||||||
return mod->type;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
===================
|
|
||||||
Mod_GetFrames
|
|
||||||
===================
|
|
||||||
*/
|
|
||||||
void Mod_GetFrames( int handle, int *numFrames )
|
|
||||||
{
|
|
||||||
model_t *mod = Mod_Handle( handle );
|
|
||||||
|
|
||||||
if( !numFrames ) return;
|
|
||||||
if( !mod )
|
|
||||||
{
|
|
||||||
*numFrames = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( mod->type == mod_brush )
|
|
||||||
*numFrames = 2; // regular and alternate animation
|
|
||||||
else *numFrames = mod->numframes;
|
|
||||||
if( *numFrames < 1 ) *numFrames = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
===================
|
|
||||||
Mod_FrameCount
|
|
||||||
|
|
||||||
model_t as input
|
|
||||||
===================
|
|
||||||
*/
|
|
||||||
int Mod_FrameCount( model_t *mod )
|
|
||||||
{
|
|
||||||
if( !mod ) return 1;
|
|
||||||
|
|
||||||
return mod->numframes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
===================
|
|
||||||
Mod_GetBounds
|
|
||||||
===================
|
|
||||||
*/
|
|
||||||
void Mod_GetBounds( int handle, vec3_t mins, vec3_t maxs )
|
|
||||||
{
|
|
||||||
model_t *cmod;
|
|
||||||
|
|
||||||
if( handle <= 0 ) return;
|
|
||||||
cmod = Mod_Handle( handle );
|
|
||||||
|
|
||||||
if( cmod )
|
|
||||||
{
|
|
||||||
if( mins ) VectorCopy( cmod->mins, mins );
|
|
||||||
if( maxs ) VectorCopy( cmod->maxs, maxs );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MsgDev( D_ERROR, "Mod_GetBounds: NULL model %i\n", handle );
|
|
||||||
if( mins ) VectorClear( mins );
|
|
||||||
if( maxs ) VectorClear( maxs );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
===============
|
===============
|
||||||
Mod_Calloc
|
Mod_Calloc
|
||||||
|
@ -559,52 +531,25 @@ Mod_LoadCacheFile
|
||||||
*/
|
*/
|
||||||
void Mod_LoadCacheFile( const char *filename, cache_user_t *cu )
|
void Mod_LoadCacheFile( const char *filename, cache_user_t *cu )
|
||||||
{
|
{
|
||||||
|
char modname[MAX_QPATH];
|
||||||
|
size_t size;
|
||||||
byte *buf;
|
byte *buf;
|
||||||
string name;
|
|
||||||
size_t i, j, size;
|
|
||||||
|
|
||||||
Assert( cu != NULL );
|
Assert( cu != NULL );
|
||||||
|
|
||||||
if( !filename || !filename[0] ) return;
|
if( !COM_CheckString( filename ))
|
||||||
|
return;
|
||||||
|
|
||||||
// eliminate '!' symbol (i'm doesn't know what this doing)
|
Q_strncpy( modname, filename, sizeof( modname ));
|
||||||
for( i = j = 0; i < Q_strlen( filename ); i++ )
|
COM_FixSlashes( modname );
|
||||||
{
|
|
||||||
if( filename[i] == '!' ) continue;
|
|
||||||
else if( filename[i] == '\\' ) name[j] = '/';
|
|
||||||
else name[j] = Q_tolower( filename[i] );
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
name[j] = '\0';
|
|
||||||
|
|
||||||
buf = FS_LoadFile( name, &size, false );
|
buf = FS_LoadFile( modname, &size, false );
|
||||||
if( !buf || !size ) Host_Error( "LoadCacheFile: ^1can't load %s^7\n", filename );
|
if( !buf || !size ) Host_Error( "LoadCacheFile: ^1can't load %s^7\n", filename );
|
||||||
cu->data = Mem_Alloc( com_studiocache, size );
|
cu->data = Mem_Alloc( com_studiocache, size );
|
||||||
memcpy( cu->data, buf, size );
|
memcpy( cu->data, buf, size );
|
||||||
Mem_Free( buf );
|
Mem_Free( buf );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
===================
|
|
||||||
Mod_RegisterModel
|
|
||||||
|
|
||||||
register model with shared index
|
|
||||||
===================
|
|
||||||
*/
|
|
||||||
qboolean Mod_RegisterModel( const char *name, int index )
|
|
||||||
{
|
|
||||||
model_t *mod;
|
|
||||||
|
|
||||||
if( index < 0 || index > MAX_MODELS )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// this array used for acess to servermodels
|
|
||||||
mod = Mod_ForName( name, false );
|
|
||||||
com_models[index] = mod;
|
|
||||||
|
|
||||||
return ( mod != NULL );
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
===============
|
===============
|
||||||
Mod_AliasExtradata
|
Mod_AliasExtradata
|
||||||
|
@ -631,20 +576,6 @@ void *Mod_StudioExtradata( model_t *mod )
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
==================
|
|
||||||
Mod_Handle
|
|
||||||
|
|
||||||
==================
|
|
||||||
*/
|
|
||||||
model_t *Mod_Handle( int handle )
|
|
||||||
{
|
|
||||||
if( handle < 0 || handle >= MAX_MODELS )
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return com_models[handle];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
==================
|
==================
|
||||||
Mod_ValidateCRC
|
Mod_ValidateCRC
|
||||||
|
@ -657,7 +588,7 @@ qboolean Mod_ValidateCRC( const char *name, CRC32_t crc )
|
||||||
model_t *mod;
|
model_t *mod;
|
||||||
|
|
||||||
mod = Mod_FindName( name, true );
|
mod = Mod_FindName( name, true );
|
||||||
p = &cm_modinfo[mod - cm_models];
|
p = &mod_crcinfo[mod - mod_known];
|
||||||
|
|
||||||
if( !FBitSet( p->flags, FCRC_CHECKSUM_DONE ))
|
if( !FBitSet( p->flags, FCRC_CHECKSUM_DONE ))
|
||||||
return true;
|
return true;
|
||||||
|
@ -678,7 +609,7 @@ void Mod_NeedCRC( const char *name, qboolean needCRC )
|
||||||
model_info_t *p;
|
model_info_t *p;
|
||||||
|
|
||||||
mod = Mod_FindName( name, true );
|
mod = Mod_FindName( name, true );
|
||||||
p = &cm_modinfo[mod - cm_models];
|
p = &mod_crcinfo[mod - mod_known];
|
||||||
|
|
||||||
if( needCRC ) SetBits( p->flags, FCRC_SHOULD_CHECKSUM );
|
if( needCRC ) SetBits( p->flags, FCRC_SHOULD_CHECKSUM );
|
||||||
else ClearBits( p->flags, FCRC_SHOULD_CHECKSUM );
|
else ClearBits( p->flags, FCRC_SHOULD_CHECKSUM );
|
||||||
|
|
|
@ -134,7 +134,7 @@ static long _stdcall Con_WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lP
|
||||||
SetFocus( s_wcd.hwndInputLine );
|
SetFocus( s_wcd.hwndInputLine );
|
||||||
break;
|
break;
|
||||||
case WM_CLOSE:
|
case WM_CLOSE:
|
||||||
if( host.state == HOST_ERR_FATAL )
|
if( host.status == HOST_ERR_FATAL )
|
||||||
{
|
{
|
||||||
// send windows message
|
// send windows message
|
||||||
PostQuitMessage( 0 );
|
PostQuitMessage( 0 );
|
||||||
|
@ -197,7 +197,7 @@ long _stdcall Con_InputLineProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPa
|
||||||
case WM_CHAR:
|
case WM_CHAR:
|
||||||
if( Con_KeyEvent( wParam, true ))
|
if( Con_KeyEvent( wParam, true ))
|
||||||
return 0;
|
return 0;
|
||||||
if( wParam == 13 && host.state != HOST_ERR_FATAL )
|
if( wParam == 13 && host.status != HOST_ERR_FATAL )
|
||||||
{
|
{
|
||||||
GetWindowText( s_wcd.hwndInputLine, inputBuffer, sizeof( inputBuffer ));
|
GetWindowText( s_wcd.hwndInputLine, inputBuffer, sizeof( inputBuffer ));
|
||||||
Q_strncat( s_wcd.consoleText, inputBuffer, sizeof( s_wcd.consoleText ) - Q_strlen( s_wcd.consoleText ) - 5 );
|
Q_strncat( s_wcd.consoleText, inputBuffer, sizeof( s_wcd.consoleText ) - Q_strlen( s_wcd.consoleText ) - 5 );
|
||||||
|
@ -499,7 +499,7 @@ void Sys_CloseLog( void )
|
||||||
char event_name[64];
|
char event_name[64];
|
||||||
|
|
||||||
// continue logged
|
// continue logged
|
||||||
switch( host.state )
|
switch( host.status )
|
||||||
{
|
{
|
||||||
case HOST_CRASHED:
|
case HOST_CRASHED:
|
||||||
Q_strncpy( event_name, "crashed", sizeof( event_name ));
|
Q_strncpy( event_name, "crashed", sizeof( event_name ));
|
||||||
|
|
|
@ -422,7 +422,7 @@ qboolean Sys_FreeLibrary( dll_info_t *dll )
|
||||||
if( !dll || !dll->link )
|
if( !dll || !dll->link )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if( host.state == HOST_CRASHED )
|
if( host.status == HOST_CRASHED )
|
||||||
{
|
{
|
||||||
// we need to hold down all modules, while MSVC can find error
|
// we need to hold down all modules, while MSVC can find error
|
||||||
MsgDev( D_NOTE, "Sys_FreeLibrary: hold %s for debugging\n", dll->name );
|
MsgDev( D_NOTE, "Sys_FreeLibrary: hold %s for debugging\n", dll->name );
|
||||||
|
@ -466,7 +466,7 @@ void Sys_WaitForQuit( void )
|
||||||
long _stdcall Sys_Crash( PEXCEPTION_POINTERS pInfo )
|
long _stdcall Sys_Crash( PEXCEPTION_POINTERS pInfo )
|
||||||
{
|
{
|
||||||
// save config
|
// save config
|
||||||
if( host.state != HOST_CRASHED )
|
if( host.status != HOST_CRASHED )
|
||||||
{
|
{
|
||||||
// check to avoid recursive call
|
// check to avoid recursive call
|
||||||
error_on_exit = true;
|
error_on_exit = true;
|
||||||
|
@ -474,17 +474,14 @@ long _stdcall Sys_Crash( PEXCEPTION_POINTERS pInfo )
|
||||||
|
|
||||||
if( host.type == HOST_NORMAL )
|
if( host.type == HOST_NORMAL )
|
||||||
CL_Crashed(); // tell client about crash
|
CL_Crashed(); // tell client about crash
|
||||||
else host.state = HOST_CRASHED;
|
else host.status = HOST_CRASHED;
|
||||||
|
|
||||||
Msg( "Sys_Crash: call %p at address %p\n", pInfo->ExceptionRecord->ExceptionAddress, pInfo->ExceptionRecord->ExceptionCode );
|
Msg( "unhandled exception: %p at address %p\n", pInfo->ExceptionRecord->ExceptionAddress, pInfo->ExceptionRecord->ExceptionCode );
|
||||||
|
#ifdef NDEBUG
|
||||||
if( host.developer <= 0 )
|
|
||||||
{
|
|
||||||
// no reason to call debugger in release build - just exit
|
// no reason to call debugger in release build - just exit
|
||||||
Sys_Quit();
|
Sys_Quit();
|
||||||
return EXCEPTION_CONTINUE_EXECUTION;
|
return EXCEPTION_CONTINUE_EXECUTION;
|
||||||
}
|
#endif
|
||||||
|
|
||||||
// all other states keep unchanged to let debugger find bug
|
// all other states keep unchanged to let debugger find bug
|
||||||
Con_DestroyConsole();
|
Con_DestroyConsole();
|
||||||
}
|
}
|
||||||
|
@ -507,14 +504,14 @@ void Sys_Error( const char *error, ... )
|
||||||
va_list argptr;
|
va_list argptr;
|
||||||
char text[MAX_SYSPATH];
|
char text[MAX_SYSPATH];
|
||||||
|
|
||||||
if( host.state == HOST_ERR_FATAL )
|
if( host.status == HOST_ERR_FATAL )
|
||||||
return; // don't multiple executes
|
return; // don't multiple executes
|
||||||
|
|
||||||
// make sure what console received last message
|
// make sure what console received last message
|
||||||
if( host.change_game ) Sys_Sleep( 200 );
|
if( host.change_game ) Sys_Sleep( 200 );
|
||||||
|
|
||||||
error_on_exit = true;
|
error_on_exit = true;
|
||||||
host.state = HOST_ERR_FATAL;
|
host.status = HOST_ERR_FATAL;
|
||||||
va_start( argptr, error );
|
va_start( argptr, error );
|
||||||
Q_vsprintf( text, error, argptr );
|
Q_vsprintf( text, error, argptr );
|
||||||
va_end( argptr );
|
va_end( argptr );
|
||||||
|
|
|
@ -166,120 +166,6 @@ void World_TransformAABB( matrix4x4 transform, const vec3_t mins, const vec3_t m
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
==================
|
|
||||||
World_PortalCSG
|
|
||||||
|
|
||||||
a portal is flush with a world surface behind it. this causes problems. namely that we can't pass through the portal plane
|
|
||||||
if the bsp behind it prevents out origin from getting through. so if the trace was clipped and ended infront of the portal,
|
|
||||||
continue the trace to the edges of the portal cutout instead.
|
|
||||||
==================
|
|
||||||
*/
|
|
||||||
void World_PortalCSG( edict_t *portal, const vec3_t trace_mins, const vec3_t trace_maxs, const vec3_t start, const vec3_t end, trace_t *trace )
|
|
||||||
{
|
|
||||||
vec4_t planes[6]; //far, near, right, left, up, down
|
|
||||||
int plane, k;
|
|
||||||
vec3_t worldpos;
|
|
||||||
float bestfrac;
|
|
||||||
int hitplane;
|
|
||||||
model_t *model;
|
|
||||||
float portalradius;
|
|
||||||
|
|
||||||
// only run this code if we impacted on the portal's parent.
|
|
||||||
if( trace->fraction == 1.0f && !trace->startsolid )
|
|
||||||
return;
|
|
||||||
|
|
||||||
// decide which clipping hull to use, based on the size
|
|
||||||
model = Mod_Handle( portal->v.modelindex );
|
|
||||||
|
|
||||||
if( !model || model->type != mod_brush )
|
|
||||||
return;
|
|
||||||
|
|
||||||
// make sure we use a sane valid position.
|
|
||||||
if( trace->startsolid ) VectorCopy( start, worldpos );
|
|
||||||
else VectorCopy( trace->endpos, worldpos );
|
|
||||||
|
|
||||||
// determine the csg area. normals should be facing in
|
|
||||||
AngleVectors( portal->v.angles, planes[1], planes[3], planes[5] );
|
|
||||||
VectorNegate(planes[1], planes[0]);
|
|
||||||
VectorNegate(planes[3], planes[2]);
|
|
||||||
VectorNegate(planes[5], planes[4]);
|
|
||||||
|
|
||||||
portalradius = model->radius * 0.5f;
|
|
||||||
planes[0][3] = DotProduct( portal->v.origin, planes[0] ) - (4.0f / 32.0f);
|
|
||||||
planes[1][3] = DotProduct( portal->v.origin, planes[1] ) - (4.0f / 32.0f); //an epsilon beyond the portal
|
|
||||||
planes[2][3] = DotProduct( portal->v.origin, planes[2] ) - portalradius;
|
|
||||||
planes[3][3] = DotProduct( portal->v.origin, planes[3] ) - portalradius;
|
|
||||||
planes[4][3] = DotProduct( portal->v.origin, planes[4] ) - portalradius;
|
|
||||||
planes[5][3] = DotProduct( portal->v.origin, planes[5] ) - portalradius;
|
|
||||||
|
|
||||||
// if we're actually inside the csg region
|
|
||||||
for( plane = 0; plane < 6; plane++ )
|
|
||||||
{
|
|
||||||
float d = DotProduct( worldpos, planes[plane] );
|
|
||||||
vec3_t nearest;
|
|
||||||
|
|
||||||
for( k = 0; k < 3; k++ )
|
|
||||||
nearest[k] = (planes[plane][k]>=0) ? trace_maxs[k] : trace_mins[k];
|
|
||||||
|
|
||||||
// front plane gets further away with side
|
|
||||||
if( !plane )
|
|
||||||
{
|
|
||||||
planes[plane][3] -= DotProduct( nearest, planes[plane] );
|
|
||||||
}
|
|
||||||
else if( plane > 1 )
|
|
||||||
{
|
|
||||||
// side planes get nearer with size
|
|
||||||
planes[plane][3] += 24; // DotProduct( nearest, planes[plane] );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( d - planes[plane][3] >= 0 )
|
|
||||||
continue; // endpos is inside
|
|
||||||
else return; // end is already outside
|
|
||||||
}
|
|
||||||
|
|
||||||
// yup, we're inside, the trace shouldn't end where it actually did
|
|
||||||
bestfrac = 1;
|
|
||||||
hitplane = -1;
|
|
||||||
|
|
||||||
for( plane = 0; plane < 6; plane++ )
|
|
||||||
{
|
|
||||||
float ds = DotProduct( start, planes[plane] ) - planes[plane][3];
|
|
||||||
float de = DotProduct( end, planes[plane] ) - planes[plane][3];
|
|
||||||
float frac;
|
|
||||||
|
|
||||||
if( ds >= 0 && de < 0 )
|
|
||||||
{
|
|
||||||
frac = (ds) / (ds - de);
|
|
||||||
if( frac < bestfrac )
|
|
||||||
{
|
|
||||||
if( frac < 0 )
|
|
||||||
frac = 0;
|
|
||||||
bestfrac = frac;
|
|
||||||
hitplane = plane;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trace->startsolid = trace->allsolid = false;
|
|
||||||
|
|
||||||
// if we cross the front of the portal, don't shorten the trace,
|
|
||||||
// that will artificially clip us
|
|
||||||
if( hitplane == 0 && trace->fraction > bestfrac )
|
|
||||||
return;
|
|
||||||
|
|
||||||
// okay, elongate to clip to the portal hole properly.
|
|
||||||
VectorLerp( start, bestfrac, end, trace->endpos );
|
|
||||||
trace->fraction = bestfrac;
|
|
||||||
|
|
||||||
if( hitplane >= 0 )
|
|
||||||
{
|
|
||||||
VectorCopy( planes[hitplane], trace->plane.normal );
|
|
||||||
trace->plane.dist = planes[hitplane][3];
|
|
||||||
if( hitplane == 1 ) trace->ent = portal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
==================
|
==================
|
||||||
RankForContents
|
RankForContents
|
||||||
|
|
|
@ -49,7 +49,6 @@ void ClearLink( link_t *l );
|
||||||
// trace common
|
// trace common
|
||||||
void World_MoveBounds( const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, vec3_t boxmins, vec3_t boxmaxs );
|
void World_MoveBounds( const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, vec3_t boxmins, vec3_t boxmaxs );
|
||||||
void World_TransformAABB( matrix4x4 transform, const vec3_t mins, const vec3_t maxs, vec3_t outmins, vec3_t outmaxs );
|
void World_TransformAABB( matrix4x4 transform, const vec3_t mins, const vec3_t maxs, vec3_t outmins, vec3_t outmaxs );
|
||||||
void World_PortalCSG( edict_t *portal, const vec3_t trace_mins, const vec3_t trace_maxs, const vec3_t start, const vec3_t end, trace_t *trace );
|
|
||||||
trace_t World_CombineTraces( trace_t *cliptrace, trace_t *trace, edict_t *touch );
|
trace_t World_CombineTraces( trace_t *cliptrace, trace_t *trace, edict_t *touch );
|
||||||
int BoxOnPlaneSide( const vec3_t emins, const vec3_t emaxs, const mplane_t *p );
|
int BoxOnPlaneSide( const vec3_t emins, const vec3_t emaxs, const mplane_t *p );
|
||||||
int RankForContents( int contents );
|
int RankForContents( int contents );
|
||||||
|
|
|
@ -151,6 +151,10 @@ SOURCE=.\client\cl_cmds.c
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\client\cl_custom.c
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\client\cl_demo.c
|
SOURCE=.\client\cl_demo.c
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
@ -327,7 +331,7 @@ SOURCE=.\common\host.c
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\common\host_cmd.c
|
SOURCE=.\common\host_state.c
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
|
|
@ -152,6 +152,7 @@ typedef struct server_s
|
||||||
char files_precache[MAX_CUSTOM][MAX_QPATH];
|
char files_precache[MAX_CUSTOM][MAX_QPATH];
|
||||||
char event_precache[MAX_EVENTS][MAX_QPATH];
|
char event_precache[MAX_EVENTS][MAX_QPATH];
|
||||||
byte model_precache_flags[MAX_MODELS];
|
byte model_precache_flags[MAX_MODELS];
|
||||||
|
model_t *models[MAX_MODELS];
|
||||||
|
|
||||||
sv_static_entity_t static_entities[MAX_STATIC_ENTITIES];
|
sv_static_entity_t static_entities[MAX_STATIC_ENTITIES];
|
||||||
int num_static_entities;
|
int num_static_entities;
|
||||||
|
@ -188,7 +189,6 @@ typedef struct server_s
|
||||||
model_t *worldmodel; // pointer to world
|
model_t *worldmodel; // pointer to world
|
||||||
|
|
||||||
qboolean simulating;
|
qboolean simulating;
|
||||||
qboolean write_bad_message; // just for debug
|
|
||||||
qboolean paused;
|
qboolean paused;
|
||||||
} server_t;
|
} server_t;
|
||||||
|
|
||||||
|
@ -238,7 +238,6 @@ typedef struct sv_client_s
|
||||||
double cmdtime;
|
double cmdtime;
|
||||||
double ignorecmdtime;
|
double ignorecmdtime;
|
||||||
|
|
||||||
int modelindex; // custom playermodel index
|
|
||||||
int packet_loss;
|
int packet_loss;
|
||||||
float latency;
|
float latency;
|
||||||
|
|
||||||
|
@ -451,7 +450,6 @@ extern convar_t *sv_check_errors;
|
||||||
extern convar_t *sv_reconnect_limit;
|
extern convar_t *sv_reconnect_limit;
|
||||||
extern convar_t *sv_lighting_modulate;
|
extern convar_t *sv_lighting_modulate;
|
||||||
extern convar_t *hostname;
|
extern convar_t *hostname;
|
||||||
extern convar_t *sv_maxclients;
|
|
||||||
extern convar_t *sv_novis;
|
extern convar_t *sv_novis;
|
||||||
extern convar_t *sv_hostmap;
|
extern convar_t *sv_hostmap;
|
||||||
extern convar_t *sv_sendvelocity;
|
extern convar_t *sv_sendvelocity;
|
||||||
|
@ -487,11 +485,10 @@ void Master_Packet( void );
|
||||||
//
|
//
|
||||||
// sv_init.c
|
// sv_init.c
|
||||||
//
|
//
|
||||||
void SV_InitGame( void );
|
|
||||||
void SV_ActivateServer( void );
|
void SV_ActivateServer( void );
|
||||||
void SV_DeactivateServer( void );
|
|
||||||
void SV_LevelInit( const char *pMapName, char const *pOldLevel, char const *pLandmarkName, qboolean loadGame );
|
void SV_LevelInit( const char *pMapName, char const *pOldLevel, char const *pLandmarkName, qboolean loadGame );
|
||||||
qboolean SV_SpawnServer( const char *server, const char *startspot );
|
qboolean SV_SpawnServer( const char *server, const char *startspot, qboolean background );
|
||||||
|
model_t *SV_ModelHandle( int modelindex );
|
||||||
|
|
||||||
//
|
//
|
||||||
// sv_phys.c
|
// sv_phys.c
|
||||||
|
@ -648,7 +645,6 @@ void SV_ServerLog_f( sv_client_t *cl );
|
||||||
void SV_ClearSaveDir( void );
|
void SV_ClearSaveDir( void );
|
||||||
void SV_SaveGame( const char *pName );
|
void SV_SaveGame( const char *pName );
|
||||||
qboolean SV_LoadGame( const char *pName );
|
qboolean SV_LoadGame( const char *pName );
|
||||||
void SV_ChangeLevel( qboolean loadfromsavedgame, const char *mapname, const char *start );
|
|
||||||
int SV_LoadGameState( char const *level, qboolean createPlayers );
|
int SV_LoadGameState( char const *level, qboolean createPlayers );
|
||||||
void SV_LoadAdjacentEnts( const char *pOldLevel, const char *pLandmarkName );
|
void SV_LoadAdjacentEnts( const char *pOldLevel, const char *pLandmarkName );
|
||||||
const char *SV_GetLatestSave( void );
|
const char *SV_GetLatestSave( void );
|
||||||
|
|
|
@ -1782,26 +1782,6 @@ void SV_UserinfoChanged( sv_client_t *cl, const char *userinfo )
|
||||||
else cl->cl_updaterate = 0.0;
|
else cl->cl_updaterate = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( svs.maxclients > 1 )
|
|
||||||
{
|
|
||||||
const char *model = Info_ValueForKey( cl->userinfo, "model" );
|
|
||||||
|
|
||||||
// apply custom playermodel
|
|
||||||
if( Q_strlen( model ) && Q_stricmp( model, "player" ))
|
|
||||||
{
|
|
||||||
const char *path = va( "models/player/%s/%s.mdl", model, model );
|
|
||||||
if( FS_FileExists( path, false ))
|
|
||||||
{
|
|
||||||
Mod_RegisterModel( path, SV_ModelIndex( path )); // register model
|
|
||||||
SV_SetModel( ent, path );
|
|
||||||
cl->modelindex = ent->v.modelindex;
|
|
||||||
}
|
|
||||||
else cl->modelindex = 0;
|
|
||||||
}
|
|
||||||
else cl->modelindex = 0;
|
|
||||||
}
|
|
||||||
else cl->modelindex = 0;
|
|
||||||
|
|
||||||
// call prog code to allow overrides
|
// call prog code to allow overrides
|
||||||
svgame.dllFuncs.pfnClientUserInfoChanged( cl->edict, cl->userinfo );
|
svgame.dllFuncs.pfnClientUserInfoChanged( cl->edict, cl->userinfo );
|
||||||
|
|
||||||
|
@ -2248,6 +2228,7 @@ static void SV_ParseClientMove( sv_client_t *cl, sizebuf_t *msg )
|
||||||
usercmd_t cmds[CMD_BACKUP];
|
usercmd_t cmds[CMD_BACKUP];
|
||||||
float packet_loss;
|
float packet_loss;
|
||||||
edict_t *player;
|
edict_t *player;
|
||||||
|
model_t *model;
|
||||||
|
|
||||||
player = cl->edict;
|
player = cl->edict;
|
||||||
|
|
||||||
|
@ -2349,9 +2330,11 @@ static void SV_ParseClientMove( sv_client_t *cl, sizebuf_t *msg )
|
||||||
// the message probably arrived 1/2 through client's frame loop
|
// the message probably arrived 1/2 through client's frame loop
|
||||||
frame->ping_time -= ( cl->lastcmd.msec * 0.5f ) / 1000.0f;
|
frame->ping_time -= ( cl->lastcmd.msec * 0.5f ) / 1000.0f;
|
||||||
frame->ping_time = Q_max( 0.0f, frame->ping_time );
|
frame->ping_time = Q_max( 0.0f, frame->ping_time );
|
||||||
|
model = SV_ModelHandle( player->v.modelindex );
|
||||||
|
|
||||||
if( Mod_GetType( player->v.modelindex ) == mod_studio )
|
if( model && model->type == mod_studio )
|
||||||
{
|
{
|
||||||
|
// g-cont. yes we using svgame.globals->time instead of sv.time
|
||||||
if( player->v.animtime > svgame.globals->time + sv.frametime )
|
if( player->v.animtime > svgame.globals->time + sv.frametime )
|
||||||
player->v.animtime = svgame.globals->time + sv.frametime;
|
player->v.animtime = svgame.globals->time + sv.frametime;
|
||||||
}
|
}
|
||||||
|
|
|
@ -170,6 +170,46 @@ qboolean SV_SetPlayer( void )
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
==================
|
||||||
|
SV_ValidateMap
|
||||||
|
|
||||||
|
check map for typically errors
|
||||||
|
==================
|
||||||
|
*/
|
||||||
|
qboolean SV_ValidateMap( const char *pMapName, qboolean check_spawn )
|
||||||
|
{
|
||||||
|
char *spawn_entity;
|
||||||
|
int flags;
|
||||||
|
|
||||||
|
// determine spawn entity classname
|
||||||
|
if( !check_spawn || svs.maxclients == 1 )
|
||||||
|
spawn_entity = GI->sp_entity;
|
||||||
|
else spawn_entity = GI->mp_entity;
|
||||||
|
|
||||||
|
flags = SV_MapIsValid( pMapName, spawn_entity, NULL );
|
||||||
|
|
||||||
|
if( FBitSet( flags, MAP_INVALID_VERSION ))
|
||||||
|
{
|
||||||
|
MsgDev( D_ERROR, "map %s is invalid or not supported\n", pMapName );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !FBitSet( flags, MAP_IS_EXIST ))
|
||||||
|
{
|
||||||
|
MsgDev( D_ERROR, "map %s doesn't exist\n", pMapName );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( check_spawn && !FBitSet( flags, MAP_HAS_SPAWNPOINT ))
|
||||||
|
{
|
||||||
|
MsgDev( D_ERROR, "map %s doesn't have a valid spawnpoint\n", pMapName );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
==================
|
==================
|
||||||
SV_Map_f
|
SV_Map_f
|
||||||
|
@ -180,9 +220,7 @@ For development work
|
||||||
*/
|
*/
|
||||||
void SV_Map_f( void )
|
void SV_Map_f( void )
|
||||||
{
|
{
|
||||||
char *spawn_entity;
|
char mapname[MAX_QPATH];
|
||||||
string mapname;
|
|
||||||
int flags;
|
|
||||||
|
|
||||||
if( Cmd_Argc() != 2 )
|
if( Cmd_Argc() != 2 )
|
||||||
{
|
{
|
||||||
|
@ -194,48 +232,16 @@ void SV_Map_f( void )
|
||||||
Q_strncpy( mapname, Cmd_Argv( 1 ), sizeof( mapname ));
|
Q_strncpy( mapname, Cmd_Argv( 1 ), sizeof( mapname ));
|
||||||
FS_StripExtension( mapname );
|
FS_StripExtension( mapname );
|
||||||
|
|
||||||
// determine spawn entity classname
|
if( !SV_ValidateMap( mapname, true ))
|
||||||
if( svs.maxclients == 1 )
|
|
||||||
spawn_entity = GI->sp_entity;
|
|
||||||
else spawn_entity = GI->mp_entity;
|
|
||||||
|
|
||||||
flags = SV_MapIsValid( mapname, spawn_entity, NULL );
|
|
||||||
|
|
||||||
if( FBitSet( flags, MAP_INVALID_VERSION ))
|
|
||||||
{
|
|
||||||
MsgDev( D_ERROR, "map %s is invalid or not supported\n", mapname );
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if( !FBitSet( flags, MAP_IS_EXIST ))
|
|
||||||
{
|
|
||||||
MsgDev( D_ERROR, "map %s doesn't exist\n", mapname );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !FBitSet( flags, MAP_HAS_SPAWNPOINT ))
|
|
||||||
{
|
|
||||||
MsgDev( D_ERROR, "map %s doesn't have a valid spawnpoint\n", mapname );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// changing singleplayer to multiplayer or back. refresh the player count
|
// changing singleplayer to multiplayer or back. refresh the player count
|
||||||
if( FBitSet( sv_maxclients->flags, FCVAR_CHANGED ))
|
if( FBitSet( sv_maxclients->flags, FCVAR_CHANGED ))
|
||||||
Host_ShutdownServer();
|
Host_ShutdownServer();
|
||||||
|
|
||||||
SCR_BeginLoadingPlaque( false );
|
|
||||||
|
|
||||||
sv.changelevel = false;
|
|
||||||
sv.background = false;
|
|
||||||
sv.loadgame = false; // set right state
|
|
||||||
SV_ClearSaveDir (); // delete all temporary *.hl files
|
|
||||||
|
|
||||||
Cvar_DirectSet( sv_hostmap, mapname );
|
Cvar_DirectSet( sv_hostmap, mapname );
|
||||||
|
|
||||||
SV_DeactivateServer();
|
COM_LoadLevel( mapname, false );
|
||||||
SV_SpawnServer( mapname, NULL );
|
|
||||||
SV_LevelInit( mapname, NULL, NULL, false );
|
|
||||||
SV_ActivateServer ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -247,8 +253,7 @@ Set background map (enable physics in menu)
|
||||||
*/
|
*/
|
||||||
void SV_MapBackground_f( void )
|
void SV_MapBackground_f( void )
|
||||||
{
|
{
|
||||||
string mapname;
|
char mapname[MAX_QPATH];
|
||||||
int flags;
|
|
||||||
|
|
||||||
if( Cmd_Argc() != 2 )
|
if( Cmd_Argc() != 2 )
|
||||||
{
|
{
|
||||||
|
@ -266,42 +271,19 @@ void SV_MapBackground_f( void )
|
||||||
Q_strncpy( mapname, Cmd_Argv( 1 ), sizeof( mapname ));
|
Q_strncpy( mapname, Cmd_Argv( 1 ), sizeof( mapname ));
|
||||||
FS_StripExtension( mapname );
|
FS_StripExtension( mapname );
|
||||||
|
|
||||||
flags = SV_MapIsValid( mapname, GI->sp_entity, NULL );
|
if( !SV_ValidateMap( mapname, false ))
|
||||||
|
|
||||||
if( FBitSet( flags, MAP_INVALID_VERSION ))
|
|
||||||
{
|
|
||||||
MsgDev( D_ERROR, "map %s is invalid or not supported\n", mapname );
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if( !FBitSet( flags, MAP_IS_EXIST ))
|
|
||||||
{
|
|
||||||
MsgDev( D_ERROR, "map %s doesn't exist\n", mapname );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// background maps allow without spawnpoints (just throw warning)
|
|
||||||
if( !FBitSet( flags, MAP_HAS_SPAWNPOINT ))
|
|
||||||
MsgDev( D_WARN, "map %s doesn't have a valid spawnpoint\n", mapname );
|
|
||||||
|
|
||||||
Q_strncpy( host.finalmsg, "", MAX_STRING );
|
Q_strncpy( host.finalmsg, "", MAX_STRING );
|
||||||
SV_Shutdown( true );
|
SV_Shutdown( true );
|
||||||
NET_Config ( false ); // close network sockets
|
NET_Config( false ); // close network sockets
|
||||||
|
|
||||||
sv.changelevel = false;
|
|
||||||
sv.background = true;
|
|
||||||
sv.loadgame = false; // set right state
|
|
||||||
|
|
||||||
// reset all multiplayer cvars
|
// reset all multiplayer cvars
|
||||||
Cvar_FullSet( "maxplayers", "1", FCVAR_LATCH );
|
Cvar_FullSet( "maxplayers", "1", FCVAR_LATCH );
|
||||||
Cvar_SetValue( "deathmatch", 0 );
|
Cvar_SetValue( "deathmatch", 0 );
|
||||||
Cvar_SetValue( "coop", 0 );
|
Cvar_SetValue( "coop", 0 );
|
||||||
|
|
||||||
SCR_BeginLoadingPlaque( true );
|
COM_LoadLevel( mapname, true );
|
||||||
|
|
||||||
SV_SpawnServer( mapname, NULL );
|
|
||||||
SV_LevelInit( mapname, NULL, NULL, false );
|
|
||||||
SV_ActivateServer ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -318,7 +300,7 @@ void SV_NewGame_f( void )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Host_NewGame( GI->startmap, false );
|
COM_NewGame( GI->startmap );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -339,9 +321,9 @@ void SV_HazardCourse_f( void )
|
||||||
if( FS_FileExists( va( "media/%s.avi", GI->trainmap ), false ))
|
if( FS_FileExists( va( "media/%s.avi", GI->trainmap ), false ))
|
||||||
{
|
{
|
||||||
Cbuf_AddText( va( "wait; movie %s\n", GI->trainmap ));
|
Cbuf_AddText( va( "wait; movie %s\n", GI->trainmap ));
|
||||||
Host_EndGame( "The End" );
|
Host_EndGame( true, DEFAULT_ENDGAME_MESSAGE );
|
||||||
}
|
}
|
||||||
else Host_NewGame( GI->trainmap, false );
|
else COM_NewGame( GI->trainmap );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -529,17 +511,11 @@ void SV_ChangeLevel_f( void )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SCR_BeginLoadingPlaque( false );
|
|
||||||
|
|
||||||
if( sv.background )
|
if( sv.background )
|
||||||
{
|
COM_LoadLevel( mapname, false );
|
||||||
// just load map
|
else if( c == 2 )
|
||||||
Cbuf_AddText( va( "map %s\n", mapname ));
|
COM_ChangeLevel( Cmd_Argv( 1 ), NULL );
|
||||||
return;
|
else COM_ChangeLevel( Cmd_Argv( 1 ), Cmd_Argv( 2 ));
|
||||||
}
|
|
||||||
|
|
||||||
if( c == 2 ) SV_ChangeLevel( false, Cmd_Argv( 1 ), NULL );
|
|
||||||
else SV_ChangeLevel( true, Cmd_Argv( 1 ), Cmd_Argv( 2 ));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -554,15 +530,7 @@ void SV_Restart_f( void )
|
||||||
if( sv.state != ss_active )
|
if( sv.state != ss_active )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// just sending console command
|
COM_LoadLevel( sv.name, sv.background );
|
||||||
if( sv.background )
|
|
||||||
{
|
|
||||||
Cbuf_AddText( va( "map_background %s\n", sv.name ));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Cbuf_AddText( va( "map %s\n", sv.name ));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -574,15 +542,8 @@ continue from latest savedgame
|
||||||
*/
|
*/
|
||||||
void SV_Reload_f( void )
|
void SV_Reload_f( void )
|
||||||
{
|
{
|
||||||
const char *savefile;
|
if( !SV_LoadGame( SV_GetLatestSave( )))
|
||||||
|
COM_LoadLevel( sv_hostmap->string, false );
|
||||||
if( sv.state != ss_active || sv.background )
|
|
||||||
return;
|
|
||||||
|
|
||||||
savefile = SV_GetLatestSave();
|
|
||||||
|
|
||||||
if( savefile ) SV_LoadGame( savefile );
|
|
||||||
else SV_NewGame( sv_hostmap->string, false );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -117,12 +117,6 @@ static void SV_AddEntitiesToPacket( edict_t *pViewEnt, edict_t *pClient, client_
|
||||||
// to prevent adds it twice through portals
|
// to prevent adds it twice through portals
|
||||||
SETVISBIT( ents->sended, e );
|
SETVISBIT( ents->sended, e );
|
||||||
|
|
||||||
if( netclient && netclient->modelindex )
|
|
||||||
{
|
|
||||||
// update playermodel if this was changed
|
|
||||||
state->modelindex = netclient->modelindex;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( SV_IsValidEdict( ent->v.aiment ) && FBitSet( ent->v.aiment->v.effects, EF_MERGE_VISIBILITY ))
|
if( SV_IsValidEdict( ent->v.aiment ) && FBitSet( ent->v.aiment->v.effects, EF_MERGE_VISIBILITY ))
|
||||||
{
|
{
|
||||||
if( cl != NULL && cl->num_viewents < MAX_VIEWENTS )
|
if( cl != NULL && cl->num_viewents < MAX_VIEWENTS )
|
||||||
|
@ -764,16 +758,6 @@ void SV_UpdateToReliableMessages( void )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1% chanse for simulate random network bugs
|
|
||||||
if( sv.write_bad_message && COM_RandomLong( 0, 512 ) == 404 )
|
|
||||||
{
|
|
||||||
// just for network debugging (send only for local client)
|
|
||||||
MSG_BeginServerCmd( &sv.reliable_datagram, svc_bad );
|
|
||||||
MSG_WriteLong( &sv.reliable_datagram, COM_RandomLong( 1, 65536 )); // send some random data
|
|
||||||
MSG_WriteString( &sv.reliable_datagram, host.finalmsg ); // send final message
|
|
||||||
sv.write_bad_message = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// clear the server datagram if it overflowed.
|
// clear the server datagram if it overflowed.
|
||||||
if( MSG_CheckOverflow( &sv.datagram ))
|
if( MSG_CheckOverflow( &sv.datagram ))
|
||||||
{
|
{
|
||||||
|
@ -997,5 +981,7 @@ void SV_InactivateClients( void )
|
||||||
|
|
||||||
// clear netchan message (but keep other buffers)
|
// clear netchan message (but keep other buffers)
|
||||||
MSG_Clear( &cl->netchan.message );
|
MSG_Clear( &cl->netchan.message );
|
||||||
|
MSG_Clear( &cl->datagram );
|
||||||
|
COM_ClearCustomizationList( &cl->customdata, false );
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -105,7 +105,7 @@ void SV_SetMinMaxSize( edict_t *e, const float *min, const float *max, qboolean
|
||||||
if( min[i] > max[i] )
|
if( min[i] > max[i] )
|
||||||
{
|
{
|
||||||
MsgDev( D_ERROR, "SV_SetMinMaxSize: %s backwards mins/maxs\n", SV_ClassName( e ));
|
MsgDev( D_ERROR, "SV_SetMinMaxSize: %s backwards mins/maxs\n", SV_ClassName( e ));
|
||||||
SV_LinkEdict( e, false ); // just relink edict and exit
|
if( relink ) SV_LinkEdict( e, false ); // just relink edict and exit
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -137,27 +137,29 @@ void SV_CopyTraceToGlobal( trace_t *trace )
|
||||||
|
|
||||||
void SV_SetModel( edict_t *ent, const char *name )
|
void SV_SetModel( edict_t *ent, const char *name )
|
||||||
{
|
{
|
||||||
vec3_t mins = { 0.0f, 0.0f, 0.0f };
|
model_t *mod;
|
||||||
vec3_t maxs = { 0.0f, 0.0f, 0.0f };
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
i = SV_ModelIndex( name );
|
// check to see if model was properly precached
|
||||||
if( i == 0 ) return;
|
for( i = 1; i < MAX_MODELS && sv.model_precache[i][0]; i++ )
|
||||||
|
|
||||||
ent->v.model = MAKE_STRING( sv.model_precache[i] );
|
|
||||||
ent->v.modelindex = i;
|
|
||||||
|
|
||||||
// studio models will be ignored here
|
|
||||||
switch( Mod_GetType( ent->v.modelindex ))
|
|
||||||
{
|
{
|
||||||
case mod_alias:
|
if( !Q_stricmp( sv.model_precache[i], name ))
|
||||||
case mod_brush:
|
|
||||||
case mod_sprite:
|
|
||||||
Mod_GetBounds( ent->v.modelindex, mins, maxs );
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
SV_SetMinMaxSize( ent, mins, maxs, true );
|
if( i == MAX_MODELS )
|
||||||
|
{
|
||||||
|
MsgDev( D_ERROR, "SetModel: %s not precached\n", name );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ent->v.model = MAKE_STRING( sv.model_precache[i] );
|
||||||
|
ent->v.modelindex = i;
|
||||||
|
mod = sv.models[i];
|
||||||
|
|
||||||
|
// set the model size
|
||||||
|
if( mod ) SV_SetMinMaxSize( ent, mod->mins, mod->maxs, true );
|
||||||
|
else SV_SetMinMaxSize( ent, vec3_origin, vec3_origin, true );
|
||||||
}
|
}
|
||||||
|
|
||||||
float SV_AngleMod( float ideal, float current, float speed )
|
float SV_AngleMod( float ideal, float current, float speed )
|
||||||
|
@ -1022,7 +1024,7 @@ pfnPrecacheModel
|
||||||
int pfnPrecacheModel( const char *s )
|
int pfnPrecacheModel( const char *s )
|
||||||
{
|
{
|
||||||
qboolean optional = false;
|
qboolean optional = false;
|
||||||
int modelIndex;
|
int i;
|
||||||
|
|
||||||
if( *s == '!' )
|
if( *s == '!' )
|
||||||
{
|
{
|
||||||
|
@ -1030,13 +1032,13 @@ int pfnPrecacheModel( const char *s )
|
||||||
*s++;
|
*s++;
|
||||||
}
|
}
|
||||||
|
|
||||||
modelIndex = SV_ModelIndex( s );
|
i = SV_ModelIndex( s );
|
||||||
Mod_RegisterModel( s, modelIndex );
|
sv.models[i] = Mod_ForName( s, false, true );
|
||||||
|
|
||||||
if( !optional )
|
if( !optional )
|
||||||
SetBits( sv.model_precache_flags[modelIndex], RES_FATALIFMISSING );
|
SetBits( sv.model_precache_flags[i], RES_FATALIFMISSING );
|
||||||
|
|
||||||
return modelIndex;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1100,11 +1102,11 @@ pfnModelFrames
|
||||||
*/
|
*/
|
||||||
int pfnModelFrames( int modelIndex )
|
int pfnModelFrames( int modelIndex )
|
||||||
{
|
{
|
||||||
int numFrames = 0;
|
model_t *pmodel = SV_ModelHandle( modelIndex );
|
||||||
|
|
||||||
Mod_GetFrames( modelIndex, &numFrames );
|
if( pmodel != NULL )
|
||||||
|
return pmodel->numframes;
|
||||||
return numFrames;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1473,7 +1475,7 @@ edict_t* pfnFindClientInPVS( edict_t *pEdict )
|
||||||
if( !SV_ClientFromEdict( pClient, true ))
|
if( !SV_ClientFromEdict( pClient, true ))
|
||||||
return svgame.edicts;
|
return svgame.edicts;
|
||||||
|
|
||||||
mod = Mod_Handle( pEdict->v.modelindex );
|
mod = SV_ModelHandle( pEdict->v.modelindex );
|
||||||
|
|
||||||
// portals & monitors
|
// portals & monitors
|
||||||
// NOTE: this specific break "radiaton tick" in normal half-life. use only as feature
|
// NOTE: this specific break "radiaton tick" in normal half-life. use only as feature
|
||||||
|
@ -2122,6 +2124,7 @@ pfnTraceModel
|
||||||
static void pfnTraceModel( const float *v1, const float *v2, int hullNumber, edict_t *pent, TraceResult *ptr )
|
static void pfnTraceModel( const float *v1, const float *v2, int hullNumber, edict_t *pent, TraceResult *ptr )
|
||||||
{
|
{
|
||||||
float *mins, *maxs;
|
float *mins, *maxs;
|
||||||
|
model_t *model;
|
||||||
trace_t trace;
|
trace_t trace;
|
||||||
|
|
||||||
if( !ptr ) return;
|
if( !ptr ) return;
|
||||||
|
@ -2137,6 +2140,7 @@ static void pfnTraceModel( const float *v1, const float *v2, int hullNumber, edi
|
||||||
|
|
||||||
mins = sv.worldmodel->hulls[hullNumber].clip_mins;
|
mins = sv.worldmodel->hulls[hullNumber].clip_mins;
|
||||||
maxs = sv.worldmodel->hulls[hullNumber].clip_maxs;
|
maxs = sv.worldmodel->hulls[hullNumber].clip_maxs;
|
||||||
|
model = SV_ModelHandle( pent->v.modelindex );
|
||||||
|
|
||||||
if( pent->v.solid == SOLID_CUSTOM )
|
if( pent->v.solid == SOLID_CUSTOM )
|
||||||
{
|
{
|
||||||
|
@ -2144,7 +2148,7 @@ static void pfnTraceModel( const float *v1, const float *v2, int hullNumber, edi
|
||||||
// even if our callbacks is not initialized
|
// even if our callbacks is not initialized
|
||||||
SV_CustomClipMoveToEntity( pent, v1, mins, maxs, v2, &trace );
|
SV_CustomClipMoveToEntity( pent, v1, mins, maxs, v2, &trace );
|
||||||
}
|
}
|
||||||
else if( Mod_GetType( pent->v.modelindex ) == mod_brush )
|
else if( model && model->type == mod_brush )
|
||||||
{
|
{
|
||||||
int oldmovetype = pent->v.movetype;
|
int oldmovetype = pent->v.movetype;
|
||||||
int oldsolid = pent->v.solid;
|
int oldsolid = pent->v.solid;
|
||||||
|
@ -3080,7 +3084,7 @@ static void *pfnGetModelPtr( edict_t *pEdict )
|
||||||
if( !SV_IsValidEdict( pEdict ))
|
if( !SV_IsValidEdict( pEdict ))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
mod = Mod_Handle( pEdict->v.modelindex );
|
mod = SV_ModelHandle( pEdict->v.modelindex );
|
||||||
return Mod_StudioExtradata( mod );
|
return Mod_StudioExtradata( mod );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4786,6 +4790,7 @@ void SV_UnloadProgs( void )
|
||||||
{
|
{
|
||||||
SV_DeactivateServer ();
|
SV_DeactivateServer ();
|
||||||
Delta_Shutdown ();
|
Delta_Shutdown ();
|
||||||
|
Mod_ClearUserData ();
|
||||||
|
|
||||||
Mem_FreePool( &svgame.stringspool );
|
Mem_FreePool( &svgame.stringspool );
|
||||||
|
|
||||||
|
|
|
@ -23,40 +23,6 @@ server_t sv; // local server
|
||||||
server_static_t svs; // persistant server info
|
server_static_t svs; // persistant server info
|
||||||
svgame_static_t svgame; // persistant game info
|
svgame_static_t svgame; // persistant game info
|
||||||
|
|
||||||
const char *check_exts[7] =
|
|
||||||
{
|
|
||||||
".cfg",
|
|
||||||
".lst",
|
|
||||||
".exe",
|
|
||||||
".vbs",
|
|
||||||
".com",
|
|
||||||
".bat",
|
|
||||||
".dll",
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
================
|
|
||||||
SV_IsGenericFileAllowed
|
|
||||||
|
|
||||||
some files is not allowed to be sended to client
|
|
||||||
================
|
|
||||||
*/
|
|
||||||
qboolean SV_IsGenericFileAllowed( const char *filename )
|
|
||||||
{
|
|
||||||
const char *ext = FS_FileExtension( filename );
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for( i = 0; i < ARRAYSIZE( check_exts ); i++ )
|
|
||||||
{
|
|
||||||
if( !Q_stricmp( ext, check_exts[i] ))
|
|
||||||
{
|
|
||||||
MsgDev( D_WARN, "Can't precache %s files: %s\n", check_exts[i], filename );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
================
|
================
|
||||||
SV_ModelIndex
|
SV_ModelIndex
|
||||||
|
@ -69,7 +35,7 @@ int SV_ModelIndex( const char *filename )
|
||||||
char name[64];
|
char name[64];
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if( !filename || !filename[0] )
|
if( !COM_CheckString( filename ))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
Q_strncpy( name, filename, sizeof( name ));
|
Q_strncpy( name, filename, sizeof( name ));
|
||||||
|
@ -116,7 +82,7 @@ int SV_SoundIndex( const char *filename )
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
// don't precache sentence names!
|
// don't precache sentence names!
|
||||||
if( !filename || !filename[0] || filename[0] == '!' )
|
if( !COM_CheckString( filename ))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
Q_strncpy( name, filename, sizeof( name ));
|
Q_strncpy( name, filename, sizeof( name ));
|
||||||
|
@ -162,7 +128,7 @@ int SV_EventIndex( const char *filename )
|
||||||
char name[64];
|
char name[64];
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if( !filename || !filename[0] )
|
if( !COM_CheckString( filename ))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
Q_strncpy( name, filename, sizeof( name ));
|
Q_strncpy( name, filename, sizeof( name ));
|
||||||
|
@ -206,7 +172,7 @@ int SV_GenericIndex( const char *filename )
|
||||||
char name[64];
|
char name[64];
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if( !filename || !filename[0] )
|
if( !COM_CheckString( filename ))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
Q_strncpy( name, filename, sizeof( name ));
|
Q_strncpy( name, filename, sizeof( name ));
|
||||||
|
@ -237,6 +203,20 @@ int SV_GenericIndex( const char *filename )
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
SV_ModelHandle
|
||||||
|
|
||||||
|
register unique model for a server and client
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
model_t *SV_ModelHandle( int modelindex )
|
||||||
|
{
|
||||||
|
if( modelindex < 0 || modelindex >= MAX_MODELS )
|
||||||
|
return NULL;
|
||||||
|
return sv.models[modelindex];
|
||||||
|
}
|
||||||
|
|
||||||
void SV_AddResource( resourcetype_t type, const char *name, int size, byte flags, int index )
|
void SV_AddResource( resourcetype_t type, const char *name, int size, byte flags, int index )
|
||||||
{
|
{
|
||||||
resource_t *pResource = &sv.resources[sv.num_resources];
|
resource_t *pResource = &sv.resources[sv.num_resources];
|
||||||
|
@ -272,28 +252,7 @@ void SV_CreateGenericResources( void )
|
||||||
|
|
||||||
while( ( pfile = COM_ParseFile( pfile, token )) != NULL )
|
while( ( pfile = COM_ParseFile( pfile, token )) != NULL )
|
||||||
{
|
{
|
||||||
if( Q_strlen( token ) <= 0 )
|
if( !COM_IsSafeFileToDownload( token ))
|
||||||
break;
|
|
||||||
|
|
||||||
if ( Q_strstr( token, ".." ) )
|
|
||||||
{
|
|
||||||
Con_Printf( "Can't precache resource with invalid relative path %s\n", token );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( Q_strstr( token, ":" ) )
|
|
||||||
{
|
|
||||||
Con_Printf( "Can't precache resource with absolute path %s\n", token );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( Q_strstr( token, "\\" ) )
|
|
||||||
{
|
|
||||||
Con_Printf( "Can't precache resource with invalid relative path %s\n", token );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !SV_IsGenericFileAllowed( token ))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
MsgDev( D_REPORT, " %s\n", token );
|
MsgDev( D_REPORT, " %s\n", token );
|
||||||
|
@ -427,7 +386,10 @@ void SV_CreateBaseline( void )
|
||||||
qboolean player;
|
qboolean player;
|
||||||
int entnum;
|
int entnum;
|
||||||
|
|
||||||
playermodel = SV_ModelIndex( "models/player.mdl" );
|
if( FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
|
||||||
|
playermodel = SV_ModelIndex( DEFAULT_PLAYER_PATH_QUAKE );
|
||||||
|
else playermodel = SV_ModelIndex( DEFAULT_PLAYER_PATH_HALFLIFE );
|
||||||
|
|
||||||
memset( &nullstate, 0, sizeof( nullstate ));
|
memset( &nullstate, 0, sizeof( nullstate ));
|
||||||
|
|
||||||
for( entnum = 0; entnum < svgame.numEntities; entnum++ )
|
for( entnum = 0; entnum < svgame.numEntities; entnum++ )
|
||||||
|
@ -648,8 +610,7 @@ void SV_DeactivateServer( void )
|
||||||
if( !svs.initialized || sv.state == ss_dead )
|
if( !svs.initialized || sv.state == ss_dead )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
sv.state = ss_dead;
|
svgame.globals->time = sv.time;
|
||||||
|
|
||||||
svgame.dllFuncs.pfnServerDeactivate();
|
svgame.dllFuncs.pfnServerDeactivate();
|
||||||
|
|
||||||
SV_FreeEdicts ();
|
SV_FreeEdicts ();
|
||||||
|
@ -671,6 +632,12 @@ void SV_DeactivateServer( void )
|
||||||
svgame.numEntities = svgame.globals->maxClients + 1; // clients + world
|
svgame.numEntities = svgame.globals->maxClients + 1; // clients + world
|
||||||
svgame.globals->startspot = 0;
|
svgame.globals->startspot = 0;
|
||||||
svgame.globals->mapname = 0;
|
svgame.globals->mapname = 0;
|
||||||
|
|
||||||
|
// clear states
|
||||||
|
sv.changelevel = false;
|
||||||
|
sv.background = false;
|
||||||
|
sv.loadgame = false;
|
||||||
|
sv.state = ss_dead;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -721,130 +688,6 @@ void SV_LevelInit( const char *pMapName, char const *pOldLevel, char const *pLan
|
||||||
SV_FreeOldEntities ();
|
SV_FreeOldEntities ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
================
|
|
||||||
SV_SpawnServer
|
|
||||||
|
|
||||||
Change the server to a new map, taking all connected
|
|
||||||
clients along with it.
|
|
||||||
================
|
|
||||||
*/
|
|
||||||
qboolean SV_SpawnServer( const char *mapname, const char *startspot )
|
|
||||||
{
|
|
||||||
int i, current_skill;
|
|
||||||
qboolean loadgame, paused;
|
|
||||||
qboolean background, changelevel;
|
|
||||||
|
|
||||||
// save state
|
|
||||||
loadgame = sv.loadgame;
|
|
||||||
background = sv.background;
|
|
||||||
changelevel = sv.changelevel;
|
|
||||||
paused = sv.paused;
|
|
||||||
|
|
||||||
if( sv.state == ss_dead )
|
|
||||||
SV_InitGame(); // the game is just starting
|
|
||||||
|
|
||||||
NET_Config(( svs.maxclients > 1 )); // init network stuff
|
|
||||||
ClearBits( sv_maxclients->flags, FCVAR_CHANGED );
|
|
||||||
|
|
||||||
if( !svs.initialized )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Log_Open();
|
|
||||||
Log_Printf( "Loading map \"%s\"\n", mapname );
|
|
||||||
Log_PrintServerVars();
|
|
||||||
|
|
||||||
svgame.globals->changelevel = false; // will be restored later if needed
|
|
||||||
svs.timestart = Sys_DoubleTime();
|
|
||||||
svs.spawncount++; // any partially connected client will be restarted
|
|
||||||
|
|
||||||
if( startspot )
|
|
||||||
{
|
|
||||||
MsgDev( D_INFO, "Spawn Server: %s [%s]\n", mapname, startspot );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MsgDev( D_INFO, "Spawn Server: %s\n", mapname );
|
|
||||||
}
|
|
||||||
|
|
||||||
sv.state = ss_dead;
|
|
||||||
Host_SetServerState( sv.state );
|
|
||||||
memset( &sv, 0, sizeof( sv )); // wipe the entire per-level structure
|
|
||||||
|
|
||||||
// restore state
|
|
||||||
sv.paused = paused;
|
|
||||||
sv.loadgame = loadgame;
|
|
||||||
sv.background = background;
|
|
||||||
sv.changelevel = changelevel;
|
|
||||||
sv.time = 1.0f; // server spawn time it's always 1.0 second
|
|
||||||
svgame.globals->time = sv.time;
|
|
||||||
|
|
||||||
// initialize buffers
|
|
||||||
MSG_Init( &sv.signon, "Signon", sv.signon_buf, sizeof( sv.signon_buf ));
|
|
||||||
MSG_Init( &sv.multicast, "Multicast", sv.multicast_buf, sizeof( sv.multicast_buf ));
|
|
||||||
MSG_Init( &sv.datagram, "Datagram", sv.datagram_buf, sizeof( sv.datagram_buf ));
|
|
||||||
MSG_Init( &sv.reliable_datagram, "Reliable Datagram", sv.reliable_datagram_buf, sizeof( sv.reliable_datagram_buf ));
|
|
||||||
MSG_Init( &sv.spec_datagram, "Spectator Datagram", sv.spectator_buf, sizeof( sv.spectator_buf ));
|
|
||||||
|
|
||||||
// leave slots at start for clients only
|
|
||||||
for( i = 0; i < svs.maxclients; i++ )
|
|
||||||
{
|
|
||||||
// needs to reconnect
|
|
||||||
if( svs.clients[i].state > cs_connected )
|
|
||||||
svs.clients[i].state = cs_connected;
|
|
||||||
}
|
|
||||||
|
|
||||||
// make cvars consistant
|
|
||||||
if( coop.value ) Cvar_SetValue( "deathmatch", 0 );
|
|
||||||
current_skill = Q_rint( skill.value );
|
|
||||||
current_skill = bound( 0, current_skill, 3 );
|
|
||||||
|
|
||||||
Cvar_SetValue( "skill", (float)current_skill );
|
|
||||||
|
|
||||||
if( sv.background )
|
|
||||||
{
|
|
||||||
// tell the game parts about background state
|
|
||||||
Cvar_FullSet( "sv_background", "1", FCVAR_READ_ONLY );
|
|
||||||
Cvar_FullSet( "cl_background", "1", FCVAR_READ_ONLY );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Cvar_FullSet( "sv_background", "0", FCVAR_READ_ONLY );
|
|
||||||
Cvar_FullSet( "cl_background", "0", FCVAR_READ_ONLY );
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure what server name doesn't contain path and extension
|
|
||||||
FS_FileBase( mapname, sv.name );
|
|
||||||
|
|
||||||
if( startspot )
|
|
||||||
Q_strncpy( sv.startspot, startspot, sizeof( sv.startspot ));
|
|
||||||
else sv.startspot[0] = '\0';
|
|
||||||
|
|
||||||
Q_snprintf( sv.model_precache[1], sizeof( sv.model_precache[0] ), "maps/%s.bsp", sv.name );
|
|
||||||
SetBits( sv.model_precache_flags[1], RES_FATALIFMISSING );
|
|
||||||
Mod_LoadWorld( sv.model_precache[1], NS_SERVER );
|
|
||||||
sv.worldmodel = Mod_Handle( 1 ); // get world pointer
|
|
||||||
|
|
||||||
CRC32_MapFile( &sv.worldmapCRC, sv.model_precache[1], svs.maxclients > 1 );
|
|
||||||
|
|
||||||
for( i = 1; i < sv.worldmodel->numsubmodels; i++ )
|
|
||||||
{
|
|
||||||
SetBits( sv.model_precache_flags[i+1], RES_FATALIFMISSING );
|
|
||||||
Q_sprintf( sv.model_precache[i+1], "*%i", i );
|
|
||||||
Mod_RegisterModel( sv.model_precache[i+1], i+1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
// precache and static commands can be issued during map initialization
|
|
||||||
sv.state = ss_loading;
|
|
||||||
|
|
||||||
Host_SetServerState( sv.state );
|
|
||||||
|
|
||||||
// clear physics interaction links
|
|
||||||
SV_ClearWorld();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
==============
|
==============
|
||||||
SV_InitGame
|
SV_InitGame
|
||||||
|
@ -932,6 +775,127 @@ void SV_InitGame( void )
|
||||||
svs.initialized = true;
|
svs.initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
SV_SpawnServer
|
||||||
|
|
||||||
|
Change the server to a new map, taking all connected
|
||||||
|
clients along with it.
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
qboolean SV_SpawnServer( const char *mapname, const char *startspot, qboolean background )
|
||||||
|
{
|
||||||
|
int i, current_skill;
|
||||||
|
qboolean loadgame, paused;
|
||||||
|
qboolean changelevel;
|
||||||
|
|
||||||
|
// save state
|
||||||
|
loadgame = sv.loadgame;
|
||||||
|
changelevel = sv.changelevel;
|
||||||
|
paused = sv.paused;
|
||||||
|
|
||||||
|
if( sv.state == ss_dead )
|
||||||
|
SV_InitGame(); // the game is just starting
|
||||||
|
|
||||||
|
NET_Config(( svs.maxclients > 1 )); // init network stuff
|
||||||
|
ClearBits( sv_maxclients->flags, FCVAR_CHANGED );
|
||||||
|
|
||||||
|
if( !svs.initialized )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Log_Open();
|
||||||
|
Log_Printf( "Loading map \"%s\"\n", mapname );
|
||||||
|
Log_PrintServerVars();
|
||||||
|
|
||||||
|
svgame.globals->changelevel = false; // will be restored later if needed
|
||||||
|
svs.timestart = Sys_DoubleTime();
|
||||||
|
svs.spawncount++; // any partially connected client will be restarted
|
||||||
|
|
||||||
|
if( startspot )
|
||||||
|
{
|
||||||
|
MsgDev( D_INFO, "Spawn Server: %s [%s]\n", mapname, startspot );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MsgDev( D_INFO, "Spawn Server: %s\n", mapname );
|
||||||
|
}
|
||||||
|
|
||||||
|
sv.state = ss_dead;
|
||||||
|
Host_SetServerState( sv.state );
|
||||||
|
memset( &sv, 0, sizeof( sv )); // wipe the entire per-level structure
|
||||||
|
|
||||||
|
// restore state
|
||||||
|
sv.paused = paused;
|
||||||
|
sv.loadgame = loadgame;
|
||||||
|
sv.background = background;
|
||||||
|
sv.changelevel = changelevel;
|
||||||
|
sv.time = 1.0f; // server spawn time it's always 1.0 second
|
||||||
|
svgame.globals->time = sv.time;
|
||||||
|
|
||||||
|
// initialize buffers
|
||||||
|
MSG_Init( &sv.signon, "Signon", sv.signon_buf, sizeof( sv.signon_buf ));
|
||||||
|
MSG_Init( &sv.multicast, "Multicast", sv.multicast_buf, sizeof( sv.multicast_buf ));
|
||||||
|
MSG_Init( &sv.datagram, "Datagram", sv.datagram_buf, sizeof( sv.datagram_buf ));
|
||||||
|
MSG_Init( &sv.reliable_datagram, "Reliable Datagram", sv.reliable_datagram_buf, sizeof( sv.reliable_datagram_buf ));
|
||||||
|
MSG_Init( &sv.spec_datagram, "Spectator Datagram", sv.spectator_buf, sizeof( sv.spectator_buf ));
|
||||||
|
|
||||||
|
// leave slots at start for clients only
|
||||||
|
for( i = 0; i < svs.maxclients; i++ )
|
||||||
|
{
|
||||||
|
// needs to reconnect
|
||||||
|
if( svs.clients[i].state > cs_connected )
|
||||||
|
svs.clients[i].state = cs_connected;
|
||||||
|
}
|
||||||
|
|
||||||
|
// make cvars consistant
|
||||||
|
if( coop.value ) Cvar_SetValue( "deathmatch", 0 );
|
||||||
|
current_skill = Q_rint( skill.value );
|
||||||
|
current_skill = bound( 0, current_skill, 3 );
|
||||||
|
|
||||||
|
Cvar_SetValue( "skill", (float)current_skill );
|
||||||
|
|
||||||
|
if( sv.background )
|
||||||
|
{
|
||||||
|
// tell the game parts about background state
|
||||||
|
Cvar_FullSet( "sv_background", "1", FCVAR_READ_ONLY );
|
||||||
|
Cvar_FullSet( "cl_background", "1", FCVAR_READ_ONLY );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Cvar_FullSet( "sv_background", "0", FCVAR_READ_ONLY );
|
||||||
|
Cvar_FullSet( "cl_background", "0", FCVAR_READ_ONLY );
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure what server name doesn't contain path and extension
|
||||||
|
FS_FileBase( mapname, sv.name );
|
||||||
|
|
||||||
|
if( startspot )
|
||||||
|
Q_strncpy( sv.startspot, startspot, sizeof( sv.startspot ));
|
||||||
|
else sv.startspot[0] = '\0';
|
||||||
|
|
||||||
|
Q_snprintf( sv.model_precache[WORLD_INDEX], sizeof( sv.model_precache[0] ), "maps/%s.bsp", sv.name );
|
||||||
|
SetBits( sv.model_precache_flags[WORLD_INDEX], RES_FATALIFMISSING );
|
||||||
|
sv.worldmodel = sv.models[WORLD_INDEX] = Mod_LoadWorld( sv.model_precache[WORLD_INDEX], true );
|
||||||
|
CRC32_MapFile( &sv.worldmapCRC, sv.model_precache[WORLD_INDEX], svs.maxclients > 1 );
|
||||||
|
|
||||||
|
for( i = WORLD_INDEX; i < sv.worldmodel->numsubmodels; i++ )
|
||||||
|
{
|
||||||
|
Q_sprintf( sv.model_precache[i+1], "*%i", i );
|
||||||
|
sv.models[i+1] = Mod_ForName( sv.model_precache[i+1], false, false );
|
||||||
|
SetBits( sv.model_precache_flags[i+1], RES_FATALIFMISSING );
|
||||||
|
}
|
||||||
|
|
||||||
|
// precache and static commands can be issued during map initialization
|
||||||
|
sv.state = ss_loading;
|
||||||
|
|
||||||
|
Host_SetServerState( sv.state );
|
||||||
|
|
||||||
|
// clear physics interaction links
|
||||||
|
SV_ClearWorld();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
qboolean SV_Active( void )
|
qboolean SV_Active( void )
|
||||||
{
|
{
|
||||||
return svs.initialized;
|
return svs.initialized;
|
||||||
|
@ -942,13 +906,6 @@ int SV_GetMaxClients( void )
|
||||||
return svs.maxclients;
|
return svs.maxclients;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SV_ForceError( void )
|
|
||||||
{
|
|
||||||
// this is only for singleplayer testing
|
|
||||||
if( svs.maxclients != 1 ) return;
|
|
||||||
sv.write_bad_message = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SV_InitGameProgs( void )
|
void SV_InitGameProgs( void )
|
||||||
{
|
{
|
||||||
if( svgame.hInstance ) return; // already loaded
|
if( svgame.hInstance ) return; // already loaded
|
||||||
|
@ -964,39 +921,3 @@ void SV_FreeGameProgs( void )
|
||||||
// unload progs (free cvars and commands)
|
// unload progs (free cvars and commands)
|
||||||
SV_UnloadProgs();
|
SV_UnloadProgs();
|
||||||
}
|
}
|
||||||
|
|
||||||
qboolean SV_NewGame( const char *mapName, qboolean loadGame )
|
|
||||||
{
|
|
||||||
if( !loadGame )
|
|
||||||
{
|
|
||||||
if( !SV_MapIsValid( mapName, GI->sp_entity, NULL ))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
SV_ClearSaveDir ();
|
|
||||||
SV_Shutdown( true );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
S_StopAllSounds (true);
|
|
||||||
SV_DeactivateServer ();
|
|
||||||
}
|
|
||||||
|
|
||||||
sv.loadgame = loadGame;
|
|
||||||
sv.background = false;
|
|
||||||
sv.changelevel = false;
|
|
||||||
|
|
||||||
SCR_BeginLoadingPlaque( false );
|
|
||||||
|
|
||||||
if( !SV_SpawnServer( mapName, NULL ))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
SV_LevelInit( mapName, NULL, NULL, loadGame );
|
|
||||||
sv.loadgame = loadGame;
|
|
||||||
|
|
||||||
SV_ActivateServer();
|
|
||||||
|
|
||||||
if( sv.state != ss_active )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
|
@ -765,14 +765,18 @@ qboolean SV_AllowPushRotate( edict_t *ent )
|
||||||
{
|
{
|
||||||
model_t *mod;
|
model_t *mod;
|
||||||
|
|
||||||
mod = Mod_Handle( ent->v.modelindex );
|
mod = SV_ModelHandle( ent->v.modelindex );
|
||||||
|
|
||||||
if( !mod || mod->type != mod_brush )
|
if( !mod || mod->type != mod_brush )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if( !FBitSet( host.features, ENGINE_PHYSICS_PUSHER_EXT ))
|
if( !FBitSet( host.features, ENGINE_PHYSICS_PUSHER_EXT ))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return (mod->flags & MODEL_HAS_ORIGIN) ? true : false;
|
if( FBitSet( mod->flags, MODEL_HAS_ORIGIN ))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2012,7 +2016,7 @@ static server_physics_api_t gPhysicsAPI =
|
||||||
SV_LinkEdict,
|
SV_LinkEdict,
|
||||||
SV_GetServerTime,
|
SV_GetServerTime,
|
||||||
SV_GetFrameTime,
|
SV_GetFrameTime,
|
||||||
Mod_Handle,
|
SV_ModelHandle,
|
||||||
SV_GetHeadNode,
|
SV_GetHeadNode,
|
||||||
SV_ServerState,
|
SV_ServerState,
|
||||||
Host_Error,
|
Host_Error,
|
||||||
|
|
|
@ -58,7 +58,7 @@ void SV_ClipPMoveToEntity( physent_t *pe, const vec3_t start, vec3_t mins, vec3_
|
||||||
|
|
||||||
qboolean SV_CopyEdictToPhysEnt( physent_t *pe, edict_t *ed )
|
qboolean SV_CopyEdictToPhysEnt( physent_t *pe, edict_t *ed )
|
||||||
{
|
{
|
||||||
model_t *mod = Mod_Handle( ed->v.modelindex );
|
model_t *mod = SV_ModelHandle( ed->v.modelindex );
|
||||||
|
|
||||||
if( !mod ) return false;
|
if( !mod ) return false;
|
||||||
pe->player = false;
|
pe->player = false;
|
||||||
|
@ -283,6 +283,7 @@ void SV_AddLaddersToPmove( areanode_t *node, const vec3_t pmove_mins, const vec3
|
||||||
{
|
{
|
||||||
link_t *l, *next;
|
link_t *l, *next;
|
||||||
edict_t *check;
|
edict_t *check;
|
||||||
|
model_t *mod;
|
||||||
physent_t *pe;
|
physent_t *pe;
|
||||||
|
|
||||||
// get water edicts
|
// get water edicts
|
||||||
|
@ -294,8 +295,10 @@ void SV_AddLaddersToPmove( areanode_t *node, const vec3_t pmove_mins, const vec3
|
||||||
if( check->v.solid != SOLID_NOT || check->v.skin != CONTENTS_LADDER )
|
if( check->v.solid != SOLID_NOT || check->v.skin != CONTENTS_LADDER )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
mod = SV_ModelHandle( check->v.modelindex );
|
||||||
|
|
||||||
// only brushes can have special contents
|
// only brushes can have special contents
|
||||||
if( Mod_GetType( check->v.modelindex ) != mod_brush )
|
if( !mod || mod->type != mod_brush )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( !BoundsIntersect( pmove_mins, pmove_maxs, check->v.absmin, check->v.absmax ))
|
if( !BoundsIntersect( pmove_mins, pmove_maxs, check->v.absmin, check->v.absmax ))
|
||||||
|
|
|
@ -1914,10 +1914,10 @@ SV_ChangeLevel
|
||||||
*/
|
*/
|
||||||
void SV_ChangeLevel( qboolean loadfromsavedgame, const char *mapname, const char *start )
|
void SV_ChangeLevel( qboolean loadfromsavedgame, const char *mapname, const char *start )
|
||||||
{
|
{
|
||||||
string level;
|
char level[MAX_QPATH];
|
||||||
string oldlevel;
|
char oldlevel[MAX_QPATH];
|
||||||
string _startspot;
|
char _startspot[MAX_QPATH];
|
||||||
char *startspot;
|
char *startspot = NULL;
|
||||||
SAVERESTOREDATA *pSaveData = NULL;
|
SAVERESTOREDATA *pSaveData = NULL;
|
||||||
|
|
||||||
if( sv.state != ss_active )
|
if( sv.state != ss_active )
|
||||||
|
@ -1926,22 +1926,15 @@ void SV_ChangeLevel( qboolean loadfromsavedgame, const char *mapname, const char
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !start )
|
if( start )
|
||||||
{
|
|
||||||
startspot = NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
Q_strncpy( _startspot, start, MAX_STRING );
|
Q_strncpy( _startspot, start, MAX_STRING );
|
||||||
startspot = _startspot;
|
startspot = _startspot;
|
||||||
}
|
}
|
||||||
|
|
||||||
// init network stuff
|
|
||||||
Q_strncpy( level, mapname, MAX_STRING );
|
Q_strncpy( level, mapname, MAX_STRING );
|
||||||
Q_strncpy( oldlevel, sv.name, MAX_STRING );
|
Q_strncpy( oldlevel, sv.name, MAX_STRING );
|
||||||
sv.background = false;
|
sv.changelevel = true;
|
||||||
sv.changelevel = true; // NOTE: this is used to indicate changelevel for classic Quake changelevel
|
|
||||||
// because demos wan't properly update clock on a new level while recording
|
|
||||||
|
|
||||||
if( loadfromsavedgame )
|
if( loadfromsavedgame )
|
||||||
{
|
{
|
||||||
|
@ -1956,8 +1949,8 @@ void SV_ChangeLevel( qboolean loadfromsavedgame, const char *mapname, const char
|
||||||
SV_InactivateClients ();
|
SV_InactivateClients ();
|
||||||
SV_DeactivateServer ();
|
SV_DeactivateServer ();
|
||||||
|
|
||||||
if( !SV_SpawnServer( level, startspot ))
|
if( !SV_SpawnServer( level, startspot, false ))
|
||||||
return;
|
return; // ???
|
||||||
|
|
||||||
if( loadfromsavedgame )
|
if( loadfromsavedgame )
|
||||||
{
|
{
|
||||||
|
@ -2119,36 +2112,26 @@ int SV_SaveReadHeader( file_t *pFile, GAME_HEADER *pHeader )
|
||||||
|
|
||||||
qboolean SV_LoadGame( const char *pPath )
|
qboolean SV_LoadGame( const char *pPath )
|
||||||
{
|
{
|
||||||
file_t *pFile;
|
|
||||||
qboolean validload = false;
|
qboolean validload = false;
|
||||||
GAME_HEADER gameHeader;
|
GAME_HEADER gameHeader;
|
||||||
|
file_t *pFile;
|
||||||
int flags;
|
int flags;
|
||||||
string name;
|
|
||||||
|
|
||||||
if( host.type == HOST_DEDICATED )
|
if( host.type == HOST_DEDICATED )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if( !pPath || !pPath[0] )
|
if( !COM_CheckString( pPath ))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
FS_FileBase( pPath, name );
|
|
||||||
|
|
||||||
// silently ignore if missed
|
// silently ignore if missed
|
||||||
if( !FS_FileExists( pPath, true ))
|
if( !FS_FileExists( pPath, true ))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if( sv.background || svs.maxclients > 1 )
|
|
||||||
SV_Shutdown( true );
|
|
||||||
sv.background = false;
|
|
||||||
|
|
||||||
SCR_BeginLoadingPlaque ( false );
|
|
||||||
S_StopBackgroundTrack();
|
|
||||||
|
|
||||||
MsgDev( D_INFO, "Loading game from %s...\n", pPath );
|
|
||||||
SV_ClearSaveDir();
|
SV_ClearSaveDir();
|
||||||
|
SV_InitGameProgs();
|
||||||
|
|
||||||
if( !svs.initialized ) SV_InitGame ();
|
if( !svgame.hInstance )
|
||||||
if( !svs.initialized ) return false;
|
return false;
|
||||||
|
|
||||||
pFile = FS_Open( pPath, "rb", true );
|
pFile = FS_Open( pPath, "rb", true );
|
||||||
|
|
||||||
|
@ -2176,20 +2159,20 @@ qboolean SV_LoadGame( const char *pPath )
|
||||||
validload = false;
|
validload = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else MsgDev( D_ERROR, "File not found or failed to open.\n" );
|
|
||||||
|
|
||||||
if( !validload )
|
if( !validload )
|
||||||
{
|
{
|
||||||
Q_snprintf( host.finalmsg, MAX_STRING, "Couldn't load %s.sav\n", name );
|
MsgDev( D_ERROR, "Couldn't load %s\n", pPath );
|
||||||
SV_Shutdown( false );
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MsgDev( D_INFO, "Loading game from %s...\n", pPath );
|
||||||
Cvar_FullSet( "maxplayers", "1", FCVAR_LATCH );
|
Cvar_FullSet( "maxplayers", "1", FCVAR_LATCH );
|
||||||
Cvar_SetValue( "deathmatch", 0 );
|
Cvar_SetValue( "deathmatch", 0 );
|
||||||
Cvar_SetValue( "coop", 0 );
|
Cvar_SetValue( "coop", 0 );
|
||||||
|
COM_LoadGame( gameHeader.mapName );
|
||||||
|
|
||||||
return Host_NewGame( gameHeader.mapName, true );
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2201,7 +2184,9 @@ void SV_SaveGetName( int lastnum, char *filename )
|
||||||
{
|
{
|
||||||
int a, b, c;
|
int a, b, c;
|
||||||
|
|
||||||
if( !filename ) return;
|
if( !COM_CheckString( filename ))
|
||||||
|
return;
|
||||||
|
|
||||||
if( lastnum < 0 || lastnum > 999 )
|
if( lastnum < 0 || lastnum > 999 )
|
||||||
{
|
{
|
||||||
// bound
|
// bound
|
||||||
|
@ -2223,7 +2208,7 @@ void SV_SaveGame( const char *pName )
|
||||||
string savename;
|
string savename;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
if( !pName || !*pName )
|
if( !COM_CheckString( pName ))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// can we save at this point?
|
// can we save at this point?
|
||||||
|
@ -2233,7 +2218,7 @@ void SV_SaveGame( const char *pName )
|
||||||
if( !Q_stricmp( pName, "new" ))
|
if( !Q_stricmp( pName, "new" ))
|
||||||
{
|
{
|
||||||
// scan for a free filename
|
// scan for a free filename
|
||||||
for( n = 0; n < 999; n++ )
|
for( n = 0; n < 1000; n++ )
|
||||||
{
|
{
|
||||||
SV_SaveGetName( n, savename );
|
SV_SaveGetName( n, savename );
|
||||||
|
|
||||||
|
@ -2243,17 +2228,16 @@ void SV_SaveGame( const char *pName )
|
||||||
|
|
||||||
if( n == 1000 )
|
if( n == 1000 )
|
||||||
{
|
{
|
||||||
Msg( "^3ERROR: no free slots for savegame\n" );
|
Msg( "^3ERROR^7: no free slots for savegame\n" );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else Q_strncpy( savename, pName, sizeof( savename ));
|
else Q_strncpy( savename, pName, sizeof( savename ));
|
||||||
|
|
||||||
// HACKHACK: unload previous image from memory
|
// unload previous image from memory (it's will be overwritten)
|
||||||
GL_FreeImage( va( "save/%s.bmp", savename ));
|
GL_FreeImage( va( "save/%s.bmp", savename ));
|
||||||
|
|
||||||
comment[0] = '\0';
|
comment[0] = '\0';
|
||||||
|
|
||||||
SV_BuildSaveComment( comment, sizeof( comment ));
|
SV_BuildSaveComment( comment, sizeof( comment ));
|
||||||
SV_SaveGameSlot( savename, comment );
|
SV_SaveGameSlot( savename, comment );
|
||||||
|
|
||||||
|
@ -2282,9 +2266,9 @@ used for reload game after player death
|
||||||
const char *SV_GetLatestSave( void )
|
const char *SV_GetLatestSave( void )
|
||||||
{
|
{
|
||||||
search_t *f = FS_Search( "save/*.sav", true, true ); // lookup only in gamedir
|
search_t *f = FS_Search( "save/*.sav", true, true ); // lookup only in gamedir
|
||||||
int i, found = 0;
|
char savename[MAX_QPATH];
|
||||||
long newest = 0, ft;
|
long newest = 0, ft;
|
||||||
string savename;
|
int i, found = 0;
|
||||||
|
|
||||||
if( !f ) return NULL;
|
if( !f ) return NULL;
|
||||||
|
|
||||||
|
@ -2295,7 +2279,7 @@ const char *SV_GetLatestSave( void )
|
||||||
// found a match?
|
// found a match?
|
||||||
if( ft > 0 )
|
if( ft > 0 )
|
||||||
{
|
{
|
||||||
// should we use the matche?
|
// should we use the matched?
|
||||||
if( !found || Host_CompareFileTime( newest, ft ) < 0 )
|
if( !found || Host_CompareFileTime( newest, ft ) < 0 )
|
||||||
{
|
{
|
||||||
newest = ft;
|
newest = ft;
|
||||||
|
|
|
@ -126,7 +126,7 @@ qboolean SV_CheckSphereIntersection( edict_t *ent, const vec3_t start, const vec
|
||||||
if( !FBitSet( ent->v.flags, FL_CLIENT|FL_FAKECLIENT ))
|
if( !FBitSet( ent->v.flags, FL_CLIENT|FL_FAKECLIENT ))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if(( mod = Mod_Handle( ent->v.modelindex )) == NULL )
|
if(( mod = SV_ModelHandle( ent->v.modelindex )) == NULL )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if(( pstudiohdr = (studiohdr_t *)Mod_StudioExtradata( mod )) == NULL )
|
if(( pstudiohdr = (studiohdr_t *)Mod_StudioExtradata( mod )) == NULL )
|
||||||
|
@ -229,7 +229,7 @@ hull_t *SV_HullForBsp( edict_t *ent, const vec3_t mins, const vec3_t maxs, vec3_
|
||||||
}
|
}
|
||||||
|
|
||||||
// decide which clipping hull to use, based on the size
|
// decide which clipping hull to use, based on the size
|
||||||
model = Mod_Handle( ent->v.modelindex );
|
model = SV_ModelHandle( ent->v.modelindex );
|
||||||
|
|
||||||
if( !model || model->type != mod_brush )
|
if( !model || model->type != mod_brush )
|
||||||
Host_Error( "Entity %i (%s) SOLID_BSP with a non bsp model %s\n", NUM_FOR_EDICT( ent ), SV_ClassName( ent ), STRING( ent->v.model ));
|
Host_Error( "Entity %i (%s) SOLID_BSP with a non bsp model %s\n", NUM_FOR_EDICT( ent ), SV_ClassName( ent ), STRING( ent->v.model ));
|
||||||
|
@ -329,7 +329,7 @@ hull_t *SV_HullForStudioModel( edict_t *ent, vec3_t mins, vec3_t maxs, vec3_t of
|
||||||
vec3_t size;
|
vec3_t size;
|
||||||
model_t *mod;
|
model_t *mod;
|
||||||
|
|
||||||
if(( mod = Mod_Handle( ent->v.modelindex )) == NULL )
|
if(( mod = SV_ModelHandle( ent->v.modelindex )) == NULL )
|
||||||
{
|
{
|
||||||
*numhitboxes = 1;
|
*numhitboxes = 1;
|
||||||
return SV_HullForEntity( ent, mins, maxs, offset );
|
return SV_HullForEntity( ent, mins, maxs, offset );
|
||||||
|
@ -505,6 +505,7 @@ void SV_TouchLinks( edict_t *ent, areanode_t *node )
|
||||||
edict_t *touch;
|
edict_t *touch;
|
||||||
hull_t *hull;
|
hull_t *hull;
|
||||||
vec3_t test, offset;
|
vec3_t test, offset;
|
||||||
|
model_t *mod;
|
||||||
|
|
||||||
// touch linked edicts
|
// touch linked edicts
|
||||||
for( l = node->trigger_edicts.next; l != &node->trigger_edicts; l = next )
|
for( l = node->trigger_edicts.next; l != &node->trigger_edicts; l = next )
|
||||||
|
@ -533,16 +534,16 @@ void SV_TouchLinks( edict_t *ent, areanode_t *node )
|
||||||
if( !BoundsIntersect( ent->v.absmin, ent->v.absmax, touch->v.absmin, touch->v.absmax ))
|
if( !BoundsIntersect( ent->v.absmin, ent->v.absmax, touch->v.absmin, touch->v.absmax ))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// check brush triggers accuracy
|
mod = SV_ModelHandle( touch->v.modelindex );
|
||||||
if( Mod_GetType( touch->v.modelindex ) == mod_brush )
|
|
||||||
{
|
|
||||||
model_t *mod = Mod_Handle( touch->v.modelindex );
|
|
||||||
|
|
||||||
|
// check brush triggers accuracy
|
||||||
|
if( mod && mod->type == mod_brush )
|
||||||
|
{
|
||||||
// force to select bsp-hull
|
// force to select bsp-hull
|
||||||
hull = SV_HullForBsp( touch, ent->v.mins, ent->v.maxs, offset );
|
hull = SV_HullForBsp( touch, ent->v.mins, ent->v.maxs, offset );
|
||||||
|
|
||||||
// support for rotational triggers
|
// support for rotational triggers
|
||||||
if(( mod->flags & MODEL_HAS_ORIGIN ) && !VectorIsNull( touch->v.angles ))
|
if( FBitSet( mod->flags, MODEL_HAS_ORIGIN ) && !VectorIsNull( touch->v.angles ))
|
||||||
{
|
{
|
||||||
matrix4x4 matrix;
|
matrix4x4 matrix;
|
||||||
Matrix4x4_CreateFromEntity( matrix, touch->v.angles, offset, 1.0f );
|
Matrix4x4_CreateFromEntity( matrix, touch->v.angles, offset, 1.0f );
|
||||||
|
@ -561,7 +562,7 @@ void SV_TouchLinks( edict_t *ent, areanode_t *node )
|
||||||
}
|
}
|
||||||
|
|
||||||
// never touch the triggers when "playersonly" is active
|
// never touch the triggers when "playersonly" is active
|
||||||
if( !( sv.hostflags & SVF_PLAYERSONLY ))
|
if( !FBitSet( sv.hostflags, SVF_PLAYERSONLY ))
|
||||||
{
|
{
|
||||||
svgame.globals->time = sv.time;
|
svgame.globals->time = sv.time;
|
||||||
svgame.dllFuncs.pfnTouch( touch, ent );
|
svgame.dllFuncs.pfnTouch( touch, ent );
|
||||||
|
@ -724,20 +725,20 @@ void SV_WaterLinks( const vec3_t origin, int *pCont, areanode_t *node )
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod = SV_ModelHandle( touch->v.modelindex );
|
||||||
|
|
||||||
// only brushes can have special contents
|
// only brushes can have special contents
|
||||||
if( Mod_GetType( touch->v.modelindex ) != mod_brush )
|
if( !mod || mod->type != mod_brush )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( !BoundsIntersect( origin, origin, touch->v.absmin, touch->v.absmax ))
|
if( !BoundsIntersect( origin, origin, touch->v.absmin, touch->v.absmax ))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
mod = Mod_Handle( touch->v.modelindex );
|
|
||||||
|
|
||||||
// check water brushes accuracy
|
// check water brushes accuracy
|
||||||
hull = SV_HullForBsp( touch, vec3_origin, vec3_origin, offset );
|
hull = SV_HullForBsp( touch, vec3_origin, vec3_origin, offset );
|
||||||
|
|
||||||
// support for rotational water
|
// support for rotational water
|
||||||
if(( mod->flags & MODEL_HAS_ORIGIN ) && !VectorIsNull( touch->v.angles ))
|
if( FBitSet( mod->flags, MODEL_HAS_ORIGIN ) && !VectorIsNull( touch->v.angles ))
|
||||||
{
|
{
|
||||||
matrix4x4 matrix;
|
matrix4x4 matrix;
|
||||||
Matrix4x4_CreateFromEntity( matrix, touch->v.angles, offset, 1.0f );
|
Matrix4x4_CreateFromEntity( matrix, touch->v.angles, offset, 1.0f );
|
||||||
|
@ -869,7 +870,7 @@ void SV_ClipMoveToEntity( edict_t *ent, const vec3_t start, vec3_t mins, vec3_t
|
||||||
trace->fraction = 1.0f;
|
trace->fraction = 1.0f;
|
||||||
trace->allsolid = 1;
|
trace->allsolid = 1;
|
||||||
|
|
||||||
model = Mod_Handle( ent->v.modelindex );
|
model = SV_ModelHandle( ent->v.modelindex );
|
||||||
|
|
||||||
if( model && model->type == mod_studio )
|
if( model && model->type == mod_studio )
|
||||||
{
|
{
|
||||||
|
@ -982,6 +983,120 @@ void SV_ClipMoveToEntity( edict_t *ent, const vec3_t start, vec3_t mins, vec3_t
|
||||||
trace->ent = ent;
|
trace->ent = ent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
==================
|
||||||
|
SV_PortalCSG
|
||||||
|
|
||||||
|
a portal is flush with a world surface behind it. this causes problems. namely that we can't pass through the portal plane
|
||||||
|
if the bsp behind it prevents out origin from getting through. so if the trace was clipped and ended infront of the portal,
|
||||||
|
continue the trace to the edges of the portal cutout instead.
|
||||||
|
==================
|
||||||
|
*/
|
||||||
|
void SV_PortalCSG( edict_t *portal, const vec3_t trace_mins, const vec3_t trace_maxs, const vec3_t start, const vec3_t end, trace_t *trace )
|
||||||
|
{
|
||||||
|
vec4_t planes[6]; //far, near, right, left, up, down
|
||||||
|
int plane, k;
|
||||||
|
vec3_t worldpos;
|
||||||
|
float bestfrac;
|
||||||
|
int hitplane;
|
||||||
|
model_t *model;
|
||||||
|
float portalradius;
|
||||||
|
|
||||||
|
// only run this code if we impacted on the portal's parent.
|
||||||
|
if( trace->fraction == 1.0f && !trace->startsolid )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// decide which clipping hull to use, based on the size
|
||||||
|
model = SV_ModelHandle( portal->v.modelindex );
|
||||||
|
|
||||||
|
if( !model || model->type != mod_brush )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// make sure we use a sane valid position.
|
||||||
|
if( trace->startsolid ) VectorCopy( start, worldpos );
|
||||||
|
else VectorCopy( trace->endpos, worldpos );
|
||||||
|
|
||||||
|
// determine the csg area. normals should be facing in
|
||||||
|
AngleVectors( portal->v.angles, planes[1], planes[3], planes[5] );
|
||||||
|
VectorNegate(planes[1], planes[0]);
|
||||||
|
VectorNegate(planes[3], planes[2]);
|
||||||
|
VectorNegate(planes[5], planes[4]);
|
||||||
|
|
||||||
|
portalradius = model->radius * 0.5f;
|
||||||
|
planes[0][3] = DotProduct( portal->v.origin, planes[0] ) - (4.0f / 32.0f);
|
||||||
|
planes[1][3] = DotProduct( portal->v.origin, planes[1] ) - (4.0f / 32.0f); //an epsilon beyond the portal
|
||||||
|
planes[2][3] = DotProduct( portal->v.origin, planes[2] ) - portalradius;
|
||||||
|
planes[3][3] = DotProduct( portal->v.origin, planes[3] ) - portalradius;
|
||||||
|
planes[4][3] = DotProduct( portal->v.origin, planes[4] ) - portalradius;
|
||||||
|
planes[5][3] = DotProduct( portal->v.origin, planes[5] ) - portalradius;
|
||||||
|
|
||||||
|
// if we're actually inside the csg region
|
||||||
|
for( plane = 0; plane < 6; plane++ )
|
||||||
|
{
|
||||||
|
float d = DotProduct( worldpos, planes[plane] );
|
||||||
|
vec3_t nearest;
|
||||||
|
|
||||||
|
for( k = 0; k < 3; k++ )
|
||||||
|
nearest[k] = (planes[plane][k]>=0) ? trace_maxs[k] : trace_mins[k];
|
||||||
|
|
||||||
|
// front plane gets further away with side
|
||||||
|
if( !plane )
|
||||||
|
{
|
||||||
|
planes[plane][3] -= DotProduct( nearest, planes[plane] );
|
||||||
|
}
|
||||||
|
else if( plane > 1 )
|
||||||
|
{
|
||||||
|
// side planes get nearer with size
|
||||||
|
planes[plane][3] += 24; // DotProduct( nearest, planes[plane] );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( d - planes[plane][3] >= 0 )
|
||||||
|
continue; // endpos is inside
|
||||||
|
else return; // end is already outside
|
||||||
|
}
|
||||||
|
|
||||||
|
// yup, we're inside, the trace shouldn't end where it actually did
|
||||||
|
bestfrac = 1;
|
||||||
|
hitplane = -1;
|
||||||
|
|
||||||
|
for( plane = 0; plane < 6; plane++ )
|
||||||
|
{
|
||||||
|
float ds = DotProduct( start, planes[plane] ) - planes[plane][3];
|
||||||
|
float de = DotProduct( end, planes[plane] ) - planes[plane][3];
|
||||||
|
float frac;
|
||||||
|
|
||||||
|
if( ds >= 0 && de < 0 )
|
||||||
|
{
|
||||||
|
frac = (ds) / (ds - de);
|
||||||
|
if( frac < bestfrac )
|
||||||
|
{
|
||||||
|
if( frac < 0 )
|
||||||
|
frac = 0;
|
||||||
|
bestfrac = frac;
|
||||||
|
hitplane = plane;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trace->startsolid = trace->allsolid = false;
|
||||||
|
|
||||||
|
// if we cross the front of the portal, don't shorten the trace,
|
||||||
|
// that will artificially clip us
|
||||||
|
if( hitplane == 0 && trace->fraction > bestfrac )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// okay, elongate to clip to the portal hole properly.
|
||||||
|
VectorLerp( start, bestfrac, end, trace->endpos );
|
||||||
|
trace->fraction = bestfrac;
|
||||||
|
|
||||||
|
if( hitplane >= 0 )
|
||||||
|
{
|
||||||
|
VectorCopy( planes[hitplane], trace->plane.normal );
|
||||||
|
trace->plane.dist = planes[hitplane][3];
|
||||||
|
if( hitplane == 1 ) trace->ent = portal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
==================
|
==================
|
||||||
SV_CustomClipMoveToEntity
|
SV_CustomClipMoveToEntity
|
||||||
|
@ -1019,6 +1134,7 @@ generic clip function
|
||||||
static qboolean SV_ClipToEntity( edict_t *touch, moveclip_t *clip )
|
static qboolean SV_ClipToEntity( edict_t *touch, moveclip_t *clip )
|
||||||
{
|
{
|
||||||
trace_t trace;
|
trace_t trace;
|
||||||
|
model_t *mod;
|
||||||
|
|
||||||
if( touch->v.groupinfo != 0 && SV_IsValidEdict( clip->passedict ) && clip->passedict->v.groupinfo != 0 )
|
if( touch->v.groupinfo != 0 && SV_IsValidEdict( clip->passedict ) && clip->passedict->v.groupinfo != 0 )
|
||||||
{
|
{
|
||||||
|
@ -1057,7 +1173,9 @@ static qboolean SV_ClipToEntity( edict_t *touch, moveclip_t *clip )
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( Mod_GetType( touch->v.modelindex ) == mod_brush && clip->flags & FMOVE_IGNORE_GLASS )
|
mod = SV_ModelHandle( touch->v.modelindex );
|
||||||
|
|
||||||
|
if( mod && mod->type == mod_brush && FBitSet( clip->flags, FMOVE_IGNORE_GLASS ))
|
||||||
{
|
{
|
||||||
// we ignore brushes with rendermode != kRenderNormal and without FL_WORLDBRUSH set
|
// we ignore brushes with rendermode != kRenderNormal and without FL_WORLDBRUSH set
|
||||||
if( touch->v.rendermode != kRenderNormal && !FBitSet( touch->v.flags, FL_WORLDBRUSH ))
|
if( touch->v.rendermode != kRenderNormal && !FBitSet( touch->v.flags, FL_WORLDBRUSH ))
|
||||||
|
@ -1098,7 +1216,7 @@ static qboolean SV_ClipToEntity( edict_t *touch, moveclip_t *clip )
|
||||||
|
|
||||||
// make sure we don't hit the world if we're inside the portal
|
// make sure we don't hit the world if we're inside the portal
|
||||||
if( touch->v.solid == SOLID_PORTAL )
|
if( touch->v.solid == SOLID_PORTAL )
|
||||||
World_PortalCSG( touch, clip->mins, clip->maxs, clip->start, clip->end, &clip->trace );
|
SV_PortalCSG( touch, clip->mins, clip->maxs, clip->start, clip->end, &clip->trace );
|
||||||
|
|
||||||
if( touch->v.solid == SOLID_CUSTOM )
|
if( touch->v.solid == SOLID_CUSTOM )
|
||||||
SV_CustomClipMoveToEntity( touch, clip->start, clip->mins, clip->maxs, clip->end, &trace );
|
SV_CustomClipMoveToEntity( touch, clip->start, clip->mins, clip->maxs, clip->end, &trace );
|
||||||
|
@ -1335,7 +1453,7 @@ msurface_t *SV_TraceSurface( edict_t *ent, const vec3_t start, const vec3_t end
|
||||||
vec3_t start_l, end_l;
|
vec3_t start_l, end_l;
|
||||||
vec3_t offset;
|
vec3_t offset;
|
||||||
|
|
||||||
bmodel = Mod_Handle( ent->v.modelindex );
|
bmodel = SV_ModelHandle( ent->v.modelindex );
|
||||||
if( !bmodel || bmodel->type != mod_brush )
|
if( !bmodel || bmodel->type != mod_brush )
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|
Reference in New Issue