06 Apr 2011

This commit is contained in:
g-cont 2011-04-06 00:00:00 +04:00 committed by Alibek Omarov
parent 40e25d5589
commit ce6752545e
54 changed files with 1061 additions and 952 deletions

View File

@ -1,3 +1,10 @@
build ????
FS: add "fallback_dir" option
Server: fix func_pushable interaction with movers. Add new cvar "sv_allow_rotate_pushables"
Server: added support for 'SV_SaveGameComment' export
Server: fixed backup for quick.sav and autosave.save (quick01.sav and autosave01.sav)
build 1516
Engine: fix Sys_Error blowout

View File

@ -68,7 +68,7 @@ void CL_WriteDemoMessage( sizebuf_t *msg, int head_size )
void CL_WriteDemoHeader( const char *name )
{
int i, j, len;
char buf_data[MAX_MSGLEN];
char buf_data[NET_MAX_PAYLOAD];
entity_state_t *state, nullstate;
movevars_t nullmovevars;
sizebuf_t buf;
@ -289,7 +289,7 @@ reads demo data and write it to client
void CL_ReadDemoMessage( void )
{
sizebuf_t buf;
char buf_data[MAX_MSGLEN];
char buf_data[NET_MAX_PAYLOAD];
int r, curSize;
if( !cls.demofile )
@ -321,7 +321,7 @@ void CL_ReadDemoMessage( void )
if( curSize > sizeof( buf_data ))
{
Host_Error( "CL_ReadDemoMessage: demoMsglen > MAX_MSGLEN\n" );
Host_Error( "CL_ReadDemoMessage: demoMsglen > NET_MAX_PAYLOAD\n" );
return;
}
@ -389,7 +389,7 @@ CL_GetComment
qboolean CL_GetComment( const char *demoname, char *comment )
{
file_t *demfile;
char buf_data[MAX_MSGLEN];
char buf_data[2048];
int r, maxClients, curSize;
string maptitle;
sizebuf_t buf;

View File

@ -830,11 +830,11 @@ static void CL_DrawLoading( float percent )
float xscale, yscale, step, s2;
R_GetTextureParms( &width, &height, cls.loadingBar );
x = ( 640 - width ) >> 1;
y = ( 480 - height) >> 1;
x = ( clgame.scrInfo.iWidth - width ) >> 1;
y = ( clgame.scrInfo.iHeight - height) >> 1;
xscale = scr_width->integer / 640.0f;
yscale = scr_height->integer / 480.0f;
xscale = scr_width->integer / (float)clgame.scrInfo.iWidth;
yscale = scr_height->integer / (float)clgame.scrInfo.iHeight;
x *= xscale;
y *= yscale;
@ -869,11 +869,11 @@ static void CL_DrawPause( void )
float xscale, yscale;
R_GetTextureParms( &width, &height, cls.pauseIcon );
x = ( 640 - width ) >> 1;
y = ( 480 - height) >> 1;
x = ( clgame.scrInfo.iWidth - width ) >> 1;
y = ( clgame.scrInfo.iHeight - height) >> 1;
xscale = scr_width->integer / 640.0f;
yscale = scr_height->integer / 480.0f;
xscale = scr_width->integer / (float)clgame.scrInfo.iWidth;
yscale = scr_height->integer / (float)clgame.scrInfo.iHeight;
x *= xscale;
y *= yscale;
@ -1737,8 +1737,15 @@ pfnServerCmd
*/
static int pfnServerCmd( const char *szCmdString )
{
// server command adding in cmds queue
Cbuf_AddText( va( "cmd %s\n", szCmdString ));
string buf;
if( !szCmdString || !szCmdString[0] )
return 0;
// just like the client typed "cmd xxxxx" at the console
Q_snprintf( buf, sizeof( buf ) - 1, "cmd %s\n", szCmdString );
Cbuf_AddText( buf );
return 1;
}
@ -1750,8 +1757,11 @@ pfnClientCmd
*/
static int pfnClientCmd( const char *szCmdString )
{
// client command executes immediately
Cmd_ExecuteString( szCmdString );
if( !szCmdString || !szCmdString[0] )
return 0;
Cbuf_AddText( szCmdString );
Cbuf_AddText( "\n" );
return 1;
}
@ -2191,7 +2201,7 @@ pfnIsSpectateOnly
*/
static int pfnIsSpectateOnly( void )
{
// FIXME: check for proxie and dev_overview 2
// TODO: check for proxie and dev_overview 2
return 0;
}
@ -2565,12 +2575,14 @@ int CL_AddEntity( int entityType, cl_entity_t *pEnt )
=============
pfnGetGameDirectory
FIXME: use Info_ValueForKey( cl.serverinfo, "*gamedir" ) instead ?
=============
*/
const char *pfnGetGameDirectory( void )
{
return GI->gamedir;
static char szGetGameDir[MAX_SYSPATH];
Q_sprintf( szGetGameDir, "%s/%s", host.rootdir, GI->gamedir );
return szGetGameDir;
}
/*
@ -3588,7 +3600,7 @@ static cl_enginefunc_t gEngfuncs =
VGui_ViewportPaintBackground,
COM_LoadFile,
COM_ParseFile,
pfnFreeFile,
COM_FreeFile,
&gTriApi,
&gEfxApi,
&gEventApi,

View File

@ -266,7 +266,7 @@ void Cmd_ForwardToServer( void )
}
cmd = Cmd_Argv( 0 );
if( cls.state <= ca_connected || *cmd == '-' || *cmd == '+' )
if( *cmd == '-' || *cmd == '+' )
{
MsgDev( D_INFO, "Unknown command \"%s\"\n", cmd );
return;

View File

@ -916,7 +916,7 @@ static ui_enginefuncs_t gEngfuncs =
pfnClientJoin,
pfnLoadFile,
COM_ParseFile,
pfnFreeFile,
COM_FreeFile,
Key_ClearStates,
Key_SetKeyDest,
Key_KeynumToString,

View File

@ -277,7 +277,7 @@ A download message has been received from the server
void CL_ParseDownload( sizebuf_t *msg )
{
int size, percent;
char buffer[MAX_MSGLEN];
char buffer[NET_MAX_PAYLOAD];
string name;
int r;
@ -349,15 +349,16 @@ CL_ParseSoundPacket
*/
void CL_ParseSoundPacket( sizebuf_t *msg, qboolean is_ambient )
{
vec3_t pos_;
float *pos = NULL;
vec3_t pos;
int chan, sound;
float volume, attn;
int flags, pitch, entnum;
sound_t handle = 0;
flags = BF_ReadWord( msg );
sound = BF_ReadWord( msg );
if( flags & SND_LARGE_INDEX )
sound = BF_ReadWord( msg );
else sound = BF_ReadByte( msg );
chan = BF_ReadByte( msg );
if( flags & SND_VOLUME )
@ -376,11 +377,7 @@ void CL_ParseSoundPacket( sizebuf_t *msg, qboolean is_ambient )
entnum = BF_ReadWord( msg );
// positioned in space
if( flags & SND_FIXED_ORIGIN )
{
pos = pos_;
BF_ReadBitVec3Coord( msg, pos );
}
BF_ReadBitVec3Coord( msg, pos );
if( flags & SND_SENTENCE )
{
@ -1003,8 +1000,7 @@ change serverinfo
*/
void CL_ServerInfo( sizebuf_t *msg )
{
char key[MAX_MSGLEN];
char value[MAX_MSGLEN];
string key, value;
Q_strncpy( key, BF_ReadString( msg ), sizeof( key ));
Q_strncpy( value, BF_ReadString( msg ), sizeof( value ));

View File

@ -190,6 +190,7 @@ CL_TruePointContents
int CL_TruePointContents( const vec3_t p )
{
int i, contents;
int oldhull;
hull_t *hull;
vec3_t test;
physent_t *pe;
@ -197,6 +198,8 @@ int CL_TruePointContents( const vec3_t p )
// sanity check
if( !p ) return CONTENTS_NONE;
oldhull = clgame.pmove->usehull;
// get base contents from world
contents = PM_HullPointContents( &cl.worldmodel->hulls[0], 0, p );
@ -212,7 +215,9 @@ int CL_TruePointContents( const vec3_t p )
continue;
// check water brushes accuracy
hull = PM_HullForBsp( pe, vec3_origin, vec3_origin, test );
clgame.pmove->usehull = 2;
hull = PM_HullForBsp( pe, clgame.pmove, test );
clgame.pmove->usehull = oldhull;
// offset the test point appropriately for this hull.
VectorSubtract( p, test, test );
@ -240,10 +245,12 @@ int CL_WaterEntity( const float *rgflPos )
physent_t *pe;
hull_t *hull;
vec3_t test;
int i;
int i, oldhull;
if( !rgflPos ) return -1;
oldhull = clgame.pmove->usehull;
for( i = 0; i < clgame.pmove->nummoveent; i++ )
{
pe = &clgame.pmove->moveents[i];
@ -256,7 +263,9 @@ int CL_WaterEntity( const float *rgflPos )
continue;
// check water brushes accuracy
hull = PM_HullForBsp( pe, vec3_origin, vec3_origin, test );
clgame.pmove->usehull = 2;
hull = PM_HullForBsp( pe, clgame.pmove, test );
clgame.pmove->usehull = oldhull;
// offset the test point appropriately for this hull.
VectorSubtract( rgflPos, test, test );
@ -318,12 +327,8 @@ static int pfnTestPlayerPosition( float *pos, pmtrace_t *ptrace )
trace = PM_PlayerTrace( clgame.pmove, pos, pos, PM_NORMAL, clgame.pmove->usehull, -1, NULL );
if( ptrace ) *ptrace = trace;
return trace.ent;
}
static double Sys_FloatTime( void )
{
return Sys_DoubleTime();
return PM_TestPlayerPosition( clgame.pmove, pos, NULL );
}
static void pfnStuckTouch( int hitent, pmtrace_t *tr )
@ -394,32 +399,9 @@ static pmtrace_t *pfnTraceLine( float *start, float *end, int flags, int usehull
return &tr;
}
static int pfnGetModelType( model_t *mod )
{
if( !mod ) return mod_bad;
return mod->type;
}
static void pfnGetModelBounds( model_t *mod, float *mins, float *maxs )
{
if( mod )
{
if( mins ) VectorCopy( mod->mins, mins );
if( maxs ) VectorCopy( mod->maxs, maxs );
}
else
{
MsgDev( D_ERROR, "Mod_GetBounds: NULL model\n" );
if( mins ) VectorClear( mins );
if( maxs ) VectorClear( maxs );
}
}
static hull_t *pfnHullForBsp( physent_t *pe, float *offset )
{
float *mins = clgame.pmove->player_mins[clgame.pmove->usehull];
float *maxs = clgame.pmove->player_maxs[clgame.pmove->usehull];
return PM_HullForBsp( pe, mins, maxs, offset );
return PM_HullForBsp( pe, clgame.pmove, offset );
}
static float pfnTraceModel( physent_t *pEnt, float *start, float *end, trace_t *trace )
@ -451,21 +433,6 @@ static const char *pfnTraceTexture( int ground, float *vstart, float *vend )
return PM_TraceTexture( pe, vstart, vend );
}
static int pfnCOM_FileSize( const char *filename )
{
return FS_FileSize( filename, false );
}
static byte *pfnCOM_LoadFile( const char *path, int usehunk, int *pLength )
{
return FS_LoadFile( path, pLength, false );
}
static void pfnCOM_FreeFile( void *buffer )
{
if( buffer ) Mem_Free( buffer );
}
static void pfnPlaySound( int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch )
{
sound_t snd = S_RegisterSound( sample );
@ -499,7 +466,8 @@ static int pfnTestPlayerPositionEx( float *pos, pmtrace_t *ptrace, pfnIgnore pmF
trace = PM_PlayerTrace( clgame.pmove, pos, pos, PM_STUDIO_BOX, clgame.pmove->usehull, -1, pmFilter );
if( ptrace ) *ptrace = trace;
return trace.ent;
return PM_TestPlayerPosition( clgame.pmove, pos, pmFilter );
}
static pmtrace_t *pfnTraceLineEx( float *start, float *end, int flags, int usehull, pfnIgnore pmFilter )
@ -547,7 +515,7 @@ void CL_InitClientMove( void )
clgame.pmove->Con_NPrintf = Con_NPrintf;
clgame.pmove->Con_DPrintf = Con_DPrintf;
clgame.pmove->Con_Printf = Con_Printf;
clgame.pmove->Sys_FloatTime = Sys_FloatTime;
clgame.pmove->Sys_FloatTime = Sys_DoubleTime;
clgame.pmove->PM_StuckTouch = pfnStuckTouch;
clgame.pmove->PM_PointContents = pfnPointContents;
clgame.pmove->PM_TruePointContents = pfnTruePointContents;
@ -560,9 +528,9 @@ void CL_InitClientMove( void )
clgame.pmove->PM_GetModelBounds = pfnGetModelBounds;
clgame.pmove->PM_HullForBsp = pfnHullForBsp;
clgame.pmove->PM_TraceModel = pfnTraceModel;
clgame.pmove->COM_FileSize = pfnCOM_FileSize;
clgame.pmove->COM_LoadFile = pfnCOM_LoadFile;
clgame.pmove->COM_FreeFile = pfnCOM_FreeFile;
clgame.pmove->COM_FileSize = COM_FileSize;
clgame.pmove->COM_LoadFile = COM_LoadFile;
clgame.pmove->COM_FreeFile = COM_FreeFile;
clgame.pmove->memfgets = pfnMemFgets;
clgame.pmove->PM_PlaySound = pfnPlaySound;
clgame.pmove->PM_TraceTexture = pfnTraceTexture;

View File

@ -40,7 +40,7 @@ void CL_PostRunCmd( usercmd_t *ucmd, int random_seed )
{
local_state_t *from, *to;
// FIXME: write real predicting code
// TODO: write real predicting code
from = &cl.predict[cl.predictcount & CL_UPDATE_MASK];
to = &cl.predict[(cl.predictcount + 1) & CL_UPDATE_MASK];

View File

@ -225,7 +225,7 @@ void SCR_DrawPlaque( void )
SCR_BeginLoadingPlaque
================
*/
void SCR_BeginLoadingPlaque( void )
void SCR_BeginLoadingPlaque( qboolean is_background )
{
S_StopAllSounds();
cl.audio_prepped = false; // don't play ambients
@ -239,6 +239,7 @@ void SCR_BeginLoadingPlaque( void )
SCR_UpdateScreen();
cls.disable_screen = host.realtime;
cls.disable_servercount = cl.servercount;
cl.background = is_background; // set right state before svc_serverdata
}
/*

View File

@ -116,7 +116,8 @@ V_RenderView
*/
void V_RenderView( void )
{
if( !cl.video_prepped ) return; // still loading
if( !cl.video_prepped || ( UI_IsVisible() && !cl.background ))
return; // still loading
if( cl.frame.valid && ( cl.force_refdef || !cl.refdef.paused ))
{

View File

@ -866,7 +866,7 @@ void DrawSurfaceDecals( msurface_t *fa )
pglEnable( GL_POLYGON_OFFSET_FILL );
pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE ); // FIXME: testing
pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
for( p = fa->pdecals; p; p = p->pnext )
DrawSingleDecal( p, fa );

View File

@ -30,6 +30,9 @@ void GL_Bind( GLenum tmu, GLenum texnum )
{
gltexture_t *texture;
// missed texture ?
if( texnum <= 0 ) texnum = tr.defaultTexture;
ASSERT( texnum > 0 && texnum < MAX_TEXTURES );
GL_SelectTexture( tmu );
@ -54,6 +57,9 @@ void GL_MBind( GLenum texnum )
gltexture_t *texture;
int tmu = 0;
// missed texture ?
if( texnum <= 0 ) texnum = tr.defaultTexture;
ASSERT( texnum > 0 && texnum < MAX_TEXTURES );
if( glState.mtexEnabled )

View File

@ -2004,10 +2004,12 @@ void R_StudioSetupTextureHeader( void )
if( !m_pStudioHeader->numtextures || !m_pStudioHeader->textureindex )
{
string texturename;
model_t *textures;
model_t *textures = NULL;
Q_strncpy( texturename, R_StudioTexName( RI.currentmodel ), sizeof( texturename ));
textures = Mod_ForName( texturename, false );
if( FS_FileExists( texturename, false ))
textures = Mod_ForName( texturename, false );
if( !textures )
{

View File

@ -6,8 +6,10 @@
#include "common.h"
#include "sound.h"
#include "client.h"
#include "con_nprint.h"
#include "ref_params.h"
#define MAX_DUPLICATED_CHANNELS 4 // threshold for identical static channels (probably error)
#define SND_CLIP_DISTANCE 1024.0f
dma_t dma;
@ -236,10 +238,21 @@ we're trying to allocate a channel for a stream sound that is
already playing.
=====================
*/
channel_t *SND_PickStaticChannel( int entnum, sfx_t *sfx )
channel_t *SND_PickStaticChannel( int entnum, sfx_t *sfx, const vec3_t pos )
{
channel_t *ch = NULL;
int i;
int i, dupe = 0;
// check for dupliacte sounds
for( i = 0; i < total_channels; i++ )
{
if( channels[i].sfx == sfx && VectorCompare( channels[i].origin, pos ))
dupe++;
}
// check for duplicated static channels (same origin and same sfx)
if( dupe > MAX_DUPLICATED_CHANNELS )
return NULL;
// check for replacement sound, or find the best one to replace
for( i = MAX_DYNAMIC_CHANNELS; i < total_channels; i++ )
@ -430,7 +443,7 @@ void S_StartSound( const vec3_t pos, int ent, int chan, sound_t handle, float fv
if( !pos ) pos = vec3_origin;
// pick a channel to play on
if( chan == CHAN_STATIC ) target_chan = SND_PickStaticChannel( ent, sfx );
if( chan == CHAN_STATIC ) target_chan = SND_PickStaticChannel( ent, sfx, pos );
else target_chan = SND_PickDynamicChannel( ent, chan, sfx );
if( !target_chan )
@ -564,7 +577,7 @@ void S_AmbientSound( const vec3_t pos, int ent, sound_t handle, float fvol, floa
if( ent != 0 ) CL_GetEntitySpatialization( ent, origin, NULL );
// pick a channel to play on from the static area
ch = SND_PickStaticChannel( ent, sfx );
ch = SND_PickStaticChannel( ent, sfx, pos );
if( !ch ) return;
if( S_TestSoundChar( sfx->name, '!' ))
@ -776,8 +789,9 @@ Called once each time through the main loop
*/
void S_RenderFrame( ref_params_t *fd )
{
int i, total;
channel_t *ch;
int i, total;
con_nprint_t info;
channel_t *ch;
if( !dma.initialized ) return;
if( !fd ) return; // too early
@ -811,15 +825,21 @@ void S_RenderFrame( ref_params_t *fd )
// debugging output
if( s_show->value )
{
for( i = total = 0, ch = channels; i < MAX_CHANNELS; i++, ch++ )
info.color[0] = 1.0f;
info.color[1] = 0.6f;
info.color[2] = 0.0f;
info.time_to_live = 0.5f;
for( i = 0, total = 1, ch = channels; i < MAX_CHANNELS; i++, ch++ )
{
if( ch->sfx && ( ch->leftvol || ch->rightvol ))
{
MsgDev( D_INFO, "%3i %3i %s\n", ch->leftvol, ch->rightvol, ch->sfx->name );
info.index = total;
Con_NXPrintf( &info, "%3i %3i %s\n", ch->leftvol, ch->rightvol, ch->sfx->name );
total++;
}
}
Msg( "----(%i)---- painted: %i\n", total, paintedtime );
Con_NPrintf( 0, "----(%i)---- painted: %i\n", total - 1, paintedtime );
}
S_StreamBackgroundTrack ();
@ -938,7 +958,7 @@ qboolean S_Init( void )
s_volume = Cvar_Get( "volume", "0.7", CVAR_ARCHIVE, "sound volume" );
s_musicvolume = Cvar_Get( "musicvolume", "1.0", CVAR_ARCHIVE, "background music volume" );
s_mixahead = Cvar_Get( "_snd_mixahead", "0.1", CVAR_ARCHIVE, "how much sound to mix ahead of time" );
s_show = Cvar_Get( "s_show", "0", 0, "show playing sounds" );
s_show = Cvar_Get( "s_show", "0", CVAR_ARCHIVE, "show playing sounds" );
s_check_errors = Cvar_Get( "s_check_errors", "1", CVAR_ARCHIVE, "ignore audio engine errors" );
s_lerping = Cvar_Get( "s_lerping", "0", CVAR_ARCHIVE, "apply interpolation to sound output" );
dsp_off = Cvar_Get( "dsp_off", "0", CVAR_ARCHIVE, "set to 1 to disable all dsp processing" );

View File

@ -30,7 +30,8 @@ extern byte *sndpool;
#define FIX_FRACTION(a,b) (FIX(a)/(b))
#define FIX_FRACPART(a) ((a) & FIX_MASK)
#define CLIP( x ) (( x ) > 32767 ? 32767 : (( x ) < -32767 ? -32767 : ( x )))
// NOTE: clipped sound at 32760 to avoid overload
#define CLIP( x ) (( x ) > 32760 ? 32760 : (( x ) < -32760 ? -32760 : ( x )))
#define SWAP( a, b, t ) {(t) = (a); (a) = (b); (b) = (t);}
#define AVG( a, b ) (((a) + (b)) >> 1 )
#define AVG4( a, b, c, d ) (((a) + (b) + (c) + (d)) >> 2 )
@ -237,7 +238,7 @@ void S_SoundList_f( void );
void S_SoundInfo_f( void );
channel_t *SND_PickDynamicChannel( int entnum, int channel, sfx_t *sfx );
channel_t *SND_PickStaticChannel( int entnum, sfx_t *sfx );
channel_t *SND_PickStaticChannel( int entnum, sfx_t *sfx, const vec3_t pos );
int S_GetCurrentStaticSounds( soundlist_t *pout, int size );
sfx_t *S_GetSfxByHandle( sound_t handle );
void S_StopSound( int entnum, int channel, const char *soundname );

View File

@ -280,7 +280,6 @@ long VGUI_SurfaceWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
break;
case WM_CHAR:
case WM_SYSCHAR:
// FIXME
// pApp->internalKeyTyped( VGUI_MapKey( wParam ), surface );
break;
case WM_KEYUP:

View File

@ -110,11 +110,11 @@ public:
CEngineSurface( Panel *embeddedPanel );
~CEngineSurface();
public:
virtual void setTitle( const char *title );
virtual Panel *getEmbeddedPanel( void );
virtual bool setFullscreenMode( int wide, int tall, int bpp );
virtual void setWindowedMode( void );
virtual void createPopup( Panel* embeddedPanel );
virtual void setTitle( const char *title ) { }
virtual void createPopup( Panel* embeddedPanel ) { }
virtual bool isWithin( int x, int y ) { return true; }
virtual bool hasFocus( void );
protected:

View File

@ -16,7 +16,6 @@ CEngineSurface :: CEngineSurface( Panel *embeddedPanel ):SurfaceBase( embeddedPa
_drawColor[0] = _drawColor[1] = _drawColor[2] = _drawColor[3] = 255;
_drawTextColor[0] = _drawTextColor[1] = _drawTextColor[2] = _drawTextColor[3] = 255;
// FIXME: this is right?
_surfaceExtents[0] = _surfaceExtents[1] = 0;
_surfaceExtents[2] = menu.globals->scrWidth;
_surfaceExtents[3] = menu.globals->scrHeight;
@ -36,18 +35,6 @@ Panel *CEngineSurface :: getEmbeddedPanel( void )
return _embeddedPanel;
}
void CEngineSurface :: setTitle( const char *title )
{
// TODO: implement
Msg( "SetTitle: %s\n", title );
}
void CEngineSurface :: createPopup( Panel* embeddedPanel )
{
// TODO: implement
Msg( "CreatePopup()\n" );
}
bool CEngineSurface :: hasFocus( void )
{
return host.state != HOST_NOFOCUS;

View File

@ -92,8 +92,6 @@ typedef enum
#define CS_TIME 16 // size of time string
#define MAX_DECALS 512 // touching TE_DECAL messages, etc
#define MAX_MSGLEN 32768 // max length of network message
// FIXME: replace with NET_MAX_PAYLOAD
// filesystem flags
#define FS_STATIC_PATH 1 // FS_ClearSearchPath will be ignore this path
@ -141,6 +139,7 @@ typedef struct gameinfo_s
char gamefolder[64]; // used for change game '-game x'
char basedir[64]; // main game directory (like 'id1' for Quake or 'valve' for Half-Life)
char gamedir[64]; // game directory (can be match with basedir, used as primary dir and as write path
char falldir[64]; // used as second basedir
char startmap[64]; // map to start singleplayer game
char trainmap[64]; // map to start hazard course (if specified)
char title[64]; // Game Main Title
@ -263,6 +262,7 @@ typedef struct host_parm_s
qboolean shutdown_issued; // engine is shutting down
qboolean decal_loading; // nasty hack to tell imagelib about decal
char rootdir[256]; // member root directory
char gamefolder[64]; // it's a default gamefolder
byte *imagepool; // imagelib mempool
byte *soundpool; // soundlib mempool
@ -304,7 +304,9 @@ void W_Close( wfile_t *wad );
file_t *FS_OpenFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly );
byte *FS_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly );
qboolean FS_WriteFile( const char *filename, const void *data, fs_offset_t len );
void FS_FreeFile( void *buffer );
int COM_FileSize( const char *filename );
void COM_FixSlashes( char *pname );
void COM_FreeFile( void *buffer );
search_t *FS_Search( const char *pattern, int caseinsensitive, int gamedironly );
file_t *FS_Open( const char *filepath, const char *mode, qboolean gamedironly );
fs_offset_t FS_Write( file_t *file, const void *data, size_t datasize );
@ -564,7 +566,9 @@ int pfnAddClientCommand( const char *cmd_name, xcommand_t func );
void pfnDelCommand( const char *cmd_name );
void *Cache_Check( byte *mempool, struct cache_user_s *c );
edict_t* pfnPEntityOfEntIndex( int iEntIndex );
void pfnGetModelBounds( model_t *mod, float *mins, float *maxs );
void pfnGetGameDir( char *szGetGameDir );
int pfnGetModelType( model_t *mod );
int pfnIsMapValid( char *filename );
char *pfnCmd_Args( void );
char *pfnCmd_Argv( int argc );
@ -685,7 +689,7 @@ qboolean CL_NextDemo( void );
void CL_Drop( void );
void SCR_Init( void );
void SCR_UpdateScreen( void );
void SCR_BeginLoadingPlaque( void );
void SCR_BeginLoadingPlaque( qboolean is_background );
void SCR_CheckStartupVids( void );
long SCR_GetAudioChunk( char *rawdata, long length );
wavdata_t *SCR_GetMovieInfo( void );

View File

@ -686,17 +686,16 @@ void Con_Print( const char *txt )
void Con_NPrintf( int idx, char *fmt, ... )
{
char buffer[2048]; // must support > 1k messages
va_list args;
if( idx < 0 || idx >= MAX_DBG_NOTIFY )
return;
va_start( args, fmt );
Q_vsnprintf( buffer, 2048, fmt, args );
va_end( args );
Q_memset( con.notify[idx].szNotify, 0, MAX_STRING );
Q_snprintf( con.notify[idx].szNotify, sizeof( con.notify[idx].szNotify ), buffer );
va_start( args, fmt );
Q_vsnprintf( con.notify[idx].szNotify, MAX_STRING, fmt, args );
va_end( args );
// reset values
con.notify[idx].expire = host.realtime + 4.0f;
@ -706,7 +705,6 @@ void Con_NPrintf( int idx, char *fmt, ... )
void Con_NXPrintf( con_nprint_t *info, char *fmt, ... )
{
char buffer[2048]; // must support > 1k messages
va_list args;
if( !info ) return;
@ -714,15 +712,15 @@ void Con_NXPrintf( con_nprint_t *info, char *fmt, ... )
if( info->index < 0 || info->index >= MAX_DBG_NOTIFY )
return;
va_start( args, fmt );
Q_vsnprintf( buffer, 2048, fmt, args );
va_end( args );
Q_memset( con.notify[info->index].szNotify, 0, MAX_STRING );
Q_snprintf( con.notify[info->index].szNotify, sizeof( con.notify[info->index].szNotify ), buffer );
va_start( args, fmt );
Q_vsnprintf( con.notify[info->index].szNotify, MAX_STRING, fmt, args );
va_end( args );
// setup values
con.notify[info->index].expire = host.realtime + info->time_to_live;
MakeRGBA( con.notify[info->index].color, info->color[0] * 255, info->color[1] * 255, info->color[2] * 255, 255 );
MakeRGBA( con.notify[info->index].color, (byte)(info->color[0] * 255), (byte)(info->color[1] * 255), (byte)(info->color[2] * 255), 255 );
con.draw_notify = true;
}

View File

@ -118,6 +118,17 @@ skipwhite:
return data;
}
/*
=============
COM_FileSize
=============
*/
int COM_FileSize( const char *filename )
{
return FS_FileSize( filename, false );
}
/*
=============
COM_AddAppDirectoryToSearchPath
@ -149,7 +160,6 @@ This doesn't search in the pak file.
int COM_ExpandFilename( const char *fileName, char *nameOutBuffer, int nameOutBufferSize )
{
const char *path;
char rootdir[MAX_SYSPATH];
char result[MAX_SYSPATH];
if( !fileName || !*fileName || !nameOutBuffer || nameOutBufferSize <= 0 )
@ -160,8 +170,7 @@ int COM_ExpandFilename( const char *fileName, char *nameOutBuffer, int nameOutBu
// models\barney.mdl - D:\Xash3D\bshift\models\barney.mdl
if(( path = FS_GetDiskPath( fileName, false )) != NULL )
{
GetCurrentDirectory( MAX_SYSPATH, rootdir );
Q_sprintf( result, "%s/%s", rootdir, path );
Q_sprintf( result, "%s/%s", host.rootdir, path );
// check for enough room
if( Q_strlen( result ) > nameOutBufferSize )
@ -173,6 +182,23 @@ int COM_ExpandFilename( const char *fileName, char *nameOutBuffer, int nameOutBu
return 0;
}
/*
============
COM_FixSlashes
Changes all '/' characters into '\' characters, in place.
============
*/
void COM_FixSlashes( char *pname )
{
while( *pname )
{
if( *pname == '/' )
*pname = '\\';
pname++;
}
}
/*
=============
pfnMemFgets
@ -261,11 +287,6 @@ byte* pfnLoadFile( const char *filename, int *pLength )
return FS_LoadFile( filename, pLength, false );
}
void pfnFreeFile( void *buffer )
{
FS_FreeFile( buffer );
}
/*
=============
pfnFileExists
@ -287,6 +308,39 @@ float pfnTime( void )
{
return Sys_DoubleTime();
}
/*
=============
pfnGetModelType
=============
*/
int pfnGetModelType( model_t *mod )
{
if( !mod ) return mod_bad;
return mod->type;
}
/*
=============
pfnGetModelBounds
=============
*/
void pfnGetModelBounds( model_t *mod, float *mins, float *maxs )
{
if( mod )
{
if( mins ) VectorCopy( mod->mins, mins );
if( maxs ) VectorCopy( mod->maxs, maxs );
}
else
{
MsgDev( D_ERROR, "Mod_GetBounds: NULL model\n" );
if( mins ) VectorClear( mins );
if( maxs ) VectorClear( maxs );
}
}
/*
=============
@ -469,7 +523,7 @@ void Con_DPrintf( char *szFmt, ... )
char buffer[2048]; // must support > 1k messages
va_list args;
if( host.developer < D_AICONSOLE )
if( host.developer < D_INFO )
return;
va_start( args, szFmt );
@ -520,9 +574,6 @@ pfnGetGameDir
*/
void pfnGetGameDir( char *szGetGameDir )
{
char rootdir[MAX_SYSPATH];
if( !szGetGameDir ) return;
GetCurrentDirectory( MAX_SYSPATH, rootdir );
Q_sprintf( szGetGameDir, "%s/%s", rootdir, GI->gamedir );
Q_sprintf( szGetGameDir, "%s/%s", host.rootdir, GI->gamedir );
}

View File

@ -85,6 +85,7 @@ searchpath_t *fs_searchpaths = NULL;
searchpath_t fs_directpath; // static direct path
char fs_rootdir[MAX_SYSPATH]; // engine root directory
char fs_basedir[MAX_SYSPATH]; // base directory of game
char fs_falldir[MAX_SYSPATH]; // game current directory
char fs_gamedir[MAX_SYSPATH]; // game current directory
char gs_basedir[MAX_SYSPATH]; // initial dir before loading gameinfo.txt (used for compilers too)
qboolean fs_ext_path = false; // attempt to read\write from ./ or ../ pathes
@ -873,6 +874,8 @@ void FS_Rescan( void )
if( Q_stricmp( GI->basedir, GI->gamedir ))
FS_AddGameHierarchy( GI->basedir, 0 );
if( Q_stricmp( GI->basedir, GI->falldir ))
FS_AddGameHierarchy( GI->falldir, 0 );
FS_AddGameHierarchy( GI->gamedir, FS_GAMEDIR_PATH );
}
@ -949,6 +952,9 @@ static qboolean FS_WriteGameInfo( const char *filepath, gameinfo_t *GameInfo )
if( Q_strlen( GameInfo->gamedir ))
FS_Printf( f, "gamedir\t\t\"%s\"\n", GameInfo->gamedir );
if( Q_strlen( GameInfo->falldir ))
FS_Printf( f, "fallback_dir\t\"%s\"\n", GameInfo->falldir );
if( Q_strlen( GameInfo->title ))
FS_Printf( f, "title\t\t\"%s\"\n", GameInfo->title );
@ -1036,6 +1042,7 @@ void FS_CreateDefaultGameInfo( const char *filename )
defGI.max_beams = 128;
defGI.max_particles = 4096;
defGI.version = 1.0;
defGI.falldir[0] = '\0';
Q_strncpy( defGI.title, "New Game", sizeof( defGI.title ));
Q_strncpy( defGI.gamedir, gs_basedir, sizeof( defGI.gamedir ));
@ -1074,6 +1081,7 @@ static qboolean FS_ParseLiblistGam( const char *filename, const char *gamedir, g
GameInfo->max_beams = 128;
GameInfo->max_particles = 4096;
GameInfo->version = 1.0f;
GameInfo->falldir[0] = '\0';
Q_strncpy( GameInfo->title, "New Game", sizeof( GameInfo->title ));
Q_strncpy( GameInfo->gamedir, gamedir, sizeof( GameInfo->gamedir ));
@ -1105,6 +1113,10 @@ static qboolean FS_ParseLiblistGam( const char *filename, const char *gamedir, g
{
pfile = COM_ParseFile( pfile, GameInfo->gamedir );
}
if( !Q_stricmp( token, "fallback_dir" ))
{
pfile = COM_ParseFile( pfile, GameInfo->falldir );
}
else if( !Q_stricmp( token, "startmap" ))
{
pfile = COM_ParseFile( pfile, GameInfo->startmap );
@ -1220,6 +1232,7 @@ static qboolean FS_ParseGameInfo( const char *gamedir, gameinfo_t *GameInfo )
GameInfo->max_beams = 128;
GameInfo->max_particles = 4096;
GameInfo->version = 1.0f;
GameInfo->falldir[0] = '\0';
Q_strncpy( GameInfo->title, "New Game", sizeof( GameInfo->title ));
Q_strncpy( GameInfo->sp_entity, "info_player_start", sizeof( GameInfo->sp_entity ));
@ -1247,6 +1260,12 @@ static qboolean FS_ParseGameInfo( const char *gamedir, gameinfo_t *GameInfo )
if( Q_stricmp( fs_path, GameInfo->basedir ) || Q_stricmp( fs_path, GameInfo->gamedir ))
Q_strncpy( GameInfo->basedir, fs_path, sizeof( GameInfo->basedir ));
}
else if( !Q_stricmp( token, "fallback_dir" ))
{
pfile = COM_ParseFile( pfile, fs_path );
if( Q_stricmp( fs_path, GameInfo->basedir ) || Q_stricmp( fs_path, GameInfo->falldir ))
Q_strncpy( GameInfo->falldir, fs_path, sizeof( GameInfo->falldir ));
}
else if( !Q_stricmp( token, "gamedir" ))
{
pfile = COM_ParseFile( pfile, fs_path );
@ -2226,7 +2245,7 @@ file_t *FS_OpenFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedi
return file;
}
void FS_FreeFile( void *buffer )
void COM_FreeFile( void *buffer )
{
if( buffer && Mem_IsAllocatedExt( fs_mempool, buffer ))
Mem_Free( buffer );
@ -2521,12 +2540,15 @@ qboolean FS_Rename( const char *oldname, const char *newname )
if( !oldname || !newname || !*oldname || !*newname )
return false;
Q_snprintf( oldpath, sizeof( oldpath ), "%s/%s", fs_gamedir, oldname );
Q_snprintf( newpath, sizeof( newpath ), "%s/%s", fs_gamedir, newname );
Q_snprintf( oldpath, sizeof( oldpath ), "%s%s", fs_gamedir, oldname );
Q_snprintf( newpath, sizeof( newpath ), "%s%s", fs_gamedir, newname );
COM_FixSlashes( oldpath );
COM_FixSlashes( newpath );
iRet = rename( oldpath, newpath );
return iRet;
return (iRet == 0);
}
/*
@ -2544,10 +2566,11 @@ qboolean FS_Delete( const char *path )
if( !path || !*path )
return false;
Q_snprintf( real_path, sizeof( real_path ), "%s/%s", fs_gamedir, path );
Q_snprintf( real_path, sizeof( real_path ), "%s%s", fs_gamedir, path );
COM_FixSlashes( real_path );
iRet = remove( real_path );
return iRet;
return (iRet == 0);
}
/*

View File

@ -519,6 +519,12 @@ void Host_InitCommon( const char *progname, qboolean bChangeGame )
lpBuffer.dwLength = sizeof( MEMORYSTATUS );
GlobalMemoryStatus( &lpBuffer );
if( !GetCurrentDirectory( sizeof( host.rootdir ), host.rootdir ))
Sys_Error( "couldn't determine current directory" );
if( host.rootdir[Q_strlen( host.rootdir ) - 1] == '/' )
host.rootdir[Q_strlen( host.rootdir ) - 1] = 0;
host.oldFilter = SetUnhandledExceptionFilter( Sys_Crash );
host.hInst = GetModuleHandle( NULL );
host.change_game = bChangeGame;

View File

@ -852,17 +852,17 @@ void HPAK_RemoveLump( const char *name, resource_t *resource )
void HPAK_List_f( void )
{
// FIXME: implement
// TODO: implement
}
void HPAK_Extract_f( void )
{
// FIXME: implement
// TODO: implement
}
void HPAK_Remove_f( void )
{
// FIXME: implement
// TODO: implement
}
void HPAK_Validate_f( void )

View File

@ -237,7 +237,7 @@ qboolean Info_SetValueForKey( char *s, const char *key, const char *value )
if( !value || !Q_strlen( value ))
return true; // just clear variable
Q_sprintf( newi, "\\%s\\%s", key, value );
Q_snprintf( newi, sizeof( newi ) - 1, "\\%s\\%s", key, value );
if( Q_strlen( newi ) + Q_strlen( s ) > maxsize )
{
MsgDev( D_ERROR, "SetValueForKey: info string length exceeded\n" );

View File

@ -171,7 +171,7 @@ void IN_ToggleClientMouse( int newstate, int oldstate )
clgame.dllFuncs.IN_ActivateMouse();
}
if( newstate == key_menu )
if( newstate == key_menu && !cl.background )
{
in_mouseactive = false;
ClipCursor( NULL );
@ -402,7 +402,7 @@ void Host_InputFrame( void )
return;
}
if(( cl.refdef.paused && cls.key_dest == key_game ) || cls.key_dest == key_console )
if( cl.refdef.paused && cls.key_dest == key_game )
shutdownMouse = true; // release mouse during pause or console typeing
if( shutdownMouse && !Cvar_VariableInteger( "fullscreen" ))

View File

@ -442,6 +442,12 @@ static void Mod_LoadSubmodels( const dlump_t *l )
out->firstface = in->firstface;
out->numfaces = in->numfaces;
if( VectorIsNull( out->origin ))
{
// NOTE: zero origin after recalculating is indicated included origin brush
VectorAverage( out->mins, out->maxs, out->origin );
}
if( i == 0 || !world.loading )
continue; // skip the world
@ -749,13 +755,6 @@ static void Mod_CalcSurfaceExtents( msurface_t *surf )
mtexinfo_t *tex;
mvertex_t *v;
if( surf->flags & ( SURF_DRAWSKY|SURF_DRAWTURB ))
{
surf->extents[0] = surf->extents[1] = 16384;
surf->texturemins[0] = surf->texturemins[1] = -8192;
return;
}
tex = surf->texinfo;
mins[0] = mins[1] = 999999;
@ -1522,7 +1521,9 @@ static void Mod_LoadBrushModel( model_t *mod, const void *buffer )
mod->radius = RadiusFromBounds( mod->mins, mod->maxs );
mod->numleafs = bm->visleafs;
mod->flags = 0; // clear flags
// flag 1 is indicated model with origin brush!
mod->flags = VectorIsNull( bm->origin ) ? 1 : 0;
for( j = 0; i != 0 && j < mod->nummodelsurfaces; j++ )
{

View File

@ -86,7 +86,7 @@ int net_drop;
netadr_t net_from;
sizebuf_t net_message;
byte *net_mempool;
byte net_message_buffer[MAX_MSGLEN];
byte net_message_buffer[NET_MAX_PAYLOAD];
/*
===============
@ -333,7 +333,7 @@ Sends an out-of-band datagram
void Netchan_OutOfBand( int net_socket, netadr_t adr, int length, byte *data )
{
sizebuf_t send;
byte send_buf[MAX_MSGLEN];
byte send_buf[NET_MAX_PAYLOAD];
// write the packet header
BF_Init( &send, "SequencePacket", send_buf, sizeof( send_buf ));

View File

@ -503,14 +503,14 @@ beginning from specified offset
void Huff_CompressPacket( sizebuf_t *msg, int offset )
{
tree_t tree;
byte buffer[MAX_MSGLEN];
byte buffer[NET_MAX_PAYLOAD];
byte *data;
int outLen;
int i, inLen;
data = BF_GetData( msg ) + offset;
inLen = BF_GetNumBytesWritten( msg ) - offset;
if( inLen <= 0 || inLen >= MAX_MSGLEN )
if( inLen <= 0 || inLen >= NET_MAX_PAYLOAD )
return;
Huff_PrepareTree( tree );
@ -541,7 +541,7 @@ beginning from specified offset
void Huff_DecompressPacket( sizebuf_t *msg, int offset )
{
tree_t tree;
byte buffer[MAX_MSGLEN];
byte buffer[NET_MAX_PAYLOAD];
byte *data;
int outLen;
int inLen;
@ -556,8 +556,8 @@ void Huff_DecompressPacket( sizebuf_t *msg, int offset )
outLen = ( data[0] << 8 ) + data[1];
huffBitPos = 16;
if( outLen > MAX_MSGLEN - offset )
outLen = MAX_MSGLEN - offset;
if( outLen > NET_MAX_PAYLOAD - offset )
outLen = NET_MAX_PAYLOAD - offset;
for( i = 0; i < outLen; i++ )
{

View File

@ -180,7 +180,7 @@ typedef struct netchan_s
extern netadr_t net_from;
extern sizebuf_t net_message;
extern byte net_message_buffer[MAX_MSGLEN];
extern byte net_message_buffer[NET_MAX_PAYLOAD];
extern convar_t *net_speeds;
extern int net_drop;

View File

@ -14,9 +14,10 @@ typedef int (*pfnIgnore)( physent_t *pe ); // custom trace filter
//
void Pmove_Init( void );
void PM_InitBoxHull( void );
hull_t *PM_HullForBsp( physent_t *pe, const vec3_t mins, const vec3_t maxs, float *offset );
hull_t *PM_HullForBsp( physent_t *pe, playermove_t *pmove, float *offset );
qboolean PM_TraceModel( physent_t *pe, const vec3_t p1, vec3_t mins, vec3_t maxs, const vec3_t p2, pmtrace_t *tr, int flags );
pmtrace_t PM_PlayerTrace( playermove_t *pm, vec3_t p1, vec3_t p2, int flags, int hull, int ignore_pe, pfnIgnore pfn );
int PM_TestPlayerPosition( playermove_t *pmove, vec3_t pos, pfnIgnore pmFilter );
int PM_HullPointContents( hull_t *hull, int num, const vec3_t p );
//

View File

@ -75,6 +75,36 @@ static void PM_HullForHitbox( const vec3_t mins, const vec3_t maxs )
===============================================================================
*/
/*
====================
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;
}
}
/*
====================
StudioSetUpTransform

View File

@ -69,8 +69,8 @@ msurface_t *PM_RecursiveSurfCheck( model_t *model, mnode_t *node, vec3_t p1, vec
if( ds >= surf->texturemins[0] && dt >= surf->texturemins[1] )
{
int s = ds - surf->texturemins[0];
int t = dt - surf->texturemins[1];
int s = ds - surf->texturemins[0];
int t = dt - surf->texturemins[1];
if( s <= surf->extents[0] && t <= surf->extents[1] )
return surf;
@ -101,7 +101,9 @@ const char *PM_TraceTexture( physent_t *pe, vec3_t start, vec3_t end )
if( !bmodel || bmodel->type != mod_brush )
return NULL;
hull = PM_HullForBsp( pe, vec3_origin, vec3_origin, offset );
hull = &pe->model->hulls[0];
VectorSubtract( hull->clip_mins, vec3_origin, offset );
VectorAdd( offset, pe->origin, offset );
VectorSubtract( start, offset, start_l );
VectorSubtract( end, offset, end_l );
@ -111,7 +113,7 @@ const char *PM_TraceTexture( physent_t *pe, vec3_t start, vec3_t end )
{
matrix4x4 imatrix;
Matrix4x4_CreateFromEntity( matrix, pe->angles, pe->origin, 1.0f );
Matrix4x4_CreateFromEntity( matrix, pe->angles, offset, 1.0f );
Matrix4x4_Invert_Simple( imatrix, matrix );
Matrix4x4_VectorTransform( imatrix, start, start_l );

View File

@ -157,54 +157,32 @@ PM_HullForBsp
assume physent is valid
==================
*/
hull_t *PM_HullForBsp( physent_t *pe, const vec3_t mins, const vec3_t maxs, float *offset )
hull_t *PM_HullForBsp( physent_t *pe, playermove_t *pmove, float *offset )
{
hull_t *hull;
model_t *model;
vec3_t hullmins, hullmaxs;
vec3_t size;
// decide which clipping hull to use, based on the size
model = pe->model;
ASSERT( pe && pe->model != NULL );
if( !model || model->type != mod_brush )
{
// studiomodel or pushable
// create a temp hull from bounding box sizes
VectorSubtract( pe->mins, maxs, hullmins );
VectorSubtract( pe->maxs, mins, hullmaxs );
hull = PM_HullForBox( hullmins, hullmaxs );
VectorCopy( pe->origin, offset );
MsgDev( D_ERROR, "Entity %i SOLID_BSP with a non bsp model %i\n", pe->info, model->type );
return hull;
}
VectorSubtract( maxs, mins, size );
if( size[0] <= 8.0f )
switch( pmove->usehull )
{
case 1:
hull = &pe->model->hulls[3];
break;
case 2:
hull = &pe->model->hulls[0];
VectorCopy( hull->clip_mins, offset );
}
else
{
if( size[0] <= 36.0f )
{
if( size[2] <= 36.0f )
hull = &pe->model->hulls[3];
else hull = &pe->model->hulls[1];
}
else hull = &pe->model->hulls[2];
VectorSubtract( hull->clip_mins, mins, offset );
break;
case 3:
hull = &pe->model->hulls[2];
break;
default:
hull = &pe->model->hulls[1];
break;
}
// calculate an offset value to center the origin
VectorAdd( offset, pe->origin, offset );
ASSERT( hull != NULL );
// calculate an offset value to center the origin
VectorSubtract( hull->clip_mins, mins, offset );
VectorSubtract( hull->clip_mins, pmove->player_mins[pmove->usehull], offset );
VectorAdd( offset, pe->origin, offset );
return hull;
@ -366,7 +344,7 @@ static qboolean PM_BmodelTrace( physent_t *pe, const vec3_t start, vec3_t mins,
{
matrix4x4 imatrix;
Matrix4x4_CreateFromEntity( matrix, pe->angles, pe->origin, 1.0f );
Matrix4x4_CreateFromEntity( matrix, pe->angles, offset, 1.0f );
Matrix4x4_Invert_Simple( imatrix, matrix );
Matrix4x4_VectorTransform( imatrix, start, start_l );
@ -554,4 +532,47 @@ pmtrace_t PM_PlayerTrace( playermove_t *pmove, vec3_t start, vec3_t end, int fla
}
return total;
}
int PM_TestPlayerPosition( playermove_t *pmove, vec3_t pos, pfnIgnore pmFilter )
{
physent_t *pe;
hull_t *hull;
float *mins = pmove->player_mins[pmove->usehull];
float *maxs = pmove->player_maxs[pmove->usehull];
vec3_t offset, pos_l;
int i;
for( i = 0; i < pmove->numphysent; i++ )
{
pe = &pmove->physents[i];
if( pmFilter != NULL && pmFilter( pe ))
continue;
if( pe->model && pe->solid == SOLID_NOT && pe->skin != 0 )
continue;
// FIXME: check studiomodels with flag 512 by each hitbox ?
hull = PM_HullForEntity( pe, mins, maxs, offset );
// offset the test point appropriately for this hull.
VectorSubtract( pos, offset, pos_l );
// CM_TransformedPointContents :-)
if( pe->solid == SOLID_BSP && !VectorIsNull( pe->angles ))
{
matrix4x4 matrix, imatrix;
Matrix4x4_CreateFromEntity( matrix, pe->angles, offset, 1.0f );
Matrix4x4_Invert_Simple( imatrix, matrix );
Matrix4x4_VectorTransform( imatrix, pos, pos_l );
}
if( PM_HullPointContents( hull, hull->firstclipnode, pos_l ) == CONTENTS_SOLID )
return i;
}
return -1; // didn't hit anything
}

View File

@ -102,8 +102,8 @@
// sound flags
#define SND_VOLUME (1<<0) // a scaled byte
#define SND_ATTENUATION (1<<1) // a byte
#define SND_PITCH (1<<2) // a byte
#define SND_FIXED_ORIGIN (1<<3) // a vector
#define SND_LARGE_INDEX (1<<2) // a send sound as short
#define SND_PITCH (1<<3) // a byte
#define SND_SENTENCE (1<<4) // set if sound num is actually a sentence num
#define SND_STOP (1<<5) // stop the sound
#define SND_CHANGE_VOL (1<<6) // change sound vol

View File

@ -449,7 +449,10 @@ void Sys_Break( const char *error, ... )
va_end( argptr );
if( host.type == HOST_NORMAL )
CL_Shutdown(); // kill video
{
if( host.hWnd ) ShowWindow( host.hWnd, SW_HIDE );
VID_RestoreGamma();
}
if( host.type != HOST_NORMAL || host.developer > 0 )
{

View File

@ -32,6 +32,7 @@ typedef enum
AREA_SOLID, // find any solid edicts
AREA_TRIGGERS, // find all SOLID_TRIGGER edicts
AREA_CUSTOM, // find all edicts with custom contents - water, lava, fog, laders etc
AREA_PUSHMOVE, // find all edicts which supposed to push with MOVETYPE_PUSH
} AREA_TYPE;
typedef struct areanode_s

View File

@ -20,7 +20,6 @@
//=============================================================================
#define MAX_MASTERS 8 // max recipients for heartbeat packets
#define RATE_MESSAGES 10
#define SV_UPDATE_MASK (SV_UPDATE_BACKUP - 1)
extern int SV_UPDATE_BACKUP;
@ -36,20 +35,19 @@ extern int SV_UPDATE_BACKUP;
#define MAP_HAS_LANDMARK BIT( 2 )
#define MAP_INVALID_VERSION BIT( 3 )
#define SV_IsValidEdict( e ) ( e && !e->free )
#define EDICT_FROM_AREA( l ) STRUCT_FROM_LINK( l, edict_t, area )
#define NUM_FOR_EDICT(e) ((int)((edict_t *)(e) - svgame.edicts))
#define EDICT_NUM( num ) SV_EDICT_NUM( num, __FILE__, __LINE__ )
#define STRING( offset ) SV_GetString( offset )
#define MAKE_STRING(str) SV_AllocString( str )
#define MAX_MULTICAST 2500
#define ALLOC_STRING(str) SV_AllocString( str )
#define MAKE_STRING(str) (int)(str - svgame.globals->pStringBase)
#define MAX_PUSHED_ENTS 256
#define DVIS_PVS 0
#define DVIS_PHS 1
// convert msecs to float time properly
#define sv_time() ( sv.time )
#define SV_IsValidEdict( e ) ( e && !e->free )
typedef enum
{
ss_dead, // no map loaded
@ -120,10 +118,13 @@ typedef struct server_s
// the multicast buffer is used to send a message to a set of clients
sizebuf_t multicast;
byte multicast_buf[MAX_MSGLEN];
byte multicast_buf[NET_MAX_PAYLOAD];
sizebuf_t signon;
byte signon_buf[MAX_MSGLEN];
byte signon_buf[NET_MAX_PAYLOAD];
sizebuf_t spectator_datagram;
byte spectator_buf[NET_MAX_PAYLOAD];
model_t *worldmodel; // pointer to world
uint checksum; // for catching cheater maps
@ -139,7 +140,7 @@ typedef struct
float latency;
clientdata_t clientdata;
weapon_data_t weapondata[32];
weapon_data_t weapondata[MAX_WEAPONS];
int num_entities;
int first_entity; // into the circular sv_packet_entities[]
} client_frame_t;
@ -190,8 +191,6 @@ typedef struct sv_client_s
int listeners; // 32 bits == MAX_CLIENTS (voice listeners)
float addangle; // add angles to client position
edict_t *edict; // EDICT_NUM(clientnum+1)
edict_t *pViewEntity; // svc_setview member
char name[32]; // extracted from userinfo, color string allowed
@ -200,15 +199,11 @@ typedef struct sv_client_s
// the datagram is written to by sound calls, prints, temp ents, etc.
// it can be harmlessly overflowed.
sizebuf_t datagram;
byte datagram_buf[MAX_MSGLEN];
byte datagram_buf[NET_MAX_PAYLOAD];
client_frame_t *frames; // updates can be delta'd from here
event_state_t events;
byte *download; // file being downloaded
int downloadsize; // total bytes (can't use EOF because of paks)
int downloadcount; // bytes sent
double lastmessage; // time when packet was last received
double lastconnect;
@ -243,7 +238,7 @@ typedef struct
typedef struct
{
char name[32];
char name[32]; // in GoldSrc max name length is 12
int number; // svc_ number
int size; // if size == -1, size come from first byte after svcnum
} sv_user_message_t;
@ -303,7 +298,12 @@ typedef struct
playermove_t *pmove; // pmove state
sv_interp_t interp[32]; // interpolate clients
sv_pushed_t pushed[256]; // no reason to keep array for all edicts
#ifdef BUILD_PUSH_LIST
int numpushents; // actual count. don't forget to reset it before
// call SV_BuildPushList
edict_t *pushlist[MAX_PUSHED_ENTS]; // array of edicts that contacted with pusher
#endif
sv_pushed_t pushed[MAX_PUSHED_ENTS]; // no reason to keep array for all edicts
// 256 it should be enough for any game situation
vec3_t player_mins[4]; // 4 hulls allowed
@ -378,6 +378,8 @@ extern convar_t *sv_allow_upload;
extern convar_t *sv_allow_download;
extern convar_t *sv_allow_studio_scaling;
extern convar_t *sv_allow_studio_attachment_angles;
extern convar_t *sv_allow_rotate_pushables;
extern convar_t *sv_clienttrace;
extern convar_t *sv_send_resources;
extern convar_t *sv_send_logos;
extern convar_t *sv_sendvelocity;
@ -425,6 +427,7 @@ void SV_FreeOldEntities( void );
qboolean SV_TestEntityPosition( edict_t *ent, edict_t *blocker ); // for EntityInSolid checks
qboolean SV_TestPlayerPosition( edict_t *ent ); // for PlayerInSolid checks
void SV_Impact( edict_t *e1, trace_t *trace );
qboolean SV_CanPushed( edict_t *ent );
void SV_CheckAllEnts( void );
//
@ -463,6 +466,7 @@ void SV_ClientThink( sv_client_t *cl, usercmd_t *cmd );
void SV_ExecuteClientMessage( sv_client_t *cl, sizebuf_t *msg );
void SV_ConnectionlessPacket( netadr_t from, sizebuf_t *msg );
edict_t *SV_FakeConnect( const char *netname );
void SV_ExecuteClientCommand( sv_client_t *cl, char *s );
void SV_PreRunCmd( sv_client_t *cl, usercmd_t *ucmd, int random_seed );
void SV_RunCmd( sv_client_t *cl, usercmd_t *ucmd, int random_seed );
void SV_PostRunCmd( sv_client_t *cl );
@ -481,7 +485,6 @@ void SV_Newgame_f( void );
//
void SV_WriteFrameToClient( sv_client_t *client, sizebuf_t *msg );
void SV_BuildClientFrame( sv_client_t *client );
void SV_ClearFrames( client_frame_t **frames );
void SV_InactivateClients( void );
void SV_SendMessagesToAll( void );
void SV_SkipUpdates( void );
@ -542,6 +545,7 @@ void SV_ChangeLevel( qboolean loadfromsavedgame, const char *mapname, const char
const char *SV_GetLatestSave( void );
int SV_LoadGameState( char const *level, qboolean createPlayers );
void SV_LoadAdjacentEnts( const char *pOldLevel, const char *pLandmarkName );
void SV_InitSaveRestore( void );
//
// sv_studio.c

View File

@ -151,10 +151,7 @@ void SV_DirectConnect( netadr_t from )
s = Info_ValueForKey( userinfo, "spectator" );
if( s && Q_strcmp( s, "0" ) && sv_maxclients->integer > 1 )
{
// FXIME: we can create listen server with spectator instead of client ?
spectator = true;
}
// if there is already a slot for this ip, reuse it
for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
@ -195,7 +192,7 @@ gotnewcl:
*newcl = temp;
if( sv_maxclients->integer == 1 ) // restore physinfo for singleplayer
if( sv_maxclients->integer == 1 ) // restore physinfo for singleplayer
Q_strncpy( newcl->physinfo, physinfo, sizeof( physinfo ));
sv_client = newcl;
@ -206,12 +203,14 @@ gotnewcl:
newcl->challenge = challenge; // save challenge for checksumming
newcl->frames = (client_frame_t *)Z_Malloc( sizeof( client_frame_t ) * SV_UPDATE_BACKUP );
newcl->userid = g_userid++; // create unique userid
newcl->spectator = spectator;
// FIXME: g-cont. i'm don't know how spectators interact with server
// newcl->spectator = spectator;
// get the game a chance to reject this connection or modify the userinfo
if( !( SV_ClientConnect( ent, userinfo )))
{
if(*Info_ValueForKey( userinfo, "rejmsg" ))
if( *Info_ValueForKey( userinfo, "rejmsg" ))
Netchan_OutOfBandPrint( NS_SERVER, from, "print\n%s\nConnection refused.\n", Info_ValueForKey( userinfo, "rejmsg" ));
else Netchan_OutOfBandPrint( NS_SERVER, from, "print\nConnection refused.\n" );
MsgDev( D_ERROR, "SV_DirectConnect: game rejected a connection.\n");
@ -260,7 +259,7 @@ edict_t *SV_FakeConnect( const char *netname )
if( !netname ) netname = "";
userinfo[0] = '\0';
// setup fake client name
// setup fake client params
Info_SetValueForKey( userinfo, "name", netname );
Info_SetValueForKey( userinfo, "model", "gordon" );
Info_SetValueForKey( userinfo, "topcolor", "1" );
@ -294,7 +293,9 @@ edict_t *SV_FakeConnect( const char *netname )
sv_client = newcl;
edictnum = (newcl - svs.clients) + 1;
SV_ClearFrames( &newcl->frames ); // fakeclients doesn't have frames
if( newcl->frames )
Mem_Free( newcl->frames ); // fakeclients doesn't have frames
newcl->frames = NULL;
ent = EDICT_NUM( edictnum );
newcl->edict = ent;
@ -336,7 +337,7 @@ qboolean SV_ClientConnect( edict_t *ent, char *userinfo )
{
qboolean result = true;
char *pszName, *pszAddress;
char szRejectReason[128];
char szRejectReason[MAX_INFO_STRING];
// make sure we start with known default
if( !sv.loadgame ) ent->v.flags = 0;
@ -365,7 +366,8 @@ void SV_DropClient( sv_client_t *drop )
{
int i;
if( drop->state == cs_zombie ) return; // already dropped
if( drop->state == cs_zombie )
return; // already dropped
// add the disconnect
if( !drop->fakeclient )
@ -393,15 +395,16 @@ void SV_DropClient( sv_client_t *drop )
drop->edict->pvPrivateData = NULL;
}
if( drop->download )
drop->download = NULL;
drop->fakeclient = false;
drop->hltv_proxy = false;
drop->state = cs_zombie; // become free in a few seconds
drop->name[0] = 0;
SV_ClearFrames( &drop->frames );
if( drop->frames )
Mem_Free( drop->frames ); // fakeclients doesn't have frames
drop->frames = NULL;
// Throw away any residual garbage in the channel.
// throw away any residual garbage in the channel.
Netchan_Clear( &drop->netchan );
// send notification to all other clients
@ -483,7 +486,7 @@ Builds the string that is sent as heartbeats and status replies
char *SV_StatusString( void )
{
char player[1024];
static char status[MAX_MSGLEN - 16];
static char status[4096];
int statusLength;
int playerLength;
sv_client_t *cl;
@ -562,7 +565,7 @@ Responds with all the info that qplug or qspy can see
*/
void SV_Status( netadr_t from )
{
Netchan_OutOfBandPrint( NS_SERVER, from, "print\n%s", SV_StatusString());
Netchan_OutOfBandPrint( NS_SERVER, from, "print\n%s", SV_StatusString( ));
}
/*
@ -652,12 +655,12 @@ Redirect all printfs
void SV_RemoteCommand( netadr_t from, sizebuf_t *msg )
{
char remaining[1024];
static char outputbuf[MAX_MSGLEN - 16];
static char outputbuf[2048];
int i;
if(!Rcon_Validate()) MsgDev(D_INFO, "Bad rcon from %s:\n%s\n", NET_AdrToString( from ), BF_GetData( msg ) + 4 );
else MsgDev( D_INFO, "Rcon from %s:\n%s\n", NET_AdrToString( from ), BF_GetData( msg ) + 4 );
SV_BeginRedirect( from, RD_PACKET, outputbuf, MAX_MSGLEN - 16, SV_FlushRedirect );
SV_BeginRedirect( from, RD_PACKET, outputbuf, sizeof( outputbuf ) - 16, SV_FlushRedirect );
if( !Rcon_Validate( ))
{
@ -882,6 +885,9 @@ void SV_PutClientInServer( edict_t *ent )
if( !sv.loadgame )
{
if( client->hltv_proxy )
ent->v.flags |= FL_PROXY;
if( client->spectator )
{
svgame.globals->time = sv.time;
@ -889,7 +895,7 @@ void SV_PutClientInServer( edict_t *ent )
}
else
{
ent->v.netname = MAKE_STRING( Info_ValueForKey( client->userinfo, "name" ));
ent->v.netname = MAKE_STRING( client->name );
// fisrt entering
svgame.globals->time = sv.time;
@ -910,6 +916,16 @@ void SV_PutClientInServer( edict_t *ent )
}
else
{
if( client->hltv_proxy )
{
MsgDev( D_ERROR, "spectator mode doesn't work with saved game\n" );
return;
}
// enable dev-mode to prevent crash cheat-protecting from invasion
if( ent->v.flags & (FL_GODMODE|FL_NOTARGET) && !Q_stricmp( GI->gamefolder, "invasion" ))
SV_ExecuteClientCommand( client, "test\n" );
// NOTE: we needs to setup angles on restore here
if( ent->v.fixangle == 1 )
{
@ -1062,7 +1078,7 @@ void SV_WriteModels_f( sv_client_t *cl )
start = Q_atoi( Cmd_Argv( 2 ));
// write a packet full of data
while( BF_GetNumBytesWritten( &cl->netchan.message ) < ( MAX_MSGLEN / 2 ) && start < MAX_MODELS )
while( BF_GetNumBytesWritten( &cl->netchan.message ) < ( NET_MAX_PAYLOAD / 2 ) && start < MAX_MODELS )
{
if( sv.model_precache[start][0] )
{
@ -1108,7 +1124,7 @@ void SV_WriteSounds_f( sv_client_t *cl )
start = Q_atoi( Cmd_Argv( 2 ));
// write a packet full of data
while( BF_GetNumBytesWritten( &cl->netchan.message ) < ( MAX_MSGLEN / 2 ) && start < MAX_SOUNDS )
while( BF_GetNumBytesWritten( &cl->netchan.message ) < ( NET_MAX_PAYLOAD / 2 ) && start < MAX_SOUNDS )
{
if( sv.sound_precache[start][0] )
{
@ -1154,7 +1170,7 @@ void SV_WriteEvents_f( sv_client_t *cl )
start = Q_atoi( Cmd_Argv( 2 ));
// write a packet full of data
while( BF_GetNumBytesWritten( &cl->netchan.message ) < ( MAX_MSGLEN / 2 ) && start < MAX_EVENTS )
while( BF_GetNumBytesWritten( &cl->netchan.message ) < ( NET_MAX_PAYLOAD / 2 ) && start < MAX_EVENTS )
{
if( sv.event_precache[start][0] )
{
@ -1200,7 +1216,7 @@ void SV_WriteLightstyles_f( sv_client_t *cl )
start = Q_atoi( Cmd_Argv( 2 ));
// write a packet full of data
while( BF_GetNumBytesWritten( &cl->netchan.message ) < ( MAX_MSGLEN / 2 ) && start < MAX_LIGHTSTYLES )
while( BF_GetNumBytesWritten( &cl->netchan.message ) < ( NET_MAX_PAYLOAD / 2 ) && start < MAX_LIGHTSTYLES )
{
if( sv.lightstyles[start].pattern[0] )
{
@ -1247,7 +1263,7 @@ void SV_UserMessages_f( sv_client_t *cl )
start = Q_atoi( Cmd_Argv( 2 ));
// write a packet full of data
while( BF_GetNumBytesWritten( &cl->netchan.message ) < ( MAX_MSGLEN / 2 ) && start < MAX_USER_MESSAGES )
while( BF_GetNumBytesWritten( &cl->netchan.message ) < ( NET_MAX_PAYLOAD / 2 ) && start < MAX_USER_MESSAGES )
{
message = &svgame.msg[start];
if( message->name[0] )
@ -1268,7 +1284,6 @@ void SV_UserMessages_f( sv_client_t *cl )
BF_WriteString( &cl->netchan.message, cmd );
}
/*
==================
SV_DeltaInfo_f
@ -1299,7 +1314,7 @@ void SV_DeltaInfo_f( sv_client_t *cl )
fieldIndex = Q_atoi( Cmd_Argv( 3 ));
// write a packet full of data
while( BF_GetNumBytesWritten( &cl->netchan.message ) < ( MAX_MSGLEN / 2 ) && tableIndex < Delta_NumTables( ))
while( BF_GetNumBytesWritten( &cl->netchan.message ) < ( NET_MAX_PAYLOAD / 2 ) && tableIndex < Delta_NumTables( ))
{
dt = Delta_FindStructByIndex( tableIndex );
@ -1308,7 +1323,7 @@ void SV_DeltaInfo_f( sv_client_t *cl )
Delta_WriteTableField( &cl->netchan.message, tableIndex, &dt->pFields[fieldIndex] );
// it's time to send another portion
if( BF_GetNumBytesWritten( &cl->netchan.message ) >= ( MAX_MSGLEN / 2 ))
if( BF_GetNumBytesWritten( &cl->netchan.message ) >= ( NET_MAX_PAYLOAD / 2 ))
break;
}
@ -1358,7 +1373,7 @@ void SV_Baselines_f( sv_client_t *cl )
Q_memset( &nullstate, 0, sizeof( nullstate ));
// write a packet full of data
while( BF_GetNumBytesWritten( &cl->netchan.message ) < ( MAX_MSGLEN / 2 ) && start < svgame.numEntities )
while( BF_GetNumBytesWritten( &cl->netchan.message ) < ( NET_MAX_PAYLOAD / 2 ) && start < svgame.numEntities )
{
base = &svs.baselines[start];
if( base->number && ( base->modelindex || base->effects != EF_NODRAW ))
@ -1412,64 +1427,6 @@ void SV_Begin_f( sv_client_t *cl )
}
}
/*
==================
SV_NextDownload_f
==================
*/
void SV_NextDownload_f( sv_client_t *cl )
{
int percent;
int r, size;
if( !cl->download ) return;
r = cl->downloadsize - cl->downloadcount;
if( r > 1024 ) r = 1024;
BF_WriteByte( &cl->netchan.message, svc_download );
BF_WriteShort( &cl->netchan.message, r );
cl->downloadcount += r;
size = cl->downloadsize;
if( !size ) size = 1;
percent = cl->downloadcount * 100 / size;
BF_WriteByte( &cl->netchan.message, percent );
BF_WriteBytes( &cl->netchan.message, cl->download + cl->downloadcount - r, r );
if( cl->downloadcount == cl->downloadsize ) cl->download = NULL;
}
/*
==================
SV_BeginDownload_f
==================
*/
void SV_BeginDownload_f( sv_client_t *cl )
{
char *name;
int offset = 0;
name = Cmd_Argv( 1 );
if(Cmd_Argc() > 2 ) offset = Q_atoi(Cmd_Argv(2)); // continue download from
cl->download = FS_LoadFile( name, &cl->downloadsize, false );
cl->downloadcount = offset;
if( offset > cl->downloadsize ) cl->downloadcount = cl->downloadsize;
if( !allow_download->integer || !cl->download )
{
MsgDev( D_ERROR, "SV_BeginDownload_f: couldn't download %s to %s\n", name, cl->name );
if( cl->download ) Mem_Free( cl->download );
BF_WriteByte( &cl->netchan.message, svc_download );
BF_WriteShort( &cl->netchan.message, -1 );
BF_WriteByte( &cl->netchan.message, 0 );
cl->download = NULL;
return;
}
SV_NextDownload_f( cl );
MsgDev( D_INFO, "Downloading %s to %s\n", name, cl->name );
}
/*
=================
SV_Disconnect_f
@ -1598,6 +1555,7 @@ void SV_UserinfoChanged( sv_client_t *cl, const char *userinfo )
cl->local_weapons = Q_atoi( Info_ValueForKey( cl->userinfo, "cl_lw" )) ? true : false;
cl->lag_compensation = Q_atoi( Info_ValueForKey( cl->userinfo, "cl_lc" )) ? true : false;
cl->hltv_proxy = Q_atoi( Info_ValueForKey( cl->userinfo, "hltv" )) ? true : false;
val = Info_ValueForKey( cl->userinfo, "cl_updaterate" );
@ -1625,8 +1583,7 @@ void SV_UserinfoChanged( sv_client_t *cl, const char *userinfo )
// call prog code to allow overrides
svgame.dllFuncs.pfnClientUserInfoChanged( cl->edict, cl->userinfo );
ent->v.netname = MAKE_STRING( Info_ValueForKey( cl->userinfo, "name" ));
ent->v.netname = MAKE_STRING( cl->name );
if( cl->state >= cs_connected ) cl->sendinfo = true; // needs for update client info
}
@ -1714,13 +1671,11 @@ ucmd_t ucmds[] =
{ "baselines", SV_Baselines_f },
{ "deltainfo", SV_DeltaInfo_f },
{ "info", SV_ShowServerinfo_f },
{ "nextdl", SV_NextDownload_f },
{ "modellist", SV_WriteModels_f },
{ "soundlist", SV_WriteSounds_f },
{ "eventlist", SV_WriteEvents_f },
{ "disconnect", SV_Disconnect_f },
{ "usermsgs", SV_UserMessages_f },
{ "download", SV_BeginDownload_f },
{ "userinfo", SV_UpdateUserinfo_f },
{ "lightstyles", SV_WriteLightstyles_f },
{ NULL, NULL }
@ -1736,6 +1691,7 @@ void SV_ExecuteClientCommand( sv_client_t *cl, char *s )
ucmd_t *u;
Cmd_TokenizeString( s );
for( u = ucmds; u->name; u++ )
{
if( !Q_strcmp( Cmd_Argv( 0 ), u->name ))
@ -1892,7 +1848,6 @@ static void SV_ParseClientMove( sv_client_t *cl, sizebuf_t *msg )
if( net_drop < 24 )
{
while( net_drop > numbackup )
{
SV_PreRunCmd( cl, &cl->lastcmd, 0 );

View File

@ -20,10 +20,7 @@ void SV_ClientPrintf( sv_client_t *cl, int level, char *fmt, ... )
va_list argptr;
char string[MAX_SYSPATH];
if( level < cl->messagelevel )
return;
if( cl->fakeclient )
if( level < cl->messagelevel || cl->fakeclient )
return;
va_start( argptr, fmt );
@ -57,6 +54,7 @@ void SV_BroadcastPrintf( int level, char *fmt, ... )
// echo to console
if( host.type == HOST_DEDICATED ) Msg( "%s", string );
for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
{
if( level < cl->messagelevel ) continue;
@ -150,7 +148,7 @@ qboolean SV_SetPlayer( void )
if( sv_maxclients->integer == 1 || Cmd_Argc() < 2 )
{
// sepcial case for local client
// special case for local client
sv_client = svs.clients;
return true;
}
@ -166,6 +164,7 @@ qboolean SV_SetPlayer( void )
Msg( "Bad client slot: %i\n", idnum );
return false;
}
sv_client = &svs.clients[idnum];
if( !sv_client->state )
{
@ -185,6 +184,7 @@ qboolean SV_SetPlayer( void )
return true;
}
}
Msg( "Userid %s is not on the server\n", s );
return false;
}
@ -237,7 +237,7 @@ void SV_Map_f( void )
return;
}
SCR_BeginLoadingPlaque();
SCR_BeginLoadingPlaque( false );
sv.background = false;
sv.loadgame = false; // set right state
@ -300,7 +300,7 @@ void SV_MapBackground_f( void )
Cvar_FullSet( "deathmatch", "0", CVAR_LATCH );
Cvar_FullSet( "maxplayers", "1", CVAR_LATCH );
SCR_BeginLoadingPlaque();
SCR_BeginLoadingPlaque( true );
SV_SpawnServer( mapname, NULL );
SV_LevelInit( mapname, NULL, NULL, false );
@ -478,7 +478,7 @@ void SV_ChangeLevel_f( void )
return;
}
SCR_BeginLoadingPlaque();
SCR_BeginLoadingPlaque( false );
if( sv.state != ss_active || sv.background )
{
@ -622,7 +622,7 @@ void SV_Status_f( void )
if( !svs.clients || sv.background )
{
Msg ( "^3no server running.\n" );
Msg( "^3no server running.\n" );
return;
}

View File

@ -39,22 +39,6 @@ static int SV_EntityNumbers( const void *a, const void *b )
return 1;
}
/*
================
SV_ClearFrames
free client frames memory
================
*/
void SV_ClearFrames( client_frame_t **frames )
{
if( *frames == NULL )
return;
Mem_Free( *frames );
*frames = NULL;
}
/*
=============
SV_AddEntitiesToPacket
@ -99,7 +83,8 @@ static void SV_AddEntitiesToPacket( edict_t *pViewEnt, edict_t *pClient, client_
if( ent->free ) continue;
// don't double add an entity through portals (already added)
if( ent->v.gamestate == sv.net_framenum )
// HACHACK: use pushmsec to keep net_framenum
if( ent->v.pushmsec == sv.net_framenum )
continue;
if( ent->v.effects & EF_REQUEST_PHS )
@ -110,14 +95,14 @@ static void SV_AddEntitiesToPacket( edict_t *pViewEnt, edict_t *pClient, client_
netclient = SV_ClientFromEdict( ent, true );
player = ( netclient != NULL );
// clear modelindex if model is not set
// clear modelindex if model is not set (Opposing Force issues)
if( !ent->v.model ) ent->v.modelindex = 0;
// add entity to the net packet
if( svgame.dllFuncs.pfnAddToFullPack( state, e, ent, pClient, sv.hostflags, player, pset ))
{
// to prevent adds it twice through portals
ent->v.gamestate = sv.net_framenum;
ent->v.pushmsec = sv.net_framenum;
if( netclient && netclient->modelindex ) // apply custom model if present
state->modelindex = netclient->modelindex;
@ -334,7 +319,8 @@ void SV_EmitPings( sizebuf_t *msg )
for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
{
if( cl->state != cs_spawned ) continue;
if( cl->state != cs_spawned )
continue;
SV_GetPlayerStats( cl, &ping, &packet_loss );
@ -391,13 +377,13 @@ void SV_WriteClientdataToMessage( sv_client_t *cl, sizebuf_t *msg )
break;
case 2:
BF_WriteByte( msg, svc_addangle );
BF_WriteBitAngle( msg, cl->addangle, 16 );
cl->addangle = 0;
BF_WriteBitAngle( msg, clent->v.avelocity[1], 16 );
clent->v.avelocity[1] = 0.0f;
break;
}
clent->v.fixangle = 0; // reset fixangle
clent->v.gamestate = 0; // reset gamestate
clent->v.pushmsec = 0; // reset net framenum
Q_memset( &frame->clientdata, 0, sizeof( frame->clientdata ));
// update clientdata_t
@ -594,6 +580,13 @@ void SV_UpdateToReliableMessages( void )
BF_Clear( &sv.datagram );
}
// clear the server datagram if it overflowed.
if( BF_CheckOverflow( &sv.spectator_datagram ))
{
MsgDev( D_ERROR, "sv.spectator_datagram overflowed!\n" );
BF_Clear( &sv.spectator_datagram );
}
// now send the reliable and server datagrams to all clients.
for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
{
@ -602,9 +595,15 @@ void SV_UpdateToReliableMessages( void )
BF_WriteBits( &cl->netchan.message, BF_GetData( &sv.reliable_datagram ), BF_GetNumBitsWritten( &sv.reliable_datagram ));
BF_WriteBits( &cl->datagram, BF_GetData( &sv.datagram ), BF_GetNumBitsWritten( &sv.datagram ));
if( cl->hltv_proxy )
{
BF_WriteBits( &cl->datagram, BF_GetData( &sv.spectator_datagram ), BF_GetNumBitsWritten( &sv.spectator_datagram ));
}
}
// now clear the reliable and datagram buffers.
BF_Clear( &sv.spectator_datagram );
BF_Clear( &sv.reliable_datagram );
BF_Clear( &sv.datagram );
}
@ -639,9 +638,7 @@ void SV_SendClientMessages( void )
}
if( !host_limitlocal->integer && NET_IsLocalAddress( cl->netchan.remote_address ))
{
cl->send_message = true;
}
if( cl->state == cs_spawned )
{
@ -652,15 +649,11 @@ void SV_SendClientMessages( void )
float time_unti_next_message = cl->next_messagetime - (host.realtime + host.frametime);
if( time_unti_next_message <= 0.0f )
{
cl->send_message = true;
}
// something got hosed
if( time_unti_next_message > 2.0f )
{
cl->send_message = true;
}
}
// if the reliable message overflowed, drop the client
@ -680,9 +673,7 @@ void SV_SendClientMessages( void )
// until we get another packet in from the client. This prevents crash/drop and reconnect where they are
// being hosed with "sequenced packet without connection" packets.
if(( host.realtime - cl->netchan.last_received ) > sv_failuretime->value )
{
cl->send_message = false;
}
}
// only send messages if the client has sent one
@ -707,6 +698,7 @@ void SV_SendClientMessages( void )
}
else
{
// jsut update reliable
Netchan_Transmit( &cl->netchan, 0, NULL );
}
}

View File

@ -1,6 +1,6 @@
//=======================================================================
// Copyright XashXT Group 2008 ©
// sv_game.c - server dlls interaction
// sv_game.c - gamedll interaction
//=======================================================================
#include "common.h"
@ -18,7 +18,7 @@ static byte *bitvector;
static int fatbytes;
// exports
typedef void (*LINK_ENTITY_FUNC)( entvars_t *pev );
typedef void (__cdecl *LINK_ENTITY_FUNC)( entvars_t *pev );
typedef void (__stdcall *GIVEFNPTRSTODLL)( enginefuncs_t* engfuncs, globalvars_t *pGlobals );
/*
@ -103,13 +103,16 @@ void SV_CopyTraceToGlobal( trace_t *trace )
svgame.globals->trace_startsolid = trace->startsolid;
svgame.globals->trace_fraction = trace->fraction;
svgame.globals->trace_plane_dist = trace->plane.dist;
svgame.globals->trace_ent = trace->ent;
svgame.globals->trace_flags = 0;
svgame.globals->trace_inopen = trace->inopen;
svgame.globals->trace_inwater = trace->inwater;
VectorCopy( trace->endpos, svgame.globals->trace_endpos );
VectorCopy( trace->plane.normal, svgame.globals->trace_plane_normal );
svgame.globals->trace_hitgroup = trace->hitgroup;
if( SV_IsValidEdict( trace->ent ))
svgame.globals->trace_ent = trace->ent;
else svgame.globals->trace_ent = svgame.edicts;
}
void SV_SetModel( edict_t *ent, const char *name )
@ -121,7 +124,7 @@ void SV_SetModel( edict_t *ent, const char *name )
i = SV_ModelIndex( name );
if( i == 0 ) return;
ent->v.model = sv.model_precache[i] - svgame.globals->pStringBase;
ent->v.model = MAKE_STRING( sv.model_precache[i] );
ent->v.modelindex = i;
mod_type = Mod_GetType( ent->v.modelindex );
@ -146,6 +149,7 @@ float SV_AngleMod( float ideal, float current, float speed )
return current;
move = ideal - current;
if( ideal > current )
{
if( move >= 180 )
@ -156,6 +160,7 @@ float SV_AngleMod( float ideal, float current, float speed )
if( move <= -180 )
move = move + 360;
}
if( move > 0 )
{
if( move > speed )
@ -166,6 +171,7 @@ float SV_AngleMod( float ideal, float current, float speed )
if( move < -speed )
move = -speed;
}
return anglemod( current + move );
}
@ -221,7 +227,7 @@ qboolean SV_Send( int dest, const vec3_t origin, const edict_t *ent )
case MSG_INIT:
if( sv.state == ss_loading )
{
// copy signon buffer
// copy to signon buffer
BF_WriteBits( &sv.signon, BF_GetData( &sv.multicast ), BF_GetNumBitsWritten( &sv.multicast ));
BF_Clear( &sv.multicast );
return true;
@ -276,12 +282,18 @@ qboolean SV_Send( int dest, const vec3_t origin, const edict_t *ent )
if( cl->state != cs_spawned && !reliable )
continue;
if( specproxy && !( cl->edict->v.flags & FL_PROXY ))
if( specproxy && !cl->hltv_proxy )
continue;
if( !cl->edict || cl->fakeclient )
continue;
if( ent != NULL && ent->v.groupinfo && cl->edict->v.groupinfo )
{
if(( !svs.groupop && !( cl->edict->v.groupinfo & ent->v.groupinfo )) || (svs.groupop == 1 && ( cl->edict->v.groupinfo & ent->v.groupinfo ) != 0 ))
continue;
}
// simple PAS checking in singleplayer (QW legacy)
if( sv_maxclients->integer == 1 && ( dest == MSG_PAS_R || dest == MSG_PAS ))
{
@ -310,7 +322,8 @@ qboolean SV_Send( int dest, const vec3_t origin, const edict_t *ent )
continue;
}
inrange:
if( reliable ) BF_WriteBits( &cl->netchan.message, BF_GetData( &sv.multicast ), BF_GetNumBitsWritten( &sv.multicast ));
if( specproxy ) BF_WriteBits( &sv.spectator_datagram, BF_GetData( &sv.multicast ), BF_GetNumBitsWritten( &sv.multicast ));
else if( reliable ) BF_WriteBits( &cl->netchan.message, BF_GetData( &sv.multicast ), BF_GetNumBitsWritten( &sv.multicast ));
else BF_WriteBits( &cl->datagram, BF_GetData( &sv.multicast ), BF_GetNumBitsWritten( &sv.multicast ));
numsends++;
}
@ -320,6 +333,13 @@ inrange:
return numsends; // debug
}
/*
=======================
SV_CreateDecal
NOTE: static decals only accepted when game is loading
=======================
*/
void SV_CreateDecal( const float *origin, int decalIndex, int entityIndex, int modelIndex, int flags )
{
if( sv.state != ss_loading ) return;
@ -440,6 +460,13 @@ static qboolean SV_BoxInPVS( const vec3_t org, const vec3_t absmin, const vec3_t
return true;
}
/*
==============
SV_WriteEntityPatch
Create entity patch for selected map
==============
*/
void SV_WriteEntityPatch( const char *filename )
{
file_t *f;
@ -462,6 +489,7 @@ void SV_WriteEntityPatch( const char *filename )
header = (dheader_t *)buf;
if( header->lumps[LUMP_ENTITIES].fileofs <= 1024 )
{
// Blue-Shift ordering
lumpofs = header->lumps[LUMP_PLANES].fileofs;
lumplen = header->lumps[LUMP_PLANES].filelen;
}
@ -490,6 +518,13 @@ void SV_WriteEntityPatch( const char *filename )
FS_Close( f );
}
/*
==============
SV_ReadEntityScript
pfnMapIsValid use this
==============
*/
char *SV_ReadEntityScript( const char *filename, int *flags )
{
file_t *f;
@ -518,6 +553,7 @@ char *SV_ReadEntityScript( const char *filename, int *flags )
header = (dheader_t *)buf;
if( header->lumps[LUMP_ENTITIES].fileofs <= 1024 )
{
// Blue-Shift ordering
lumpofs = header->lumps[LUMP_PLANES].fileofs;
lumplen = header->lumps[LUMP_PLANES].filelen;
}
@ -548,6 +584,13 @@ char *SV_ReadEntityScript( const char *filename, int *flags )
return ents;
}
/*
==============
SV_MapIsValid
Validate map
==============
*/
int SV_MapIsValid( const char *filename, const char *spawn_entity, const char *landmark_name )
{
char *ents = NULL;
@ -566,7 +609,7 @@ int SV_MapIsValid( const char *filename, const char *spawn_entity, const char *l
if( !need_landmark && host.developer >= 2 )
{
// not transition,
// not transition
Mem_Free( ents );
// skip spawnpoint checks in devmode
@ -617,6 +660,12 @@ void SV_InitEdict( edict_t *pEdict )
Q_memset( &pEdict->v, 0, sizeof( entvars_t ));
// g-cont. trying to setup controllers here...
pEdict->v.controller[0] = 0x7F;
pEdict->v.controller[1] = 0x7F;
pEdict->v.controller[2] = 0x7F;
pEdict->v.controller[3] = 0x7F;
pEdict->v.pContainingEntity = pEdict; // make cross-links for consistency
pEdict->pvPrivateData = NULL; // will be alloced later by pfnAllocPrivateData
pEdict->free = false;
@ -651,11 +700,12 @@ void SV_FreeEdict( edict_t *pEdict )
pEdict->pvPrivateData = NULL;
}
// Q_memset( &pEdict->v, 0, sizeof( entvars_t ));
// NOTE: don't clear all edict fields on releasing
// because gamedll may trying to use edict pointers and crash game (e.g. Opposing Force)
// mark edict as freed
pEdict->freetime = sv.time;
pEdict->serialnumber++; // now EHANDLE is invalidate
pEdict->serialnumber++; // invalidate EHANDLE's
pEdict->v.solid = SOLID_NOT;
pEdict->v.flags = 0;
pEdict->v.model = 0;
@ -701,7 +751,7 @@ edict_t* SV_AllocPrivateData( edict_t *ent, string_t className )
if( !ent )
{
// allocate new one
// allocate a new one
ent = SV_AllocEdict();
}
else if( ent->free )
@ -717,7 +767,7 @@ edict_t* SV_AllocPrivateData( edict_t *ent, string_t className )
SpawnEdict = (LINK_ENTITY_FUNC)Com_GetProcAddress( svgame.hInstance, pszClassName );
if( !SpawnEdict )
{
// attempt to create custom entity
// attempt to create custom entity (Xash3D extension)
if( svgame.dllFuncs2.pfnCreate && svgame.dllFuncs2.pfnCreate( ent, pszClassName ) != -1 )
return ent;
@ -754,7 +804,7 @@ void SV_PlaybackEvent( sizebuf_t *msg, event_info_t *info )
BF_WriteWord( msg, info->index ); // send event index
BF_WriteWord( msg, (int)( info->fire_time * 100.0f )); // send event delay
MSG_WriteDeltaEvent( msg, &nullargs, &info->args ); // TODO: delta-compressing
MSG_WriteDeltaEvent( msg, &nullargs, &info->args ); // FIXME: use delta-compressing
}
const char *SV_ClassName( const edict_t *e )
@ -838,6 +888,7 @@ void SV_BaselineForEntity( edict_t *pEdict )
// take current state as baseline
Q_memset( &baseline, 0, sizeof( baseline ));
baseline.number = NUM_FOR_EDICT( pEdict );
svgame.dllFuncs.pfnCreateBaseline( player, baseline.number, &baseline, pEdict, modelindex, mins, maxs );
// set entity type
@ -927,7 +978,7 @@ int pfnModelIndex( const char *m )
for( i = 1; i < MAX_MODELS && sv.model_precache[i][0]; i++ )
{
if( !Q_strcmp( sv.model_precache[i], m ))
if( !Q_stricmp( sv.model_precache[i], m ))
return i;
}
MsgDev( D_ERROR, "SV_ModelIndex: %s not precached\n", m );
@ -964,10 +1015,6 @@ void pfnSetSize( edict_t *e, const float *rgflMin, const float *rgflMax )
return;
}
// ignore world silently
if( e == EDICT_NUM( 0 ))
return;
SV_SetMinMaxSize( e, rgflMin, rgflMax );
}
@ -990,7 +1037,7 @@ void pfnChangeLevel( const char* s1, const char* s2 )
last_spawncount = svs.spawncount;
// make sure we don't issue two changelevels
// make sure we don't issue two changelevels at one time
if( svs.changelevel_next_time > host.realtime )
return;
@ -1034,7 +1081,7 @@ pfnVecToYaw
*/
float pfnVecToYaw( const float *rgflVector )
{
if( !rgflVector ) return 0;
if( !rgflVector ) return 0.0f;
return SV_VecToYaw( rgflVector );
}
@ -1170,7 +1217,7 @@ pfnFindEntityInSphere
return NULL instead of world
=================
*/
edict_t* pfnFindEntityInSphere( edict_t *pStartEdict, const float *org, float flRadius )
edict_t *pfnFindEntityInSphere( edict_t *pStartEdict, const float *org, float flRadius )
{
edict_t *ent;
float distSquared;
@ -1209,7 +1256,6 @@ edict_t* pfnFindEntityInSphere( edict_t *pStartEdict, const float *org, float fl
=================
pfnFindClientInPVS
return NULL instead of world
=================
*/
edict_t* pfnFindClientInPVS( edict_t *pEdict )
@ -1239,40 +1285,6 @@ edict_t* pfnFindClientInPVS( edict_t *pEdict )
return svgame.edicts;
}
/*
=================
pfnFindClientInPHS
return NULL instead of world
=================
*/
edict_t* pfnFindClientInPHS( edict_t *pEdict )
{
edict_t *pClient;
sv_client_t *cl;
const float *org;
int i;
if( !SV_IsValidEdict( pEdict ))
return svgame.edicts;
for( i = 0; i < svgame.globals->maxClients; i++ )
{
pClient = EDICT_NUM( i + 1 );
if(( cl = SV_ClientFromEdict( pClient, true )) == NULL )
continue;
// check for SET_VIEW
if( SV_IsValidEdict( cl->pViewEntity ))
org = cl->pViewEntity->v.origin;
else org = pClient->v.origin;
if( SV_OriginIn( DVIS_PHS, pEdict->v.origin, org ))
return pClient;
}
return svgame.edicts;
}
/*
=================
pfnEntitiesInPVS
@ -1299,7 +1311,7 @@ edict_t *pfnEntitiesInPVS( edict_t *pplayer )
if( pEdict->v.movetype == MOVETYPE_FOLLOW && SV_IsValidEdict( pEdict->v.aiment ))
{
// HACKHACK to transfer weapons across the levels
// HACKHACK to transfer weapons across the levels (Retribution issues)
if( pEdict->v.aiment == EDICT_NUM( 1 ))
{
pEdict->v.chain = chain;
@ -1323,6 +1335,9 @@ edict_t *pfnEntitiesInPVS( edict_t *pplayer )
return chain;
}
// disable this when QNAN error in MakeVectors will be sucessfully reached
#define TEMPORARY_FIX_QNAN_ERROR
/*
==============
pfnMakeVectors
@ -1331,29 +1346,23 @@ pfnMakeVectors
*/
void pfnMakeVectors( const float *rgflVector )
{
int i;
vec3_t inVec;
#ifdef TEMPORARY_FIX_QNAN_ERROR
char charVec[128];
vec3_t outVec;
ASSERT( rgflVector != NULL );
VectorCopy( rgflVector, inVec );
for( i = 0; i < 3; i++ )
{
if( IS_NAN( rgflVector[i] ))
{
MsgDev( D_INFO, "SV_MakeVectors: got a NaN angle\n" );
inVec[i] = 0.0f;
}
}
AngleVectors( inVec, svgame.globals->v_forward, svgame.globals->v_right, svgame.globals->v_up );
Q_snprintf( charVec, sizeof( charVec ) - 1, "%f %f %f", rgflVector[0], rgflVector[1], rgflVector[2] );
Q_atov( outVec, charVec, 3 );
AngleVectors( outVec, svgame.globals->v_forward, svgame.globals->v_right, svgame.globals->v_up );
#else
AngleVectors( rgflVector, svgame.globals->v_forward, svgame.globals->v_right, svgame.globals->v_up );
#endif
}
/*
==============
pfnCreateEntity
just allocate new one
just allocate a new one
==============
*/
edict_t* pfnCreateEntity( void )
@ -1401,7 +1410,7 @@ edict_t* pfnCreateNamedEntity( string_t className )
=============
pfnMakeStatic
disable entity updates to client
move entity to client (Q1 legacy)
=============
*/
static void pfnMakeStatic( edict_t *ent )
@ -1625,9 +1634,16 @@ int SV_BuildSoundMsg( edict_t *ent, int chan, const char *samp, int vol, float a
if( attn != ATTN_NONE ) flags |= SND_ATTENUATION;
if( pitch != PITCH_NORM ) flags |= SND_PITCH;
if( sound_idx > 255 ) flags |= SND_LARGE_INDEX;
// not sending (because this is out of range)
flags &= ~SND_SPAWNING;
BF_WriteByte( &sv.multicast, svc_sound );
BF_WriteWord( &sv.multicast, flags );
BF_WriteWord( &sv.multicast, sound_idx );
if( flags & SND_LARGE_INDEX )
BF_WriteWord( &sv.multicast, sound_idx );
else BF_WriteByte( &sv.multicast, sound_idx );
BF_WriteByte( &sv.multicast, chan );
if( flags & SND_VOLUME ) BF_WriteByte( &sv.multicast, vol );
@ -1635,7 +1651,7 @@ int SV_BuildSoundMsg( edict_t *ent, int chan, const char *samp, int vol, float a
if( flags & SND_PITCH ) BF_WriteByte( &sv.multicast, pitch );
BF_WriteWord( &sv.multicast, entityIndex );
if( flags & SND_FIXED_ORIGIN ) BF_WriteBitVec3Coord( &sv.multicast, pos );
BF_WriteBitVec3Coord( &sv.multicast, pos );
return 1;
}
@ -1675,9 +1691,6 @@ void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float
if( attn != ATTN_NONE ) flags |= SND_ATTENUATION;
if( pitch != PITCH_NORM ) flags |= SND_PITCH;
// send origin for first spatialize
flags |= SND_FIXED_ORIGIN;
// ultimate method for detect bsp models with invalid solidity (e.g. func_pushable)
if( Mod_GetType( ent->v.modelindex ) == mod_brush )
{
@ -1686,7 +1699,6 @@ void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float
if( flags & SND_SPAWNING )
{
msg_dest = MSG_INIT;
flags |= SND_FIXED_ORIGIN; // first-time spatialize
}
else
{
@ -1703,7 +1715,6 @@ void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float
if( flags & SND_SPAWNING )
{
msg_dest = MSG_INIT;
flags |= SND_FIXED_ORIGIN; // first-time spatialize
}
else msg_dest = MSG_PAS_R;
}
@ -1716,6 +1727,11 @@ void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float
flags |= SND_SENTENCE;
sound_idx = Q_atoi( sample + 1 );
}
else if( sample[0] == '#' && Q_isdigit( sample + 1 ))
{
flags |= SND_SENTENCE;
sound_idx = Q_atoi( sample + 1 ) + 1536;
}
else
{
// precache_sound can be used twice: cache sounds when loading
@ -1727,9 +1743,16 @@ void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float
entityIndex = NUM_FOR_EDICT( ent->v.aiment );
else entityIndex = NUM_FOR_EDICT( ent );
if( sound_idx > 255 ) flags |= SND_LARGE_INDEX;
// not sending (because this is out of range)
flags &= ~SND_SPAWNING;
BF_WriteByte( &sv.multicast, svc_sound );
BF_WriteWord( &sv.multicast, flags );
BF_WriteWord( &sv.multicast, sound_idx );
if( flags & SND_LARGE_INDEX )
BF_WriteWord( &sv.multicast, sound_idx );
else BF_WriteByte( &sv.multicast, sound_idx );
BF_WriteByte( &sv.multicast, chan );
if( flags & SND_VOLUME ) BF_WriteByte( &sv.multicast, vol * 255 );
@ -1737,7 +1760,7 @@ void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float
if( flags & SND_PITCH ) BF_WriteByte( &sv.multicast, pitch );
BF_WriteWord( &sv.multicast, entityIndex );
if( flags & SND_FIXED_ORIGIN ) BF_WriteBitVec3Coord( &sv.multicast, origin );
BF_WriteBitVec3Coord( &sv.multicast, origin );
SV_Send( msg_dest, origin, NULL );
}
@ -1796,13 +1819,17 @@ void pfnEmitAmbientSound( edict_t *ent, float *pos, const char *sample, float vo
// always sending stop sound command
if( flags & SND_STOP ) msg_dest = MSG_ALL;
flags |= SND_FIXED_ORIGIN;
if( sample[0] == '!' && Q_isdigit( sample + 1 ))
{
flags |= SND_SENTENCE;
sound_idx = Q_atoi( sample + 1 );
}
else if( sample[0] == '#' && Q_isdigit( sample + 1 ))
{
flags |= SND_SENTENCE;
sound_idx = Q_atoi( sample + 1 ) + 1536;
}
else
{
// precache_sound can be used twice: cache sounds when loading
@ -1810,9 +1837,16 @@ void pfnEmitAmbientSound( edict_t *ent, float *pos, const char *sample, float vo
sound_idx = SV_SoundIndex( sample );
}
if( sound_idx > 255 ) flags |= SND_LARGE_INDEX;
// not sending (because this is out of range)
flags &= ~SND_SPAWNING;
BF_WriteByte( &sv.multicast, svc_ambientsound );
BF_WriteWord( &sv.multicast, flags );
BF_WriteWord( &sv.multicast, sound_idx );
if( flags & SND_LARGE_INDEX )
BF_WriteWord( &sv.multicast, sound_idx );
else BF_WriteByte( &sv.multicast, sound_idx );
BF_WriteByte( &sv.multicast, CHAN_STATIC );
if( flags & SND_VOLUME ) BF_WriteByte( &sv.multicast, vol * 255 );
@ -1981,6 +2015,7 @@ void pfnTraceSphere( const float *v1, const float *v2, int fNoMonsters, float ra
=============
pfnBoxVisible
unused but working
=============
*/
static int pfnBoxVisible( const float *mins, const float *maxs, const byte *pset )
@ -1997,49 +2032,40 @@ NOTE: speed is unused
*/
void pfnGetAimVector( edict_t* ent, float speed, float *rgflReturn )
{
edict_t *check, *bestent;
edict_t *check;
vec3_t start, dir, end, bestdir;
float dist, bestdist;
qboolean fNoFriendlyFire;
int i, j;
trace_t tr;
// these vairable defined in game.dll
fNoFriendlyFire = Cvar_VariableValue( "mp_friendlyfire" );
Msg( "GetAimVector for %s\n", SV_ClassName( ent ));
VectorCopy( svgame.globals->v_forward, rgflReturn ); // assume failure if it returns early
if( !SV_IsValidEdict( ent ))
{
MsgDev( D_WARN, "SV_GetAimVector: invalid entity %s\n", SV_ClassName( ent ));
if( !SV_IsValidEdict( ent ) || (ent->v.flags & FL_FAKECLIENT))
return;
}
VectorCopy( ent->v.origin, start );
start[2] += 20;
VectorAdd( start, ent->v.view_ofs, start );
// try sending a trace straight
VectorCopy( svgame.globals->v_forward, dir );
VectorMA( start, 2048, dir, end );
tr = SV_Move( start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent );
if( tr.ent && (tr.ent->v.takedamage == DAMAGE_AIM && fNoFriendlyFire || ent->v.team <= 0 || ent->v.team != tr.ent->v.team ))
{
VectorCopy( svgame.globals->v_forward, rgflReturn );
if( tr.ent && (tr.ent->v.takedamage == DAMAGE_AIM || ent->v.team <= 0 || ent->v.team != tr.ent->v.team ))
return;
}
// try all possible entities
VectorCopy( dir, bestdir );
bestdist = 0.5f;
bestent = NULL;
bestdist = Cvar_VariableValue( "sv_aim" );
check = EDICT_NUM( 1 ); // start at first client
for( i = 1; i < svgame.numEntities; i++, check++ )
{
if( check->v.takedamage != DAMAGE_AIM ) continue;
if( check->v.flags & FL_FAKECLIENT ) continue;
if( ent->v.team > 0 && ent->v.team == check->v.team ) continue;
if( check == ent ) continue;
if( fNoFriendlyFire && ent->v.team > 0 && ent->v.team == check->v.team )
continue; // don't aim at teammate
for( j = 0; j < 3; j++ )
end[j] = check->v.origin[j] + 0.5f * (check->v.mins[j] + check->v.maxs[j]);
VectorSubtract( end, start, dir );
@ -2049,22 +2075,12 @@ void pfnGetAimVector( edict_t* ent, float speed, float *rgflReturn )
tr = SV_Move( start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent );
if( tr.ent == check )
{
// can shoot at this one
bestdist = dist;
bestent = check;
VectorCopy( dir, bestdir );
}
}
if( bestent )
{
VectorSubtract( bestent->v.origin, ent->v.origin, dir );
dist = DotProduct( dir, svgame.globals->v_forward );
VectorScale( svgame.globals->v_forward, dist, end );
end[2] = dir[2];
VectorNormalize( end );
VectorCopy( end, rgflReturn );
}
else VectorCopy( bestdir, rgflReturn );
VectorCopy( bestdir, rgflReturn );
}
/*
@ -2197,7 +2213,7 @@ int pfnDecalIndex( const char *m )
return i;
}
// throw warning
// throw warning (this can happens if decal not present in decals.wad)
MsgDev( D_WARN, "Can't find decal %s\n", m );
return 0;
@ -2378,7 +2394,7 @@ pfnWriteByte
void pfnWriteByte( int iValue )
{
if( iValue == -1 ) iValue = 0xFF; // convert char to byte
BF_WriteByte( &sv.multicast, iValue );
BF_WriteByte( &sv.multicast, (byte)iValue );
svgame.msg_realsize++;
}
@ -2390,7 +2406,7 @@ pfnWriteChar
*/
void pfnWriteChar( int iValue )
{
BF_WriteChar( &sv.multicast, iValue );
BF_WriteChar( &sv.multicast, (char)iValue );
svgame.msg_realsize++;
}
@ -2509,7 +2525,7 @@ void pfnWriteEntity( int iValue )
{
if( iValue < 0 || iValue >= svgame.numEntities )
Host_Error( "BF_WriteEntity: invalid entnumber %i\n", iValue );
BF_WriteShort( &sv.multicast, iValue );
BF_WriteShort( &sv.multicast, (short)iValue );
svgame.msg_realsize += 2;
}
@ -2558,10 +2574,6 @@ static void pfnAlertMessage( ALERT_TYPE level, char *szFmt, ... )
{
Sys_Print( buffer );
}
else if( level == at_aiconsole && host.developer >= D_AICONSOLE )
{
Sys_Print( buffer );
}
else if( level == at_warning && host.developer >= D_WARN )
{
Sys_Print( va( "^3Warning:^7 %s", buffer ));
@ -2570,6 +2582,10 @@ static void pfnAlertMessage( ALERT_TYPE level, char *szFmt, ... )
{
Sys_Print( va( "^1Error:^7 %s", buffer ));
}
else if( level == at_aiconsole && host.developer >= D_AICONSOLE )
{
Sys_Print( buffer );
}
}
/*
@ -2581,7 +2597,7 @@ legacy. probably was a part of early save\restore system
*/
static void pfnEngineFprintf( FILE *pfile, char *szFmt, ... )
{
char buffer[2048]; // must support > 1k messages
char buffer[2048];
va_list args;
va_start( args, szFmt );
@ -2595,6 +2611,7 @@ static void pfnEngineFprintf( FILE *pfile, char *szFmt, ... )
=============
pfnBuildSoundMsg
Customizable sound message
=============
*/
void pfnBuildSoundMsg( edict_t *pSource, int chan, const char *samp, float fvol, float attn, int fFlags, int pitch, int msg_dest, int msg_type, const float *pOrigin, edict_t *pSend )
@ -2615,8 +2632,10 @@ void *pfnPvAllocEntPrivateData( edict_t *pEdict, long cb )
ASSERT( pEdict );
ASSERT( pEdict->free == false );
// to avoid multiple alloc
pEdict->pvPrivateData = (void *)Mem_Realloc( svgame.mempool, pEdict->pvPrivateData, cb );
if( Mem_IsAllocated( pEdict->pvPrivateData ))
Mem_Free( pEdict->pvPrivateData );
pEdict->pvPrivateData = Mem_Alloc( svgame.mempool, cb );
return pEdict->pvPrivateData;
}
@ -2625,6 +2644,7 @@ void *pfnPvAllocEntPrivateData( edict_t *pEdict, long cb )
=============
pfnPvEntPrivateData
we already have copy of this function in 'enginecallback.h' :-)
=============
*/
void *pfnPvEntPrivateData( edict_t *pEdict )
@ -2652,6 +2672,7 @@ void pfnFreeEntPrivateData( edict_t *pEdict )
=============
SV_AllocString
allocate new engine string
=============
*/
string_t SV_AllocString( const char *szValue )
@ -2973,39 +2994,6 @@ static void pfnGetAttachment( const edict_t *pEdict, int iAttachment, float *rgf
SV_StudioGetAttachment(( edict_t *)pEdict, iAttachment, rgflOrigin, rgflAngles );
}
/*
=============
pfnCRC32_Init
=============
*/
void pfnCRC32_Init( dword *pulCRC )
{
CRC32_Init( pulCRC );
}
/*
=============
pfnCRC32_ProcessBuffer
=============
*/
void pfnCRC32_ProcessBuffer( dword *pulCRC, void *p, int len )
{
CRC32_ProcessBuffer( pulCRC, p, len );
}
/*
=============
pfnCRC32_ProcessByte
=============
*/
void pfnCRC32_ProcessByte( dword *pulCRC, byte ch )
{
CRC32_ProcessByte( pulCRC, ch );
}
/*
=============
pfnCRC32_Final
@ -3081,7 +3069,7 @@ void pfnSetView( const edict_t *pClient, const edict_t *pViewent )
if( pClient == pViewent ) client->pViewEntity = NULL;
else client->pViewEntity = (edict_t *)pViewent;
// fakeclients ignore to send client message
// fakeclients ignore to send client message (but can see into the trigger_camera through the PVS)
if( client->fakeclient ) return;
BF_WriteByte( &client->netchan.message, svc_setview );
@ -3175,9 +3163,7 @@ uint pfnGetPlayerWONId( edict_t *e )
for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
{
if( cl->edict == e && cl->authentication_method == 0 )
{
return cl->WonID;
}
}
return -1;
}
@ -3605,6 +3591,12 @@ void SV_PlaybackEventFull( int flags, const edict_t *pInvoker, word eventindex,
if( flags & FEV_HOSTONLY && cl->edict != pInvoker )
continue; // sending only to invoker
if( SV_IsValidEdict( pInvoker ) && pInvoker->v.groupinfo && cl->edict->v.groupinfo )
{
if(( !svs.groupop && !(cl->edict->v.groupinfo & pInvoker->v.groupinfo)) || ( svs.groupop == 1 && ( cl->edict->v.groupinfo & pInvoker->v.groupinfo )))
continue;
}
if(!( flags & FEV_GLOBAL ))
{
// -1 is because pvs rows are 1 based, not 0 based like leafs
@ -3761,7 +3753,7 @@ int pfnCheckVisibility( const edict_t *ent, byte *pset )
{
if( !Mod_BoxVisible( ent->v.absmin, ent->v.absmax, pset ))
return 0;
result = 3; // visible passed by BoxVisible
result = 3; // visible passed by BoxVisible
}
#endif
return result;
@ -3778,11 +3770,7 @@ int pfnCanSkipPlayer( const edict_t *player )
sv_client_t *cl;
cl = SV_ClientFromEdict( player, false );
if( cl == NULL )
{
MsgDev( D_ERROR, "SV_CanSkip: client is not connected!\n" );
return false;
}
if( !cl ) return false;
return cl->local_weapons;
}
@ -3867,9 +3855,7 @@ int pfnGetPlayerUserId( edict_t *e )
for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
{
if( cl->edict == e )
{
return cl->userid;
}
}
// couldn't find it
@ -3878,50 +3864,7 @@ int pfnGetPlayerUserId( edict_t *e )
/*
=============
pfnSoundTrack
empty trackname - stop previous
=============
*/
void pfnSoundTrack( const char *trackname, int flags )
{
sizebuf_t *msg;
if( !trackname ) return;
if( sv.state == ss_loading )
msg = &sv.signon;
else msg = &sv.reliable_datagram;
// tell the client about new user message
BF_WriteByte( &sv.reliable_datagram, svc_cdtrack );
BF_WriteString( &sv.reliable_datagram, trackname );
}
/*
=============
pfnDropClient
=============
*/
void pfnDropClient( int clientIndex )
{
if( clientIndex < 0 || clientIndex >= svgame.globals->maxClients )
{
MsgDev( D_ERROR, "SV_DropClient: not a client\n" );
return;
}
if( svs.clients[clientIndex].state != cs_spawned )
{
MsgDev( D_ERROR, "SV_DropClient: that client slot is not connected\n" );
return;
}
SV_DropClient( svs.clients + clientIndex );
}
/*
=============
pfnGetPlayerPing
pfnGetPlayerStats
=============
*/
@ -3952,9 +3895,7 @@ void pfnForceUnmodified( FORCE_TYPE type, float *mins, float *maxs, const char *
int i;
if( !filename || !*filename )
{
Host_Error( "SV_ForceUnmodified: bad filename string.\n" );
}
if( sv.state == ss_loading )
{
@ -3970,37 +3911,23 @@ void pfnForceUnmodified( FORCE_TYPE type, float *mins, float *maxs, const char *
return;
}
else if( !Q_strcmp( filename, pData->name ))
{
return;
}
}
Host_Error( "SV_ForceUnmodified: MAX_MODELS limit exceeded\n" );
}
else
{
for( i = 0, pData = sv.consistency_files; i < MAX_MODELS; i++, pData++ )
{
if( !pData->name || Q_strcmp( filename, pData->name ))
continue;
// if we are here' we found a match.
return;
if( pData->name && !Q_strcmp( filename, pData->name ))
return;
}
Host_Error( "SV_ForceUnmodified: can only be done during precache\n" );
}
}
/*
=============
pfnAddServerCommand
=============
*/
void pfnAddServerCommand( const char *cmd_name, void (*function)(void) )
{
Cmd_AddGameCommand( cmd_name, function );
}
/*
=============
pfnVoice_GetClientListening
@ -4185,9 +4112,9 @@ static enginefuncs_t gEngfuncs =
pfnCmd_Argv,
pfnCmd_Argc,
pfnGetAttachment,
pfnCRC32_Init,
pfnCRC32_ProcessBuffer,
pfnCRC32_ProcessByte,
CRC32_Init,
CRC32_ProcessBuffer,
CRC32_ProcessByte,
pfnCRC32_Final,
Com_RandomLong,
Com_RandomFloat,
@ -4195,7 +4122,7 @@ static enginefuncs_t gEngfuncs =
pfnTime,
pfnCrosshairAngle,
pfnLoadFile,
pfnFreeFile,
COM_FreeFile,
pfnEndSection,
pfnCompareFileTime,
pfnGetGameDir,
@ -4239,7 +4166,7 @@ static enginefuncs_t gEngfuncs =
pfnCvar_DirectSet,
pfnForceUnmodified,
pfnGetPlayerStats,
pfnAddServerCommand,
Cmd_AddGameCommand,
pfnVoice_GetClientListening,
pfnVoice_SetClientListening,
pfnGetPlayerAuthId,
@ -4282,7 +4209,7 @@ qboolean SV_ParseEdict( char **pfile, edict_t *ent )
// ignore attempts to set key ""
if( !keyname[0] ) continue;
// "wad" field is completely ignored
// "wad" field is completely ignored in Xash3D
if( !Q_strcmp( keyname, "wad" ))
continue;
@ -4305,7 +4232,7 @@ qboolean SV_ParseEdict( char **pfile, edict_t *ent )
if( ++numpairs >= 256 ) break;
}
ent = SV_AllocPrivateData( ent, MAKE_STRING( classname ));
ent = SV_AllocPrivateData( ent, ALLOC_STRING( classname ));
if( ent->v.flags & FL_KILLME )
{
@ -4467,7 +4394,7 @@ void SV_SpawnEntities( const char *mapname, char *entities )
ent = EDICT_NUM( 0 );
if( ent->free ) SV_InitEdict( ent );
ent->v.model = MAKE_STRING( sv.model_precache[1] );
ent->v.modelindex = 1; // world model
ent->v.modelindex = 1; // world model
ent->v.solid = SOLID_BSP;
ent->v.movetype = MOVETYPE_PUSH;
@ -4479,8 +4406,10 @@ void SV_SpawnEntities( const char *mapname, char *entities )
// spawn the rest of the entities on the map
SV_LoadFromFile( entities );
// free memory that allocated by entpatch only
if( !Mem_IsAllocatedExt( sv.worldmodel->mempool, entities ))
Mem_Free( entities ); // only free memory that allocated by entpatch
Mem_Free( entities );
MsgDev( D_NOTE, "Total %i entities spawned\n", svgame.numEntities );
}
@ -4602,6 +4531,9 @@ qboolean SV_LoadProgs( const char *name )
return false;
}
// grab function SV_SaveGameComment
SV_InitSaveRestore ();
svgame.globals->pStringBase = ""; // setup string base
svgame.force_retouch = 0.0f;
@ -4619,7 +4551,7 @@ qboolean SV_LoadProgs( const char *name )
svgame.stringspool = Mem_AllocPool( "Server Strings" );
// fire once
MsgDev( D_INFO, "Dll loaded for mod %s\n", svgame.dllFuncs.pfnGetGameDescription() );
MsgDev( D_INFO, "Dll loaded for mod %s\n", svgame.dllFuncs.pfnGetGameDescription( ));
// all done, initialize game
svgame.dllFuncs.pfnGameInit();

View File

@ -12,13 +12,24 @@ server_static_t svs; // persistant server info
svgame_static_t svgame; // persistant game info
server_t sv; // local server
int SV_ModelIndex( const char *name )
int SV_ModelIndex( const char *filename )
{
int i;
char name[64];
int i, j;
if( !name || !name[0] )
if( !filename || !filename[0] )
return 0;
// eliminate '!' symbol (i'm doesn't know what this doing)
for( i = j = 0; i < Q_strlen( filename ); i++ )
{
if( filename[i] == '!' ) continue;
else if( filename[i] == '\\' ) name[j] = '/';
else name[j] = filename[i];
j++;
}
name[j] = '\0';
for( i = 1; i < MAX_MODELS && sv.model_precache[i][0]; i++ )
{
if( !Q_stricmp( sv.model_precache[i], name ))
@ -45,13 +56,23 @@ int SV_ModelIndex( const char *name )
return i;
}
int SV_SoundIndex( const char *name )
int SV_SoundIndex( const char *filename )
{
int i;
char name[64];
int i, j;
if( !name || !name[0] )
// don't precache sentence names
if( !filename || !filename[0] || filename[0] == '!' )
return 0;
for( i = j = 0; i < Q_strlen( filename ); i++ )
{
if( filename[i] == '\\' ) name[j] = '/';
else name[j] = filename[i];
j++;
}
name[j] = '\0';
for( i = 1; i < MAX_SOUNDS && sv.sound_precache[i][0]; i++ )
{
if( !Q_stricmp( sv.sound_precache[i], name ))
@ -78,13 +99,24 @@ int SV_SoundIndex( const char *name )
return i;
}
int SV_EventIndex( const char *name )
int SV_EventIndex( const char *filename )
{
int i;
char name[64];
int i, j;
if( !name || !name[0] )
if( !filename || !filename[0] )
return 0;
// eliminate '!' symbol (i'm doesn't know what this doing)
for( i = j = 0; i < Q_strlen( filename ); i++ )
{
if( filename[i] == '!' ) continue;
else if( filename[i] == '\\' ) name[j] = '/';
else name[j] = filename[i];
j++;
}
name[j] = '\0';
for( i = 1; i < MAX_EVENTS && sv.event_precache[i][0]; i++ )
{
if( !Q_stricmp( sv.event_precache[i], name ))
@ -111,13 +143,24 @@ int SV_EventIndex( const char *name )
return i;
}
int SV_GenericIndex( const char *name )
int SV_GenericIndex( const char *filename )
{
int i;
char name[64];
int i, j;
if( !name || !name[0] )
if( !filename || !filename[0] )
return 0;
// eliminate '!' symbol (i'm doesn't know what this doing)
for( i = j = 0; i < Q_strlen( filename ); i++ )
{
if( filename[i] == '!' ) continue;
else if( filename[i] == '\\' ) name[j] = '/';
else name[j] = filename[i];
j++;
}
name[j] = '\0';
for( i = 1; i < MAX_CUSTOM && sv.files_precache[i][0]; i++ )
{
if( !Q_stricmp( sv.files_precache[i], name ))
@ -221,7 +264,7 @@ void SV_FreeOldEntities( void )
}
// decrement svgame.numEntities if the highest number entities died
for( ; EDICT_NUM( svgame.numEntities - 1)->free; svgame.numEntities-- );
for( ; EDICT_NUM( svgame.numEntities - 1 )->free; svgame.numEntities-- );
}
/*
@ -256,7 +299,7 @@ void SV_ActivateServer( void )
// create a baseline for more efficient communications
SV_CreateBaseline();
// Send serverinfo to all connected clients
// send serverinfo to all connected clients
for( i = 0; i < sv_maxclients->integer; i++ )
{
if( svs.clients[i].state >= cs_connected )
@ -300,7 +343,9 @@ void SV_ActivateServer( void )
}
if( host.type == HOST_DEDICATED )
{
Mod_FreeUnused ();
}
sv.state = ss_active;
physinfo->modified = true;
@ -334,12 +379,15 @@ void SV_DeactivateServer( void )
for( i = 0; i < svgame.globals->maxClients; i++ )
{
// release client frames
SV_ClearFrames( &svs.clients[i].frames );
if( svs.clients[i].frames )
Mem_Free( svs.clients[i].frames );
svs.clients[i].frames = NULL;
}
svgame.globals->maxEntities = GI->max_edicts;
svgame.globals->maxClients = sv_maxclients->integer;
svgame.numEntities = svgame.globals->maxClients + 1; // clients + world
svgame.globals->startspot = 0;
svgame.globals->mapname = 0;
}
@ -394,7 +442,6 @@ 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 )
@ -416,7 +463,7 @@ qboolean SV_SpawnServer( const char *mapname, const char *startspot )
if( !svs.initialized )
return false;
svgame.globals->changelevel = false; // will be restored later if needed
svgame.globals->changelevel = false; // will be restored later if needed
svs.timestart = Sys_DoubleTime();
svs.spawncount++; // any partially connected client will be restarted
@ -445,6 +492,7 @@ qboolean SV_SpawnServer( const char *mapname, const char *startspot )
BF_Init( &sv.reliable_datagram, "Datagram R", sv.reliable_datagram_buf, sizeof( sv.reliable_datagram_buf ));
BF_Init( &sv.multicast, "Multicast", sv.multicast_buf, sizeof( sv.multicast_buf ));
BF_Init( &sv.signon, "Signon", sv.signon_buf, sizeof( sv.signon_buf ));
BF_Init( &sv.spectator_datagram, "Spectator Datagram", sv.spectator_buf, sizeof( sv.spectator_buf ));
// leave slots at start for clients only
for( i = 0; i < sv_maxclients->integer; i++ )
@ -586,7 +634,7 @@ void SV_InitGame( void )
// heartbeats will always be sent to the id master
svs.last_heartbeat = MAX_HEARTBEAT; // send immediately
Q_sprintf( idmaster, "192.246.40.37:%i", PORT_MASTER );
Q_sprintf( idmaster, "192.246.40.37:%i", PORT_MASTER ); // TODO: parse woncomm.lst
NET_StringToAdr( idmaster, &master_adr[0] );
// set client fields on player ents
@ -626,7 +674,7 @@ void SV_FreeGameProgs( void )
{
if( svs.initialized ) return; // server is active
// unload progs (and free cvars and commands)
// unload progs (free cvars and commands)
SV_UnloadProgs();
}
@ -635,7 +683,7 @@ qboolean SV_NewGame( const char *mapName, qboolean loadGame )
if( !loadGame )
{
if( !SV_MapIsValid( mapName, GI->sp_entity, NULL ))
return false;
return false;
}
S_StopAllSounds ();

View File

@ -7,7 +7,7 @@
#include "server.h"
#include "net_encode.h"
#define HEARTBEAT_SECONDS 300.0 // 300 seconds
#define HEARTBEAT_SECONDS 300.0f // 300 seconds
netadr_t master_adr[MAX_MASTERS]; // address of group servers
@ -23,7 +23,6 @@ convar_t *sv_wateramp;
convar_t *timeout; // seconds without any message
convar_t *zombietime; // seconds to sink messages after disconnect
convar_t *rcon_password; // password for remote server commands
convar_t *allow_download;
convar_t *sv_airaccelerate;
convar_t *sv_wateraccelerate;
convar_t *sv_maxvelocity;
@ -45,13 +44,15 @@ convar_t *sv_lighting_modulate;
convar_t *sv_maxclients;
convar_t *sv_check_errors;
convar_t *sv_footsteps;
convar_t *public_server; // should heartbeats be sent
convar_t *sv_reconnect_limit; // minimum seconds between connect messages
convar_t *public_server; // should heartbeats be sent
convar_t *sv_reconnect_limit; // minimum seconds between connect messages
convar_t *sv_failuretime;
convar_t *sv_allow_upload;
convar_t *sv_allow_download;
convar_t *sv_allow_studio_scaling;
convar_t *sv_allow_studio_attachment_angles;
convar_t *sv_allow_rotate_pushables;
convar_t *sv_clienttrace;
convar_t *sv_send_resources;
convar_t *sv_send_logos;
convar_t *sv_sendvelocity;
@ -252,7 +253,7 @@ void SV_CheckCmdTimes( void )
double timewindow;
int i;
if( 1.0 > host.realtime - lastreset )
if(( host.realtime - lastreset ) < 1.0 )
return;
lastreset = host.realtime;
@ -312,10 +313,15 @@ void SV_ReadPackets( void )
// check for packets from connected clients
for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
{
if( cl->state == cs_free ) continue;
if( cl->fakeclient ) continue;
if( !NET_CompareBaseAdr( net_from, cl->netchan.remote_address )) continue;
if( cl->netchan.qport != qport ) continue;
if( cl->state == cs_free || cl->fakeclient )
continue;
if( !NET_CompareBaseAdr( net_from, cl->netchan.remote_address ))
continue;
if( cl->netchan.qport != qport )
continue;
if( cl->netchan.remote_address.port != net_from.port )
{
MsgDev( D_INFO, "SV_ReadPackets: fixing up a translated port\n");
@ -334,7 +340,7 @@ void SV_ReadPackets( void )
}
}
// Fragmentation/reassembly sending takes priority over all game messages, want this in the future?
// fragmentation/reassembly sending takes priority over all game messages, want this in the future?
if( Netchan_IncomingReady( &cl->netchan ))
{
if( Netchan_CopyNormalFragments( &cl->netchan, &net_message ))
@ -411,7 +417,7 @@ void SV_CheckTimeouts( void )
if( sv.paused && !numclients )
{
// nobody left, unpause the server
SV_TogglePause( "Pause released since no players are left.\n" );
SV_TogglePause( "Pause released since no players are left." );
}
}
@ -448,12 +454,13 @@ SV_IsSimulating
*/
qboolean SV_IsSimulating( void )
{
if( sv.background && CL_Active( ))
if( sv.background && SV_Active() && CL_Active( ))
{
if( CL_IsInConsole( ))
return false;
return true; // force simulating for background map
}
if( sv.hostflags & SVF_PLAYERSONLY )
return false;
if( !SV_HasActivePlayers())
@ -626,7 +633,7 @@ void SV_Init( void )
sv_skyvec_x = Cvar_Get ("sv_skyvec_x", "0", CVAR_PHYSICINFO, "sky direction x (hl1 compatibility)" );
sv_skyvec_y = Cvar_Get ("sv_skyvec_y", "0", CVAR_PHYSICINFO, "sky direction y (hl1 compatibility)" );
sv_skyvec_z = Cvar_Get ("sv_skyvec_z", "0", CVAR_PHYSICINFO, "sky direction z (hl1 compatibility)" );
sv_skyname = Cvar_Get ("sv_skyname", "2desert", CVAR_PHYSICINFO, "skybox name (can be dynamically changed in-game)" );
sv_skyname = Cvar_Get ("sv_skyname", "desert", CVAR_PHYSICINFO, "skybox name (can be dynamically changed in-game)" );
sv_footsteps = Cvar_Get ("mp_footsteps", "1", CVAR_PHYSICINFO, "can hear footsteps from other players" );
rcon_password = Cvar_Get( "rcon_password", "", 0, "remote connect password" );
@ -636,9 +643,10 @@ void SV_Init( void )
timeout = Cvar_Get( "timeout", "125", CVAR_SERVERNOTIFY, "connection timeout" );
zombietime = Cvar_Get( "zombietime", "2", CVAR_SERVERNOTIFY, "timeout for clients-zombie (who died but not respawned)" );
sv_pausable = Cvar_Get( "pausable", "1", CVAR_SERVERNOTIFY, "allow players to pause or not" );
allow_download = Cvar_Get( "allow_download", "0", CVAR_ARCHIVE, "allow download resources" );
sv_allow_studio_scaling = Cvar_Get( "sv_allow_studio_scaling", "0", CVAR_ARCHIVE|CVAR_PHYSICINFO, "allow to apply scale for studio models" );
sv_allow_studio_attachment_angles = Cvar_Get( "sv_allow_studio_attachment_angles", "0", CVAR_ARCHIVE, "enable calc angles for attachment points (on studio models)" );
sv_allow_rotate_pushables = Cvar_Get( "sv_allow_rotate_pushables", "0", CVAR_ARCHIVE, "let the pushers rotate pushables with included origin-brush" );
sv_clienttrace = Cvar_Get( "sv_clienttrace", "0", CVAR_SERVERNOTIFY, "scaling factor for client hitboxes" );
sv_wallbounce = Cvar_Get( "sv_wallbounce", "1.0", CVAR_PHYSICINFO, "bounce factor for client with MOVETYPE_BOUNCE" );
sv_spectatormaxspeed = Cvar_Get( "sv_spectatormaxspeed", "500", CVAR_PHYSICINFO, "spectator maxspeed" );
sv_waterfriction = Cvar_Get( "sv_waterfriction", "1", CVAR_PHYSICINFO, "how fast you slow down in water" );
@ -692,7 +700,7 @@ to totally exit after returning from this function.
void SV_FinalMessage( char *message, qboolean reconnect )
{
sv_client_t *cl;
byte msg_buf[MAX_MSGLEN];
byte msg_buf[1024];
sizebuf_t msg;
int i;

View File

@ -41,6 +41,7 @@ qboolean SV_CheckBottom( edict_t *ent, int iMode )
{
start[0] = x ? maxs[0] : mins[0];
start[1] = y ? maxs[1] : mins[1];
svs.groupmask = ent->v.groupinfo;
if( SV_PointContents( start ) != CONTENTS_SOLID )
goto realcheck;
@ -96,15 +97,12 @@ float SV_VecToYaw( const vec3_t src )
{
float yaw;
if( src[1] == 0 && src[0] == 0 )
{
yaw = 0;
}
else
{
yaw = (int)( atan2( src[1], src[0] ) * 180 / M_PI );
if( yaw < 0 ) yaw += 360;
}
if( src[1] == 0.0f && src[0] == 0.0f )
return 0.0f;
yaw = RAD2DEG( atan2( src[1], src[0] ));
if( yaw < 0 ) yaw += 360;
return yaw;
}
@ -147,21 +145,16 @@ qboolean SV_MoveStep( edict_t *ent, vec3_t move, qboolean relink )
// that move takes us out of the water.
// apparently though, it's okay to travel into solids, lava, sky, etc :)
if(( ent->v.flags & FL_SWIM ) && SV_PointContents( trace.endpos ) == CONTENTS_EMPTY )
{
return 0;
}
VectorCopy( trace.endpos, ent->v.origin );
if( relink ) SV_LinkEdict( ent, true );
if( relink != 0 )
{
SV_LinkEdict( ent, true );
}
return 1;
}
else
{
if( enemy == NULL )
if( !SV_IsValidEdict( enemy ))
break;
}
}
@ -176,7 +169,7 @@ qboolean SV_MoveStep( edict_t *ent, vec3_t move, qboolean relink )
end[2] -= dz * 2.0f;
trace = SV_Move( neworg, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent );
if( trace.allsolid != 0 )
if( trace.allsolid )
return 0;
if( trace.startsolid != 0 )
@ -193,10 +186,7 @@ qboolean SV_MoveStep( edict_t *ent, vec3_t move, qboolean relink )
if( ent->v.flags & FL_PARTIALGROUND )
{
VectorAdd( ent->v.origin, move, ent->v.origin );
if( relink != 0 )
{
SV_LinkEdict( ent, true );
}
if( relink ) SV_LinkEdict( ent, true );
ent->v.flags &= ~FL_ONGROUND;
return 1;
}
@ -210,10 +200,7 @@ qboolean SV_MoveStep( edict_t *ent, vec3_t move, qboolean relink )
{
if( ent->v.flags & FL_PARTIALGROUND )
{
if( relink != 0 )
{
SV_LinkEdict( ent, true );
}
if( relink ) SV_LinkEdict( ent, true );
return 1;
}
@ -222,15 +209,10 @@ qboolean SV_MoveStep( edict_t *ent, vec3_t move, qboolean relink )
}
else
{
if( ent->v.flags & FL_PARTIALGROUND )
ent->v.flags &= ~FL_PARTIALGROUND;
ent->v.flags &= ~FL_PARTIALGROUND;
ent->v.groundentity = trace.ent;
if( relink ) SV_LinkEdict( ent, true );
if( relink != 0 )
{
SV_LinkEdict( ent, true );
}
return 1;
}
}
@ -271,10 +253,7 @@ qboolean SV_MoveTest( edict_t *ent, vec3_t move, qboolean relink )
if( ent->v.flags & FL_PARTIALGROUND )
{
VectorAdd( ent->v.origin, move, ent->v.origin );
if( relink != 0 )
{
SV_LinkEdict( ent, true );
}
if( relink ) SV_LinkEdict( ent, true );
ent->v.flags &= ~FL_ONGROUND;
return 1;
}
@ -288,10 +267,7 @@ qboolean SV_MoveTest( edict_t *ent, vec3_t move, qboolean relink )
{
if( ent->v.flags & FL_PARTIALGROUND )
{
if( relink != 0 )
{
SV_LinkEdict( ent, true );
}
if( relink ) SV_LinkEdict( ent, true );
return 1;
}
@ -300,15 +276,10 @@ qboolean SV_MoveTest( edict_t *ent, vec3_t move, qboolean relink )
}
else
{
if( ent->v.flags & FL_PARTIALGROUND )
ent->v.flags &= ~FL_PARTIALGROUND;
ent->v.flags &= ~FL_PARTIALGROUND;
ent->v.groundentity = trace.ent;
if( relink ) SV_LinkEdict( ent, true );
if( relink != 0 )
{
SV_LinkEdict( ent, true );
}
return 1;
}
}
@ -344,7 +315,6 @@ void SV_NewChaseDir( edict_t *actor, vec3_t destination, float dist )
float tempdir, olddir, turnaround;
vec3_t d;
// so, we're shaving down some of the precision. Ohkay.
olddir = anglemod(((int)( actor->v.ideal_yaw / 45.0f )) * 45.0f );
turnaround = anglemod( olddir - 180 );
@ -410,7 +380,7 @@ void SV_NewChaseDir( edict_t *actor, vec3_t destination, float dist )
}
}
// we tried. Run backwards. THAT ought to work...
// we tried. run backwards. that ought to work...
if( turnaround != -1 && SV_StepDirection( actor, turnaround, dist ))
return;
@ -419,7 +389,6 @@ void SV_NewChaseDir( edict_t *actor, vec3_t destination, float dist )
// if a bridge was pulled out from underneath a monster, it may not have
// a valid standing position at all.
if( !SV_CheckBottom( actor, MOVE_NORMAL ))
{
actor->v.flags |= FL_PARTIALGROUND;

View File

@ -23,7 +23,7 @@ flying/floating monsters are SOLID_BBOX and MOVETYPE_FLY
solid_edge items only clip against bsp models.
*/
#define MOVE_EPSILON 0.01
#define MOVE_EPSILON 0.01f
#define MAX_CLIP_PLANES 5
/*
@ -151,17 +151,23 @@ qboolean SV_RunThink( edict_t *ent )
{
float thinktime;
thinktime = ent->v.nextthink;
if( thinktime <= 0.0f || thinktime > sv.time + host.frametime )
return true;
if(!( ent->v.flags & FL_SPECTATOR ))
{
thinktime = ent->v.nextthink;
if( thinktime <= 0.0f || thinktime > sv.time + host.frametime )
return true;
if( thinktime < sv.time )
thinktime = sv.time; // don't let things stay in the past.
// it is possible to start that way
// by a trigger with a local time.
ent->v.nextthink = 0;
svgame.globals->time = thinktime;
svgame.dllFuncs.pfnThink( ent );
if( thinktime < sv.time )
thinktime = sv.time; // don't let things stay in the past.
// it is possible to start that way
// by a trigger with a local time.
ent->v.nextthink = 0.0f;
svgame.globals->time = thinktime;
svgame.dllFuncs.pfnThink( ent );
}
if( ent->v.flags & FL_SPECTATOR )
SV_FreeEdict( ent );
return !ent->free;
}
@ -177,18 +183,18 @@ void SV_Impact( edict_t *e1, trace_t *trace )
{
edict_t *e2 = trace->ent;
svgame.globals->time = sv.time;
if(( e1->v.flags|e2->v.flags ) & FL_SPECTATOR )
return;
if( e1->v.groupinfo && e2->v.groupinfo )
{
if(( svs.groupop == 0 && ( e1->v.groupinfo & e2->v.groupinfo )) == 0 ||
(svs.groupop == 1 && (e1->v.groupinfo & e2->v.groupinfo) != 0 ))
if(( !svs.groupop && !( e1->v.groupinfo & e2->v.groupinfo )) ||
( svs.groupop == 1 && ( e1->v.groupinfo & e2->v.groupinfo )))
return;
}
svgame.globals->time = sv.time;
if( e1->v.solid != SOLID_NOT )
{
SV_CopyTraceToGlobal( trace );
@ -216,6 +222,7 @@ void SV_AngularMove( edict_t *ent, float frametime, float friction )
VectorMA( ent->v.angles, frametime, ent->v.avelocity, ent->v.angles );
if( friction == 0.0f ) return;
adjustment = frametime * (sv_stopspeed->value / 10) * sv_friction->value * fabs( friction );
for( i = 0; i < 3; i++ )
@ -249,6 +256,7 @@ void SV_LinearMove( edict_t *ent, float frametime, float friction )
VectorMA( ent->v.origin, frametime, ent->v.velocity, ent->v.origin );
if( friction == 0.0f ) return;
adjustment = frametime * (sv_stopspeed->value / 10) * sv_friction->value * fabs( friction );
for( i = 0; i < 3; i++ )
@ -282,10 +290,12 @@ qboolean SV_CheckWater( edict_t *ent )
ent->v.waterlevel = 0;
ent->v.watertype = CONTENTS_EMPTY;
svs.groupmask = ent->v.groupinfo;
cont = SV_PointContents( point );
if( cont <= CONTENTS_WATER && cont > CONTENTS_TRANSLUCENT )
{
svs.groupmask = ent->v.groupinfo;
truecont = SV_TruePointContents( point );
ent->v.watertype = cont;
@ -293,11 +303,13 @@ qboolean SV_CheckWater( edict_t *ent )
point[2] = ent->v.origin[2] + (ent->v.mins[2] + ent->v.maxs[2]) * 0.5f;
svs.groupmask = ent->v.groupinfo;
cont = SV_PointContents( point );
if( cont <= CONTENTS_WATER && cont > CONTENTS_TRANSLUCENT )
{
ent->v.waterlevel = 2;
point[2] = ent->v.origin[2] + ent->v.view_ofs[2];
svs.groupmask = ent->v.groupinfo;
cont = SV_PointContents( point );
if( cont <= CONTENTS_WATER )
ent->v.waterlevel = 3;
@ -503,7 +515,7 @@ int SV_FlyMove( edict_t *ent, float time, trace_t *steptrace )
}
}
if( allFraction == 0 )
if( allFraction == 0.0f )
VectorClear( ent->v.velocity );
return blocked;
@ -526,13 +538,14 @@ void SV_AddGravity( edict_t *ent )
if( ent->v.gravity )
ent_gravity = ent->v.gravity;
else ent_gravity = 1.0;
else ent_gravity = 1.0f;
// add gravity incorrectly
ent->v.velocity[2] -= (ent_gravity * sv_gravity->value * host.frametime );
ent->v.velocity[2] += ent->v.basevelocity[2] * host.frametime;
ent->v.basevelocity[2] = 0.0f;
// bound velocity
SV_CheckVelocity( ent );
}
@ -566,6 +579,27 @@ PUSHMOVE
===============================================================================
*/
/*
============
SV_AllowPushRotate
Allows to chnage entity yaw?
============
*/
qboolean SV_AllowPushRotate( edict_t *ent )
{
model_t *mod;
mod = Mod_Handle( ent->v.modelindex );
if( !mod || mod->type != mod_brush )
return true;
if( !sv_allow_rotate_pushables->integer )
return false;
return (mod->flags & 1) ? true : false;
}
/*
============
SV_PushEntity
@ -590,18 +624,19 @@ trace_t SV_PushEntity( edict_t *ent, const vec3_t lpush, const vec3_t apush, int
trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, end, type, ent );
if( trace.fraction != 0.0f )
// NOTE: this condition may doing wrong results with spawn repels from osprey in SvenCoop 4.5. revisit
if( !trace.allsolid && trace.fraction != 0.0f )
{
VectorCopy( trace.endpos, ent->v.origin );
if( apush[YAW] && ent->v.flags & FL_CLIENT && ( cl = SV_ClientFromEdict( ent, true )) != NULL )
{
cl->addangle = apush[1];
ent->v.avelocity[1] += apush[1];
ent->v.fixangle = 2;
}
// don't rotate pushables!
if( ent->v.movetype != MOVETYPE_PUSHSTEP )
if( SV_AllowPushRotate( ent ))
ent->v.angles[YAW] += trace.fraction * apush[YAW];
}
@ -615,7 +650,14 @@ trace_t SV_PushEntity( edict_t *ent, const vec3_t lpush, const vec3_t apush, int
return trace;
}
static qboolean SV_CanPushed( edict_t *ent )
/*
============
SV_CanPushed
filter entities for push
============
*/
qboolean SV_CanPushed( edict_t *ent )
{
// filter movetypes to collide with
switch( ent->v.movetype )
@ -630,6 +672,13 @@ static qboolean SV_CanPushed( edict_t *ent )
return true;
}
/*
============
SV_CanBlock
allow entity to block pusher?
============
*/
static qboolean SV_CanBlock( edict_t *ent )
{
if( ent->v.solid == SOLID_NOT || ent->v.solid == SOLID_TRIGGER )
@ -646,94 +695,70 @@ static qboolean SV_CanBlock( edict_t *ent )
return true;
}
static qboolean SV_AllowToPush( edict_t *check, edict_t *pusher, const vec3_t mins, const vec3_t maxs )
{
int oldsolid, block;
// filter movetypes to collide with
if( !SV_CanPushed( check ))
return false;
oldsolid = pusher->v.solid;
pusher->v.solid = SOLID_NOT;
block = SV_TestEntityPosition( check, pusher );
pusher->v.solid = oldsolid;
if( block ) return false;
// if the entity is standing on the pusher, it will definately be moved
if( !(( check->v.flags & FL_ONGROUND ) && check->v.groundentity == pusher ))
{
if( check->v.absmin[0] >= maxs[0]
|| check->v.absmin[1] >= maxs[1]
|| check->v.absmin[2] >= maxs[2]
|| check->v.absmax[0] <= mins[0]
|| check->v.absmax[1] <= mins[1]
|| check->v.absmax[2] <= mins[2] )
return false;
// see if the ent's bbox is inside the pusher's final position
if( !SV_TestEntityPosition( check, NULL ))
return false;
}
// all tests are passed
return true;
}
/*
============
SV_BuildPushList
build the list of all entities which contacted with pusher
NOTE: don't use this. This optimization is required personal linked-list in edict_t (edict->area2)
and can't working correctly with node->solid_edicts only.
============
*/
sv_pushed_t *SV_BuildPushList( edict_t *pusher, int *numpushed, const vec3_t mins, const vec3_t maxs )
void SV_BuildPushList( areanode_t *node, edict_t *pusher, const vec3_t mins, const vec3_t maxs )
{
sv_pushed_t *pushed_p;
edict_t *check;
int e;
link_t *l, *next;
edict_t *check;
int oldsolid;
qboolean block;
// first entry always reseved by pusher
pushed_p = svgame.pushed + 1;
oldsolid = pusher->v.solid;
// now add all non-player entities
for( e = svgame.globals->maxClients + 1; e < svgame.numEntities; e++ )
// touch linked edicts
for( l = node->solid_edicts.next; l != &node->solid_edicts; l = next )
{
check = EDICT_NUM( e );
next = l->next;
check = EDICT_FROM_AREA( l );
if( !SV_AllowToPush( check, pusher, mins, maxs ))
continue;
pusher->v.solid = SOLID_NOT;
block = SV_TestEntityPosition( check, pusher );
pusher->v.solid = oldsolid;
if( block ) continue;
// remove the onground flag for non-players
if( check->v.movetype != MOVETYPE_WALK )
check->v.flags &= ~FL_ONGROUND;
// if the entity is standing on the pusher, it will definately be moved
if( !(( check->v.flags & FL_ONGROUND ) && check->v.groundentity == pusher ))
{
if( check->v.absmin[0] >= maxs[0]
|| check->v.absmin[1] >= maxs[1]
|| check->v.absmin[2] >= maxs[2]
|| check->v.absmax[0] <= mins[0]
|| check->v.absmax[1] <= mins[1]
|| check->v.absmax[2] <= mins[2] )
continue;
// save original position of contacted entity
pushed_p->ent = check;
VectorCopy( check->v.origin, pushed_p->origin );
VectorCopy( check->v.angles, pushed_p->angles );
pushed_p++;
// see if the ent's bbox is inside the pusher's final position
if( !SV_TestEntityPosition( check, NULL ))
continue;
}
#ifdef BUILD_PUSH_LIST
if( svgame.numpushents >= MAX_PUSHED_ENTS )
{
MsgDev( D_ERROR, "SV_BuildPushList: overflow!\n" );
return;
}
// all tests passed. add entity to pushlist
svgame.pushlist[svgame.numpushents] = check;
svgame.numpushents++;
#endif
}
// add all player entities (must be last)
// now add all non-player entities
for( e = 1; e < svgame.globals->maxClients + 1; e++ )
{
check = EDICT_NUM( e );
// recurse down both sides
if( node->axis == -1 ) return;
if( !SV_AllowToPush( check, pusher, mins, maxs ))
continue;
// save original position of contacted entity
pushed_p->ent = check;
VectorCopy( check->v.origin, pushed_p->origin );
VectorCopy( check->v.angles, pushed_p->angles );
pushed_p++;
}
if( numpushed ) *numpushed = pushed_p - svgame.pushed;
return svgame.pushed;
if( maxs[node->axis] > node->dist )
SV_BuildPushList( node->children[0], pusher, mins, maxs );
if( mins[node->axis] < node->dist )
SV_BuildPushList( node->children[1], pusher, mins, maxs );
}
/*
@ -779,6 +804,15 @@ static edict_t *SV_PushMove( edict_t *pusher, float movetime )
// see if any solid entities are inside the final position
num_moved = 0;
#ifdef BUILD_PUSH_LIST
svgame.numpushents = 0;
SV_BuildPushList( sv_areanodes, pusher, mins, maxs );
for( e = 0; e < svgame.numpushents; e++ )
{
check = svgame.pushlist[e];
#else
for( e = 1; e < svgame.numEntities; e++ )
{
check = EDICT_NUM( e );
@ -808,7 +842,7 @@ static edict_t *SV_PushMove( edict_t *pusher, float movetime )
if( !SV_TestEntityPosition( check, NULL ))
continue;
}
#endif
// remove the onground flag for non-players
if( check->v.movetype != MOVETYPE_WALK )
check->v.flags &= ~FL_ONGROUND;
@ -892,6 +926,14 @@ static edict_t *SV_PushRotate( edict_t *pusher, float movetime )
// create pusher final position
Matrix4x4_CreateFromEntity( end_l, pusher->v.angles, pusher->v.origin, 1.0f );
#ifdef BUILD_PUSH_LIST
svgame.numpushents = 0;
SV_BuildPushList( sv_areanodes, pusher, pusher->v.absmin, pusher->v.absmax );
for( e = 0; e < svgame.numpushents; e++ )
{
check = svgame.pushlist[e];
#else
// see if any solid entities are inside the final position
for( e = 1; e < svgame.numEntities; e++ )
{
@ -922,7 +964,7 @@ static edict_t *SV_PushRotate( edict_t *pusher, float movetime )
if( !SV_TestEntityPosition( check, NULL ))
continue;
}
#endif
// save original position of contacted entity
pushed_p->ent = check;
VectorCopy( check->v.origin, pushed_p->origin );
@ -930,18 +972,12 @@ static edict_t *SV_PushRotate( edict_t *pusher, float movetime )
pushed_p++;
// calculate destination position
VectorCopy( check->v.origin, org );
if( check->v.movetype == MOVETYPE_PUSHSTEP )
{
Matrix4x4_VectorITransform( start_l, org, temp );
Matrix4x4_VectorITransform( end_l, temp, org2 );
}
else
{
Matrix4x4_VectorTransform( start_l, org, temp );
Matrix4x4_VectorTransform( end_l, temp, org2 );
}
VectorAverage( check->v.absmin, check->v.absmax, org );
else VectorCopy( check->v.origin, org );
Matrix4x4_VectorTransform( start_l, org, temp );
Matrix4x4_VectorTransform( end_l, temp, org2 );
VectorSubtract( org2, org, lmove );
// try moving the contacted entity
@ -965,7 +1001,7 @@ static edict_t *SV_PushRotate( edict_t *pusher, float movetime )
VectorCopy( p->origin, p->ent->v.origin );
VectorCopy( p->angles, p->ent->v.angles );
SV_LinkEdict( p->ent, (p->ent == check) ? true : false );
p->ent->v.fixangle = 0; // save old fixangle state into pushed array ?
p->ent->v.fixangle = 0; // FIXME: save old fixangle state into pushed array ?
}
return check;
}
@ -1093,9 +1129,9 @@ void SV_Physics_Compound( edict_t *ent )
default: return;
}
// not initialized ?
if( ent->v.ltime == 0.0f )
{
// not initialized ?
VectorCopy( parent->v.origin, ent->v.oldorigin );
VectorCopy( parent->v.angles, ent->v.avelocity );
ent->v.ltime = parent->v.ltime ? parent->v.ltime : host.frametime;
@ -1118,7 +1154,7 @@ void SV_Physics_Compound( edict_t *ent )
Matrix4x4_VectorTransform( end_l, temp, org2 );
VectorSubtract( org2, org, lmove );
amove[0] = 0.0f; // don't pitch rotate
amove[0] = 0.0f; // don't pitch rotate
VectorAdd( ent->v.angles, amove, ent->v.angles );
VectorAdd( ent->v.origin, lmove, ent->v.origin );
@ -1170,6 +1206,7 @@ void SV_CheckWaterTransition( edict_t *ent )
{
int cont;
svs.groupmask = ent->v.groupinfo;
cont = SV_PointContents( ent->v.origin );
if( !ent->v.watertype )
@ -1535,7 +1572,7 @@ static void SV_Physics_Entity( edict_t *ent )
SV_LinkEdict( ent, true );
}
// user dll can override movement type
// user dll can override movement type (Xash3D extension)
if( svgame.dllFuncs2.pfnPhysicsEntity )
{
if( svgame.dllFuncs2.pfnPhysicsEntity( ent ))
@ -1618,4 +1655,7 @@ void SV_Physics( void )
// animate lightstyles (used for GetEntityIllum)
SV_RunLightStyles ();
// decrement svgame.numEntities if the highest number entities died
for( ; EDICT_NUM( svgame.numEntities - 1 )->free; svgame.numEntities-- );
}

View File

@ -8,19 +8,22 @@
#include "const.h"
#include "pm_local.h"
static qboolean has_update = false;
void SV_CopyPmtraceToGlobal( pmtrace_t *trace )
{
svgame.globals->trace_allsolid = trace->allsolid;
svgame.globals->trace_startsolid = trace->startsolid;
svgame.globals->trace_fraction = trace->fraction;
svgame.globals->trace_plane_dist = trace->plane.dist;
svgame.globals->trace_ent = EDICT_NUM( svgame.pmove->physents[trace->ent].info );
svgame.globals->trace_flags = 0;
svgame.globals->trace_inopen = trace->inopen;
svgame.globals->trace_inwater = trace->inwater;
VectorCopy( trace->endpos, svgame.globals->trace_endpos );
VectorCopy( trace->plane.normal, svgame.globals->trace_plane_normal );
svgame.globals->trace_hitgroup = trace->hitgroup;
if( trace->ent == -1 ) svgame.globals->trace_ent = svgame.edicts;
else svgame.globals->trace_ent = EDICT_NUM( svgame.pmove->physents[trace->ent].info );
}
qboolean SV_CopyEdictToPhysEnt( physent_t *pe, edict_t *ed )
@ -240,12 +243,8 @@ static int pfnTestPlayerPosition( float *pos, pmtrace_t *ptrace )
trace = PM_PlayerTrace( svgame.pmove, pos, pos, PM_NORMAL, svgame.pmove->usehull, -1, NULL );
if( ptrace ) *ptrace = trace;
return trace.ent;
}
static double Sys_FloatTime( void )
{
return Sys_DoubleTime();
return PM_TestPlayerPosition( svgame.pmove, pos, NULL );
}
static void pfnStuckTouch( int hitent, pmtrace_t *tr )
@ -316,32 +315,9 @@ static pmtrace_t *pfnTraceLine( float *start, float *end, int flags, int usehull
return &tr;
}
static int pfnGetModelType( model_t *mod )
{
if( !mod ) return mod_bad;
return mod->type;
}
static void pfnGetModelBounds( model_t *mod, float *mins, float *maxs )
{
if( mod )
{
if( mins ) VectorCopy( mod->mins, mins );
if( maxs ) VectorCopy( mod->maxs, maxs );
}
else
{
MsgDev( D_ERROR, "Mod_GetBounds: NULL model\n" );
if( mins ) VectorClear( mins );
if( maxs ) VectorClear( maxs );
}
}
static hull_t *pfnHullForBsp( physent_t *pe, float *offset )
{
float *mins = svgame.pmove->player_mins[svgame.pmove->usehull];
float *maxs = svgame.pmove->player_maxs[svgame.pmove->usehull];
return PM_HullForBsp( pe, mins, maxs, offset );
return PM_HullForBsp( pe, svgame.pmove, offset );
}
static float pfnTraceModel( physent_t *pEnt, float *start, float *end, trace_t *trace )
@ -373,21 +349,6 @@ static const char *pfnTraceTexture( int ground, float *vstart, float *vend )
return PM_TraceTexture( pe, vstart, vend );
}
static int pfnCOM_FileSize( const char *filename )
{
return FS_FileSize( filename, false );
}
static byte *pfnCOM_LoadFile( const char *path, int usehunk, int *pLength )
{
return FS_LoadFile( path, pLength, false );
}
static void pfnCOM_FreeFile( void *buffer )
{
if( buffer ) Mem_Free( buffer );
}
static void pfnPlaySound( int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch )
{
edict_t *ent;
@ -424,7 +385,8 @@ static int pfnTestPlayerPositionEx( float *pos, pmtrace_t *ptrace, pfnIgnore pmF
trace = PM_PlayerTrace( svgame.pmove, pos, pos, PM_STUDIO_BOX, svgame.pmove->usehull, -1, pmFilter );
if( ptrace ) *ptrace = trace;
return trace.ent;
return PM_TestPlayerPosition( svgame.pmove, pos, pmFilter );
}
static pmtrace_t *pfnTraceLineEx( float *start, float *end, int flags, int usehull, pfnIgnore pmFilter )
@ -472,7 +434,7 @@ void SV_InitClientMove( void )
svgame.pmove->Con_NPrintf = Con_NPrintf;
svgame.pmove->Con_DPrintf = Con_DPrintf;
svgame.pmove->Con_Printf = Con_Printf;
svgame.pmove->Sys_FloatTime = Sys_FloatTime;
svgame.pmove->Sys_FloatTime = Sys_DoubleTime;
svgame.pmove->PM_StuckTouch = pfnStuckTouch;
svgame.pmove->PM_PointContents = pfnPointContents;
svgame.pmove->PM_TruePointContents = pfnTruePointContents;
@ -485,9 +447,9 @@ void SV_InitClientMove( void )
svgame.pmove->PM_GetModelBounds = pfnGetModelBounds;
svgame.pmove->PM_HullForBsp = pfnHullForBsp;
svgame.pmove->PM_TraceModel = pfnTraceModel;
svgame.pmove->COM_FileSize = pfnCOM_FileSize;
svgame.pmove->COM_LoadFile = pfnCOM_LoadFile;
svgame.pmove->COM_FreeFile = pfnCOM_FreeFile;
svgame.pmove->COM_FileSize = COM_FileSize;
svgame.pmove->COM_LoadFile = COM_LoadFile;
svgame.pmove->COM_FreeFile = COM_FreeFile;
svgame.pmove->memfgets = pfnMemFgets;
svgame.pmove->PM_PlaySound = pfnPlaySound;
svgame.pmove->PM_TraceTexture = pfnTraceTexture;
@ -626,21 +588,15 @@ static void SV_FinishPMove( playermove_t *pmove, edict_t *clent )
VectorCopy( pmove->vuser2, clent->v.vuser2 );
VectorCopy( pmove->vuser3, clent->v.vuser3 );
VectorCopy( pmove->vuser4, clent->v.vuser4 );
#if 1
if( svgame.pmove->onground == -1 )
{
clent->v.flags &= ~FL_ONGROUND;
}
else if( pmove->onground >= 0 && pmove->onground < pmove->numphysent )
{
clent->v.flags |= FL_ONGROUND;
clent->v.groundentity = EDICT_NUM( svgame.pmove->physents[svgame.pmove->onground].info );
}
#else
if( pmove->onground >= 0 && pmove->onground < pmove->numphysent )
clent->v.groundentity = EDICT_NUM( pmove->physents[pmove->onground].info );
else clent->v.groundentity = NULL;
#endif
// angles
// show 1/3 the pitch angle and all the roll angle
if( !clent->v.fixangle )
@ -652,8 +608,6 @@ static void SV_FinishPMove( playermove_t *pmove, edict_t *clent )
}
}
int nofind = 0;
entity_state_t *SV_FindEntInPack( int index, client_frame_t *frame )
{
entity_state_t *state;
@ -683,16 +637,17 @@ int SV_UnlagCheckTeleport( vec3_t old_pos, vec3_t new_pos )
void SV_SetupMoveInterpolant( sv_client_t *cl )
{
int i, j, var_C_entindex;
float finalpush, lerp_msec, latency, temp, lerpFrac;
client_frame_t *frame, *var_24;
entity_state_t *state, *var_38_FoundEntity;
int i, j, clientnum;
float finalpush, lerp_msec;
float latency, temp, lerpFrac;
client_frame_t *frame, *frame2;
entity_state_t *state, *lerpstate;
vec3_t tempvec, tempvec2;
sv_client_t *check;
sv_interp_t *lerp;
vec3_t tempvec, tempvec2;
Q_memset( svgame.interp, 0, sizeof( svgame.interp ));
nofind = 1;
has_update = false;
// don't allow unlag in singleplayer
if( sv_maxclients->integer <= 1 ) return;
@ -705,7 +660,7 @@ void SV_SetupMoveInterpolant( sv_client_t *cl )
if( cl->state != cs_spawned || !cl->lag_compensation )
return;
nofind = 0;
has_update = true;
for( i = 0, check = svs.clients; i < sv_maxclients->integer; i++, cl++ )
{
@ -742,7 +697,7 @@ void SV_SetupMoveInterpolant( sv_client_t *cl )
frame = NULL;
for( var_24 = NULL, i = 0; i < SV_UPDATE_BACKUP; i++, var_24 = frame )
for( frame2 = NULL, i = 0; i < SV_UPDATE_BACKUP; i++, frame2 = frame )
{
frame = &cl->frames[(cl->netchan.outgoing_sequence - 1) & SV_UPDATE_MASK];
@ -779,24 +734,24 @@ void SV_SetupMoveInterpolant( sv_client_t *cl )
if( i == SV_UPDATE_BACKUP || finalpush - frame->senttime > 1.0 )
{
Q_memset( svgame.interp, 0, sizeof( svgame.interp ));
nofind = 1;
has_update = false;
return;
}
if( var_24 == NULL )
if( !frame2 )
{
var_24 = frame;
frame2 = frame;
lerpFrac = 0;
}
else
{
if( var_24->senttime - frame->senttime == 0.0 )
if( frame2->senttime - frame->senttime == 0.0 )
{
lerpFrac = 0;
}
else
{
lerpFrac = (finalpush - frame->senttime) / (var_24->senttime - frame->senttime);
lerpFrac = (finalpush - frame->senttime) / (frame2->senttime - frame->senttime);
lerpFrac = bound( 0.0f, lerpFrac, 1.0f );
}
}
@ -808,20 +763,20 @@ void SV_SetupMoveInterpolant( sv_client_t *cl )
if( state->number <= 0 || state->number >= sv_maxclients->integer )
continue;
var_C_entindex = state->number - 1;
check = &svs.clients[var_C_entindex];
clientnum = state->number - 1;
check = &svs.clients[clientnum];
if( check->state != cs_spawned || check == cl )
continue;
lerp = &svgame.interp[var_C_entindex];
lerp = &svgame.interp[clientnum];
if( !lerp->active || lerp->nointerp )
continue;
var_38_FoundEntity = SV_FindEntInPack( state->number, var_24 );
lerpstate = SV_FindEntInPack( state->number, frame2 );
if( var_38_FoundEntity == NULL )
if( !lerpstate )
{
tempvec[0] = state->origin[0];
tempvec[1] = state->origin[1];
@ -829,9 +784,9 @@ void SV_SetupMoveInterpolant( sv_client_t *cl )
}
else
{
tempvec2[0] = var_38_FoundEntity->origin[0] - state->origin[0];
tempvec2[1] = var_38_FoundEntity->origin[1] - state->origin[1];
tempvec2[2] = var_38_FoundEntity->origin[2] - state->origin[2];
tempvec2[0] = lerpstate->origin[0] - state->origin[0];
tempvec2[1] = lerpstate->origin[1] - state->origin[1];
tempvec2[2] = lerpstate->origin[2] - state->origin[2];
VectorMA( state->origin, lerpFrac, tempvec2, tempvec );
}

View File

@ -1,10 +1,11 @@
//=======================================================================
// Copyright XashXT Group 2008 ©
// sv_save.c - save\restore implementation
// sv_save.c - save\restore implementation
//=======================================================================
#include "common.h"
#include "server.h"
#include "library.h"
#include "const.h"
/*
@ -22,6 +23,8 @@ half-life implementation of saverestore system
#define SAVE_AGED_COUNT 1
#define SAVENAME_LENGTH 128 // matches with MAX_OSPATH
void (__cdecl *pfnSaveGameComment)( char *buffer, int max_length ) = NULL;
typedef struct
{
int nBytesSymbols;
@ -130,6 +133,11 @@ int SumBytes( SaveFileSectionsInfo_t *section )
return ( section->nBytesSymbols + section->nBytesDataHeaders + section->nBytesData );
}
void SV_InitSaveRestore( void )
{
pfnSaveGameComment = Com_GetProcAddress( svgame.hInstance, "SV_SaveGameComment" );
}
/*
----------------------------------------------------------
SaveRestore helpers
@ -159,7 +167,7 @@ void SaveRestore_Rebase( SAVERESTOREDATA *pSaveData )
void SaveRestore_Rewind( SAVERESTOREDATA *pSaveData, int nBytes )
{
if( pSaveData->size < nBytes )
if( nBytes > pSaveData->size )
nBytes = pSaveData->size;
SaveRestore_MoveCurPos( pSaveData, -nBytes );
@ -299,21 +307,30 @@ const char *SaveRestore_StringFromSymbol( SAVERESTOREDATA *pSaveData, int token
void SV_BuildSaveComment( char *text, int maxlength )
{
const char *pName;
edict_t *pWorld = EDICT_NUM( 0 );
float time = sv_time();
if( pWorld && pWorld->v.message )
if( pfnSaveGameComment != NULL )
{
// trying to extract message from world
pName = STRING( pWorld->v.message );
// get save comment from gamedll
pfnSaveGameComment( text, maxlength );
}
else
{
// or use mapname
pName = STRING( svgame.globals->mapname );
const char *pName;
edict_t *pWorld = EDICT_NUM( 0 );
float time = sv.time;
if( pWorld && pWorld->v.message )
{
// trying to extract message from world
pName = STRING( pWorld->v.message );
}
else
{
// or use mapname
pName = STRING( svgame.globals->mapname );
}
Q_snprintf( text, maxlength, "%-64.64s %02d:%02d", pName, (int)(time / 60.0f ), (int)fmod( time, 60.0f ));
}
Q_snprintf( text, maxlength, "%-64.64s %02d:%02d", pName, (int)(time / 60.0f ), (int)fmod( time, 60.0f ));
}
int SV_MapCount( const char *pPath )
@ -338,7 +355,7 @@ int EntryInTable( SAVERESTOREDATA *pSaveData, const char *pMapName, int index )
for( i = index; i < pSaveData->connectionCount; i++ )
{
if ( !Q_strcmp( pSaveData->levelList[i].mapName, pMapName ) )
if ( !Q_strcmp( pSaveData->levelList[i].mapName, pMapName ))
return i;
}
return -1;
@ -404,6 +421,7 @@ void ReapplyDecal( SAVERESTOREDATA *pSaveData, decallist_t *entry, qboolean adja
tr = SV_Move( testspot, vec3_origin, vec3_origin, testend, MOVE_NOMONSTERS, NULL );
// FIXME: this code may does wrong result on moving brushes e.g. func_tracktrain
if( tr.fraction != 1.0f && !tr.allsolid )
{
// check impact plane normal
@ -422,7 +440,6 @@ void ReapplyDecal( SAVERESTOREDATA *pSaveData, decallist_t *entry, qboolean adja
edict_t *pEdict = pSaveData->pTable[entry->entityIndex].pent;
if( SV_IsValidEdict( pEdict )) modelIndex = pEdict->v.modelindex;
if( SV_IsValidEdict( pEdict )) entityIndex = NUM_FOR_EDICT( pEdict );
SV_CreateDecal( entry->position, decalIndex, entityIndex, modelIndex, flags );
}
}
@ -437,21 +454,23 @@ void SV_ClearSaveDir( void )
if( !t ) return; // already empty
for( i = 0; i < t->numfilenames; i++ )
{
FS_Delete( t->filenames[i] );
}
Mem_Free( t );
}
int SV_IsValidSave( void )
{
if( !svs.initialized || sv.state != ss_active || sv.background )
if( sv.background )
return 0;
if( !svs.initialized || sv.state != ss_active )
{
Msg( "Not playing a local game.\n" );
return 0;
}
if( CL_Active() == false )
if( !CL_Active( ))
{
Msg( "Can't save if not active.\n" );
return 0;
@ -517,7 +536,7 @@ void SV_AgeSaveList( const char *pName, int count )
Q_snprintf( newName, sizeof( newName ), "save/%s%02d.sav", pName, count );
Q_snprintf( newImage, sizeof( newImage ), "save/%s%02d.bmp", pName, count );
// Scroll the name list down (rename quick04.sav to quick05.sav)
// scroll the name list down (rename quick04.sav to quick05.sav)
FS_Rename( oldName, newName );
FS_Rename( oldImage, newImage );
count--;
@ -1379,7 +1398,7 @@ void SV_LoadAdjacentEnts( const char *pOldLevel, const char *pLandmarkName )
SV_EntityPatchRead( pSaveData, currentLevelData.levelList[i].mapName );
pSaveData->time = sv_time(); // - header.time;
pSaveData->time = sv.time; // - header.time;
pSaveData->fUseLandmark = true;
// calculate landmark offset
@ -1534,7 +1553,7 @@ int SV_SaveGameSlot( const char *pSaveName, const char *pSaveComment )
Cbuf_AddText( va( "saveshot \"%s\"\n", pSaveName ));
// output to disk
if( Q_stricmp( pSaveName, "quick" ) || Q_stricmp( pSaveName, "autosave" ))
if( !Q_stricmp( pSaveName, "quick" ) || !Q_stricmp( pSaveName, "autosave" ))
SV_AgeSaveList( pSaveName, SAVE_AGED_COUNT );
pFile = FS_Open( name, "wb", false );
@ -1651,7 +1670,7 @@ qboolean SV_LoadGame( const char *pName )
if( !FS_FileExists( name, true ))
return false;
SCR_BeginLoadingPlaque ();
SCR_BeginLoadingPlaque ( false );
MsgDev( D_INFO, "Loading game from %s...\n", name );
SV_ClearSaveDir();
@ -1740,15 +1759,11 @@ void SV_SaveGame( const char *pName )
}
else Q_strncpy( savename, pName, sizeof( savename ));
// make sure what oldsave is removed
if( FS_FileExists( va( "save/%s.sav", savename ), false ))
FS_Delete( va( "save/%s.sav", savename ));
if( FS_FileExists( va( "save/%s.bmp", savename ), false ))
FS_Delete( va( "save/%s.bmp", savename ));
// HACKHACK: unload previous image from memory
GL_FreeImage( va( "save/%s.bmp", savename ));
comment[0] = '\0';
SV_BuildSaveComment( comment, sizeof( comment ));
SV_SaveGameSlot( savename, comment );
@ -1838,12 +1853,14 @@ qboolean SV_GetComment( const char *savename, char *comment )
FS_Close( f );
return 0;
}
if( tag < SAVEGAME_VERSION )
{
Q_strncpy( comment, "<old version>", MAX_STRING );
FS_Close( f );
return 0;
}
if( tag > SAVEGAME_VERSION )
{
// old xash version ?
@ -1879,8 +1896,8 @@ qboolean SV_GetComment( const char *savename, char *comment )
FS_Read( f, pSaveData, size );
pData = pSaveData;
// Allocate a table for the strings, and parse the table
if ( tokenSize > 0 )
// allocate a table for the strings, and parse the table
if( tokenSize > 0 )
{
pTokenList = Mem_Alloc( host.mempool, tokenCount * sizeof( char* ));
@ -1910,7 +1927,7 @@ qboolean SV_GetComment( const char *savename, char *comment )
// int (fieldcount)
pData += sizeof( short );
nNumberOfFields = ( int )*pData;
nNumberOfFields = (int)*pData;
pData += nFieldSize;
// each field is a short (size), short (index of name), binary string of "size" bytes (data)

View File

@ -79,19 +79,32 @@ static void SV_HullForHitbox( const vec3_t mins, const vec3_t maxs )
*/
/*
====================
StudioSetUpTransform
StudioPlayerBlend
====================
*/
static void SV_StudioSetUpTransform( edict_t *ent )
void SV_StudioPlayerBlend( mstudioseqdesc_t *pseqdesc, int *pBlend, float *pPitch )
{
vec3_t ang;
float scale = 1.0f;
// calc up/down pointing
*pBlend = (*pPitch * 3);
VectorCopy( ent->v.angles, ang );
ang[PITCH] = -ang[PITCH]; // stupid Half-Life bug
if( ent->v.scale != 0.0f && sv_allow_studio_scaling->integer ) scale = ent->v.scale;
Matrix3x4_CreateFromEntity( sv_studiomatrix, ang, ent->v.origin, scale );
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;
}
}
/*
@ -462,6 +475,7 @@ static void SV_StudioSetupBones( model_t *pModel, float frame, int sequence, con
{
int i, j, numbones;
int boneused[MAXSTUDIOBONES];
float scale = 1.0f;
double f;
mstudiobone_t *pbones;
@ -494,9 +508,7 @@ static void SV_StudioSetupBones( model_t *pModel, float frame, int sequence, con
{
numbones = sv_studiohdr->numbones;
for( i = 0; i < sv_studiohdr->numbones; i++ )
{
boneused[(numbones - i) - 1] = i;
}
}
else
{
@ -539,9 +551,17 @@ static void SV_StudioSetupBones( model_t *pModel, float frame, int sequence, con
}
}
if( SV_IsValidEdict( pEdict ) && pEdict->v.scale != 0.0f && sv_allow_studio_scaling->integer )
scale = pEdict->v.scale;
else if( SV_IsValidEdict( pEdict ) && (pEdict->v.flags & FL_CLIENT) && sv_clienttrace->value != 0.0f )
scale = sv_clienttrace->value * 0.5f;
Matrix3x4_CreateFromEntity( sv_studiomatrix, angles, origin, scale );
for( j = numbones - 1; j >= 0; j-- )
{
i = boneused[j];
Matrix3x4_FromOriginQuat( bonematrix, q[i], pos[i] );
if( pbones[i].parent == -1 )
Matrix3x4_ConcatTransforms( sv_studiobones[i], sv_studiomatrix, bonematrix );
@ -555,17 +575,46 @@ StudioSetupModel
====================
*/
static qboolean SV_StudioSetupModel( edict_t *ent, int iBone )
static qboolean SV_StudioSetupModel( edict_t *ent, int iBone, qboolean bInversePitch )
{
model_t *mod = Mod_Handle( ent->v.modelindex );
void *hdr = Mod_Extradata( mod );
vec3_t angles;
if( !hdr ) return false;
sv_studiohdr = (studiohdr_t *)hdr;
SV_StudioSetUpTransform( ent );
pBlendAPI->SV_StudioSetupBones( mod, ent->v.frame, ent->v.sequence, ent->v.angles, ent->v.origin,
ent->v.controller, ent->v.blending, iBone, ent );
VectorCopy( ent->v.angles, angles );
if( bInversePitch )
{
angles[PITCH] = -angles[PITCH];
}
// calc blending for player
if( ent->v.flags & FL_CLIENT )
{
mstudioseqdesc_t *pseqdesc;
byte controller[4];
byte blending[2];
int iBlend;
pseqdesc = (mstudioseqdesc_t *)((byte *)sv_studiohdr + sv_studiohdr->seqindex) + ent->v.sequence;
SV_StudioPlayerBlend( pseqdesc, &iBlend, &angles[PITCH] );
controller[0] = controller[1] = controller[2] = controller[3] = 0x7F;
blending[0] = (byte)iBlend;
blending[1] = 0;
pBlendAPI->SV_StudioSetupBones( mod, ent->v.frame, ent->v.sequence, angles, ent->v.origin,
controller, blending, iBone, ent );
}
else
{
pBlendAPI->SV_StudioSetupBones( mod, ent->v.frame, ent->v.sequence, angles, ent->v.origin,
ent->v.controller, ent->v.blending, iBone, ent );
}
return true;
}
@ -862,7 +911,7 @@ trace_t SV_TraceHitbox( edict_t *ent, const vec3_t start, vec3_t mins, vec3_t ma
if( !SV_StudioIntersect( ent, start, mins, maxs, end ))
return trace;
if( !SV_StudioSetupModel( ent, -1 )) // all bones used
if( !SV_StudioSetupModel( ent, -1, false )) // all bones used
return trace;
if( VectorCompare( start, end ))
@ -936,7 +985,7 @@ void SV_StudioGetAttachment( edict_t *e, int iAttachment, float *org, float *ang
// calculate attachment origin and angles
pAtt = (mstudioattachment_t *)((byte *)sv_studiohdr + sv_studiohdr->attachmentindex);
SV_StudioSetupModel( e, pAtt[iAttachment].bone );
SV_StudioSetupModel( e, pAtt[iAttachment].bone, true );
// compute pos and angles
Matrix3x4_VectorTransform( sv_studiobones[pAtt[iAttachment].bone], pAtt[iAttachment].org, localOrg );
@ -955,7 +1004,7 @@ void SV_StudioGetAttachment( edict_t *e, int iAttachment, float *org, float *ang
void SV_GetBonePosition( edict_t *e, int iBone, float *org, float *ang )
{
if( !SV_StudioSetupModel( e, iBone ) || sv_studiohdr->numbones <= 0 )
if( !SV_StudioSetupModel( e, iBone, false ) || sv_studiohdr->numbones <= 0 )
return;
iBone = bound( 0, iBone, sv_studiohdr->numbones );

View File

@ -598,7 +598,7 @@ void SV_LinkEdict( edict_t *ent, qboolean touch_triggers )
}
}
// ignore not solid bodies
// ignore not solid bodies (but pass allowed for push)
if( ent->v.solid == SOLID_NOT && ent->v.skin == CONTENTS_NONE )
return;
@ -738,15 +738,13 @@ qboolean SV_TestEntityPosition( edict_t *ent, edict_t *blocker )
}
trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, MOVE_NORMAL|FMOVE_SIMPLEBOX, ent );
#if 1
// FIXME: this is need to be detail testing
if( SV_IsValidEdict( blocker ) && SV_IsValidEdict( trace.ent ))
{
if( trace.ent->v.movetype == MOVETYPE_PUSH || trace.ent == blocker )
return trace.startsolid;
return false;
}
#endif
return trace.startsolid;
}
@ -1063,7 +1061,7 @@ const char *SV_TraceTexture( edict_t *ent, const vec3_t start, const vec3_t end
{
matrix4x4 imatrix;
Matrix4x4_CreateFromEntity( matrix, ent->v.angles, ent->v.origin, 1.0f );
Matrix4x4_CreateFromEntity( matrix, ent->v.angles, offset, 1.0f );
Matrix4x4_Invert_Simple( imatrix, matrix );
Matrix4x4_VectorTransform( imatrix, start, start_l );

BIN
game_launch/hl.exe Normal file

Binary file not shown.

View File

@ -89,8 +89,8 @@ static void UI_CreateGame_Begin( void )
if( !MAP_IS_VALID( uiCreateGame.mapName[uiCreateGame.mapsList.curItem] ))
return; // bad map
if( CVAR_GET_FLOAT( "host_serverstate" ))
CLIENT_COMMAND( TRUE, "killserver\n" );
if( CVAR_GET_FLOAT( "host_serverstate" ) && CVAR_GET_FLOAT( "maxplayers" ) == 1 )
HOST_ENDGAME( "end of the game" );
CVAR_SET_FLOAT( "deathmatch", 1.0f ); // FIXME
CVAR_SET_FLOAT( "maxplayers", atoi( uiCreateGame.maxClients.buffer ));

View File

@ -78,7 +78,7 @@ static void UI_GameOptions_UpdateConfig( void )
uiGameOptions.maxFPS.generic.name = fpsText;
CVAR_SET_FLOAT( "hand", uiGameOptions.hand.enabled );
CVAR_SET_FLOAT( "allow_download", uiGameOptions.allowDownload.enabled );
CVAR_SET_FLOAT( "sv_allow_download", uiGameOptions.allowDownload.enabled );
CVAR_SET_FLOAT( "fps_max", uiGameOptions.maxFPS.curValue );
CVAR_SET_FLOAT( "cl_run", uiGameOptions.alwaysRun.enabled );
}
@ -91,7 +91,7 @@ UI_GameOptions_DiscardChanges
static void UI_GameOptions_DiscardChanges( void )
{
CVAR_SET_FLOAT( "hand", uiGameInitial.hand );
CVAR_SET_FLOAT( "allow_download", uiGameInitial.allowDownload );
CVAR_SET_FLOAT( "sv_allow_download", uiGameInitial.allowDownload );
CVAR_SET_FLOAT( "fps_max", uiGameInitial.maxFPS );
CVAR_SET_FLOAT( "cl_run", uiGameInitial.alwaysRun );
}
@ -123,7 +123,7 @@ static void UI_GameOptions_GetConfig( void )
if( CVAR_GET_FLOAT( "cl_run" ))
uiGameInitial.alwaysRun = uiGameOptions.alwaysRun.enabled = 1;
if( CVAR_GET_FLOAT( "allow_download" ))
if( CVAR_GET_FLOAT( "sv_allow_download" ))
uiGameInitial.allowDownload = uiGameOptions.allowDownload.enabled = 1;
UI_GameOptions_UpdateConfig ();

View File

@ -78,6 +78,7 @@ static void UI_NewGame_StartGame( float skill )
CVAR_SET_FLOAT( "deathmatch", 0.0f );
CVAR_SET_FLOAT( "teamplay", 0.0f );
CVAR_SET_FLOAT( "pausable", 1.0f ); // singleplayer is always allowing pause
CVAR_SET_FLOAT( "maxplayers", 1.0f );
CVAR_SET_FLOAT( "coop", 0.0f );
CLIENT_COMMAND( FALSE, "newgame\n" );