02 Mar 2012
This commit is contained in:
parent
fb92e01470
commit
ef39a73480
|
@ -24,6 +24,8 @@ Server: clear savedir when new game is started
|
||||||
GameUI: loading maps.lst from basedir while mod doesn't contain multiplayer maps
|
GameUI: loading maps.lst from basedir while mod doesn't contain multiplayer maps
|
||||||
Network: implemented QueryCvarValue and QueryCvarValue2
|
Network: implemented QueryCvarValue and QueryCvarValue2
|
||||||
Physic: new pm-trace code, new server trace code, new studio hitbox trace code
|
Physic: new pm-trace code, new server trace code, new studio hitbox trace code
|
||||||
|
Client: rewrite demo record and playback
|
||||||
|
Render: add support for STUDIO_NF_FULLBRIGHT
|
||||||
|
|
||||||
build 1770
|
build 1770
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -213,25 +213,19 @@ qboolean CL_AddVisibleEntity( cl_entity_t *ent, int entityType )
|
||||||
// add in muzzleflash effect
|
// add in muzzleflash effect
|
||||||
if( ent->curstate.effects & EF_MUZZLEFLASH )
|
if( ent->curstate.effects & EF_MUZZLEFLASH )
|
||||||
{
|
{
|
||||||
vec3_t pos;
|
dlight_t *dl;
|
||||||
|
|
||||||
if( ent == &clgame.viewent )
|
if( ent == &clgame.viewent )
|
||||||
ent->curstate.effects &= ~EF_MUZZLEFLASH;
|
ent->curstate.effects &= ~EF_MUZZLEFLASH;
|
||||||
|
|
||||||
VectorCopy( ent->attachment[0], pos );
|
dl = CL_AllocElight( 0 );
|
||||||
|
|
||||||
// make sure what attachment is valid
|
VectorCopy( ent->attachment[0], dl->origin );
|
||||||
if( !VectorCompare( pos, ent->origin ))
|
dl->die = cl.time + 0.05f;
|
||||||
{
|
dl->color.r = 255;
|
||||||
dlight_t *dl = CL_AllocElight( 0 );
|
dl->color.g = 180;
|
||||||
|
dl->color.b = 64;
|
||||||
VectorCopy( pos, dl->origin );
|
dl->radius = 100;
|
||||||
dl->die = cl.time + 0.05f;
|
|
||||||
dl->color.r = 255;
|
|
||||||
dl->color.g = 180;
|
|
||||||
dl->color.b = 64;
|
|
||||||
dl->radius = 100;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// add light effect
|
// add light effect
|
||||||
|
@ -576,6 +570,10 @@ void CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
|
||||||
entity_state_t *oldent;
|
entity_state_t *oldent;
|
||||||
int i, count;
|
int i, count;
|
||||||
|
|
||||||
|
// save first uncompressed packet as timestamp
|
||||||
|
if( cls.changelevel && !delta && cls.demorecording )
|
||||||
|
CL_WriteDemoJumpTime();
|
||||||
|
|
||||||
// first, allocate packet for new frame
|
// first, allocate packet for new frame
|
||||||
count = BF_ReadWord( msg );
|
count = BF_ReadWord( msg );
|
||||||
|
|
||||||
|
@ -622,7 +620,7 @@ void CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
|
||||||
// this is a full update that we can start delta compressing from now
|
// this is a full update that we can start delta compressing from now
|
||||||
oldframe = NULL;
|
oldframe = NULL;
|
||||||
|
|
||||||
oldpacket = -1; // delta too old or is initial message
|
oldpacket = -1; // delta too old or is initial message
|
||||||
cl.force_send_usercmd = true; // send reply
|
cl.force_send_usercmd = true; // send reply
|
||||||
cls.demowaiting = false; // we can start recording now
|
cls.demowaiting = false; // we can start recording now
|
||||||
}
|
}
|
||||||
|
|
|
@ -2948,7 +2948,7 @@ Demo_WriteBuffer
|
||||||
*/
|
*/
|
||||||
static void Demo_WriteBuffer( int size, byte *buffer )
|
static void Demo_WriteBuffer( int size, byte *buffer )
|
||||||
{
|
{
|
||||||
// TODO: implement
|
CL_WriteDemoUserMessage( buffer, size );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -224,7 +224,7 @@ CLIENT MOVEMENT COMMUNICATION
|
||||||
CL_CreateCmd
|
CL_CreateCmd
|
||||||
=================
|
=================
|
||||||
*/
|
*/
|
||||||
usercmd_t CL_CreateCmd( void )
|
void CL_CreateCmd( void )
|
||||||
{
|
{
|
||||||
usercmd_t cmd;
|
usercmd_t cmd;
|
||||||
color24 color;
|
color24 color;
|
||||||
|
@ -257,9 +257,16 @@ usercmd_t CL_CreateCmd( void )
|
||||||
// because it may contain leftover inputs
|
// because it may contain leftover inputs
|
||||||
// from the last level
|
// from the last level
|
||||||
if( ++cl.movemessages <= 10 )
|
if( ++cl.movemessages <= 10 )
|
||||||
return cmd;
|
{
|
||||||
|
if( !cls.demoplayback )
|
||||||
|
{
|
||||||
|
cl.refdef.cmd = &cl.cmds[cls.netchan.outgoing_sequence & CL_UPDATE_MASK];
|
||||||
|
*cl.refdef.cmd = cmd;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
active = ( cls.state == ca_active && !cl.refdef.paused );
|
active = ( cls.state == ca_active && !cl.refdef.paused && !cls.demoplayback );
|
||||||
clgame.dllFuncs.CL_CreateMove( cl.time - cl.oldtime, &cmd, active );
|
clgame.dllFuncs.CL_CreateMove( cl.time - cl.oldtime, &cmd, active );
|
||||||
|
|
||||||
R_LightForPoint( cl.frame.local.client.origin, &color, false, false, 128.0f );
|
R_LightForPoint( cl.frame.local.client.origin, &color, false, false, 128.0f );
|
||||||
|
@ -271,13 +278,20 @@ usercmd_t CL_CreateCmd( void )
|
||||||
|
|
||||||
V_ProcessOverviewCmds( &cmd );
|
V_ProcessOverviewCmds( &cmd );
|
||||||
|
|
||||||
if( cl.background || cls.demoplayback || gl_overview->integer )
|
if( cl.background || gl_overview->integer )
|
||||||
{
|
{
|
||||||
VectorCopy( angles, cl.refdef.cl_viewangles );
|
VectorCopy( angles, cl.refdef.cl_viewangles );
|
||||||
VectorCopy( angles, cmd.viewangles );
|
VectorCopy( angles, cmd.viewangles );
|
||||||
cmd.msec = 0;
|
cmd.msec = 0;
|
||||||
}
|
}
|
||||||
return cmd;
|
|
||||||
|
// demo always have commands
|
||||||
|
// so don't overwrite them
|
||||||
|
if( !cls.demoplayback )
|
||||||
|
{
|
||||||
|
cl.refdef.cmd = &cl.cmds[cls.netchan.outgoing_sequence & CL_UPDATE_MASK];
|
||||||
|
*cl.refdef.cmd = cmd;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CL_WriteUsercmd( sizebuf_t *msg, int from, int to )
|
void CL_WriteUsercmd( sizebuf_t *msg, int from, int to )
|
||||||
|
@ -361,7 +375,7 @@ void CL_WritePacket( void )
|
||||||
|
|
||||||
if(( cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged ) >= CL_UPDATE_MASK )
|
if(( cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged ) >= CL_UPDATE_MASK )
|
||||||
{
|
{
|
||||||
if(( host.realtime - cls.netchan.last_received ) > CONNECTION_PROBLEM_TIME && !cls.demoplayback )
|
if(( host.realtime - cls.netchan.last_received ) > CONNECTION_PROBLEM_TIME )
|
||||||
{
|
{
|
||||||
Con_NPrintf( 1, "^3Warning:^1 Connection Problem^7\n" );
|
Con_NPrintf( 1, "^3Warning:^1 Connection Problem^7\n" );
|
||||||
cl.validsequence = 0;
|
cl.validsequence = 0;
|
||||||
|
@ -475,6 +489,13 @@ void CL_WritePacket( void )
|
||||||
cls.netchan.outgoing_sequence++;
|
cls.netchan.outgoing_sequence++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( cls.demorecording )
|
||||||
|
{
|
||||||
|
// Back up one because we've incremented outgoing_sequence each frame by 1 unit
|
||||||
|
cmdnumber = ( cls.netchan.outgoing_sequence - 1 ) & CL_UPDATE_MASK;
|
||||||
|
CL_WriteDemoUserCmd( cmdnumber );
|
||||||
|
}
|
||||||
|
|
||||||
// update download/upload slider.
|
// update download/upload slider.
|
||||||
Netchan_UpdateProgress( &cls.netchan );
|
Netchan_UpdateProgress( &cls.netchan );
|
||||||
}
|
}
|
||||||
|
@ -489,8 +510,7 @@ Called every frame to builds and sends a command packet to the server.
|
||||||
void CL_SendCmd( void )
|
void CL_SendCmd( void )
|
||||||
{
|
{
|
||||||
// we create commands even if a demo is playing,
|
// we create commands even if a demo is playing,
|
||||||
cl.refdef.cmd = &cl.cmds[cls.netchan.outgoing_sequence & CL_UPDATE_MASK];
|
CL_CreateCmd();
|
||||||
*cl.refdef.cmd = CL_CreateCmd();
|
|
||||||
|
|
||||||
// clc_move, userinfo etc
|
// clc_move, userinfo etc
|
||||||
CL_WritePacket();
|
CL_WritePacket();
|
||||||
|
@ -917,13 +937,6 @@ void CL_Reconnect_f( void )
|
||||||
|
|
||||||
S_StopAllSounds ();
|
S_StopAllSounds ();
|
||||||
|
|
||||||
if( cls.demoplayback )
|
|
||||||
{
|
|
||||||
// demo issues changelevel
|
|
||||||
cls.changelevel = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( cls.state == ca_connected )
|
if( cls.state == ca_connected )
|
||||||
{
|
{
|
||||||
cls.demonum = cls.movienum = -1; // not in the demo loop now
|
cls.demonum = cls.movienum = -1; // not in the demo loop now
|
||||||
|
@ -940,6 +953,8 @@ void CL_Reconnect_f( void )
|
||||||
cl.delta_sequence = -1; // we'll request a full delta from the baseline
|
cl.delta_sequence = -1; // we'll request a full delta from the baseline
|
||||||
cls.lastoutgoingcommand = -1; // we don't have a backed up cmd history yet
|
cls.lastoutgoingcommand = -1; // we don't have a backed up cmd history yet
|
||||||
cls.nextcmdtime = host.realtime; // we can send a cmd right away
|
cls.nextcmdtime = host.realtime; // we can send a cmd right away
|
||||||
|
|
||||||
|
CL_StartupDemoHeader ();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1226,6 +1241,8 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
|
||||||
cls.lastoutgoingcommand = -1; // we don't have a backed up cmd history yet
|
cls.lastoutgoingcommand = -1; // we don't have a backed up cmd history yet
|
||||||
cls.nextcmdtime = host.realtime; // we can send a cmd right away
|
cls.nextcmdtime = host.realtime; // we can send a cmd right away
|
||||||
|
|
||||||
|
CL_StartupDemoHeader ();
|
||||||
|
|
||||||
UI_SetActiveMenu( false );
|
UI_SetActiveMenu( false );
|
||||||
}
|
}
|
||||||
else if( !Q_strcmp( c, "info" ))
|
else if( !Q_strcmp( c, "info" ))
|
||||||
|
@ -1317,6 +1334,27 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
|
||||||
else MsgDev( D_ERROR, "bad connectionless packet from %s:\n%s\n", NET_AdrToString( from ), args );
|
else MsgDev( D_ERROR, "bad connectionless packet from %s:\n%s\n", NET_AdrToString( from ), args );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
====================
|
||||||
|
CL_GetMessage
|
||||||
|
|
||||||
|
Handles recording and playback of demos, on top of NET_ code
|
||||||
|
====================
|
||||||
|
*/
|
||||||
|
int CL_GetMessage( byte *data, size_t *length )
|
||||||
|
{
|
||||||
|
if( cls.demoplayback )
|
||||||
|
{
|
||||||
|
if( CL_DemoReadMessage( data, length ))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( NET_GetPacket( NS_CLIENT, &net_from, data, length ))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=================
|
=================
|
||||||
CL_ReadNetMessage
|
CL_ReadNetMessage
|
||||||
|
@ -1324,13 +1362,10 @@ CL_ReadNetMessage
|
||||||
*/
|
*/
|
||||||
void CL_ReadNetMessage( void )
|
void CL_ReadNetMessage( void )
|
||||||
{
|
{
|
||||||
int curSize;
|
size_t curSize;
|
||||||
|
|
||||||
while( NET_GetPacket( NS_CLIENT, &net_from, net_message_buffer, &curSize ))
|
while( CL_GetMessage( net_message_buffer, &curSize ))
|
||||||
{
|
{
|
||||||
if( host.type == HOST_DEDICATED || cls.demoplayback )
|
|
||||||
return;
|
|
||||||
|
|
||||||
BF_Init( &net_message, "ServerData", net_message_buffer, curSize );
|
BF_Init( &net_message, "ServerData", net_message_buffer, curSize );
|
||||||
|
|
||||||
// check for connectionless packet (0xffffffff) first
|
// check for connectionless packet (0xffffffff) first
|
||||||
|
@ -1350,24 +1385,16 @@ void CL_ReadNetMessage( void )
|
||||||
}
|
}
|
||||||
|
|
||||||
// packet from server
|
// packet from server
|
||||||
if( !NET_CompareAdr( net_from, cls.netchan.remote_address ))
|
if( !cls.demoplayback && !NET_CompareAdr( net_from, cls.netchan.remote_address ))
|
||||||
{
|
{
|
||||||
MsgDev( D_ERROR, "CL_ReadPackets: %s:sequenced packet without connection\n", NET_AdrToString( net_from ));
|
MsgDev( D_ERROR, "CL_ReadPackets: %s:sequenced packet without connection\n", NET_AdrToString( net_from ));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( Netchan_Process( &cls.netchan, &net_message ))
|
if( !cls.demoplayback && !Netchan_Process( &cls.netchan, &net_message ))
|
||||||
{
|
continue; // wasn't accepted for some reason
|
||||||
// the header is different lengths for reliable and unreliable messages
|
|
||||||
int headerBytes = BF_GetNumBytesRead( &net_message );
|
|
||||||
|
|
||||||
CL_ParseServerMessage( &net_message );
|
CL_ParseServerMessage( &net_message );
|
||||||
|
|
||||||
// we don't know if it is ok to save a demo message until
|
|
||||||
// after we have parsed the frame
|
|
||||||
if( cls.demorecording && !cls.demowaiting )
|
|
||||||
CL_WriteDemoMessage( &net_message, headerBytes );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for fragmentation/reassembly related packets.
|
// check for fragmentation/reassembly related packets.
|
||||||
|
@ -1380,11 +1407,6 @@ void CL_ReadNetMessage( void )
|
||||||
if( Netchan_CopyNormalFragments( &cls.netchan, &net_message ))
|
if( Netchan_CopyNormalFragments( &cls.netchan, &net_message ))
|
||||||
{
|
{
|
||||||
CL_ParseServerMessage( &net_message );
|
CL_ParseServerMessage( &net_message );
|
||||||
|
|
||||||
// we don't know if it is ok to save a demo message until
|
|
||||||
// after we have parsed the frame
|
|
||||||
if( cls.demorecording && !cls.demowaiting )
|
|
||||||
CL_WriteDemoMessage( &net_message, headerBytes );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( Netchan_CopyFileFragments( &cls.netchan, &net_message ))
|
if( Netchan_CopyFileFragments( &cls.netchan, &net_message ))
|
||||||
|
@ -1399,9 +1421,7 @@ void CL_ReadNetMessage( void )
|
||||||
|
|
||||||
void CL_ReadPackets( void )
|
void CL_ReadPackets( void )
|
||||||
{
|
{
|
||||||
if( cls.demoplayback )
|
CL_ReadNetMessage();
|
||||||
CL_ReadDemoMessage();
|
|
||||||
else CL_ReadNetMessage();
|
|
||||||
|
|
||||||
cl.lerpFrac = CL_LerpPoint();
|
cl.lerpFrac = CL_LerpPoint();
|
||||||
cl.thirdperson = clgame.dllFuncs.CL_IsThirdPerson();
|
cl.thirdperson = clgame.dllFuncs.CL_IsThirdPerson();
|
||||||
|
@ -1492,8 +1512,6 @@ void CL_Precache_f( void )
|
||||||
CL_PrepSound();
|
CL_PrepSound();
|
||||||
CL_PrepVideo();
|
CL_PrepVideo();
|
||||||
|
|
||||||
if( cls.demoplayback ) return; // not really connected
|
|
||||||
|
|
||||||
BF_WriteByte( &cls.netchan.message, clc_stringcmd );
|
BF_WriteByte( &cls.netchan.message, clc_stringcmd );
|
||||||
BF_WriteString( &cls.netchan.message, va( "begin %i\n", spawncount ));
|
BF_WriteString( &cls.netchan.message, va( "begin %i\n", spawncount ));
|
||||||
}
|
}
|
||||||
|
@ -1646,7 +1664,7 @@ Host_ClientFrame
|
||||||
void Host_ClientFrame( void )
|
void Host_ClientFrame( void )
|
||||||
{
|
{
|
||||||
// if client is not active, do nothing
|
// if client is not active, do nothing
|
||||||
if ( !cls.initialized ) return;
|
if( !cls.initialized ) return;
|
||||||
|
|
||||||
// decide the simulation time
|
// decide the simulation time
|
||||||
cl.oldtime = cl.time;
|
cl.oldtime = cl.time;
|
||||||
|
@ -1748,6 +1766,7 @@ void CL_Shutdown( void )
|
||||||
Host_WriteOpenGLConfig ();
|
Host_WriteOpenGLConfig ();
|
||||||
Host_WriteVideoConfig ();
|
Host_WriteVideoConfig ();
|
||||||
|
|
||||||
|
CL_CloseDemoHeader();
|
||||||
IN_Shutdown ();
|
IN_Shutdown ();
|
||||||
SCR_Shutdown ();
|
SCR_Shutdown ();
|
||||||
CL_UnloadProgs ();
|
CL_UnloadProgs ();
|
||||||
|
|
|
@ -479,7 +479,8 @@ void CL_ParseServerData( sizebuf_t *msg )
|
||||||
|
|
||||||
MsgDev( D_NOTE, "Serverdata packet received.\n" );
|
MsgDev( D_NOTE, "Serverdata packet received.\n" );
|
||||||
|
|
||||||
clgame.load_sequence++; // now all hud sprites are invalid
|
cls.demowaiting = false; // server is changed
|
||||||
|
clgame.load_sequence++; // now all hud sprites are invalid
|
||||||
|
|
||||||
// wipe the client_t struct
|
// wipe the client_t struct
|
||||||
if( !cls.changelevel ) CL_ClearState();
|
if( !cls.changelevel ) CL_ClearState();
|
||||||
|
@ -1348,7 +1349,9 @@ void CL_ParseServerMessage( sizebuf_t *msg )
|
||||||
CL_ClearState ();
|
CL_ClearState ();
|
||||||
CL_InitEdicts (); // re-arrange edicts
|
CL_InitEdicts (); // re-arrange edicts
|
||||||
|
|
||||||
cls.state = ca_connecting;
|
if( cls.demoplayback )
|
||||||
|
cls.state = ca_connected;
|
||||||
|
else cls.state = ca_connecting;
|
||||||
cls.connect_time = MAX_HEARTBEAT; // CL_CheckForResend() will fire immediately
|
cls.connect_time = MAX_HEARTBEAT; // CL_CheckForResend() will fire immediately
|
||||||
break;
|
break;
|
||||||
case svc_setview:
|
case svc_setview:
|
||||||
|
@ -1512,4 +1515,18 @@ void CL_ParseServerMessage( sizebuf_t *msg )
|
||||||
}
|
}
|
||||||
|
|
||||||
cls_message_debug.parsing = false; // done
|
cls_message_debug.parsing = false; // done
|
||||||
|
|
||||||
|
// we don't know if it is ok to save a demo message until
|
||||||
|
// after we have parsed the frame
|
||||||
|
if( !cls.demoplayback )
|
||||||
|
{
|
||||||
|
if( cls.demorecording && !cls.demowaiting )
|
||||||
|
{
|
||||||
|
CL_WriteDemoMessage( false, starting_count, msg );
|
||||||
|
}
|
||||||
|
else if( cls.state != ca_active )
|
||||||
|
{
|
||||||
|
CL_WriteDemoMessage( true, starting_count, msg );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -771,12 +771,10 @@ void CL_PredictMovement( void )
|
||||||
viewent = CL_GetEntityByIndex( cl.refdef.viewentity );
|
viewent = CL_GetEntityByIndex( cl.refdef.viewentity );
|
||||||
cd = &cl.frame.local.client;
|
cd = &cl.frame.local.client;
|
||||||
|
|
||||||
if( cls.demoplayback && viewent )
|
if( cls.demoplayback && cl.refdef.cmd != NULL )
|
||||||
{
|
{
|
||||||
// restore viewangles from angles
|
// restore viewangles from cmd.angles
|
||||||
cl.refdef.cl_viewangles[PITCH] = viewent->angles[PITCH] * 6;
|
VectorCopy( cl.refdef.cmd->viewangles, cl.refdef.cl_viewangles );
|
||||||
cl.refdef.cl_viewangles[YAW] = viewent->angles[YAW];
|
|
||||||
cl.refdef.cl_viewangles[ROLL] = 0; // roll will be computed in view.cpp
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// unpredicted pure angled values converted into axis
|
// unpredicted pure angled values converted into axis
|
||||||
|
|
|
@ -509,6 +509,7 @@ typedef struct
|
||||||
string demoname; // for demo looping
|
string demoname; // for demo looping
|
||||||
|
|
||||||
file_t *demofile;
|
file_t *demofile;
|
||||||
|
file_t *demoheader; // contain demo startup info in case we record a demo on this level
|
||||||
} client_static_t;
|
} client_static_t;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -579,12 +580,13 @@ void SCR_Viewpos_f( void );
|
||||||
void SCR_TimeRefresh_f( void );
|
void SCR_TimeRefresh_f( void );
|
||||||
|
|
||||||
//
|
//
|
||||||
// cl_main
|
// cl_main.c
|
||||||
//
|
//
|
||||||
void CL_Init( void );
|
void CL_Init( void );
|
||||||
void CL_SendCommand( void );
|
void CL_SendCommand( void );
|
||||||
void CL_Disconnect_f( void );
|
void CL_Disconnect_f( void );
|
||||||
void CL_ProcessFile( qboolean successfully_received, const char *filename );
|
void CL_ProcessFile( qboolean successfully_received, const char *filename );
|
||||||
|
void CL_WriteUsercmd( sizebuf_t *msg, int from, int to );
|
||||||
void CL_GetChallengePacket( void );
|
void CL_GetChallengePacket( void );
|
||||||
void CL_PingServers_f( void );
|
void CL_PingServers_f( void );
|
||||||
void CL_ClearState( void );
|
void CL_ClearState( void );
|
||||||
|
@ -592,9 +594,14 @@ void CL_ClearState( void );
|
||||||
//
|
//
|
||||||
// cl_demo.c
|
// cl_demo.c
|
||||||
//
|
//
|
||||||
|
void CL_StartupDemoHeader( void );
|
||||||
void CL_DrawDemoRecording( void );
|
void CL_DrawDemoRecording( void );
|
||||||
void CL_WriteDemoMessage( sizebuf_t *msg, int head_size );
|
void CL_WriteDemoUserCmd( int cmdnumber );
|
||||||
void CL_ReadDemoMessage( void );
|
void CL_WriteDemoMessage( qboolean startup, int start, sizebuf_t *msg );
|
||||||
|
void CL_WriteDemoUserMessage( const byte *buffer, size_t size );
|
||||||
|
qboolean CL_DemoReadMessage( byte *buffer, size_t *length );
|
||||||
|
void CL_WriteDemoJumpTime( void );
|
||||||
|
void CL_CloseDemoHeader( void );
|
||||||
void CL_StopPlayback( void );
|
void CL_StopPlayback( void );
|
||||||
void CL_StopRecord( void );
|
void CL_StopRecord( void );
|
||||||
void CL_PlayDemo_f( void );
|
void CL_PlayDemo_f( void );
|
||||||
|
|
|
@ -18,6 +18,7 @@ GNU General Public License for more details.
|
||||||
#include "gl_local.h"
|
#include "gl_local.h"
|
||||||
#include "cl_tent.h"
|
#include "cl_tent.h"
|
||||||
|
|
||||||
|
#define DECAL_OVERLAP_DISTANCE 2
|
||||||
#define DECAL_DISTANCE 4 // too big values produce more clipped polygons
|
#define DECAL_DISTANCE 4 // too big values produce more clipped polygons
|
||||||
#define MAX_DECALCLIPVERT 32 // produced vertexes of fragmented decal
|
#define MAX_DECALCLIPVERT 32 // produced vertexes of fragmented decal
|
||||||
#define DECAL_CACHEENTRY 256 // MUST BE POWER OF 2 or code below needs to change!
|
#define DECAL_CACHEENTRY 256 // MUST BE POWER OF 2 or code below needs to change!
|
||||||
|
@ -459,19 +460,7 @@ static float *R_DecalVertsNoclip( decal_t *pdecal, msurface_t *surf, int texture
|
||||||
return vlist;
|
return vlist;
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
// Check for intersecting decals on this surface
|
||||||
// Purpose: Check for intersecting decals on this surface
|
|
||||||
// Input : *psurf -
|
|
||||||
// *pcount -
|
|
||||||
// x -
|
|
||||||
// y -
|
|
||||||
// Output : static decal_t
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// UNDONE: This probably doesn't work quite right any more
|
|
||||||
// we should base overlap on the new decal basis matrix
|
|
||||||
// decal basis is constant per plane, perhaps we should store it (unscaled) in the shared plane struct
|
|
||||||
// BRJ: Note, decal basis is not constant when decals need to specify an s direction
|
|
||||||
// but that certainly isn't the majority case
|
|
||||||
static decal_t *R_DecalIntersect( decalinfo_t *decalinfo, msurface_t *surf, int *pcount )
|
static decal_t *R_DecalIntersect( decalinfo_t *decalinfo, msurface_t *surf, int *pcount )
|
||||||
{
|
{
|
||||||
int texture;
|
int texture;
|
||||||
|
@ -1015,7 +1004,7 @@ static int DecalListAdd( decallist_t *pList, int count )
|
||||||
{
|
{
|
||||||
VectorSubtract( pdecal->position, pList[i].position, tmp ); // Merge
|
VectorSubtract( pdecal->position, pList[i].position, tmp ); // Merge
|
||||||
|
|
||||||
if( VectorLength( tmp ) < 2 ) // UNDONE: Tune this '2' constant
|
if( VectorLength( tmp ) < DECAL_OVERLAP_DISTANCE )
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -313,11 +313,6 @@ int R_LightTraceFilter( physent_t *pe )
|
||||||
if( !pe || pe->solid != SOLID_BSP )
|
if( !pe || pe->solid != SOLID_BSP )
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
// optimization. Ignore world to avoid
|
|
||||||
// unneeded transformations
|
|
||||||
if( pe->info == 0 )
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1025,7 +1025,8 @@ void R_RenderBrushPoly( msurface_t *fa )
|
||||||
fullbright_polys[t->fb_texturenum] = fa->polys;
|
fullbright_polys[t->fb_texturenum] = fa->polys;
|
||||||
draw_fullbrights = true;
|
draw_fullbrights = true;
|
||||||
}
|
}
|
||||||
else if( r_detailtextures->integer && t->dt_texturenum )
|
|
||||||
|
if( r_detailtextures->integer && t->dt_texturenum )
|
||||||
{
|
{
|
||||||
mextrasurf_t *es = SURF_INFO( fa, RI.currentmodel );
|
mextrasurf_t *es = SURF_INFO( fa, RI.currentmodel );
|
||||||
es->detailchain = detail_surfaces[t->dt_texturenum];
|
es->detailchain = detail_surfaces[t->dt_texturenum];
|
||||||
|
|
|
@ -960,7 +960,6 @@ void R_StudioCalcRotations( cl_entity_t *e, float pos[][3], vec4_t *q, mstudiose
|
||||||
}
|
}
|
||||||
else if( f < -0.01f )
|
else if( f < -0.01f )
|
||||||
{
|
{
|
||||||
// BUGBUG ( somewhere else ) but this code should validate this data.
|
|
||||||
// this could cause a crash if the frame # is negative, so we'll go ahead
|
// this could cause a crash if the frame # is negative, so we'll go ahead
|
||||||
// and clamp it here
|
// and clamp it here
|
||||||
MsgDev( D_ERROR, "StudioCalcRotations: f = %g\n", f );
|
MsgDev( D_ERROR, "StudioCalcRotations: f = %g\n", f );
|
||||||
|
@ -1429,6 +1428,9 @@ void R_StudioDynamicLight( cl_entity_t *ent, alight_t *lightinfo )
|
||||||
}
|
}
|
||||||
else VectorSet( plight->lightvec, 0.0f, 0.0f, -1.0f );
|
else VectorSet( plight->lightvec, 0.0f, 0.0f, -1.0f );
|
||||||
|
|
||||||
|
if( VectorIsNull( plight->lightvec ))
|
||||||
|
VectorSet( plight->lightvec, 0.0f, 0.0f, -1.0f );
|
||||||
|
|
||||||
VectorCopy( plight->lightvec, lightinfo->plightvec );
|
VectorCopy( plight->lightvec, lightinfo->plightvec );
|
||||||
|
|
||||||
// setup ambient lighting
|
// setup ambient lighting
|
||||||
|
@ -1649,14 +1651,14 @@ void R_StudioLighting( float *lv, int bone, int flags, vec3_t normal )
|
||||||
for( i = 0; i < plight->numdlights; i++)
|
for( i = 0; i < plight->numdlights; i++)
|
||||||
{
|
{
|
||||||
lightcos = -DotProduct( normal, plight->dlightvec[i][bone] );
|
lightcos = -DotProduct( normal, plight->dlightvec[i][bone] );
|
||||||
if( lightcos > 0 ) VectorMA( illum, lightcos, plight->dlightcolor[i], illum );
|
if( lightcos > 0.0f ) VectorMA( illum, lightcos, plight->dlightcolor[i], illum );
|
||||||
}
|
}
|
||||||
|
|
||||||
// now add all entity lights
|
// now add all entity lights
|
||||||
for( i = 0; i < plight->numelights; i++)
|
for( i = 0; i < plight->numelights; i++)
|
||||||
{
|
{
|
||||||
lightcos = -DotProduct( normal, plight->elightvec[i][bone] );
|
lightcos = -DotProduct( normal, plight->elightvec[i][bone] );
|
||||||
if( lightcos > 0 ) VectorMA( illum, lightcos, plight->elightcolor[i], illum );
|
if( lightcos > 0.0f ) VectorMA( illum, lightcos, plight->elightcolor[i], illum );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1962,6 +1964,10 @@ static void R_StudioDrawPoints( void )
|
||||||
clr = &RI.currententity->curstate.rendercolor;
|
clr = &RI.currententity->curstate.rendercolor;
|
||||||
pglColor4ub( clr->r, clr->g, clr->b, alpha * 255 );
|
pglColor4ub( clr->r, clr->g, clr->b, alpha * 255 );
|
||||||
}
|
}
|
||||||
|
else if( g_nFaceFlags & STUDIO_NF_FULLBRIGHT )
|
||||||
|
{
|
||||||
|
pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
lv = (float *)g_lightvalues[ptricmds[1]];
|
lv = (float *)g_lightvalues[ptricmds[1]];
|
||||||
|
|
|
@ -378,7 +378,7 @@ void VOX_FreeWord( channel_t *pchan )
|
||||||
pchan->currentWord = NULL; // sentence is finished
|
pchan->currentWord = NULL; // sentence is finished
|
||||||
Q_memset( &pchan->pMixer, 0, sizeof( pchan->pMixer ));
|
Q_memset( &pchan->pMixer, 0, sizeof( pchan->pMixer ));
|
||||||
|
|
||||||
// UNDONE: release unused sounds ?
|
// release unused sounds ?
|
||||||
#if 0
|
#if 0
|
||||||
if( pchan->words[pchan->wordIndex].sfx )
|
if( pchan->words[pchan->wordIndex].sfx )
|
||||||
{
|
{
|
||||||
|
|
|
@ -731,7 +731,7 @@ void Cmd_ForwardToServer( void )
|
||||||
|
|
||||||
if( cls.demoplayback )
|
if( cls.demoplayback )
|
||||||
{
|
{
|
||||||
if( !Q_stricmp( Cmd_Argv( 1 ), "pause" ))
|
if( !Q_stricmp( Cmd_Argv( 0 ), "pause" ))
|
||||||
cl.refdef.paused ^= 1;
|
cl.refdef.paused ^= 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -266,6 +266,7 @@ typedef struct
|
||||||
float volume;
|
float volume;
|
||||||
float attenuation;
|
float attenuation;
|
||||||
qboolean looping;
|
qboolean looping;
|
||||||
|
int channel;
|
||||||
int pitch;
|
int pitch;
|
||||||
} soundlist_t;
|
} soundlist_t;
|
||||||
|
|
||||||
|
@ -310,6 +311,7 @@ typedef struct host_parm_s
|
||||||
qboolean overview_loading; // another nasty hack to tell imagelib about ovierview
|
qboolean overview_loading; // another nasty hack to tell imagelib about ovierview
|
||||||
qboolean force_draw_version; // used when fraps is loaded
|
qboolean force_draw_version; // used when fraps is loaded
|
||||||
qboolean write_to_clipboard; // put image to clipboard instead of disk
|
qboolean write_to_clipboard; // put image to clipboard instead of disk
|
||||||
|
qboolean crashed; // set to true if crashed
|
||||||
|
|
||||||
char rootdir[256]; // member root directory
|
char rootdir[256]; // member root directory
|
||||||
char gamefolder[64]; // it's a default gamefolder
|
char gamefolder[64]; // it's a default gamefolder
|
||||||
|
@ -370,6 +372,7 @@ fs_offset_t FS_FileTime( const char *filename, qboolean gamedironly );
|
||||||
int FS_Print( file_t *file, const char *msg );
|
int FS_Print( file_t *file, const char *msg );
|
||||||
qboolean FS_Rename( const char *oldname, const char *newname );
|
qboolean FS_Rename( const char *oldname, const char *newname );
|
||||||
qboolean FS_FileExists( const char *filename, qboolean gamedironly );
|
qboolean FS_FileExists( const char *filename, qboolean gamedironly );
|
||||||
|
void FS_FileCopy( file_t *pOutput, file_t *pInput, int fileSize );
|
||||||
qboolean FS_Delete( const char *path );
|
qboolean FS_Delete( const char *path );
|
||||||
int FS_UnGetc( file_t *file, byte c );
|
int FS_UnGetc( file_t *file, byte c );
|
||||||
void FS_StripExtension( char *path );
|
void FS_StripExtension( char *path );
|
||||||
|
@ -569,6 +572,7 @@ void Host_NewInstance( const char *name, const char *finalmsg );
|
||||||
qboolean Host_NewGame( const char *mapName, qboolean loadGame );
|
qboolean Host_NewGame( const char *mapName, qboolean loadGame );
|
||||||
void Host_EndGame( const char *message, ... );
|
void Host_EndGame( const char *message, ... );
|
||||||
void Host_AbortCurrentFrame( void );
|
void Host_AbortCurrentFrame( void );
|
||||||
|
void Host_RestartAmbientSounds( void );
|
||||||
qboolean CL_ChangeGame( const char *gamefolder, qboolean bReset );
|
qboolean CL_ChangeGame( const char *gamefolder, qboolean bReset );
|
||||||
void Host_WriteServerConfig( const char *name );
|
void Host_WriteServerConfig( const char *name );
|
||||||
void Host_WriteOpenGLConfig( void );
|
void Host_WriteOpenGLConfig( void );
|
||||||
|
|
|
@ -2008,7 +2008,7 @@ fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize )
|
||||||
done += nb;
|
done += nb;
|
||||||
file->position += nb;
|
file->position += nb;
|
||||||
// Purge cached data
|
// Purge cached data
|
||||||
FS_Purge (file);
|
FS_Purge( file );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -2618,6 +2618,30 @@ qboolean FS_Delete( const char *path )
|
||||||
return (iRet == 0);
|
return (iRet == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
==================
|
||||||
|
FS_FileCopy
|
||||||
|
|
||||||
|
==================
|
||||||
|
*/
|
||||||
|
void FS_FileCopy( file_t *pOutput, file_t *pInput, int fileSize )
|
||||||
|
{
|
||||||
|
char buf[MAX_SYSPATH]; // A small buffer for the copy
|
||||||
|
int size;
|
||||||
|
|
||||||
|
while( fileSize > 0 )
|
||||||
|
{
|
||||||
|
if( fileSize > MAX_SYSPATH )
|
||||||
|
size = MAX_SYSPATH;
|
||||||
|
else size = fileSize;
|
||||||
|
|
||||||
|
FS_Read( pInput, buf, size );
|
||||||
|
FS_Write( pOutput, buf, size );
|
||||||
|
|
||||||
|
fileSize -= size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
===========
|
===========
|
||||||
FS_Search
|
FS_Search
|
||||||
|
|
|
@ -318,6 +318,37 @@ void Host_InitDecals( void )
|
||||||
MsgDev( D_NOTE, "InitDecals: %i decals\n", num_decals );
|
MsgDev( D_NOTE, "InitDecals: %i decals\n", num_decals );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=================
|
||||||
|
Host_RestartAmbientSounds
|
||||||
|
|
||||||
|
Write ambient sounds into demo
|
||||||
|
=================
|
||||||
|
*/
|
||||||
|
void Host_RestartAmbientSounds( void )
|
||||||
|
{
|
||||||
|
soundlist_t soundInfo[64];
|
||||||
|
int i, nSounds;
|
||||||
|
|
||||||
|
if( !SV_Active( ))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nSounds = S_GetCurrentStaticSounds( soundInfo, 64 );
|
||||||
|
|
||||||
|
for( i = 0; i < nSounds; i++ )
|
||||||
|
{
|
||||||
|
if( !soundInfo[i].looping || soundInfo[i].entnum == -1 )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Msg( "Restarting sound %s...\n", soundInfo[i].name );
|
||||||
|
S_StopSound( soundInfo[i].entnum, soundInfo[i].channel, soundInfo[i].name );
|
||||||
|
SV_StartSound( pfnPEntityOfEntIndex( soundInfo[i].entnum ), CHAN_STATIC, soundInfo[i].name,
|
||||||
|
soundInfo[i].volume, soundInfo[i].attenuation, 0, soundInfo[i].pitch );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
===================
|
===================
|
||||||
Host_GetConsoleCommands
|
Host_GetConsoleCommands
|
||||||
|
@ -373,7 +404,7 @@ qboolean Host_FilterTime( float time )
|
||||||
host.realframetime = bound( MIN_FRAMETIME, host.frametime, MAX_FRAMETIME );
|
host.realframetime = bound( MIN_FRAMETIME, host.frametime, MAX_FRAMETIME );
|
||||||
oldtime = host.realtime;
|
oldtime = host.realtime;
|
||||||
|
|
||||||
if( host_framerate->value > 0 && ( Host_IsLocalGame() || CL_IsPlaybackDemo() ))
|
if( host_framerate->value > 0 && ( Host_IsLocalGame()/* || CL_IsPlaybackDemo() */))
|
||||||
{
|
{
|
||||||
float fps = host_framerate->value;
|
float fps = host_framerate->value;
|
||||||
if( fps > 1 ) fps = 1.0f / fps;
|
if( fps > 1 ) fps = 1.0f / fps;
|
||||||
|
@ -782,8 +813,6 @@ int EXPORT Host_Main( const char *progname, int bChangeGame, pfnChangeGame func
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
SCR_CheckStartupVids(); // must be last
|
|
||||||
|
|
||||||
host.change_game = false; // done
|
host.change_game = false; // done
|
||||||
Cmd_RemoveCommand( "setr" ); // remove potentially backdoor for change render settings
|
Cmd_RemoveCommand( "setr" ); // remove potentially backdoor for change render settings
|
||||||
Cmd_RemoveCommand( "setgl" );
|
Cmd_RemoveCommand( "setgl" );
|
||||||
|
@ -791,9 +820,10 @@ int EXPORT Host_Main( const char *progname, int bChangeGame, pfnChangeGame func
|
||||||
// we need to execute it again here
|
// we need to execute it again here
|
||||||
Cmd_ExecuteString( "exec config.cfg\n", src_command );
|
Cmd_ExecuteString( "exec config.cfg\n", src_command );
|
||||||
oldtime = Sys_DoubleTime();
|
oldtime = Sys_DoubleTime();
|
||||||
|
SCR_CheckStartupVids(); // must be last
|
||||||
|
|
||||||
// main window message loop
|
// main window message loop
|
||||||
while( 1 )
|
while( !host.crashed )
|
||||||
{
|
{
|
||||||
newtime = Sys_DoubleTime ();
|
newtime = Sys_DoubleTime ();
|
||||||
Host_Frame( newtime - oldtime );
|
Host_Frame( newtime - oldtime );
|
||||||
|
|
|
@ -353,8 +353,11 @@ void Netchan_OutOfBand( int net_socket, netadr_t adr, int length, byte *data )
|
||||||
BF_WriteLong( &send, -1 ); // -1 sequence means out of band
|
BF_WriteLong( &send, -1 ); // -1 sequence means out of band
|
||||||
BF_WriteBytes( &send, data, length );
|
BF_WriteBytes( &send, data, length );
|
||||||
|
|
||||||
// send the datagram
|
if( !CL_IsPlaybackDemo( ))
|
||||||
NET_SendPacket( net_socket, BF_GetNumBytesWritten( &send ), BF_GetData( &send ), adr );
|
{
|
||||||
|
// send the datagram
|
||||||
|
NET_SendPacket( net_socket, BF_GetNumBytesWritten( &send ), BF_GetData( &send ), adr );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1429,7 +1432,10 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data )
|
||||||
chan->total_sended_uncompressed += size1;
|
chan->total_sended_uncompressed += size1;
|
||||||
|
|
||||||
// send the datagram
|
// send the datagram
|
||||||
NET_SendPacket( chan->sock, BF_GetNumBytesWritten( &send ), BF_GetData( &send ), chan->remote_address );
|
if( !CL_IsPlaybackDemo( ))
|
||||||
|
{
|
||||||
|
NET_SendPacket( chan->sock, BF_GetNumBytesWritten( &send ), BF_GetData( &send ), chan->remote_address );
|
||||||
|
}
|
||||||
|
|
||||||
fRate = 1.0f / chan->rate;
|
fRate = 1.0f / chan->rate;
|
||||||
|
|
||||||
|
@ -1492,7 +1498,7 @@ qboolean Netchan_Process( netchan_t *chan, sizebuf_t *msg )
|
||||||
size_t size1, size2;
|
size_t size1, size2;
|
||||||
int i, qport;
|
int i, qport;
|
||||||
|
|
||||||
if( !NET_CompareAdr( net_from, chan->remote_address ))
|
if( !CL_IsPlaybackDemo() && !NET_CompareAdr( net_from, chan->remote_address ))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,22 +32,22 @@ static qboolean delta_init = false;
|
||||||
// list of all the struct names
|
// list of all the struct names
|
||||||
static const delta_field_t cmd_fields[] =
|
static const delta_field_t cmd_fields[] =
|
||||||
{
|
{
|
||||||
{ UCMD_DEF(lerp_msec) },
|
{ UCMD_DEF( lerp_msec ) },
|
||||||
{ UCMD_DEF(msec) },
|
{ UCMD_DEF( msec ) },
|
||||||
{ UCMD_DEF(viewangles[0]) },
|
{ UCMD_DEF( viewangles[0] ) },
|
||||||
{ UCMD_DEF(viewangles[1]) },
|
{ UCMD_DEF( viewangles[1] ) },
|
||||||
{ UCMD_DEF(viewangles[2]) },
|
{ UCMD_DEF( viewangles[2] ) },
|
||||||
{ UCMD_DEF(forwardmove) },
|
{ UCMD_DEF( forwardmove ) },
|
||||||
{ UCMD_DEF(sidemove) },
|
{ UCMD_DEF( sidemove ) },
|
||||||
{ UCMD_DEF(upmove) },
|
{ UCMD_DEF( upmove ) },
|
||||||
{ UCMD_DEF(lightlevel) },
|
{ UCMD_DEF( lightlevel ) },
|
||||||
{ UCMD_DEF(buttons) },
|
{ UCMD_DEF( buttons ) },
|
||||||
{ UCMD_DEF(impulse) },
|
{ UCMD_DEF( impulse ) },
|
||||||
{ UCMD_DEF(weaponselect) },
|
{ UCMD_DEF( weaponselect ) },
|
||||||
{ UCMD_DEF(impact_index) },
|
{ UCMD_DEF( impact_index ) },
|
||||||
{ UCMD_DEF(impact_position[0])},
|
{ UCMD_DEF( impact_position[0] ) },
|
||||||
{ UCMD_DEF(impact_position[1])},
|
{ UCMD_DEF( impact_position[1] ) },
|
||||||
{ UCMD_DEF(impact_position[2])},
|
{ UCMD_DEF( impact_position[2] ) },
|
||||||
{ NULL },
|
{ NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,934 @@
|
||||||
|
/*
|
||||||
|
pm_studio.c - stduio models tracing
|
||||||
|
Copyright (C) 2010 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 "studio.h"
|
||||||
|
#include "mathlib.h"
|
||||||
|
#include "mod_local.h"
|
||||||
|
#include "pm_local.h"
|
||||||
|
#include "pm_movevars.h"
|
||||||
|
#include "world.h"
|
||||||
|
|
||||||
|
static studiohdr_t *pm_studiohdr;
|
||||||
|
static mplane_t pm_hitboxplanes[6]; // there a temp hitbox
|
||||||
|
static matrix3x4 pm_studiomatrix;
|
||||||
|
static matrix3x4 pm_studiobones[MAXSTUDIOBONES];
|
||||||
|
typedef qboolean (*pfnTrace)( pmtrace_t *trace );
|
||||||
|
static float trace_realfraction;
|
||||||
|
static vec3_t trace_startmins, trace_endmins;
|
||||||
|
static vec3_t trace_startmaxs, trace_endmaxs;
|
||||||
|
static vec3_t trace_absmins, trace_absmaxs;
|
||||||
|
|
||||||
|
/*
|
||||||
|
====================
|
||||||
|
PM_InitStudioHull
|
||||||
|
====================
|
||||||
|
*/
|
||||||
|
void PM_InitStudioHull( void )
|
||||||
|
{
|
||||||
|
int i, side;
|
||||||
|
mplane_t *p;
|
||||||
|
|
||||||
|
for( i = 0; i < 6; i++ )
|
||||||
|
{
|
||||||
|
side = i & 1;
|
||||||
|
|
||||||
|
// planes
|
||||||
|
p = &pm_hitboxplanes[i];
|
||||||
|
VectorClear( p->normal );
|
||||||
|
|
||||||
|
if( side )
|
||||||
|
{
|
||||||
|
p->type = PLANE_NONAXIAL;
|
||||||
|
p->normal[i>>1] = -1.0f;
|
||||||
|
p->signbits = (1<<(i>>1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p->type = i>>1;
|
||||||
|
p->normal[i>>1] = 1.0f;
|
||||||
|
p->signbits = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
====================
|
||||||
|
PM_HullForHitbox
|
||||||
|
====================
|
||||||
|
*/
|
||||||
|
static void PM_HullForHitbox( const vec3_t mins, const vec3_t maxs )
|
||||||
|
{
|
||||||
|
pm_hitboxplanes[0].dist = maxs[0];
|
||||||
|
pm_hitboxplanes[1].dist = -mins[0];
|
||||||
|
pm_hitboxplanes[2].dist = maxs[1];
|
||||||
|
pm_hitboxplanes[3].dist = -mins[1];
|
||||||
|
pm_hitboxplanes[4].dist = maxs[2];
|
||||||
|
pm_hitboxplanes[5].dist = -mins[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
===============================================================================
|
||||||
|
|
||||||
|
STUDIO MODELS TRACING
|
||||||
|
|
||||||
|
===============================================================================
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
====================
|
||||||
|
StudioPlayerBlend
|
||||||
|
|
||||||
|
====================
|
||||||
|
*/
|
||||||
|
void PM_StudioPlayerBlend( mstudioseqdesc_t *pseqdesc, int *pBlend, float *pPitch )
|
||||||
|
{
|
||||||
|
// calc up/down pointing
|
||||||
|
*pBlend = (*pPitch * 3);
|
||||||
|
|
||||||
|
if( *pBlend < pseqdesc->blendstart[0] )
|
||||||
|
{
|
||||||
|
*pPitch -= pseqdesc->blendstart[0] / 3.0f;
|
||||||
|
*pBlend = 0;
|
||||||
|
}
|
||||||
|
else if( *pBlend > pseqdesc->blendend[0] )
|
||||||
|
{
|
||||||
|
*pPitch -= pseqdesc->blendend[0] / 3.0f;
|
||||||
|
*pBlend = 255;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( pseqdesc->blendend[0] - pseqdesc->blendstart[0] < 0.1f ) // catch qc error
|
||||||
|
*pBlend = 127;
|
||||||
|
else *pBlend = 255.0f * (*pBlend - pseqdesc->blendstart[0]) / (pseqdesc->blendend[0] - pseqdesc->blendstart[0]);
|
||||||
|
*pPitch = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
====================
|
||||||
|
StudioCalcBoneAdj
|
||||||
|
|
||||||
|
====================
|
||||||
|
*/
|
||||||
|
static void PM_StudioCalcBoneAdj( float *adj, const byte *pcontroller )
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
float value;
|
||||||
|
mstudiobonecontroller_t *pbonecontroller;
|
||||||
|
|
||||||
|
pbonecontroller = (mstudiobonecontroller_t *)((byte *)pm_studiohdr + pm_studiohdr->bonecontrollerindex);
|
||||||
|
|
||||||
|
for( j = 0; j < pm_studiohdr->numbonecontrollers; j++ )
|
||||||
|
{
|
||||||
|
i = pbonecontroller[j].index;
|
||||||
|
|
||||||
|
if( i == 4 ) continue; // ignore mouth
|
||||||
|
if( i <= MAXSTUDIOCONTROLLERS )
|
||||||
|
{
|
||||||
|
// check for 360% wrapping
|
||||||
|
if( pbonecontroller[j].type & STUDIO_RLOOP )
|
||||||
|
{
|
||||||
|
value = pcontroller[i] * (360.0/256.0) + pbonecontroller[j].start;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
value = pcontroller[i] / 255.0f;
|
||||||
|
if( value < 0.0f ) value = 0.0f;
|
||||||
|
if( value > 1.0f ) value = 1.0f;
|
||||||
|
value = (1.0f - value) * pbonecontroller[j].start + value * pbonecontroller[j].end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch( pbonecontroller[j].type & STUDIO_TYPES )
|
||||||
|
{
|
||||||
|
case STUDIO_XR:
|
||||||
|
case STUDIO_YR:
|
||||||
|
case STUDIO_ZR:
|
||||||
|
adj[j] = value * (M_PI / 180.0);
|
||||||
|
break;
|
||||||
|
case STUDIO_X:
|
||||||
|
case STUDIO_Y:
|
||||||
|
case STUDIO_Z:
|
||||||
|
adj[j] = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
====================
|
||||||
|
StudioCalcBoneQuaterion
|
||||||
|
|
||||||
|
====================
|
||||||
|
*/
|
||||||
|
static void PM_StudioCalcBoneQuaterion( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *q )
|
||||||
|
{
|
||||||
|
int j, k;
|
||||||
|
vec4_t q1, q2;
|
||||||
|
vec3_t angle1, angle2;
|
||||||
|
mstudioanimvalue_t *panimvalue;
|
||||||
|
|
||||||
|
for( j = 0; j < 3; j++ )
|
||||||
|
{
|
||||||
|
if( panim->offset[j+3] == 0 )
|
||||||
|
{
|
||||||
|
angle2[j] = angle1[j] = pbone->value[j+3]; // default;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j+3]);
|
||||||
|
k = frame;
|
||||||
|
|
||||||
|
// debug
|
||||||
|
if( panimvalue->num.total < panimvalue->num.valid )
|
||||||
|
k = 0;
|
||||||
|
|
||||||
|
while( panimvalue->num.total <= k )
|
||||||
|
{
|
||||||
|
k -= panimvalue->num.total;
|
||||||
|
panimvalue += panimvalue->num.valid + 1;
|
||||||
|
// DEBUG
|
||||||
|
if( panimvalue->num.total < panimvalue->num.valid )
|
||||||
|
k = 0;
|
||||||
|
}
|
||||||
|
// Bah, missing blend!
|
||||||
|
if( panimvalue->num.valid > k )
|
||||||
|
{
|
||||||
|
angle1[j] = panimvalue[k+1].value;
|
||||||
|
|
||||||
|
if( panimvalue->num.valid > k + 1 )
|
||||||
|
{
|
||||||
|
angle2[j] = panimvalue[k+2].value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( panimvalue->num.total > k + 1 )
|
||||||
|
angle2[j] = angle1[j];
|
||||||
|
else angle2[j] = panimvalue[panimvalue->num.valid+2].value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
angle1[j] = panimvalue[panimvalue->num.valid].value;
|
||||||
|
if( panimvalue->num.total > k + 1 )
|
||||||
|
{
|
||||||
|
angle2[j] = angle1[j];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
angle2[j] = panimvalue[panimvalue->num.valid + 2].value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
angle1[j] = pbone->value[j+3] + angle1[j] * pbone->scale[j+3];
|
||||||
|
angle2[j] = pbone->value[j+3] + angle2[j] * pbone->scale[j+3];
|
||||||
|
}
|
||||||
|
|
||||||
|
if( pbone->bonecontroller[j+3] != -1 )
|
||||||
|
{
|
||||||
|
angle1[j] += adj[pbone->bonecontroller[j+3]];
|
||||||
|
angle2[j] += adj[pbone->bonecontroller[j+3]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !VectorCompare( angle1, angle2 ))
|
||||||
|
{
|
||||||
|
AngleQuaternion( angle1, q1 );
|
||||||
|
AngleQuaternion( angle2, q2 );
|
||||||
|
QuaternionSlerp( q1, q2, s, q );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AngleQuaternion( angle1, q );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
====================
|
||||||
|
StudioCalcBonePosition
|
||||||
|
|
||||||
|
====================
|
||||||
|
*/
|
||||||
|
static void PM_StudioCalcBonePosition( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *pos )
|
||||||
|
{
|
||||||
|
int j, k;
|
||||||
|
mstudioanimvalue_t *panimvalue;
|
||||||
|
|
||||||
|
for( j = 0; j < 3; j++ )
|
||||||
|
{
|
||||||
|
pos[j] = pbone->value[j]; // default;
|
||||||
|
if( panim->offset[j] != 0.0f )
|
||||||
|
{
|
||||||
|
panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j]);
|
||||||
|
|
||||||
|
k = frame;
|
||||||
|
|
||||||
|
// debug
|
||||||
|
if( panimvalue->num.total < panimvalue->num.valid )
|
||||||
|
k = 0;
|
||||||
|
|
||||||
|
// find span of values that includes the frame we want
|
||||||
|
while( panimvalue->num.total <= k )
|
||||||
|
{
|
||||||
|
k -= panimvalue->num.total;
|
||||||
|
panimvalue += panimvalue->num.valid + 1;
|
||||||
|
|
||||||
|
// DEBUG
|
||||||
|
if( panimvalue->num.total < panimvalue->num.valid )
|
||||||
|
k = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we're inside the span
|
||||||
|
if( panimvalue->num.valid > k )
|
||||||
|
{
|
||||||
|
// and there's more data in the span
|
||||||
|
if( panimvalue->num.valid > k + 1 )
|
||||||
|
{
|
||||||
|
pos[j] += (panimvalue[k+1].value * (1.0f - s) + s * panimvalue[k+2].value) * pbone->scale[j];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pos[j] += panimvalue[k+1].value * pbone->scale[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// are we at the end of the repeating values section and there's another section with data?
|
||||||
|
if( panimvalue->num.total <= k + 1 )
|
||||||
|
{
|
||||||
|
pos[j] += (panimvalue[panimvalue->num.valid].value * (1.0f - s) + s * panimvalue[panimvalue->num.valid + 2].value) * pbone->scale[j];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pos[j] += panimvalue[panimvalue->num.valid].value * pbone->scale[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( pbone->bonecontroller[j] != -1 && adj )
|
||||||
|
{
|
||||||
|
pos[j] += adj[pbone->bonecontroller[j]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
====================
|
||||||
|
StudioCalcRotations
|
||||||
|
|
||||||
|
====================
|
||||||
|
*/
|
||||||
|
static void PM_StudioCalcRotations( physent_t *pe, const byte *pcontroller, float pos[][3], vec4_t *q, mstudioseqdesc_t *pseqdesc, mstudioanim_t *panim, float f )
|
||||||
|
{
|
||||||
|
int i, frame;
|
||||||
|
mstudiobone_t *pbone;
|
||||||
|
float adj[MAXSTUDIOCONTROLLERS];
|
||||||
|
float s;
|
||||||
|
|
||||||
|
if( f > pseqdesc->numframes - 1 )
|
||||||
|
f = 0;
|
||||||
|
else if( f < -0.01f )
|
||||||
|
f = -0.01f;
|
||||||
|
|
||||||
|
frame = (int)f;
|
||||||
|
s = (f - frame);
|
||||||
|
|
||||||
|
// add in programtic controllers
|
||||||
|
pbone = (mstudiobone_t *)((byte *)pm_studiohdr + pm_studiohdr->boneindex);
|
||||||
|
|
||||||
|
PM_StudioCalcBoneAdj( adj, pcontroller );
|
||||||
|
|
||||||
|
for( i = 0; i < pm_studiohdr->numbones; i++, pbone++, panim++ )
|
||||||
|
{
|
||||||
|
PM_StudioCalcBoneQuaterion( frame, s, pbone, panim, adj, q[i] );
|
||||||
|
PM_StudioCalcBonePosition( frame, s, pbone, panim, adj, pos[i] );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( pseqdesc->motiontype & STUDIO_X ) pos[pseqdesc->motionbone][0] = 0.0f;
|
||||||
|
if( pseqdesc->motiontype & STUDIO_Y ) pos[pseqdesc->motionbone][1] = 0.0f;
|
||||||
|
if( pseqdesc->motiontype & STUDIO_Z ) pos[pseqdesc->motionbone][2] = 0.0f;
|
||||||
|
|
||||||
|
s = 0 * ((1.0 - (f - (int)(f))) / (pseqdesc->numframes)) * 1.0f; // framerate
|
||||||
|
|
||||||
|
if( pseqdesc->motiontype & STUDIO_LX ) pos[pseqdesc->motionbone][0] += s * pseqdesc->linearmovement[0];
|
||||||
|
if( pseqdesc->motiontype & STUDIO_LY ) pos[pseqdesc->motionbone][1] += s * pseqdesc->linearmovement[1];
|
||||||
|
if( pseqdesc->motiontype & STUDIO_LZ ) pos[pseqdesc->motionbone][2] += s * pseqdesc->linearmovement[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
====================
|
||||||
|
StudioEstimateFrame
|
||||||
|
|
||||||
|
====================
|
||||||
|
*/
|
||||||
|
static float PM_StudioEstimateFrame( physent_t *pe, mstudioseqdesc_t *pseqdesc )
|
||||||
|
{
|
||||||
|
double f;
|
||||||
|
|
||||||
|
if( pseqdesc->numframes <= 1 )
|
||||||
|
f = 0;
|
||||||
|
else f = (pe->frame * (pseqdesc->numframes - 1)) / 256.0;
|
||||||
|
|
||||||
|
if( pseqdesc->flags & STUDIO_LOOPING )
|
||||||
|
{
|
||||||
|
if( pseqdesc->numframes > 1 )
|
||||||
|
f -= (int)(f / (pseqdesc->numframes - 1)) * (pseqdesc->numframes - 1);
|
||||||
|
if( f < 0 ) f += (pseqdesc->numframes - 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( f >= pseqdesc->numframes - 1.001 )
|
||||||
|
f = pseqdesc->numframes - 1.001;
|
||||||
|
if( f < 0.0 ) f = 0.0;
|
||||||
|
}
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
====================
|
||||||
|
StudioSlerpBones
|
||||||
|
|
||||||
|
====================
|
||||||
|
*/
|
||||||
|
static void PM_StudioSlerpBones( vec4_t q1[], float pos1[][3], vec4_t q2[], float pos2[][3], float s )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
vec4_t q3;
|
||||||
|
float s1;
|
||||||
|
|
||||||
|
s = bound( 0.0f, s, 1.0f );
|
||||||
|
s1 = 1.0f - s;
|
||||||
|
|
||||||
|
for( i = 0; i < pm_studiohdr->numbones; i++ )
|
||||||
|
{
|
||||||
|
QuaternionSlerp( q1[i], q2[i], s, q3 );
|
||||||
|
q1[i][0] = q3[0];
|
||||||
|
q1[i][1] = q3[1];
|
||||||
|
q1[i][2] = q3[2];
|
||||||
|
q1[i][3] = q3[3];
|
||||||
|
pos1[i][0] = pos1[i][0] * s1 + pos2[i][0] * s;
|
||||||
|
pos1[i][1] = pos1[i][1] * s1 + pos2[i][1] * s;
|
||||||
|
pos1[i][2] = pos1[i][2] * s1 + pos2[i][2] * s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
====================
|
||||||
|
PM_StudioGetAnim
|
||||||
|
|
||||||
|
====================
|
||||||
|
*/
|
||||||
|
static mstudioanim_t *PM_StudioGetAnim( model_t *m_pSubModel, mstudioseqdesc_t *pseqdesc )
|
||||||
|
{
|
||||||
|
mstudioseqgroup_t *pseqgroup;
|
||||||
|
cache_user_t *paSequences;
|
||||||
|
size_t filesize;
|
||||||
|
byte *buf;
|
||||||
|
|
||||||
|
pseqgroup = (mstudioseqgroup_t *)((byte *)pm_studiohdr + pm_studiohdr->seqgroupindex) + pseqdesc->seqgroup;
|
||||||
|
if( pseqdesc->seqgroup == 0 )
|
||||||
|
return (mstudioanim_t *)((byte *)pm_studiohdr + pseqgroup->data + pseqdesc->animindex);
|
||||||
|
|
||||||
|
paSequences = (cache_user_t *)m_pSubModel->submodels;
|
||||||
|
|
||||||
|
if( paSequences == NULL )
|
||||||
|
{
|
||||||
|
paSequences = (cache_user_t *)Mem_Alloc( com_studiocache, MAXSTUDIOGROUPS * sizeof( cache_user_t ));
|
||||||
|
m_pSubModel->submodels = (void *)paSequences;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for already loaded
|
||||||
|
if( !Mod_CacheCheck(( cache_user_t *)&( paSequences[pseqdesc->seqgroup] )))
|
||||||
|
{
|
||||||
|
string filepath, modelname, modelpath;
|
||||||
|
|
||||||
|
FS_FileBase( m_pSubModel->name, modelname );
|
||||||
|
FS_ExtractFilePath( m_pSubModel->name, modelpath );
|
||||||
|
Q_snprintf( filepath, sizeof( filepath ), "%s/%s%i%i.mdl", modelpath, modelname, pseqdesc->seqgroup / 10, pseqdesc->seqgroup % 10 );
|
||||||
|
|
||||||
|
buf = FS_LoadFile( filepath, &filesize, false );
|
||||||
|
if( !buf || !filesize ) Host_Error( "StudioGetAnim: can't load %s\n", filepath );
|
||||||
|
if( IDSEQGRPHEADER != *(uint *)buf )
|
||||||
|
Host_Error( "StudioGetAnim: %s is corrupted\n", filepath );
|
||||||
|
|
||||||
|
MsgDev( D_INFO, "loading: %s\n", filepath );
|
||||||
|
|
||||||
|
paSequences[pseqdesc->seqgroup].data = Mem_Alloc( com_studiocache, filesize );
|
||||||
|
Q_memcpy( paSequences[pseqdesc->seqgroup].data, buf, filesize );
|
||||||
|
Mem_Free( buf );
|
||||||
|
}
|
||||||
|
return (mstudioanim_t *)((byte *)paSequences[pseqdesc->seqgroup].data + pseqdesc->animindex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
====================
|
||||||
|
PM_StudioSetupBones
|
||||||
|
====================
|
||||||
|
*/
|
||||||
|
static void PM_StudioSetupBones( playermove_t *pmove, physent_t *pe, const vec3_t angles, const vec3_t origin, const byte *pcontroller, const byte *pblending )
|
||||||
|
{
|
||||||
|
int i, oldseq;
|
||||||
|
float scale = 1.0f;
|
||||||
|
double f;
|
||||||
|
|
||||||
|
mstudiobone_t *pbones;
|
||||||
|
mstudioseqdesc_t *pseqdesc;
|
||||||
|
mstudioanim_t *panim;
|
||||||
|
|
||||||
|
static float pos[MAXSTUDIOBONES][3];
|
||||||
|
static vec4_t q[MAXSTUDIOBONES];
|
||||||
|
matrix3x4 bonematrix;
|
||||||
|
|
||||||
|
static float pos2[MAXSTUDIOBONES][3];
|
||||||
|
static vec4_t q2[MAXSTUDIOBONES];
|
||||||
|
static float pos3[MAXSTUDIOBONES][3];
|
||||||
|
static vec4_t q3[MAXSTUDIOBONES];
|
||||||
|
static float pos4[MAXSTUDIOBONES][3];
|
||||||
|
static vec4_t q4[MAXSTUDIOBONES];
|
||||||
|
|
||||||
|
oldseq = pe->sequence; // TraceCode can't change sequence
|
||||||
|
|
||||||
|
if( pe->sequence >= pm_studiohdr->numseq ) pe->sequence = 0;
|
||||||
|
pseqdesc = (mstudioseqdesc_t *)((byte *)pm_studiohdr + pm_studiohdr->seqindex) + pe->sequence;
|
||||||
|
|
||||||
|
f = PM_StudioEstimateFrame( pe, pseqdesc );
|
||||||
|
|
||||||
|
panim = PM_StudioGetAnim( pe->studiomodel, pseqdesc );
|
||||||
|
PM_StudioCalcRotations( pe, pcontroller, pos, q, pseqdesc, panim, f );
|
||||||
|
|
||||||
|
if( pseqdesc->numblends > 1 )
|
||||||
|
{
|
||||||
|
float s;
|
||||||
|
|
||||||
|
panim += pm_studiohdr->numbones;
|
||||||
|
PM_StudioCalcRotations( pe, pcontroller, pos2, q2, pseqdesc, panim, f );
|
||||||
|
|
||||||
|
s = (float)pe->blending[0] / 255.0f;
|
||||||
|
|
||||||
|
PM_StudioSlerpBones( q, pos, q2, pos2, s );
|
||||||
|
|
||||||
|
if( pseqdesc->numblends == 4 )
|
||||||
|
{
|
||||||
|
panim += pm_studiohdr->numbones;
|
||||||
|
PM_StudioCalcRotations( pe, pcontroller, pos3, q3, pseqdesc, panim, f );
|
||||||
|
|
||||||
|
panim += pm_studiohdr->numbones;
|
||||||
|
PM_StudioCalcRotations( pe, pcontroller, pos4, q4, pseqdesc, panim, f );
|
||||||
|
|
||||||
|
s = (float)pe->blending[0] / 255.0f;
|
||||||
|
PM_StudioSlerpBones( q3, pos3, q4, pos4, s );
|
||||||
|
|
||||||
|
s = (float)pe->blending[1] / 255.0f;
|
||||||
|
PM_StudioSlerpBones( q, pos, q3, pos3, s );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( pmove->movevars->studio_scale && pe->fuser1 > 0.0f )
|
||||||
|
scale = pe->fuser1;
|
||||||
|
else if( pe->player && pmove->movevars->clienttrace != 0.0f )
|
||||||
|
scale = pmove->movevars->clienttrace * 0.5f;
|
||||||
|
|
||||||
|
Matrix3x4_CreateFromEntity( pm_studiomatrix, angles, origin, scale );
|
||||||
|
|
||||||
|
pbones = (mstudiobone_t *)((byte *)pm_studiohdr + pm_studiohdr->boneindex);
|
||||||
|
|
||||||
|
for( i = 0; i < pm_studiohdr->numbones; i++ )
|
||||||
|
{
|
||||||
|
Matrix3x4_FromOriginQuat( bonematrix, q[i], pos[i] );
|
||||||
|
if( pbones[i].parent == -1 )
|
||||||
|
Matrix3x4_ConcatTransforms( pm_studiobones[i], pm_studiomatrix, bonematrix );
|
||||||
|
else Matrix3x4_ConcatTransforms( pm_studiobones[i], pm_studiobones[pbones[i].parent], bonematrix );
|
||||||
|
}
|
||||||
|
|
||||||
|
pe->sequence = oldseq; // restore original value
|
||||||
|
}
|
||||||
|
|
||||||
|
static qboolean PM_StudioSetupModel( playermove_t *pmove, physent_t *pe )
|
||||||
|
{
|
||||||
|
model_t *mod = pe->studiomodel;
|
||||||
|
vec3_t angles;
|
||||||
|
|
||||||
|
if( !mod || !mod->cache.data )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
pm_studiohdr = (studiohdr_t *)mod->cache.data;
|
||||||
|
VectorCopy( pe->angles, angles );
|
||||||
|
|
||||||
|
// calc blending for player
|
||||||
|
if( pe->player )
|
||||||
|
{
|
||||||
|
mstudioseqdesc_t *pseqdesc;
|
||||||
|
byte controller[4];
|
||||||
|
byte blending[2];
|
||||||
|
int iBlend;
|
||||||
|
|
||||||
|
pseqdesc = (mstudioseqdesc_t *)((byte *)pm_studiohdr + pm_studiohdr->seqindex) + pe->sequence;
|
||||||
|
|
||||||
|
PM_StudioPlayerBlend( pseqdesc, &iBlend, &angles[PITCH] );
|
||||||
|
|
||||||
|
controller[0] = controller[1] = controller[2] = controller[3] = 0x7F;
|
||||||
|
blending[0] = (byte)iBlend;
|
||||||
|
blending[1] = 0;
|
||||||
|
|
||||||
|
PM_StudioSetupBones( pmove, pe, angles, pe->origin, controller, blending );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PM_StudioSetupBones( pmove, pe, angles, pe->origin, pe->controller, pe->blending );
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
qboolean PM_StudioExtractBbox( playermove_t *pmove, physent_t *pe, model_t *mod, int sequence, float *mins, float *maxs )
|
||||||
|
{
|
||||||
|
mstudioseqdesc_t *pseqdesc;
|
||||||
|
studiohdr_t *phdr;
|
||||||
|
float scale = 1.0f;
|
||||||
|
|
||||||
|
ASSERT( mod != NULL );
|
||||||
|
|
||||||
|
if( mod->type != mod_studio || !mod->cache.data )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
phdr = (studiohdr_t *)mod->cache.data;
|
||||||
|
if( !phdr->numhitboxes ) return false;
|
||||||
|
|
||||||
|
pseqdesc = (mstudioseqdesc_t *)((byte *)phdr + phdr->seqindex);
|
||||||
|
|
||||||
|
if( sequence < 0 || sequence >= phdr->numseq )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( pmove->movevars->studio_scale && pe->fuser1 > 0.0f )
|
||||||
|
scale = pe->fuser1;
|
||||||
|
|
||||||
|
VectorScale( pseqdesc[sequence].bbmin, scale, mins );
|
||||||
|
VectorScale( pseqdesc[sequence].bbmax, scale, maxs );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
PM_ClipBoxToHitbox
|
||||||
|
|
||||||
|
trace hitbox
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
qboolean PM_ClipBoxToHitbox( pmtrace_t *trace )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
mplane_t *p, *clipplane;
|
||||||
|
float enterfrac, leavefrac, distfrac;
|
||||||
|
float d, d1, d2;
|
||||||
|
qboolean getout, startout;
|
||||||
|
float f;
|
||||||
|
|
||||||
|
enterfrac = -1.0f;
|
||||||
|
leavefrac = 1.0f;
|
||||||
|
clipplane = NULL;
|
||||||
|
|
||||||
|
getout = false;
|
||||||
|
startout = false;
|
||||||
|
|
||||||
|
for( i = 0; i < 6; i++ )
|
||||||
|
{
|
||||||
|
p = &pm_hitboxplanes[i];
|
||||||
|
|
||||||
|
// push the plane out apropriately for mins/maxs
|
||||||
|
if( p->type < 3 )
|
||||||
|
{
|
||||||
|
d1 = trace_startmins[p->type] - p->dist;
|
||||||
|
d2 = trace_endmins[p->type] - p->dist;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch( p->signbits )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
d1 = p->normal[0]*trace_startmins[0] + p->normal[1]*trace_startmins[1] + p->normal[2]*trace_startmins[2] - p->dist;
|
||||||
|
d2 = p->normal[0]*trace_endmins[0] + p->normal[1]*trace_endmins[1] + p->normal[2]*trace_endmins[2] - p->dist;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
d1 = p->normal[0]*trace_startmaxs[0] + p->normal[1]*trace_startmins[1] + p->normal[2]*trace_startmins[2] - p->dist;
|
||||||
|
d2 = p->normal[0]*trace_endmaxs[0] + p->normal[1]*trace_endmins[1] + p->normal[2]*trace_endmins[2] - p->dist;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
d1 = p->normal[0]*trace_startmins[0] + p->normal[1]*trace_startmaxs[1] + p->normal[2]*trace_startmins[2] - p->dist;
|
||||||
|
d2 = p->normal[0]*trace_endmins[0] + p->normal[1]*trace_endmaxs[1] + p->normal[2]*trace_endmins[2] - p->dist;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
d1 = p->normal[0]*trace_startmaxs[0] + p->normal[1]*trace_startmaxs[1] + p->normal[2]*trace_startmins[2] - p->dist;
|
||||||
|
d2 = p->normal[0]*trace_endmaxs[0] + p->normal[1]*trace_endmaxs[1] + p->normal[2]*trace_endmins[2] - p->dist;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
d1 = p->normal[0]*trace_startmins[0] + p->normal[1]*trace_startmins[1] + p->normal[2]*trace_startmaxs[2] - p->dist;
|
||||||
|
d2 = p->normal[0]*trace_endmins[0] + p->normal[1]*trace_endmins[1] + p->normal[2]*trace_endmaxs[2] - p->dist;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
d1 = p->normal[0]*trace_startmaxs[0] + p->normal[1]*trace_startmins[1] + p->normal[2]*trace_startmaxs[2] - p->dist;
|
||||||
|
d2 = p->normal[0]*trace_endmaxs[0] + p->normal[1]*trace_endmins[1] + p->normal[2]*trace_endmaxs[2] - p->dist;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
d1 = p->normal[0]*trace_startmins[0] + p->normal[1]*trace_startmaxs[1] + p->normal[2]*trace_startmaxs[2] - p->dist;
|
||||||
|
d2 = p->normal[0]*trace_endmins[0] + p->normal[1]*trace_endmaxs[1] + p->normal[2]*trace_endmaxs[2] - p->dist;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
d1 = p->normal[0]*trace_startmaxs[0] + p->normal[1]*trace_startmaxs[1] + p->normal[2]*trace_startmaxs[2] - p->dist;
|
||||||
|
d2 = p->normal[0]*trace_endmaxs[0] + p->normal[1]*trace_endmaxs[1] + p->normal[2]*trace_endmaxs[2] - p->dist;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
d1 = d2 = 0; // shut up compiler
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( d2 > 0 ) getout = true; // endpoint is not in solid
|
||||||
|
if( d1 > 0 ) startout = true;
|
||||||
|
|
||||||
|
// if completely in front of face, no intersection
|
||||||
|
if( d1 > 0 && d2 >= d1 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( d1 <= 0 && d2 <= 0 )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// crosses face
|
||||||
|
d = 1.0f / ( d1 - d2 );
|
||||||
|
f = d1 * d;
|
||||||
|
|
||||||
|
if( d > 0 )
|
||||||
|
{
|
||||||
|
// enter
|
||||||
|
if( f > enterfrac )
|
||||||
|
{
|
||||||
|
distfrac = d;
|
||||||
|
enterfrac = f;
|
||||||
|
clipplane = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( d < 0 )
|
||||||
|
{
|
||||||
|
// leave
|
||||||
|
if( f < leavefrac )
|
||||||
|
leavefrac = f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !startout )
|
||||||
|
{
|
||||||
|
// original point was inside hitbox
|
||||||
|
trace->startsolid = true;
|
||||||
|
if( !getout ) trace->allsolid = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( enterfrac - FRAC_EPSILON <= leavefrac )
|
||||||
|
{
|
||||||
|
if( enterfrac > -1.0f && enterfrac < trace_realfraction )
|
||||||
|
{
|
||||||
|
if( enterfrac < 0 )
|
||||||
|
enterfrac = 0;
|
||||||
|
trace_realfraction = enterfrac;
|
||||||
|
trace->fraction = enterfrac - DIST_EPSILON * distfrac;
|
||||||
|
VectorCopy( clipplane->normal, trace->plane.normal );
|
||||||
|
trace->plane.dist = clipplane->dist;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
PM_TestBoxInHitbox
|
||||||
|
|
||||||
|
test point trace in hibox
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
qboolean PM_TestBoxInHitbox( pmtrace_t *trace )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
mplane_t *p;
|
||||||
|
|
||||||
|
for( i = 0; i < 6; i++ )
|
||||||
|
{
|
||||||
|
p = &pm_hitboxplanes[i];
|
||||||
|
|
||||||
|
// push the plane out apropriately for mins/maxs
|
||||||
|
// if completely in front of face, no intersection
|
||||||
|
if( p->type < 3 )
|
||||||
|
{
|
||||||
|
if( trace_startmins[p->type] > p->dist )
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch( p->signbits )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
if( p->normal[0]*trace_startmins[0] + p->normal[1]*trace_startmins[1] + p->normal[2]*trace_startmins[2] > p->dist )
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if( p->normal[0]*trace_startmaxs[0] + p->normal[1]*trace_startmins[1] + p->normal[2]*trace_startmins[2] > p->dist )
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if( p->normal[0]*trace_startmins[0] + p->normal[1]*trace_startmaxs[1] + p->normal[2]*trace_startmins[2] > p->dist )
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
if( p->normal[0]*trace_startmaxs[0] + p->normal[1]*trace_startmaxs[1] + p->normal[2]*trace_startmins[2] > p->dist )
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
if( p->normal[0]*trace_startmins[0] + p->normal[1]*trace_startmins[1] + p->normal[2]*trace_startmaxs[2] > p->dist )
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
if( p->normal[0]*trace_startmaxs[0] + p->normal[1]*trace_startmins[1] + p->normal[2]*trace_startmaxs[2] > p->dist )
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
if( p->normal[0]*trace_startmins[0] + p->normal[1]*trace_startmaxs[1] + p->normal[2]*trace_startmaxs[2] > p->dist )
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
if( p->normal[0]*trace_startmaxs[0] + p->normal[1]*trace_startmaxs[1] + p->normal[2]*trace_startmaxs[2] > p->dist )
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// inside this hitbox
|
||||||
|
trace->fraction = trace_realfraction = 0;
|
||||||
|
trace->startsolid = trace->allsolid = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
PM_StudioIntersect
|
||||||
|
|
||||||
|
testing for potentially intersection of trace and animation bboxes
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
static qboolean PM_StudioIntersect( playermove_t *pmove, physent_t *pe, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end )
|
||||||
|
{
|
||||||
|
vec3_t trace_mins, trace_maxs;
|
||||||
|
vec3_t anim_mins, anim_maxs;
|
||||||
|
|
||||||
|
// create the bounding box of the entire move
|
||||||
|
World_MoveBounds( start, mins, maxs, end, trace_mins, trace_maxs );
|
||||||
|
|
||||||
|
if( !PM_StudioExtractBbox( pmove, pe, pe->studiomodel, pe->sequence, anim_mins, anim_maxs ))
|
||||||
|
return false; // invalid sequence
|
||||||
|
|
||||||
|
if( !VectorIsNull( pe->angles ))
|
||||||
|
{
|
||||||
|
// expand for rotation
|
||||||
|
float max, v;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for( i = 0, max = 0.0f; i < 3; i++ )
|
||||||
|
{
|
||||||
|
v = fabs( anim_mins[i] );
|
||||||
|
if( v > max ) max = v;
|
||||||
|
v = fabs( anim_maxs[i] );
|
||||||
|
if( v > max ) max = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
for( i = 0; i < 3; i++ )
|
||||||
|
{
|
||||||
|
anim_mins[i] = pe->origin[i] - max;
|
||||||
|
anim_maxs[i] = pe->origin[i] + max;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
VectorAdd( anim_mins, pe->origin, anim_mins );
|
||||||
|
VectorAdd( anim_maxs, pe->origin, anim_maxs );
|
||||||
|
}
|
||||||
|
|
||||||
|
// check intersection with trace entire move and animation bbox
|
||||||
|
return BoundsIntersect( trace_mins, trace_maxs, anim_mins, anim_maxs );
|
||||||
|
}
|
||||||
|
|
||||||
|
qboolean PM_StudioTrace( playermove_t *pmove, physent_t *pe, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, pmtrace_t *ptr )
|
||||||
|
{
|
||||||
|
vec3_t start_l, end_l;
|
||||||
|
int i, outBone = -1;
|
||||||
|
pfnTrace StudioTrace = NULL;
|
||||||
|
|
||||||
|
// assume we didn't hit anything
|
||||||
|
Q_memset( ptr, 0, sizeof( pmtrace_t ));
|
||||||
|
VectorCopy( end, ptr->endpos );
|
||||||
|
ptr->fraction = trace_realfraction = 1.0f;
|
||||||
|
ptr->hitgroup = -1;
|
||||||
|
ptr->ent = -1;
|
||||||
|
|
||||||
|
if( !PM_StudioIntersect( pmove, pe, start, mins, maxs, end ))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( !PM_StudioSetupModel( pmove, pe ))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( VectorCompare( start, end ))
|
||||||
|
StudioTrace = PM_TestBoxInHitbox;
|
||||||
|
else StudioTrace = PM_ClipBoxToHitbox;
|
||||||
|
|
||||||
|
// go to check individual hitboxes
|
||||||
|
for( i = 0; i < pm_studiohdr->numhitboxes; i++ )
|
||||||
|
{
|
||||||
|
mstudiobbox_t *phitbox = (mstudiobbox_t *)((byte*)pm_studiohdr + pm_studiohdr->hitboxindex) + i;
|
||||||
|
|
||||||
|
// transform traceline into local bone space
|
||||||
|
Matrix3x4_VectorITransform( pm_studiobones[phitbox->bone], start, start_l );
|
||||||
|
Matrix3x4_VectorITransform( pm_studiobones[phitbox->bone], end, end_l );
|
||||||
|
|
||||||
|
PM_HullForHitbox( phitbox->bbmin, phitbox->bbmax );
|
||||||
|
|
||||||
|
VectorAdd( start_l, mins, trace_startmins );
|
||||||
|
VectorAdd( start_l, maxs, trace_startmaxs );
|
||||||
|
VectorAdd( end_l, mins, trace_endmins );
|
||||||
|
VectorAdd( end_l, maxs, trace_endmaxs );
|
||||||
|
|
||||||
|
if( StudioTrace( ptr ))
|
||||||
|
{
|
||||||
|
outBone = phitbox->bone;
|
||||||
|
ptr->hitgroup = phitbox->group;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ptr->allsolid )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// all hitboxes were swept, get trace result
|
||||||
|
if( outBone >= 0 )
|
||||||
|
{
|
||||||
|
vec3_t temp;
|
||||||
|
|
||||||
|
VectorCopy( ptr->plane.normal, temp );
|
||||||
|
ptr->fraction = bound( 0, ptr->fraction, 1.0f );
|
||||||
|
VectorLerp( start, ptr->fraction, end, ptr->endpos );
|
||||||
|
Matrix3x4_TransformPositivePlane( pm_studiobones[outBone], temp, ptr->plane.dist, ptr->plane.normal, &ptr->plane.dist );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
|
@ -396,10 +396,13 @@ long _stdcall Sys_Crash( PEXCEPTION_POINTERS pInfo )
|
||||||
{
|
{
|
||||||
// check to avoid recursive call
|
// check to avoid recursive call
|
||||||
error_on_exit = true;
|
error_on_exit = true;
|
||||||
|
host.crashed = true;
|
||||||
|
|
||||||
|
if( host.type == HOST_NORMAL )
|
||||||
|
CL_Crashed(); // tell client about crash
|
||||||
|
else host.state = HOST_CRASHED;
|
||||||
|
|
||||||
if( host.type == HOST_NORMAL ) CL_Crashed(); // tell client about crash
|
|
||||||
Msg( "Sys_Crash: call %p at address %p\n", pInfo->ExceptionRecord->ExceptionAddress, pInfo->ExceptionRecord->ExceptionCode );
|
Msg( "Sys_Crash: call %p at address %p\n", pInfo->ExceptionRecord->ExceptionAddress, pInfo->ExceptionRecord->ExceptionCode );
|
||||||
host.state = HOST_CRASHED;
|
|
||||||
|
|
||||||
if( host.developer <= 0 )
|
if( host.developer <= 0 )
|
||||||
{
|
{
|
||||||
|
|
|
@ -4110,22 +4110,22 @@ int pfnGetLocalizedStringLength( const char *label )
|
||||||
=============
|
=============
|
||||||
pfnRegisterTutorMessageShown
|
pfnRegisterTutorMessageShown
|
||||||
|
|
||||||
|
only exists in PlayStation version
|
||||||
=============
|
=============
|
||||||
*/
|
*/
|
||||||
void pfnRegisterTutorMessageShown( int mid )
|
void pfnRegisterTutorMessageShown( int mid )
|
||||||
{
|
{
|
||||||
// UNDONE: no description
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=============
|
=============
|
||||||
pfnGetTimesTutorMessageShown
|
pfnGetTimesTutorMessageShown
|
||||||
|
|
||||||
|
only exists in PlayStation version
|
||||||
=============
|
=============
|
||||||
*/
|
*/
|
||||||
int pfnGetTimesTutorMessageShown( int mid )
|
int pfnGetTimesTutorMessageShown( int mid )
|
||||||
{
|
{
|
||||||
// UNDONE: no description
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4133,28 +4133,29 @@ int pfnGetTimesTutorMessageShown( int mid )
|
||||||
=============
|
=============
|
||||||
pfnProcessTutorMessageDecayBuffer
|
pfnProcessTutorMessageDecayBuffer
|
||||||
|
|
||||||
|
only exists in PlayStation version
|
||||||
=============
|
=============
|
||||||
*/
|
*/
|
||||||
void pfnProcessTutorMessageDecayBuffer( int *buffer, int bufferLength )
|
void pfnProcessTutorMessageDecayBuffer( int *buffer, int bufferLength )
|
||||||
{
|
{
|
||||||
// UNDONE: no description
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=============
|
=============
|
||||||
pfnConstructTutorMessageDecayBuffer
|
pfnConstructTutorMessageDecayBuffer
|
||||||
|
|
||||||
|
only exists in PlayStation version
|
||||||
=============
|
=============
|
||||||
*/
|
*/
|
||||||
void pfnConstructTutorMessageDecayBuffer( int *buffer, int bufferLength )
|
void pfnConstructTutorMessageDecayBuffer( int *buffer, int bufferLength )
|
||||||
{
|
{
|
||||||
// UNDONE: no description
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=============
|
=============
|
||||||
pfnResetTutorMessageDecayData
|
pfnResetTutorMessageDecayData
|
||||||
|
|
||||||
|
only exists in PlayStation version
|
||||||
=============
|
=============
|
||||||
*/
|
*/
|
||||||
void pfnResetTutorMessageDecayData( void )
|
void pfnResetTutorMessageDecayData( void )
|
||||||
|
|
|
@ -509,6 +509,10 @@ int SV_IsValidSave( void )
|
||||||
if( sv.background )
|
if( sv.background )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
// don't parse autosave/transition save/restores during playback!
|
||||||
|
if( CL_IsPlaybackDemo( ))
|
||||||
|
return 0;
|
||||||
|
|
||||||
if( !svs.initialized || sv.state != ss_active )
|
if( !svs.initialized || sv.state != ss_active )
|
||||||
{
|
{
|
||||||
Msg( "Not playing a local game.\n" );
|
Msg( "Not playing a local game.\n" );
|
||||||
|
@ -592,24 +596,6 @@ void SV_AgeSaveList( const char *pName, int count )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SV_FileCopy( file_t *pOutput, file_t *pInput, int fileSize )
|
|
||||||
{
|
|
||||||
char buf[MAX_SYSPATH]; // A small buffer for the copy
|
|
||||||
int size;
|
|
||||||
|
|
||||||
while( fileSize > 0 )
|
|
||||||
{
|
|
||||||
if( fileSize > MAX_SYSPATH )
|
|
||||||
size = MAX_SYSPATH;
|
|
||||||
else size = fileSize;
|
|
||||||
|
|
||||||
FS_Read( pInput, buf, size );
|
|
||||||
FS_Write( pOutput, buf, size );
|
|
||||||
|
|
||||||
fileSize -= size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SV_DirectoryCopy( const char *pPath, file_t *pFile )
|
void SV_DirectoryCopy( const char *pPath, file_t *pFile )
|
||||||
{
|
{
|
||||||
search_t *t;
|
search_t *t;
|
||||||
|
@ -630,7 +616,7 @@ void SV_DirectoryCopy( const char *pPath, file_t *pFile )
|
||||||
Q_strncpy( szName, FS_FileWithoutPath( t->filenames[i] ), SAVENAME_LENGTH );
|
Q_strncpy( szName, FS_FileWithoutPath( t->filenames[i] ), SAVENAME_LENGTH );
|
||||||
FS_Write( pFile, szName, SAVENAME_LENGTH );
|
FS_Write( pFile, szName, SAVENAME_LENGTH );
|
||||||
FS_Write( pFile, &fileSize, sizeof( int ));
|
FS_Write( pFile, &fileSize, sizeof( int ));
|
||||||
SV_FileCopy( pFile, pCopy, fileSize );
|
FS_FileCopy( pFile, pCopy, fileSize );
|
||||||
FS_Close( pCopy );
|
FS_Close( pCopy );
|
||||||
}
|
}
|
||||||
Mem_Free( t );
|
Mem_Free( t );
|
||||||
|
@ -650,7 +636,7 @@ void SV_DirectoryExtract( file_t *pFile, int fileCount )
|
||||||
Q_snprintf( szName, sizeof( szName ), "save/%s", fileName );
|
Q_snprintf( szName, sizeof( szName ), "save/%s", fileName );
|
||||||
|
|
||||||
pCopy = FS_Open( szName, "wb", false );
|
pCopy = FS_Open( szName, "wb", false );
|
||||||
SV_FileCopy( pCopy, pFile, fileSize );
|
FS_FileCopy( pCopy, pFile, fileSize );
|
||||||
FS_Close( pCopy );
|
FS_Close( pCopy );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -39,7 +39,7 @@ RSC=rc.exe
|
||||||
# PROP Ignore_Export_Lib 0
|
# PROP Ignore_Export_Lib 0
|
||||||
# PROP Target_Dir ""
|
# PROP Target_Dir ""
|
||||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
|
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
|
||||||
# ADD CPP /nologo /W3 /GX /O2 /Ob0 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c
|
# ADD CPP /nologo /MT /W3 /GX /O2 /Ob0 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c
|
||||||
# SUBTRACT CPP /YX
|
# SUBTRACT CPP /YX
|
||||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||||
|
@ -50,7 +50,7 @@ BSC32=bscmake.exe
|
||||||
# ADD BSC32 /nologo
|
# ADD BSC32 /nologo
|
||||||
LINK32=link.exe
|
LINK32=link.exe
|
||||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /opt:nowin98
|
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /opt:nowin98
|
||||||
# ADD LINK32 msvcrt.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /pdb:none /machine:I386 /nodefaultlib:"libc.lib" /out:"hl.exe" /opt:nowin98
|
# ADD LINK32 msvcrt.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /pdb:none /machine:I386 /nodefaultlib:"libcmt.lib" /out:"hl.exe" /opt:nowin98
|
||||||
# Begin Custom Build
|
# Begin Custom Build
|
||||||
InputPath=.\hl.exe
|
InputPath=.\hl.exe
|
||||||
SOURCE="$(InputPath)"
|
SOURCE="$(InputPath)"
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue