18 Oct 2010

This commit is contained in:
g-cont 2010-10-18 00:00:00 +04:00 committed by Alibek Omarov
parent dca58964c0
commit a2a61486e2
20 changed files with 696 additions and 231 deletions

View File

@ -271,6 +271,12 @@ int CHud :: Redraw( float flTime )
// clock was reset, reset delta
if( m_flTimeDelta < 0 ) m_flTimeDelta = 0;
if( v_dark )
{
SetScreenFade( Vector( 0, 0, 0 ), 255, 4, 4, FFADE_IN );
v_dark = FALSE;
}
// draw screen fade before hud
DrawScreenFade();

View File

@ -639,6 +639,9 @@ public:
Vector m_vecFadeColor;
float m_flFadeAlpha;
BOOL m_bModulate;
// v_dark issues
BOOL v_dark;
// error sprite
int m_HUD_error;

View File

@ -146,12 +146,9 @@ int CHud :: MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf )
m_flStartDist = 0;
m_flEndDist = 0;
if( CVAR_GET_FLOAT( "v_dark" ))
{
SetScreenFade( Vector( 0, 0, 0 ), 255, 4, 4, FFADE_IN );
CVAR_SET_FLOAT( "v_dark", 0.0f );
}
v_dark = CVAR_GET_FLOAT( "v_dark" );
CVAR_SET_FLOAT( "v_dark", 0.0f );
return 1;
}

76
common/custom.h Normal file
View File

@ -0,0 +1,76 @@
//=======================================================================
// Copyright XashXT Group 2010 ©
// custom.h - create custom user recources
//=======================================================================
#ifndef CUSTOM_H
#define CUSTOM_H
#include "const.h"
/////////////////
// Customization
// passed to pfnPlayerCustomization
// For automatic downloading.
typedef enum
{
t_sound = 0,
t_skin,
t_model,
t_decal,
t_generic,
t_eventscript,
t_world, // fake type for world, is really t_model
} resourcetype_t;
typedef struct
{
int size;
} _resourceinfo_t;
typedef struct resourceinfo_s
{
_resourceinfo_t info[8];
} resourceinfo_t;
#define RES_FATALIFMISSING (1<<0) // Disconnect if we can't get this file.
#define RES_WASMISSING (1<<1) // Do we have the file locally, did we get it ok?
#define RES_CUSTOM (1<<2) // Is this resource one that corresponds to another player's customization
// or is it a server startup resource.
#define RES_REQUESTED (1<<3) // Already requested a download of this one
#define RES_PRECACHED (1<<4) // Already precached
typedef struct resource_s
{
char szFileName[64]; // file name to download/precache.
resourcetype_t type; // t_sound, t_skin, t_model, t_decal.
int nIndex; // for t_decals
int nDownloadSize; // size in bytes if this must be downloaded.
byte ucFlags;
// for handling client to client resource propagation
byte rgucMD5_hash[16]; // to determine if we already have it.
byte playernum; // which player index this resource is associated with,
// if it's a custom resource.
byte rguc_reserved[32]; // for future expansion
struct resource_s *pNext; // Next in chain.
struct resource_s *pPrev;
} resource_t;
typedef struct custom_s
{
BOOL bInUse; // is this customization in use;
resource_t resource; // the resource_t for this customization
BOOL bTranslated; // has the raw data been translated into a useable format?
// (e.g., raw decal .wad make into texture_t *)
int nUserData1; // sustomization specific data
int nUserData2; // customization specific data
void *pInfo; // buffer that holds the data structure that references
// the data (e.g., the cachewad_t)
void *pBuffer; // buffer that holds the data for the customization
// (the raw .wad data)
struct customization_s *pNext; // next in chain
} customization_t;
#endif // CUSTOM_H

View File

@ -6,6 +6,7 @@
#define EIFACE_H
#include "cvardef.h"
#include "custom.h"
#define INTERFACE_VERSION 140 // GetEntityAPI, GetEntityAPI2
#define NEW_DLL_FUNCTIONS_VERSION 2 // GetNewDLLFunctions (Xash3D uses version 2)
@ -17,9 +18,9 @@ typedef enum
{
at_notice,
at_console, // format: [msg]
at_aiconsole, // same as at_console, but only shown if developer level is 2!
at_warning, // format: Warning: [msg]
at_error, // format: Error: [msg]
at_aiconsole, // same as at_console, but only shown if developer level is 5!
at_logged // server print to console ( only in multiplayer games ). (NOT IMPLEMENTED)
} ALERT_TYPE;
@ -34,9 +35,10 @@ typedef enum
// for integrity checking of content on clients
typedef enum
{
force_exactfile, // file on client must exactly match server's file
force_model_samebounds, // for model files only, the geometry must fit in the same bbox
force_model_specifybounds, // for model files only, the geometry must fit in the specified bbox
force_exactfile, // file on client must exactly match server's file
force_model_samebounds, // for model files only, the geometry must fit in the same bbox
force_model_specifybounds, // for model files only, the geometry must fit in the specified bbox
force_model_specifybounds_if_avail, // for model files only, the geometry must fit in the specified bbox (if the file is available)
} FORCE_TYPE;
typedef struct
@ -63,16 +65,16 @@ typedef struct enginefuncs_s
int (*pfnModelFrames)( int modelIndex );
void (*pfnSetSize)( edict_t *e, const float *rgflMin, const float *rgflMax );
void (*pfnChangeLevel)( const char* s1, const char* s2 );
edict_t* (*pfnFindClientInPHS)( edict_t *pEdict );
edict_t* (*pfnEntitiesInPHS)( edict_t *pplayer );
edict_t* (*pfnFindClientInPHS)( edict_t *pEdict ); // was pfnGetSpawnParms
edict_t* (*pfnEntitiesInPHS)( edict_t *pplayer ); // was pfnSaveSpawnParms
float (*pfnVecToYaw)( const float *rgflVector );
void (*pfnVecToAngles)( const float *rgflVectorIn, float *rgflVectorOut );
void (*pfnMoveToOrigin)( edict_t *ent, const float *pflGoal, float dist, int iMoveType );
void (*pfnChangeYaw)( edict_t* ent );
void (*pfnChangePitch)( edict_t* ent );
edict_t* (*pfnFindEntityByString)( edict_t *pStartEdict, const char *pszField, const char *pszValue);
edict_t* (*pfnFindEntityByString)( edict_t *pEdictStartSearchAfter, const char *pszField, const char *pszValue );
int (*pfnGetEntityIllum)( edict_t* pEnt );
edict_t* (*pfnFindEntityInSphere)( edict_t *pStartEdict, const float *org, float rad );
edict_t* (*pfnFindEntityInSphere)( edict_t *pEdictStartSearchAfter, const float *org, float rad );
edict_t* (*pfnFindClientInPVS)( edict_t *pEdict );
edict_t* (*pfnEntitiesInPVS)( edict_t *pplayer );
void (*pfnMakeVectors)( const float *rgflVector );
@ -81,7 +83,7 @@ typedef struct enginefuncs_s
void (*pfnRemoveEntity)( edict_t* e );
edict_t* (*pfnCreateNamedEntity)( string_t className );
void (*pfnMakeStatic)( edict_t *ent );
void (*pfnLinkEdict)( edict_t *e, int touch_triggers ); // a part of CustomPhysics implementation
int (*pfnEntIsOnFloor)( edict_t *e );
int (*pfnDropToFloor)( edict_t* e );
int (*pfnWalkMove)( edict_t *ent, float yaw, float dist, int iMode );
void (*pfnSetOrigin)( edict_t *e, const float *rgflOrigin );
@ -93,7 +95,7 @@ typedef struct enginefuncs_s
void (*pfnTraceHull)( const float *v1, const float *v2, int fNoMonsters, int hullNumber, edict_t *pentToSkip, TraceResult *ptr );
void (*pfnTraceModel)( const float *v1, const float *v2, int hullNumber, edict_t *pent, TraceResult *ptr );
const char *(*pfnTraceTexture)( edict_t *pTextureEntity, const float *v1, const float *v2 );
int (*pfnBoxVisible)( const float *mins, const float *maxs, const byte *pset );
int (*pfnBoxVisible)( const float *mins, const float *maxs, const byte *pset ); // was pfnTraceSphere
void (*pfnGetAimVector)( edict_t* ent, float speed, float *rgflReturn );
void (*pfnServerCommand)( const char* str );
void (*pfnServerExecute)( void );

View File

@ -285,6 +285,14 @@ usercmd_t CL_CreateCmd( void )
clgame.dllFuncs.pfnCreateMove( &cmd, cl.time - cl.oldtime, ( cls.state == ca_active && !cl.refdef.paused ));
if( re )
{
vec3_t color;
re->LightForPoint( cl.frame.clientdata.origin, color );
cmd.lightlevel = VectorAvg( color ) * 255;
}
// random seed for predictable random values
cl.random_seed = Com_RandomLong( 0, 0x7fffffff ); // full range

View File

@ -28,13 +28,13 @@ const char *svc_strings[256] =
"svc_setangle",
"svc_serverdata",
"svc_restore",
"svc_frame",
"svc_updateuserinfo",
"svc_usermessage",
"svc_clientdata",
"svc_download",
"svc_updatepings",
"svc_particle",
"svc_ambientsound",
"svc_frame",
"svc_spawnstatic",
"svc_crosshairangle",
"svc_spawnbaseline",
@ -44,7 +44,7 @@ const char *svc_strings[256] =
"svc_centerprint",
"svc_event",
"svc_event_reliable",
"svc_updateuserinfo",
"svc_ambientsound",
"svc_intermission",
"svc_soundfade",
"svc_cdtrack",
@ -452,6 +452,46 @@ void CL_ParseParticles( sizebuf_t *msg )
clgame.dllFuncs.pfnParticleEffect( org, dir, color, count );
}
/*
==================
CL_ParseStaticEntity
==================
*/
void CL_ParseStaticEntity( sizebuf_t *msg )
{
entity_state_t ent;
int i;
Mem_Set( &ent, 0, sizeof( ent ));
ent.modelindex = BF_ReadShort( msg );
ent.sequence = BF_ReadByte( msg );
ent.frame = BF_ReadByte( msg );
ent.colormap = BF_ReadWord( msg );
ent.skin = BF_ReadByte( msg );
for( i = 0; i < 3; i++ )
{
ent.origin[i] = BF_ReadBitCoord( msg );
ent.angles[i] = BF_ReadBitAngle( msg, 16 );
}
ent.rendermode = BF_ReadByte( msg );
if( ent.rendermode != kRenderNormal )
{
ent.renderamt = BF_ReadByte( msg );
ent.rendercolor.r = BF_ReadByte( msg );
ent.rendercolor.g = BF_ReadByte( msg );
ent.rendercolor.b = BF_ReadByte( msg );
ent.renderfx = BF_ReadByte( msg );
}
// FIXME: allocate client entity, add new static...
MsgDev( D_ERROR, "Static entities are not implemented\n" );
}
/*
==================
CL_ParseStaticDecal
@ -1081,12 +1121,12 @@ void CL_ParseServerMessage( sizebuf_t *msg )
case svc_particle:
CL_ParseParticles( msg );
break;
case svc_spawnstatic:
CL_ParseStaticEntity( msg );
break;
case svc_ambientsound:
CL_ParseSoundPacket( msg, true );
break;
case svc_spawnstatic:
Host_Error( "svc_spawnstatic: not implemented\n" );
break;
case svc_crosshairangle:
CL_ParseCrosshairAngle( msg );
break;

View File

@ -187,6 +187,13 @@ int CM_LightEntity( edict_t *pEdict )
return 255;
}
if( pEdict->v.flags & FL_CLIENT )
{
// client has more precision light level
// that come from client
return pEdict->v.light_level;
}
VectorCopy( pEdict->v.origin, start );
VectorCopy( pEdict->v.origin, end );

View File

@ -697,7 +697,7 @@ void Delta_ParseTable( script_t *delta_script, delta_info_t *dt, const char *enc
if( !com.stricmp( encodeDll, "none" ))
dt->customEncode = CUSTOM_NONE;
else if( !com.stricmp( encodeDll, "gamedll" ))
dt->customEncode = CUSTOM_SEREVR_ENCODE;
dt->customEncode = CUSTOM_SERVER_ENCODE;
else if( !com.stricmp( encodeDll, "clientdll" ))
dt->customEncode = CUSTOM_CLIENT_ENCODE;

View File

@ -29,7 +29,7 @@
enum
{
CUSTOM_NONE = 0,
CUSTOM_SEREVR_ENCODE, // keyword "gamedll"
CUSTOM_SERVER_ENCODE, // keyword "gamedll"
CUSTOM_CLIENT_ENCODE, // keyword "client"
};

View File

@ -21,14 +21,14 @@
#define svc_setangle 10 // [angle angle] set the view angle to this absolute value
#define svc_serverdata 11 // [long] protocol ...
#define svc_restore 12 // restore saved game on the client
#define svc_frame 13 // begin a new server frame
#define svc_updateuserinfo 13 // [byte] playernum, [string] userinfo
#define svc_usermessage 14 // [string][byte] REG_USER_MSG stuff
#define svc_clientdata 15 // [...]
#define svc_download 16 // [short] size [size bytes]
#define svc_updatepings 17 // [bit][idx][ping][packet_loss]
#define svc_particle 18 // [float*3][char*3][byte][byte]
#define svc_ambientsound 19 // <see code>
#define svc_spawnstatic 20 // NOT IMPLEMENTED
#define svc_frame 19 // <OBSOLETE>
#define svc_spawnstatic 20 // creates a static client entity
#define svc_crosshairangle 21 // [short][short][short]
#define svc_spawnbaseline 22 // <see code>
#define svc_temp_entity 23 // <variable sized>
@ -37,7 +37,7 @@
#define svc_centerprint 26 // [string] to put in center of the screen
#define svc_event 27 // playback event queue
#define svc_event_reliable 28 // playback event directly from message, not queue
#define svc_updateuserinfo 29 // [byte] playernum, [string] userinfo
#define svc_ambientsound 29 // <see code>
#define svc_intermission 30 // empty message (event)
#define svc_soundfade 31 // [float*4] sound fade parms
#define svc_cdtrack 32 // [byte] track [byte] looptrack

View File

@ -219,7 +219,7 @@ void Host_CheckChanges( void )
if(( host_video->modified || host_audio->modified ) && CL_Active( ))
{
host.soundList = (soundlist_t *)Z_Malloc( sizeof( soundlist_t ) * 128 );
host.numsounds = S_GetCurrentStaticSounds( host.soundList, 128, CHAN_AUTO );
host.numsounds = S_GetCurrentStaticSounds( host.soundList, 128, CHAN_STATIC );
Msg( "Total stored %i sounds\n", host.numsounds );
}

View File

@ -153,6 +153,8 @@ typedef struct sv_client_s
float latency;
float ping;
int listeners; // 32 bits == MAX_CLIENTS (voice listeners)
float addangle; // add angles to client position
edict_t *edict; // EDICT_NUM(clientnum+1)
@ -381,9 +383,10 @@ bool SV_TestPlayerPosition( edict_t *ent ); // for PlayerInSolid checks
//
// sv_move.c
//
bool SV_WalkMove( edict_t *ent, const vec3_t move, int iMode );
bool SV_MoveStep( edict_t *ent, vec3_t move, bool relink );
bool SV_MoveTest( edict_t *ent, vec3_t move, bool relink );
void SV_MoveToOrigin( edict_t *ed, const vec3_t goal, float dist, int iMode );
bool SV_CheckBottom( edict_t *ent, float flStepSize, int iMode );
bool SV_CheckBottom( edict_t *ent, int iMode );
float SV_VecToYaw( const vec3_t src );
//
@ -432,6 +435,7 @@ 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 );
//
// sv_game.c

View File

@ -814,6 +814,7 @@ void SV_PutClientInServer( edict_t *ent )
{
if( ent->v.flags & FL_SPECTATOR )
{
svgame.globals->time = sv.time;
svgame.dllFuncs.pfnSpectatorConnect( ent );
}
else
@ -823,6 +824,7 @@ void SV_PutClientInServer( edict_t *ent )
else ent->v.netname = MAKE_STRING( "player" );
// fisrt entering
svgame.globals->time = sv.time;
svgame.dllFuncs.pfnClientPutInServer( ent );
}
}

View File

@ -723,6 +723,9 @@ void SV_SendMessagesToAll( void )
int i;
sv_client_t *cl;
if( sv.state == ss_dead )
return;
for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
{
if( cl->state >= cs_connected )
@ -731,6 +734,29 @@ void SV_SendMessagesToAll( void )
SV_SendClientMessages();
}
/*
=======================
SV_SkipUpdates
used before changing level
=======================
*/
void SV_SkipUpdates( void )
{
int i;
sv_client_t *cl;
if( sv.state == ss_dead )
return;
for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
{
if( cl->state != cs_spawned || cl->fakeclient )
continue;
cl->skip_message = true;
}
}
/*
=======================
SV_InactivateClients

View File

@ -560,6 +560,18 @@ void SV_FreeEdict( edict_t *pEdict )
// unlink from world
SV_UnlinkEdict( pEdict );
// never remove global entities from map
if( pEdict->v.globalname && sv.state == ss_active )
{
pEdict->v.solid = SOLID_NOT;
pEdict->v.flags &= ~FL_KILLME;
pEdict->v.effects = EF_NODRAW;
pEdict->v.movetype = MOVETYPE_NONE;
pEdict->v.modelindex = 0;
pEdict->v.nextthink = -1;
return;
}
if( pEdict->pvPrivateData )
{
if( svgame.dllFuncs2.pfnOnFreeEntPrivateData )
@ -912,6 +924,8 @@ void pfnChangeLevel( const char* s1, const char* s2 )
svs.changelevel_next_time = host.realtime + 1.0f; // rest 1 secs if failed
SV_SkipUpdates ();
if( !s2 ) Cbuf_AddText( va( "changelevel %s\n", s1 )); // Quake changlevel
else Cbuf_AddText( va( "changelevel %s %s\n", s1, s2 )); // Half-Life changelevel
}
@ -1341,32 +1355,60 @@ disable entity updates to client
*/
static void pfnMakeStatic( edict_t *ent )
{
int index, i;
if( !SV_IsValidEdict( ent ))
{
MsgDev( D_WARN, "SV_MakeStatic: invalid entity %s\n", SV_ClassName( ent ));
return;
}
// FIXME: write svc_spawnstatic to the client
ent->v.flags |= FL_KILLME;
index = SV_ModelIndex( STRING( ent->v.model ));
BF_WriteByte( &sv.signon, svc_spawnstatic );
BF_WriteShort(&sv.signon, index );
BF_WriteByte( &sv.signon, ent->v.sequence );
BF_WriteByte( &sv.signon, ent->v.frame );
BF_WriteWord( &sv.signon, ent->v.colormap );
BF_WriteByte( &sv.signon, ent->v.skin );
for(i = 0; i < 3; i++ )
{
BF_WriteBitCoord( &sv.signon, ent->v.origin[i] );
BF_WriteBitAngle( &sv.signon, ent->v.angles[i], 16 );
}
BF_WriteByte( &sv.signon, ent->v.rendermode );
if( ent->v.rendermode != kRenderNormal )
{
BF_WriteByte( &sv.signon, ent->v.renderamt );
BF_WriteByte( &sv.signon, ent->v.rendercolor[0] );
BF_WriteByte( &sv.signon, ent->v.rendercolor[1] );
BF_WriteByte( &sv.signon, ent->v.rendercolor[2] );
BF_WriteByte( &sv.signon, ent->v.renderfx );
}
// remove at end of the frame
ent->v.flags |= FL_KILLME;
}
/*
=============
pfnLinkEntity
pfnEntIsOnFloor
Xash3D extension
legacy builtin
=============
*/
static void pfnLinkEntity( edict_t *e, int touch_triggers )
static int pfnEntIsOnFloor( edict_t *e )
{
if( !SV_IsValidEdict( e ))
{
MsgDev( D_WARN, "SV_LinkEntity: invalid entity %s\n", SV_ClassName( e ));
return;
MsgDev( D_WARN, "SV_CheckBottom: invalid entity %s\n", SV_ClassName( e ));
return 0;
}
SV_LinkEdict( e, touch_triggers );
return SV_CheckBottom( e, MOVE_NORMAL );
}
/*
@ -1429,7 +1471,19 @@ int pfnWalkMove( edict_t *ent, float yaw, float dist, int iMode )
yaw = yaw * M_PI * 2 / 360;
VectorSet( move, com.cos( yaw ) * dist, com.sin( yaw ) * dist, 0.0f );
return SV_WalkMove( ent, move, iMode );
switch( iMode )
{
case WALKMOVE_NORMAL:
return SV_MoveStep( ent, move, true );
case WALKMOVE_WORLDONLY:
return SV_MoveTest( ent, move, true );
case WALKMOVE_CHECKONLY:
return SV_MoveStep( ent, move, false);
default:
MsgDev( D_ERROR, "SV_WalkMove: invalid walk mode %i.\n", iMode );
break;
}
return false;
}
/*
@ -1623,7 +1677,7 @@ void pfnEmitAmbientSound( edict_t *ent, float *pos, const char *sample, float vo
BF_WriteByte( &sv.multicast, svc_ambientsound );
BF_WriteWord( &sv.multicast, flags );
BF_WriteWord( &sv.multicast, sound_idx );
BF_WriteByte( &sv.multicast, CHAN_AUTO );
BF_WriteByte( &sv.multicast, CHAN_STATIC );
if( flags & SND_VOLUME ) BF_WriteByte( &sv.multicast, vol * 255 );
if( flags & SND_ATTENUATION ) BF_WriteByte( &sv.multicast, attn * 64 );
@ -1651,6 +1705,7 @@ static void pfnTraceLine( const float *v1, const float *v2, int fNoMonsters, edi
svgame.globals->trace_flags = 0;
*ptr = SV_Move( v1, vec3_origin, vec3_origin, v2, fNoMonsters, pentToSkip );
SV_CopyTraceToGlobal( ptr );
}
/*
@ -1670,6 +1725,7 @@ static void pfnTraceToss( edict_t* pent, edict_t* pentToIgnore, TraceResult *ptr
}
*ptr = SV_MoveToss( pent, pentToIgnore );
SV_CopyTraceToGlobal( ptr );
}
/*
@ -1687,6 +1743,7 @@ static void pfnTraceHull( const float *v1, const float *v2, int fNoMonsters, int
svgame.globals->trace_flags = 0;
*ptr = SV_MoveHull( v1, hullNumber, v2, fNoMonsters, pentToSkip );
SV_CopyTraceToGlobal( ptr );
}
/*
@ -1698,7 +1755,6 @@ pfnTraceMonsterHull
static int pfnTraceMonsterHull( edict_t *pEdict, const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr )
{
trace_t result;
float *mins, *maxs;
if( !SV_IsValidEdict( pEdict ))
{
@ -1710,15 +1766,16 @@ static int pfnTraceMonsterHull( edict_t *pEdict, const float *v1, const float *v
fNoMonsters |= FMOVE_SIMPLEBOX;
svgame.globals->trace_flags = 0;
mins = pEdict->v.mins;
maxs = pEdict->v.maxs;
result = SV_Move( v1, pEdict->v.mins, pEdict->v.maxs, v2, fNoMonsters, pentToSkip );
if( ptr )
{
SV_CopyTraceToGlobal( ptr );
*ptr = result;
}
if( VectorIsNAN( v1 ) || VectorIsNAN( v2 ))
Host_Error( "TraceMonsterHull: NAN errors detected '%f %f %f', '%f %f %f'\n", v1[0], v1[1], v1[2], v2[0], v2[1], v2[2] );
result = SV_Move( v1, mins, maxs, v2, fNoMonsters, pentToSkip );
if( ptr ) Mem_Copy( ptr, &result, sizeof( *ptr ));
return ptr->fAllSolid;
if( result.fAllSolid || result.flFraction != 1.0f )
return true;
return false;
}
/*
@ -1744,6 +1801,7 @@ static void pfnTraceModel( const float *v1, const float *v2, int hullNumber, edi
maxs = sv.worldmodel->hulls[hullNumber].clip_maxs;
*ptr = SV_TraceHull( pent, hullNumber, v1, mins, maxs, v2 );
SV_CopyTraceToGlobal( ptr );
}
/*
@ -2294,23 +2352,26 @@ static void pfnAlertMessage( ALERT_TYPE level, char *szFmt, ... )
com.vsnprintf( buffer, 2048, szFmt, args );
va_end( args );
if( host.developer < level )
return;
switch( level )
if( level == at_notice )
{
case at_notice:
case at_console:
case at_aiconsole:
com.print( buffer );
break;
case at_warning:
com.print( va( "^3Warning:^7 %s", buffer ));
break;
case at_error:
com.print( va( "^1Error:^7 %s", buffer ));
break;
com.print( buffer ); // notice printing always
}
else if( level == at_console && host.developer >= D_INFO )
{
com.print( buffer );
}
else if( level == at_aiconsole && host.developer >= D_AICONSOLE )
{
com.print( buffer );
}
else if( level == at_warning && host.developer >= D_WARN )
{
com.print( va( "^3Warning:^7 %s", buffer ));
}
else if( level == at_error && host.developer >= D_ERROR )
{
com.print( va( "^1Error:^7 %s", buffer ));
}
}
/*
@ -3636,7 +3697,7 @@ static enginefuncs_t gEngfuncs =
pfnRemoveEntity,
pfnCreateNamedEntity,
pfnMakeStatic,
pfnLinkEntity,
pfnEntIsOnFloor,
pfnDropToFloor,
pfnWalkMove,
pfnSetOrigin,

View File

@ -172,11 +172,11 @@ void SV_DeactivateServer( void )
if( !svs.initialized ) return;
SV_FreeEdicts ();
if( sv.state == ss_dead ) return;
sv.state = ss_dead;
SV_FreeEdicts ();
if( svgame.globals->pStringBase )
Mem_EmptyPool( svgame.stringspool );
else StringTable_Clear( svgame.hStringTable );

View File

@ -22,7 +22,7 @@ is not a staircase.
=============
*/
bool SV_CheckBottom( edict_t *ent, float flStepSize, int iMode )
bool SV_CheckBottom( edict_t *ent, int iMode )
{
vec3_t mins, maxs, start, stop;
float mid, bottom;
@ -50,12 +50,12 @@ bool SV_CheckBottom( edict_t *ent, float flStepSize, int iMode )
return true; // we got out easy
realcheck:
// check it for real...
start[2] = mins[2] + flStepSize;
start[2] = mins[2] + svgame.movevars.stepsize;
// the midpoint must be within 16 of the bottom
start[0] = stop[0] = (mins[0] + maxs[0]) * 0.5f;
start[1] = stop[1] = (mins[1] + maxs[1]) * 0.5f;
stop[2] = start[2] - 2 * flStepSize;
stop[2] = start[2] - 2 * svgame.movevars.stepsize;
if( iMode == WALKMOVE_WORLDONLY )
trace = SV_Move( start, vec3_origin, vec3_origin, stop, MOVE_WORLDONLY, ent );
@ -79,7 +79,7 @@ realcheck:
if( trace.flFraction != 1.0f && trace.vecEndPos[2] > bottom )
bottom = trace.vecEndPos[2];
if( trace.flFraction == 1.0f || mid - trace.vecEndPos[2] > flStepSize )
if( trace.flFraction == 1.0f || mid - trace.vecEndPos[2] > svgame.movevars.stepsize )
return false;
}
}
@ -110,199 +110,350 @@ float SV_VecToYaw( const vec3_t src )
}
//============================================================================
/*
======================
SV_WalkMove
======================
*/
bool SV_WalkMove( edict_t *ent, const vec3_t move, int iMode )
bool SV_MoveStep( edict_t *ent, vec3_t move, bool relink )
{
int i;
trace_t trace;
vec3_t oldorg, neworg, end;
edict_t *groundent = NULL;
float flStepSize;
bool relink;
edict_t *enemy;
float dz;
if( iMode == WALKMOVE_NORMAL )
relink = true;
else relink = false;
// try the move
VectorCopy( ent->v.origin, oldorg );
VectorAdd( oldorg, move, neworg );
// flying pawns don't step up
VectorAdd( ent->v.origin, move, neworg );
// well, try it. Flying and swimming monsters are easiest.
if( ent->v.flags & ( FL_SWIM|FL_FLY ))
{
if( iMode == WALKMOVE_WORLDONLY )
trace = SV_Move( oldorg, ent->v.mins, ent->v.maxs, neworg, MOVE_WORLDONLY, ent );
else trace = SV_Move( oldorg, ent->v.mins, ent->v.maxs, neworg, MOVE_NORMAL, ent );
// try one move with vertical motion, then one without
for( i = 0; i < 2; i++ )
{
VectorAdd( ent->v.origin, move, neworg );
enemy = ent->v.enemy;
if( i == 0 && enemy != NULL )
{
dz = ent->v.origin[2] - enemy->v.origin[2];
if( dz > 40 ) neworg[2] -= 8;
else if( dz < 30 ) neworg[2] += 8;
}
trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, neworg, MOVE_NORMAL, ent );
if( trace.flFraction == 1.0f )
{
svs.groupmask = ent->v.groupinfo;
// 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.vecEndPos ) == CONTENTS_EMPTY )
{
return 0;
}
VectorCopy( trace.vecEndPos, ent->v.origin );
if( relink != 0 )
{
SV_LinkEdict( ent, true );
}
return 1;
}
else
{
if( enemy == NULL )
break;
}
}
return 0;
}
else
{
dz = svgame.movevars.stepsize;
neworg[2] += dz;
VectorCopy( neworg, end );
end[2] -= dz * 2.0f;
trace = SV_Move( neworg, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent );
if( trace.fAllSolid != 0 )
return 0;
if( trace.fStartSolid != 0 )
{
neworg[2] -= dz;
trace = SV_Move( neworg, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent );
if( trace.fAllSolid != 0 || trace.fStartSolid != 0 )
return 0;
}
if( trace.flFraction == 1.0f )
{
if( ent->v.flags & FL_SWIM && SV_PointContents( trace.vecEndPos ) == CONTENTS_EMPTY )
return false; // swim monster left water
if( ent->v.flags & FL_PARTIALGROUND )
{
VectorAdd( ent->v.origin, move, ent->v.origin );
if( relink != 0 )
{
SV_LinkEdict( ent, true );
}
ent->v.flags &= ~FL_ONGROUND;
return 1;
}
return 0;
}
else
{
VectorCopy( trace.vecEndPos, ent->v.origin );
if( !VectorCompare( ent->v.origin, oldorg ))
SV_LinkEdict( ent, relink );
return true;
if( SV_CheckBottom( ent, MOVE_NORMAL ) == 0 )
{
if( ent->v.flags & FL_PARTIALGROUND )
{
if( relink != 0 )
{
SV_LinkEdict( ent, true );
}
return 1;
}
VectorCopy( oldorg, ent->v.origin );
return 0;
}
else
{
if( ent->v.flags & FL_PARTIALGROUND )
ent->v.flags &= ~FL_PARTIALGROUND;
ent->v.groundentity = trace.pHit;
if( relink != 0 )
{
SV_LinkEdict( ent, true );
}
return 1;
}
}
return false;
}
}
// push down from a step height above the wished position
flStepSize = svgame.movevars.stepsize;
neworg[2] += flStepSize;
bool SV_MoveTest( edict_t *ent, vec3_t move, bool relink )
{
float temp;
vec3_t oldorg, neworg, end;
trace_t trace;
VectorCopy( ent->v.origin, oldorg );
VectorAdd( ent->v.origin, move, neworg );
temp = svgame.movevars.stepsize;
neworg[2] += temp;
VectorCopy( neworg, end );
end[2] -= flStepSize * 2;
end[2] -= temp * 2.0f;
if( iMode == WALKMOVE_WORLDONLY )
trace = SV_Move( neworg, ent->v.mins, ent->v.maxs, end, MOVE_WORLDONLY, ent );
else trace = SV_Move( neworg, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent );
if( trace.fAllSolid )
return false;
trace = SV_Move( neworg, ent->v.mins, ent->v.maxs, end, MOVE_WORLDONLY, ent );
if( trace.fStartSolid )
if( trace.fAllSolid != 0 )
return 0;
if( trace.fStartSolid != 0 )
{
neworg[2] -= flStepSize;
neworg[2] -= temp;
trace = SV_Move( neworg, ent->v.mins, ent->v.maxs, end, MOVE_WORLDONLY, ent );
if( iMode == WALKMOVE_WORLDONLY )
trace = SV_Move( neworg, ent->v.mins, ent->v.maxs, end, MOVE_WORLDONLY, ent );
else trace = SV_Move( neworg, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent );
if( trace.fAllSolid || trace.fStartSolid )
return false;
if( trace.fAllSolid != 0 || trace.fStartSolid != 0 )
return 0;
}
if( trace.flFraction == 1.0f )
{
// if monster had the ground pulled out, go ahead and fall
if( ent->v.flags & FL_PARTIALGROUND )
{
VectorAdd( ent->v.origin, move, ent->v.origin );
if( !VectorCompare( ent->v.origin, oldorg ))
SV_LinkEdict( ent, relink );
ent->v.flags &= ~FL_ONGROUND;
return true;
}
return false; // walked off an edge
}
// check point traces down for dangling corners
VectorCopy( trace.vecEndPos, ent->v.origin );
groundent = trace.pHit;
// check our pos
if( iMode == WALKMOVE_WORLDONLY )
trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, MOVE_WORLDONLY, ent );
else trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, MOVE_NORMAL, ent );
if( trace.fStartSolid )
{
VectorCopy( oldorg, ent->v.origin );
return false;
}
if( !SV_CheckBottom( ent, flStepSize, iMode ))
{
if( ent->v.flags & FL_PARTIALGROUND )
{
// actor had floor mostly pulled out from underneath it
// and is trying to correct
if( !VectorCompare( ent->v.origin, oldorg ))
SV_LinkEdict( ent, relink );
return true;
}
ent->v.flags |= FL_PARTIALGROUND;
VectorCopy( oldorg, ent->v.origin );
return false;
}
if( ent->v.flags & FL_PARTIALGROUND )
ent->v.flags &= ~FL_PARTIALGROUND;
ent->v.groundentity = groundent;
// the move is ok
if( !VectorCompare( ent->v.origin, oldorg ))
SV_LinkEdict( ent, relink );
return true;
}
/*
======================
SV_StepDirection
Turns to the movement direction, and walks the current distance if
facing it.
======================
*/
bool SV_StepDirection( edict_t *ent, float yaw, float dist, int iMode )
{
vec3_t move, oldorigin;
float delta;
yaw = yaw * M_PI * 2 / 360;
VectorSet( move, com.cos( yaw ) * dist, com.sin( yaw ) * dist, 0.0f );
VectorCopy( ent->v.origin, oldorigin );
if( SV_WalkMove( ent, move, WALKMOVE_NORMAL ))
{
if( iMode != MOVE_STRAFE )
{
delta = ent->v.angles[YAW] - ent->v.ideal_yaw;
if( delta > 45 && delta < 315 )
{
// not turned far enough, so don't take the step
VectorCopy( oldorigin, ent->v.origin );
if( relink != 0 )
{
SV_LinkEdict( ent, true );
}
ent->v.flags &= ~FL_ONGROUND;
return 1;
}
SV_LinkEdict( ent, false );
return true;
}
SV_LinkEdict( ent, false );
return false;
}
/*
======================
SV_MoveToOrigin
Turns to the movement direction, and walks the current distance if
facing it.
======================
*/
void SV_MoveToOrigin( edict_t *ed, const vec3_t goal, float dist, int iMode )
{
float yaw, distToGoal;
vec3_t vecDist;
if( iMode == MOVE_STRAFE )
{
vec3_t delta;
VectorSubtract( goal, ed->v.origin, delta );
VectorNormalizeFast( delta );
yaw = SV_VecToYaw( delta );
return 0;
}
else
{
yaw = ed->v.ideal_yaw;
VectorCopy( trace.vecEndPos, ent->v.origin );
if( SV_CheckBottom( ent, MOVE_WORLDONLY ) == 0 )
{
if( ent->v.flags & FL_PARTIALGROUND )
{
if( relink != 0 )
{
SV_LinkEdict( ent, true );
}
return 1;
}
VectorCopy( oldorg, ent->v.origin );
return 0;
}
else
{
if( ent->v.flags & FL_PARTIALGROUND )
ent->v.flags &= ~FL_PARTIALGROUND;
ent->v.groundentity = trace.pHit;
if( relink != 0 )
{
SV_LinkEdict( ent, true );
}
return 1;
}
}
}
bool SV_StepDirection( edict_t *ent, float yaw, float dist )
{
int ret;
vec3_t move;
yaw = yaw * M_PI * 2 / 360;
VectorSet( move, com.cos( yaw ) * dist, com.sin( yaw ) * dist, 0.0f );
ret = SV_MoveStep( ent, move, 0 );
SV_LinkEdict( ent, true );
return ret;
}
bool SV_FlyDirection( edict_t *ent, vec3_t move )
{
int ret;
ret = SV_MoveStep( ent, move, 0 );
SV_LinkEdict( ent, true );
return ret;
}
void SV_NewChaseDir( edict_t *actor, vec3_t destination, float dist )
{
float deltax, deltay;
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 );
deltax = destination[0] - actor->v.origin[0];
deltay = destination[1] - actor->v.origin[1];
if( deltax > 10 )
d[1] = 0.0f;
else if( deltax < -10 )
d[1] = 180.0f;
else d[1] = -1;
if( deltay < -10 )
d[2] = 270.0f;
else if( deltay > 10 )
d[2] = 90.0f;
else d[2] = -1;
// try direct route
if( d[1] != -1 && d[2] != -1 )
{
if( d[1] == 0.0f )
tempdir = ( d[2] == 90.0f ) ? 45.0f : 315.0f;
else tempdir = ( d[2] == 90.0f ) ? 135.0f : 215.0f;
if( tempdir != turnaround && SV_StepDirection( actor, tempdir, dist ))
return;
}
// try other directions
if( Com_RandomLong( 0, 1 ) != 0 || fabs( deltay ) > fabs( deltax ))
{
tempdir = d[1];
d[1] = d[2];
d[2] = tempdir;
}
VectorSubtract( ed->v.origin, goal, vecDist );
distToGoal = com.sqrt( vecDist[0] * vecDist[0] + vecDist[1] * vecDist[1] );
if( dist > distToGoal ) dist = distToGoal;
if( d[1] != -1 && d[1] != turnaround && SV_StepDirection( actor, d[1], dist ))
return;
SV_StepDirection( ed, yaw, dist, iMode );
if( d[2] != -1 && d[2] != turnaround && SV_StepDirection( actor, d[2], dist ))
return;
// there is no direct path to the player, so pick another direction
if( olddir != -1 && SV_StepDirection( actor, olddir, dist ))
return;
// fine, just run somewhere.
if( Com_RandomLong( 0, 1 ) != 1 )
{
for( tempdir = 0; tempdir <= 315; tempdir += 45 )
{
if( tempdir != turnaround && SV_StepDirection( actor, tempdir, dist ))
return;
}
}
else
{
for( tempdir = 315; tempdir >= 0; tempdir -= 45 )
{
if( tempdir != turnaround && SV_StepDirection( actor, tempdir, dist ))
return;
}
}
// we tried. Run backwards. THAT ought to work...
if( turnaround != -1 && SV_StepDirection( actor, turnaround, dist ))
return;
// well, we're stuck somehow.
actor->v.ideal_yaw = olddir;
// 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;
}
}
void SV_MoveToOrigin( edict_t *ent, const vec3_t pflGoal, float dist, int iMoveType )
{
vec3_t vecDist;
VectorCopy( pflGoal, vecDist );
if( ent->v.flags & ( FL_FLY|FL_SWIM|FL_ONGROUND ))
{
if( iMoveType == MOVE_NORMAL )
{
if( SV_StepDirection( ent, ent->v.ideal_yaw, dist ) == 0 )
{
SV_NewChaseDir( ent, vecDist, dist );
}
}
else
{
vecDist[0] -= ent->v.origin[0];
vecDist[1] -= ent->v.origin[1];
if( ent->v.flags & ( FL_FLY|FL_SWIM ))
vecDist[2] -= ent->v.origin[2];
else vecDist[2] = 0.0f;
VectorNormalize( vecDist );
VectorScale( vecDist, dist, vecDist );
SV_FlyDirection( ent, vecDist );
}
}
}

View File

@ -176,6 +176,7 @@ void SV_Impact( edict_t *e1, trace_t *trace )
return;
}
svgame.globals->time = sv.time;
SV_CopyTraceToGlobal( trace );
if( !e1->free && !e2->free && e1->v.solid != SOLID_NOT )
@ -562,7 +563,7 @@ trace_t SV_PushEntity( edict_t *ent, const vec3_t lpush, const vec3_t apush, int
type = MOVE_NOMONSTERS; // only clip against bmodels
else type = MOVE_NORMAL;
trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, end, type|FMOVE_SIMPLEBOX, ent );
trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, end, type, ent );
if( !trace.fAllSolid && !trace.fStartSolid )
{
VectorCopy( trace.vecEndPos, ent->v.origin );
@ -928,12 +929,14 @@ void SV_Physics_Pusher( edict_t *ent )
if( thinktime > oldtime && thinktime <= ent->v.ltime )
{
ent->v.nextthink = 0.0f;
svgame.globals->time = sv.time;
svgame.dllFuncs.pfnThink( ent );
if( ent->free ) return;
}
else if( ent->v.flags & FL_ALWAYSTHINK || ( sv.state == ss_loading && !sv.loadgame ))
{
ent->v.nextthink = 0.0f;
svgame.globals->time = sv.time;
svgame.dllFuncs.pfnThink( ent );
if( ent->free ) return;
}

View File

@ -367,6 +367,8 @@ void SV_TouchLinks( edict_t *ent, areanode_t *node )
if( SV_HullPointContents( hull, hull->firstclipnode, test ) == CONTENTS_EMPTY )
continue;
}
svgame.globals->time = sv.time;
svgame.dllFuncs.pfnTouch( touch, ent );
}
@ -933,6 +935,83 @@ trace_t SV_TraceHull( edict_t *ent, int hullNum, const vec3_t start, vec3_t mins
return trace;
}
/* DESCRIPTION: SurfaceAtPoint
// LOCATION:
// PATH: TraceTexture, recursive
//
// A weird one. First, it seems to recursively call itself to dig deep into
// the node tree, treating its own failure as a sign that it's dug deep
// enough. Then, it loops through some odd texture stuff, looking for
// a match. A match of what? Don't know yet.
*/
msurface_t *SV_RecursiveSurfCheck( model_t *model, mnode_t *node, vec3_t v1, vec3_t v2 )
{
double var_4, var_8, var_c;
int var_10, var_10_2;
mplane_t * var_14_plane;
vec3_t var_20;
msurface_t * var_24_surface;
int var_28, var_2c;
int var_30, var_34;
int var_38;
mtexinfo_t * var_3C_texinfo;
if(node->contents < 0) { return(NULL); }
var_14_plane = node->plane;
var_4 = ((v1[0] * var_14_plane->normal[0]) + (v1[1] * var_14_plane->normal[1]) + (v1[2] * var_14_plane->normal[2])) - var_14_plane->dist;
var_8 = ((v2[0] * var_14_plane->normal[0]) + (v2[1] * var_14_plane->normal[1]) + (v2[2] * var_14_plane->normal[2])) - var_14_plane->dist;
if(var_4 < 0) { var_10 = 1; }
else { var_10 = 0; }
if(var_8 < 0) { var_10_2 = 1; }
else { var_10_2 = 0; }
if(var_10 == var_10_2) {
return(SV_RecursiveSurfCheck(model, node->children[var_10], v1, v2));
}
var_c = var_4 / (var_4 - var_8);
var_20[0] = ((v2[0] - v1[0]) * var_c) + v1[0];
var_20[1] = ((v2[1] - v1[1]) * var_c) + v1[1];
var_20[2] = ((v2[2] - v1[2]) * var_c) + v1[2];
//Now THIS is weird.
var_24_surface = SV_RecursiveSurfCheck(model, node->children[var_10], v1, var_20);
if(var_24_surface != NULL || var_10 == var_10_2) { return(var_24_surface); } //Second check not possible as in asm... I think.
var_24_surface = node->firstface;
for(var_38 = 0; var_38 < node->numfaces; var_38++, var_24_surface++) {
var_3C_texinfo = var_24_surface->texinfo;
var_28 = (var_20[0] * var_3C_texinfo->vecs[0][0]) + (var_20[1] * var_3C_texinfo->vecs[0][1]) + (var_20[2] * var_3C_texinfo->vecs[0][2]) + var_3C_texinfo->vecs[0][3];
var_2c = (var_20[0] * var_3C_texinfo->vecs[1][0]) + (var_20[1] * var_3C_texinfo->vecs[1][1]) + (var_20[2] * var_3C_texinfo->vecs[1][2]) + var_3C_texinfo->vecs[1][3];
if(var_28 >= var_24_surface->texturemins[0] && var_2c >= var_24_surface->texturemins[1]) {
var_30 = var_28 - var_24_surface->texturemins[0];
var_34 = var_2c - var_24_surface->texturemins[1];
if(var_30 <= var_24_surface->extents[0] && var_34 <= var_24_surface->extents[1]) {
return(var_24_surface);
}
}
}
if(var_10 == 1) { var_10 = 0; }
else { var_10 = 1; }
return(SV_RecursiveSurfCheck( model, node->children[var_10], var_20, v2 ));
}
/*
====================
SV_ClipToLinks