15 Oct 2011

This commit is contained in:
g-cont 2011-10-15 00:00:00 +04:00 committed by Alibek Omarov
parent 0ccdeddcea
commit 5157440f45
33 changed files with 812 additions and 156 deletions

View File

@ -42,12 +42,15 @@ GameUI: added support for Steam backgrounds
GameUI: hide input symbols for "password" field in "create server" menu page
Client: initial implementation of NetAPI
Render: clear decals code. Add transparent rendering for 'glass' decals
GameUI: added new function into menu interface called a pfnProcessImage, added new argument for pfnPIC_Load.
GameUI: added new argument for pfnPIC_Load.
GameUI: fix loading flipped Steam background images
Client: remove gravity for R_Implosion effect
Sound: add SND_MoveMouth16 for support 16-bit sounds lip-sync
Engine: fix potentially crash during parsing titles.txt when file is empty
Engine: increase MAX_VALUE field up to 2048 characters
Console: rename con_gamemaps to con_mapfilter
Sound: add check by PVS for dynamic entity channels
Sound: add sound culling by geometry (cvar 's_cull' for enable or disable)
build 1662

View File

@ -317,12 +317,20 @@ splash logo while map is loading
*/
void CL_LevelShot_f( void )
{
size_t ft1, ft2;
if( cls.scrshot_request != scrshot_plaque ) return;
cls.scrshot_request = scrshot_inactive;
// check for exist
Q_sprintf( cls.shotname, "levelshots/%s.bmp", clgame.mapname );
if( !FS_FileExists( cls.shotname, true ))
// make sure what entity patch is never than bsp
ft1 = FS_FileTime( cl.worldmodel->name, false );
ft2 = FS_FileTime( cls.shotname, true );
// missing levelshot or level never than levelshot
if( ft2 == -1 || ft1 > ft2 )
cls.scrshot_action = scrshot_plaque; // build new frame for levelshot
else cls.scrshot_action = scrshot_inactive; // disable - not needs
}

View File

@ -120,9 +120,9 @@ void CL_UpdateEntityFields( cl_entity_t *ent )
if( applyVel || applyAvel )
{
ent->origin[0] += ( m_pGround->curstate.origin[0] - m_pGround->latched.prevorigin[0] ) * d;
ent->origin[1] += ( m_pGround->curstate.origin[1] - m_pGround->latched.prevorigin[1] ) * d;
ent->origin[2] += ( m_pGround->curstate.origin[2] - m_pGround->latched.prevorigin[2] ) * d;
ent->origin[0] += ( m_pGround->curstate.origin[0] - m_pGround->prevstate.origin[0] ) * d;
ent->origin[1] += ( m_pGround->curstate.origin[1] - m_pGround->prevstate.origin[1] ) * d;
ent->origin[2] += ( m_pGround->curstate.origin[2] - m_pGround->prevstate.origin[2] ) * d;
}
if( applyAvel )
@ -132,7 +132,7 @@ void CL_UpdateEntityFields( cl_entity_t *ent )
float ang1, ang2;
ang1 = m_pGround->curstate.angles[i];
ang2 = m_pGround->latched.prevangles[i];
ang2 = m_pGround->prevstate.angles[i];
f = ang1 - ang2;
if( d > 180 ) f -= 360;
else if( d < -180 ) f += 360;
@ -881,13 +881,15 @@ void CL_AddEntities( void )
//
// sound engine implementation
//
qboolean CL_GetEntitySpatialization( int entnum, vec3_t origin )
qboolean CL_GetEntitySpatialization( int entnum, vec3_t origin, float *pradius )
{
cl_entity_t *ent;
qboolean valid_origin;
ASSERT( origin != NULL );
if( entnum == 0 ) return true; // static sound
valid_origin = VectorIsNull( origin ) ? false : true;
ent = CL_GetEntityByIndex( entnum );
@ -902,6 +904,10 @@ qboolean CL_GetEntitySpatialization( int entnum, vec3_t origin )
VectorAverage( ent->curstate.mins, ent->curstate.maxs, origin );
VectorAdd( origin, ent->curstate.origin, origin );
// setup radius
if( pradius && ent->model != NULL )
*pradius = ent->model->radius;
return true;
}

View File

@ -924,6 +924,7 @@ static ui_enginefuncs_t gEngfuncs =
IN_SetCursor,
pfnIsMapValid,
GL_ProcessTexture,
COM_CompareFileTime,
};
void UI_UnloadProgs( void )

View File

@ -711,7 +711,7 @@ qboolean CL_InitStudioAPI( void );
void CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta );
qboolean CL_AddVisibleEntity( cl_entity_t *ent, int entityType );
void CL_UpdateStudioVars( cl_entity_t *ent, entity_state_t *newstate, qboolean noInterp );
qboolean CL_GetEntitySpatialization( int entnum, vec3_t origin );
qboolean CL_GetEntitySpatialization( int entnum, vec3_t origin, float *pradius );
void CL_UpdateEntityFields( cl_entity_t *ent );
qboolean CL_IsPlayerIndex( int idx );

View File

@ -1158,7 +1158,6 @@ void R_RenderFrame( const ref_params_t *fd, qboolean drawWorld )
return;
if( drawWorld ) r_lastRefdef = *fd;
GL_BackendStartFrame();
RI.params = RP_NONE;
RI.farClip = 0;
@ -1167,6 +1166,8 @@ void R_RenderFrame( const ref_params_t *fd, qboolean drawWorld )
RI.thirdPerson = cl.thirdperson;
RI.drawOrtho = gl_overview->integer;
GL_BackendStartFrame();
// adjust field of view for widescreen
if( glState.wideScreen && r_adjust_fov->integer )
V_AdjustFov( &RI.refdef.fov_x, &RI.refdef.fov_y, glState.width, glState.height, false );

View File

@ -32,7 +32,7 @@ typedef struct
static const dmaterial_t detail_table[] =
{
{ "crt", "dt_conc", 'C', 0, 0 }, // concrete
{ "rock", "dt_rock", 'C', 0, 0 },
{ "rock", "dt_rock1", 'C', 0, 0 },
{ "conc", "dt_conc", 'C', 0, 0 },
{ "wall", "dt_brick", 'C', 0, 0 },
{ "crete", "dt_conc", 'C', 0, 0 },
@ -137,6 +137,8 @@ static const char *R_DetailTextureForName( const char *name )
return NULL;
if( !Q_strnicmp( name, "3dsky", 5 )) // xash-mod support :-)
return NULL;
if( !Q_strnicmp( name, "scroll", 6 ))
return NULL;
if( name[0] == '@' )
return NULL;

View File

@ -508,7 +508,7 @@ float R_GetSpriteFrameInterpolant( cl_entity_t *ent, mspriteframe_t **oldframe,
}
else if( frame >= psprite->numframes )
{
MsgDev( D_WARN, "R_GetSpriteFrame: no such frame %d (%s)\n", frame, ent->model->name );
MsgDev( D_WARN, "R_GetSpriteFrameInterpolant: no such frame %d (%s)\n", frame, ent->model->name );
frame = psprite->numframes - 1;
}

View File

@ -441,7 +441,7 @@ qboolean R_CullStudioModel( cl_entity_t *e )
{
vec3_t origin;
if( !e->model->cache.data )
if( !e || !e->model || !e->model->cache.data )
return true;
if( e == &clgame.viewent && r_lefthand->integer >= 2 )

View File

@ -161,21 +161,24 @@ S_FindName
==================
*/
sfx_t *S_FindName( const char *name, int *pfInCache )
sfx_t *S_FindName( const char *pname, int *pfInCache )
{
int i;
sfx_t *sfx;
uint hash;
uint i, hash;
string name;
if( !name || !name[0] || !dma.initialized )
if( !pname || !pname[0] || !dma.initialized )
return NULL;
if( Q_strlen( name ) >= MAX_STRING )
if( Q_strlen( pname ) >= MAX_STRING )
{
MsgDev( D_ERROR, "S_FindSound: sound name too long: %s", name );
MsgDev( D_ERROR, "S_FindSound: sound name too long: %s", pname );
return NULL;
}
Q_strncpy( name, pname, sizeof( name ));
COM_FixSlashes( name );
// see if already loaded
hash = Com_HashKey( name, MAX_SFX_HASH );
for( sfx = s_sfxHashList[hash]; sfx; sfx = sfx->hashNext )

View File

@ -18,8 +18,9 @@ GNU General Public License for more details.
#include "client.h"
#include "con_nprint.h"
#include "ref_params.h"
#include "pm_local.h"
#define MAX_DUPLICATED_CHANNELS 4 // threshold for identical static channels (probably error)
#define MAX_DUPLICATED_CHANNELS 4 // threshold for identical static channels (probably error)
#define SND_CLIP_DISTANCE 1000.0f
dma_t dma;
@ -32,6 +33,8 @@ listener_t s_listener;
int total_channels;
int soundtime; // sample PAIRS
int paintedtime; // sample PAIRS
static int trace_count = 0;
static int last_trace_chan = 0;
convar_t *s_volume;
convar_t *s_musicvolume;
@ -42,8 +45,37 @@ convar_t *s_lerping;
convar_t *s_ambient_level;
convar_t *s_ambient_fade;
convar_t *s_combine_sounds;
convar_t *s_test; // cvar for testing new effects
convar_t *snd_foliage_db_loss;
convar_t *snd_gain;
convar_t *snd_gain_max;
convar_t *snd_gain_min;
convar_t *s_refdist;
convar_t *s_refdb;
convar_t *dsp_off; // set to 1 to disable all dsp processing
convar_t *s_cull; // cull sounds by geometry
convar_t *s_test; // cvar for testing new effects
/*
=============================================================================
SOUND COMMON UTILITES
=============================================================================
*/
// dB = 20 log (amplitude/32768) 0 to -90.3dB
// amplitude = 32768 * 10 ^ (dB/20) 0 to +/- 32768
// gain = amplitude/32768 0 to 1.0
_inline float Gain_To_dB( float gain ) { return 20 * log( gain ); }
_inline float dB_To_Gain ( float dB ) { return pow( 10, dB / 20.0f ); }
_inline float Gain_To_Amplitude( float gain ) { return gain * 32768; }
_inline float Amplitude_To_Gain( float amplitude ) { return amplitude / 32768; }
// convert sound db level to approximate sound source radius,
// used only for determining how much of sound is obscured by world
_inline float dB_To_Radius( float db )
{
return (SND_RADIUS_MIN + (SND_RADIUS_MAX - SND_RADIUS_MIN) * (db - SND_DB_MIN) / (SND_DB_MAX - SND_DB_MIN));
}
/*
=============================================================================
@ -161,6 +193,74 @@ void S_UpdateSoundFade( void )
soundfade.percent = soundfade.initial_percent * f;
}
/*
=================
SND_ChannelOkToTrace
All new sounds must traceline once,
but cap the max number of tracelines performed per frame
for longer or looping sounds to SND_TRACE_UPDATE_MAX.
=================
*/
qboolean SND_ChannelOkToTrace( channel_t *ch )
{
int i, j;
// always trace first time sound is spatialized
if( ch->bfirstpass ) return true;
// if already traced max channels, return
if( trace_count >= SND_TRACE_UPDATE_MAX )
return false;
// search through all channels starting at g_snd_last_trace_chan index
j = last_trace_chan;
for( i = 0; i < total_channels; i++ )
{
if( &( channels[j] ) == ch )
{
ch->bTraced = true;
trace_count++;
return true;
}
// wrap channel index
if( ++j >= total_channels )
j = 0;
}
// why didn't we find this channel?
return false;
}
/*
=================
SND_ChannelTraceReset
reset counters for traceline limiting per audio update
=================
*/
void SND_ChannelTraceReset( void )
{
int i;
// reset search point - make sure we start counting from a new spot
// in channel list each time
last_trace_chan += SND_TRACE_UPDATE_MAX;
// wrap at total_channels
if( last_trace_chan >= total_channels )
last_trace_chan = last_trace_chan - total_channels;
// reset traceline counter
trace_count = 0;
// reset channel traceline flag
for( i = 0; i < total_channels; i++ )
channels[i].bTraced = false;
}
/*
=================
SND_PickDynamicChannel
@ -256,6 +356,7 @@ channel_t *SND_PickStaticChannel( int entnum, sfx_t *sfx, const vec3_t pos )
channel_t *ch = NULL;
int i, dupe = 0;
#if 1 // FIXME: remove this code when predicting is will be done
// check for dupliacte sounds
for( i = 0; i < total_channels; i++ )
{
@ -266,7 +367,7 @@ channel_t *SND_PickStaticChannel( int entnum, sfx_t *sfx, const vec3_t pos )
// check for duplicated static channels (same origin and same sfx)
if( dupe > MAX_DUPLICATED_CHANNELS )
return NULL;
#endif
// check for replacement sound, or find the best one to replace
for( i = MAX_DYNAMIC_CHANNELS; i < total_channels; i++ )
{
@ -361,53 +462,353 @@ int S_AlterChannel( int entnum, int channel, sfx_t *sfx, int vol, int pitch, int
/*
=================
SND_Spatialize
SND_FadeToNewGain
always ramp channel gain changes over time
returns ramped gain, given new target gain
=================
*/
void SND_Spatialize( channel_t *ch )
float SND_FadeToNewGain( channel_t *ch, float gain_new )
{
float dist, dot;
float lscale, rscale, scale;
vec3_t source_vec;
float speed, frametime;
// anything coming from the view entity will allways be full volume
if( S_IsClient( ch->entnum ))
if( gain_new == -1.0 )
{
ch->leftvol = ch->master_vol;
ch->rightvol = ch->master_vol;
return;
// if -1 passed in, just keep fading to existing target
gain_new = ch->ob_gain_target;
}
if( !ch->staticsound )
// if first time updating, store new gain into gain & target, return
// if gain_new is close to existing gain, store new gain into gain & target, return
if( ch->bfirstpass || ( fabs( gain_new - ch->ob_gain ) < 0.01f ))
{
if( !CL_GetEntitySpatialization( ch->entnum, ch->origin ))
ch->ob_gain = gain_new;
ch->ob_gain_target = gain_new;
ch->ob_gain_inc = 0.0f;
return gain_new;
}
// set up new increment to new target
frametime = s_listener.frametime;
speed = ( frametime / SND_GAIN_FADE_TIME ) * ( gain_new - ch->ob_gain );
ch->ob_gain_inc = fabs( speed );
// ch->ob_gain_inc = fabs( gain_new - ch->ob_gain ) / 10.0f;
ch->ob_gain_target = gain_new;
// if not hit target, keep approaching
if( fabs( ch->ob_gain - ch->ob_gain_target ) > 0.01f )
{
ch->ob_gain = ApproachVal( ch->ob_gain_target, ch->ob_gain, ch->ob_gain_inc );
}
else
{
// close enough, set gain = target
ch->ob_gain = ch->ob_gain_target;
}
return ch->ob_gain;
}
/*
=================
SND_GetGainObscured
drop gain on channel if sound emitter obscured by
world, unbroken windows, closed doors, large solid entities etc.
=================
*/
float SND_GetGainObscured( channel_t *ch, qboolean fplayersound, qboolean flooping )
{
float gain = 1.0f;
vec3_t endpoint;
int count = 1;
pmtrace_t tr;
if( fplayersound ) return gain; // unchanged
// during signon just apply regular state machine since world hasn't been
// created or settled yet...
if( !CL_Active( ))
{
gain = SND_FadeToNewGain( ch, -1.0f );
return gain;
}
// don't do gain obscuring more than once on short one-shot sounds
if( !ch->bfirstpass && !ch->isSentence && !flooping && ( ch->entchannel != CHAN_STREAM ))
{
gain = SND_FadeToNewGain( ch, -1.0f );
return gain;
}
// if long or looping sound, process N channels per frame - set 'processed' flag, clear by
// cycling through all channels - this maintains a cap on traces per frame
if( !SND_ChannelOkToTrace( ch ))
{
// just keep updating fade to existing target gain - no new trace checking
gain = SND_FadeToNewGain( ch, -1.0 );
return gain;
}
// set up traceline from player eyes to sound emitting entity origin
VectorCopy( ch->origin, endpoint );
tr = PM_PlayerTrace( clgame.pmove, s_listener.origin, endpoint, PM_STUDIO_IGNORE, 2, -1, NULL );
if(( tr.fraction < 1.0f || tr.allsolid || tr.startsolid ) && tr.fraction < 0.99f )
{
// can't see center of sound source:
// build extents based on dB sndlvl of source,
// test to see how many extents are visible,
// drop gain by g_snd_obscured_loss_db per extent hidden
vec3_t endpoints[4];
int i, sndlvl = DIST_MULT_TO_SNDLVL( ch->dist_mult );
vec3_t vecl, vecr, vecl2, vecr2;
vec3_t vsrc_forward;
vec3_t vsrc_right;
vec3_t vsrc_up;
float radius;
// get radius
if( ch->radius > 0 ) radius = ch->radius;
else radius = dB_To_Radius( sndlvl ); // approximate radius from soundlevel
// set up extent endpoints - on upward or downward diagonals, facing player
for( i = 0; i < 4; i++ ) VectorCopy( endpoint, endpoints[i] );
// vsrc_forward is normalized vector from sound source to listener
VectorSubtract( s_listener.origin, endpoint, vsrc_forward );
VectorNormalize( vsrc_forward );
VectorVectors( vsrc_forward, vsrc_right, vsrc_up );
VectorAdd( vsrc_up, vsrc_right, vecl );
// if src above listener, force 'up' vector to point down - create diagonals up & down
if( endpoint[2] > s_listener.origin[2] + ( 10 * 12 ))
vsrc_up[2] = -vsrc_up[2];
VectorSubtract( vsrc_up, vsrc_right, vecr );
VectorNormalize( vecl );
VectorNormalize( vecr );
// get diagonal vectors from sound source
VectorScale( vecl, radius, vecl2 );
VectorScale( vecr, radius, vecr2 );
VectorScale( vecl, (radius / 2.0f), vecl );
VectorScale( vecr, (radius / 2.0f), vecr );
// endpoints from diagonal vectors
VectorAdd( endpoints[0], vecl, endpoints[0] );
VectorAdd( endpoints[1], vecr, endpoints[1] );
VectorAdd( endpoints[2], vecl2, endpoints[2] );
VectorAdd( endpoints[3], vecr2, endpoints[3] );
// drop gain for each point on radius diagonal that is obscured
for( count = 0, i = 0; i < 4; i++ )
{
// origin is null and entity not exist on client
ch->leftvol = ch->rightvol = 0;
return;
// UNDONE: some endpoints are in walls - in this case, trace from the wall hit location
tr = PM_PlayerTrace( clgame.pmove, s_listener.origin, endpoints[i], PM_STUDIO_IGNORE, 2, -1, NULL );
if(( tr.fraction < 1.0f || tr.allsolid || tr.startsolid ) && tr.fraction < 0.99f && !tr.startsolid )
{
// skip first obscured point: at least 2 points + center should be obscured to hear db loss
if( ++count > 1 ) gain = gain * dB_To_Gain( SND_OBSCURED_LOSS_DB );
}
}
}
// calculate stereo seperation and distance attenuation
VectorSubtract( ch->origin, s_listener.origin, source_vec );
dist = VectorNormalizeLength( source_vec ) * ch->dist_mult;
dot = DotProduct( s_listener.right, source_vec );
// crossfade to new gain
gain = SND_FadeToNewGain( ch, gain );
return gain;
}
/*
=================
SND_GetGain
The complete gain calculation, with SNDLVL given in dB is:
GAIN = 1/dist * snd_refdist * 10 ^ (( SNDLVL - snd_refdb - (dist * snd_foliage_db_loss / 1200)) / 20 )
for gain > SND_GAIN_THRESH, start curve smoothing with
GAIN = 1 - 1 / (Y * GAIN ^ SND_GAIN_POWER)
where Y = -1 / ( (SND_GAIN_THRESH ^ SND_GAIN_POWER) * ( SND_GAIN_THRESH - 1 ))
gain curve construction
=================
*/
float SND_GetGain( channel_t *ch, qboolean fplayersound, qboolean flooping, float dist )
{
float gain = snd_gain->value;
if( ch->dist_mult )
{
// test additional attenuation
// at 30c, 14.7psi, 60% humidity, 1000Hz == 0.22dB / 100ft.
// dense foliage is roughly 2dB / 100ft
float additional_dB_loss = snd_foliage_db_loss->value * (dist / 1200);
float additional_dist_mult = pow( 10, additional_dB_loss / 20 );
float relative_dist = dist * ch->dist_mult * additional_dist_mult;
// hard code clamp gain to 10x normal (assumes volume and external clipping)
if( relative_dist > 0.1f )
gain *= ( 1.0f / relative_dist );
else gain *= 10.0f;
// if gain passess threshold, compress gain curve such that gain smoothly approaches 1.0
if( gain > SND_GAIN_COMP_THRESH )
{
float snd_gain_comp_power = SND_GAIN_COMP_EXP_MAX;
int sndlvl = DIST_MULT_TO_SNDLVL( ch->dist_mult );
float Y;
// decrease compression curve fit for higher sndlvl values
if( sndlvl > SND_DB_MED )
{
// snd_gain_power varies from max to min as sndlvl varies from 90 to 140
snd_gain_comp_power = RemapVal((float)sndlvl, SND_DB_MED, SND_DB_MAX, SND_GAIN_COMP_EXP_MAX, SND_GAIN_COMP_EXP_MIN );
}
// calculate crossover point
Y = -1.0f / ( pow( SND_GAIN_COMP_THRESH, snd_gain_comp_power ) * ( SND_GAIN_COMP_THRESH - 1 ));
// calculate compressed gain
gain = 1.0f - 1.0f / (Y * pow( gain, snd_gain_comp_power ));
gain = gain * snd_gain_max->value;
}
if( gain < snd_gain_min->value )
{
// sounds less than snd_gain_min fall off to 0 in distance it took them to fall to snd_gain_min
gain = snd_gain_min->value * ( 2.0f - relative_dist * snd_gain_min->value );
if( gain <= 0.0f ) gain = 0.001f; // don't propagate 0 gain
}
}
if( fplayersound )
{
// player weapon sounds get extra gain - this compensates
// for npc distance effect weapons which mix louder as L+R into L, R
// Hack.
if( ch->entchannel == CHAN_WEAPON )
gain = gain * dB_To_Gain( SND_GAIN_PLAYER_WEAPON_DB );
}
// modify gain if sound source not visible to player
gain = gain * SND_GetGainObscured( ch, fplayersound, flooping );
return gain;
}
/*
=================
S_SpatializeChannel
=================
*/
void S_SpatializeChannel( int *left_vol, int *right_vol, int master_vol, float gain, float dot, float dist )
{
float lscale, rscale, scale;
rscale = 1.0f + dot;
lscale = 1.0f - dot;
// add in distance effect
scale = ( 1.0f - dist ) * rscale;
ch->rightvol = (int)( ch->master_vol * scale );
ch->rightvol = bound( 0, ch->rightvol, 255 );
if( s_cull->integer ) scale = gain * rscale / 2;
else scale = ( 1.0f - dist ) * rscale;
*right_vol = (int)( master_vol * scale );
scale = ( 1.0f - dist ) * lscale;
ch->leftvol = (int)( ch->master_vol * scale );
ch->leftvol = bound( 0, ch->leftvol, 255 );
if( s_cull->integer ) scale = gain * lscale / 2;
else scale = ( 1.0f - dist ) * lscale;
*left_vol = (int)( master_vol * scale );
*right_vol = bound( 0, *right_vol, 255 );
*left_vol = bound( 0, *left_vol, 255 );
}
/*
=================
SND_Spatialize
=================
*/
void SND_Spatialize( channel_t *ch )
{
vec3_t source_vec;
float dist, dot, gain = 1.0f;
qboolean fplayersound = false;
qboolean looping = false;
wavdata_t *pSource;
// anything coming from the view entity will allways be full volume
if( S_IsClient( ch->entnum ))
{
if( !s_cull->integer )
{
ch->leftvol = ch->master_vol;
ch->rightvol = ch->master_vol;
return;
}
// sounds coming from listener actually come from a short distance directly in front of listener
fplayersound = true;
}
pSource = ch->sfx->cache;
if( ch->use_loop && pSource && pSource->loopStart != -1 )
looping = true;
if( !ch->staticsound )
{
if( !CL_GetEntitySpatialization( ch->entnum, ch->origin, &ch->radius ))
{
// origin is null and entity not exist on client
ch->leftvol = ch->rightvol = 0;
ch->bfirstpass = false;
return;
}
}
// source_vec is vector from listener to sound source
// player sounds come from 1' in front of player
if( fplayersound ) VectorScale( s_listener.forward, 12.0f, source_vec );
else VectorSubtract( ch->origin, s_listener.origin, source_vec );
// normalize source_vec and get distance from listener to source
dist = VectorNormalizeLength( source_vec );
dot = DotProduct( s_listener.right, source_vec );
// for sounds with a radius, spatialize left/right evenly within the radius
if( ch->radius > 0 && dist < ch->radius )
{
float interval = ch->radius * 0.5f;
float blend = dist - interval;
if( blend < 0 ) blend = 0;
blend /= interval;
// blend is 0.0 - 1.0, from 50% radius -> 100% radius
// at radius * 0.5, dot is 0 (ie: sound centered left/right)
// at radius dot == dot
dot *= blend;
}
if( s_cull->integer )
{
// calculate gain based on distance, atmospheric attenuation, interposed objects
// perform compression as gain approaches 1.0
gain = SND_GetGain( ch, fplayersound, looping, dist );
}
// don't pan sounds with no attenuation
if( ch->dist_mult <= 0 ) dot = 0.0f;
// fill out channel volumes for single location
S_SpatializeChannel( &ch->leftvol, &ch->rightvol, ch->master_vol, gain, dot, dist * ch->dist_mult );
// if playing a word, set volume
VOX_SetChanVol( ch );
// end of first time spatializing sound
if( CL_Active( )) ch->bfirstpass = false;
}
/*
@ -481,8 +882,16 @@ void S_StartSound( const vec3_t pos, int ent, int chan, sound_t handle, float fv
target_chan->entchannel = chan;
target_chan->basePitch = pitch;
target_chan->isSentence = false;
target_chan->radius = 0.0f;
target_chan->sfx = sfx;
// initialize gain due to obscured sound source
target_chan->bfirstpass = true;
target_chan->ob_gain = 0.0f;
target_chan->ob_gain_inc = 0.0f;
target_chan->ob_gain_target = 0.0f;
target_chan->bTraced = false;
pSource = NULL;
if( S_TestSoundChar( sfx->name, '!' ))
@ -567,6 +976,7 @@ void S_AmbientSound( const vec3_t pos, int ent, sound_t handle, float fvol, floa
sfx_t *sfx = NULL;
int vol, fvox = 0;
qboolean looping = false;
float radius = SND_RADIUS_MAX;
vec3_t origin;
if( !dma.initialized ) return;
@ -589,12 +999,13 @@ void S_AmbientSound( const vec3_t pos, int ent, sound_t handle, float fvol, floa
return;
}
if( !pos ) pos = origin;
if( pos ) VectorCopy( pos, origin );
else VectorClear( origin );
if( ent != 0 ) CL_GetEntitySpatialization( ent, origin );
CL_GetEntitySpatialization( ent, origin, &radius );
// pick a channel to play on from the static area
ch = SND_PickStaticChannel( ent, sfx, pos );
ch = SND_PickStaticChannel( ent, sfx, origin );
if( !ch ) return;
if( S_TestSoundChar( sfx->name, '!' ))
@ -624,7 +1035,7 @@ void S_AmbientSound( const vec3_t pos, int ent, sound_t handle, float fvol, floa
return;
}
VectorCopy( pos, ch->origin );
VectorCopy( origin, ch->origin );
// never update positions if source entity is 0
ch->staticsound = ( ent == 0 ) ? true : false;
@ -635,6 +1046,14 @@ void S_AmbientSound( const vec3_t pos, int ent, sound_t handle, float fvol, floa
ch->entchannel = CHAN_STATIC;
ch->basePitch = pitch;
ch->entnum = ent;
ch->radius = radius;
// initialize gain due to obscured sound source
ch->bfirstpass = true;
ch->ob_gain = 0.0;
ch->ob_gain_inc = 0.0;
ch->ob_gain_target = 0.0;
ch->bTraced = false;
SND_Spatialize( ch );
}
@ -978,7 +1397,13 @@ void S_RenderFrame( ref_params_t *fd )
total++;
}
}
Con_NPrintf( 0, "----(%i)---- painted: %i\n", total - 1, paintedtime );
// to differentiate modes
if( s_cull->integer ) VectorSet( info.color, 0.0f, 1.0f, 0.0f );
else VectorSet( info.color, 1.0f, 1.0f, 1.0f );
info.index = 0;
Con_NXPrintf( &info, "----(%i)---- painted: %i\n", total - 1, paintedtime );
}
S_StreamBackgroundTrack ();
@ -1097,13 +1522,20 @@ 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_mixahead = Cvar_Get( "_snd_mixahead", "0.1", 0, "how much sound to mix ahead of time" );
s_show = Cvar_Get( "s_show", "0", CVAR_ARCHIVE, "show playing sounds" );
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" );
s_ambient_level = Cvar_Get( "ambient_level", "0.3", 0, "volume of environment noises (water and wind)" );
s_ambient_fade = Cvar_Get( "ambient_fade", "100", 0, "rate of volume fading when client is moving" );
s_combine_sounds = Cvar_Get( "s_combine_channels", "1", CVAR_ARCHIVE, "combine the channels with same sounds" );
s_combine_sounds = Cvar_Get( "s_combine_channels", "1", CVAR_ARCHIVE, "combine channels with same sounds" );
snd_foliage_db_loss = Cvar_Get( "snd_foliage_db_loss", "4", 0, "foliage loss factor" );
snd_gain_max = Cvar_Get( "snd_gain_max", "1", 0, "gain maximal threshold" );
snd_gain_min = Cvar_Get( "snd_gain_min", "0.01", 0, "gain minimal threshold" );
s_refdist = Cvar_Get( "s_refdist", "36", 0, "soundlevel reference distance" );
s_refdb = Cvar_Get( "s_refdb", "60", 0, "soundlevel refernce dB" );
snd_gain = Cvar_Get( "snd_gain", "1", 0, "sound default gain" );
s_cull = Cvar_Get( "s_cull", "1", CVAR_ARCHIVE, "engine developer cvar for quick testing new features" );
s_test = Cvar_Get( "s_test", "0", 0, "engine developer cvar for quick testing new features" );
Cmd_AddCommand( "play", S_Play_f, "playing a specified sound file" );

View File

@ -32,6 +32,23 @@ extern byte *sndpool;
#define SOUND_32k 32000 // 32khz sample rate
#define SOUND_44k 44100 // 44khz sample rate
#define SND_TRACE_UPDATE_MAX 2 // max of N channels may be checked for obscured source per frame
#define SND_RADIUS_MAX 240.0f // max sound source radius
#define SND_RADIUS_MIN 24.0f // min sound source radius
#define SND_OBSCURED_LOSS_DB -2.70f // dB loss due to obscured sound source
// calculate gain based on atmospheric attenuation.
// as gain excedes threshold, round off (compress) towards 1.0 using spline
#define SND_GAIN_COMP_EXP_MAX 2.5f // Increasing SND_GAIN_COMP_EXP_MAX fits compression curve
// more closely to original gain curve as it approaches 1.0.
#define SND_GAIN_FADE_TIME 0.25f // xfade seconds between obscuring gain changes
#define SND_GAIN_COMP_EXP_MIN 0.8f
#define SND_GAIN_COMP_THRESH 0.5f // gain value above which gain curve is rounded to approach 1.0
#define SND_DB_MAX 140.0f // max db of any sound source
#define SND_DB_MED 90.0f // db at which compression curve changes
#define SND_DB_MIN 60.0f // min db of any sound source
#define SND_GAIN_PLAYER_WEAPON_DB 2.0f // increase player weapon gain by N dB
// fixed point stuff for real-time resampling
#define FIX_BITS 28
#define FIX_SCALE (1 << FIX_BITS)
@ -42,6 +59,12 @@ extern byte *sndpool;
#define FIX_FRACTION(a,b) (FIX(a)/(b))
#define FIX_FRACPART(a) ((a) & FIX_MASK)
#define SNDLVL_TO_DIST_MULT( sndlvl ) \
( sndlvl ? ((pow( 10, s_refdb->value / 20 ) / pow( 10, (float)sndlvl / 20 )) / s_refdist->value ) : 0 )
#define DIST_MULT_TO_SNDLVL( dist_mult ) \
(int)( dist_mult ? ( 20 * log10( pow( 10, s_refdb->value / 20 ) / (dist_mult * s_refdist->value ))) : 0 )
// 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);}
@ -138,6 +161,14 @@ typedef struct
qboolean localsound; // it's a local menu sound (not looped, not paused)
mixer_t pMixer;
// sound culling
qboolean bfirstpass; // true if this is first time sound is spatialized
float ob_gain; // gain drop if sound source obscured from listener
float ob_gain_target; // target gain while crossfading between ob_gain & ob_gain_target
float ob_gain_inc; // crossfade increment
qboolean bTraced; // true if channel was already checked this frame for obscuring
float radius; // radius of this sound effect
// sentence mixer
int wordIndex;
mixer_t *currentWord; // NULL if sentence is finished

View File

@ -20,28 +20,6 @@ GNU General Public License for more details.
#include "client.h"
#include "library.h"
/*
=============
COM_LoadFile
=============
*/
byte *COM_LoadFile( const char *filename, int usehunk, int *pLength )
{
string name;
if( !filename || !*filename )
{
if( pLength ) *pLength = 0;
return NULL;
}
Q_strncpy( name, filename, sizeof( name ));
COM_FixSlashes( name );
return FS_LoadFile( name, pLength, false );
}
/*
==============
COM_ParseFile
@ -283,7 +261,8 @@ COM_LoadFileForMe
byte* COM_LoadFileForMe( const char *filename, int *pLength )
{
string name;
int i;
byte *file, *pfile;
int iLength;
if( !filename || !*filename )
{
@ -291,15 +270,71 @@ byte* COM_LoadFileForMe( const char *filename, int *pLength )
return NULL;
}
// replace all backward slashes
for( i = 0; i < Q_strlen( filename ); i++ )
{
if( filename[i] == '\\' ) name[i] = '/';
else name[i] = Q_tolower( filename[i] );
}
name[i] = '\0';
Q_strncpy( name, filename, sizeof( name ));
COM_FixSlashes( name );
return FS_LoadFile( name, pLength, false );
pfile = FS_LoadFile( name, &iLength, false );
if( pLength ) *pLength = iLength;
if( pfile )
{
file = malloc( iLength + 1 );
Q_memcpy( file, pfile, iLength );
file[iLength] = '\0';
Mem_Free( pfile );
pfile = file;
}
return pfile;
}
/*
=============
COM_LoadFile
=============
*/
byte *COM_LoadFile( const char *filename, int usehunk, int *pLength )
{
string name;
byte *file, *pfile;
int iLength;
ASSERT( usehunk == 5 );
if( !filename || !*filename )
{
if( pLength ) *pLength = 0;
return NULL;
}
Q_strncpy( name, filename, sizeof( name ));
COM_FixSlashes( name );
pfile = FS_LoadFile( name, &iLength, false );
if( pLength ) *pLength = iLength;
if( pfile )
{
file = malloc( iLength + 1 );
Q_memcpy( file, pfile, iLength );
file[iLength] = '\0';
Mem_Free( pfile );
pfile = file;
}
return pfile;
}
/*
=============
COM_FreeFile
=============
*/
void COM_FreeFile( void *buffer )
{
free( buffer );
}
/*
@ -421,6 +456,33 @@ void Con_DPrintf( char *szFmt, ... )
Sys_Print( buffer );
}
/*
=============
COM_CompareFileTime
=============
*/
int COM_CompareFileTime( const char *filename1, const char *filename2, int *iCompare )
{
int bRet = 0;
*iCompare = 0;
if( filename1 && filename2 )
{
long ft1 = FS_FileTime( filename1, false );
long ft2 = FS_FileTime( filename2, false );
// one of files is missing
if( ft1 == -1 || ft2 == -1 )
return bRet;
*iCompare = Host_CompareFileTime( ft1, ft2 );
bRet = 1;
}
return bRet;
}
/*
=============
pfnGetGameDir

View File

@ -76,7 +76,7 @@ typedef enum
#include "com_model.h"
#include "crtlib.h"
#define XASH_VERSION 0.9f // engine current version
#define XASH_VERSION 0.91f // engine current version
// PERFORMANCE INFO
#define MIN_FPS 15.0 // host minimum fps value for maxfps.
@ -365,6 +365,7 @@ qboolean FS_WriteFile( const char *filename, const void *data, fs_offset_t len )
int COM_FileSize( const char *filename );
void COM_FixSlashes( char *pname );
void COM_FreeFile( void *buffer );
int COM_CompareFileTime( const char *filename1, const char *filename2, int *iCompare );
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 );

View File

@ -1548,6 +1548,9 @@ int Con_DrawDebugLines( void )
{
int i, count = 0;
int y = 20;
int defaultX;
defaultX = glState.width / 4;
for( i = 0; i < MAX_DBG_NOTIFY; i++ )
{
@ -1557,7 +1560,7 @@ int Con_DrawDebugLines( void )
int fontTall;
Con_DrawStringLen( con.notify[i].szNotify, &len, &fontTall );
x = scr_width->integer - 10 - len;
x = scr_width->integer - max( defaultX, len ) - 10;
fontTall += 1;
if( y + fontTall > (int)scr_height->integer - 20 )

View File

@ -2297,12 +2297,6 @@ file_t *FS_OpenFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedi
return file;
}
void COM_FreeFile( void *buffer )
{
if( buffer && Mem_IsAllocatedExt( fs_mempool, buffer ))
Mem_Free( buffer );
}
/*
============
FS_WriteFile

View File

@ -711,7 +711,7 @@ int EXPORT Host_Main( const char *progname, int bChangeGame, pfnChangeGame func
host_clientloaded = Cvar_Get( "host_clientloaded", "0", CVAR_INIT, "inidcates a loaded client.dll" );
host_limitlocal = Cvar_Get( "host_limitlocal", "0", 0, "apply cl_cmdrate and rate to loopback connection" );
host_allow_materials = Cvar_Get( "host_allow_materials", "0", CVAR_LATCH|CVAR_ARCHIVE, "allow HD textures" );
con_gamemaps = Cvar_Get( "con_gamemaps", "1", CVAR_ARCHIVE, "when true show only maps in game folder" );
con_gamemaps = Cvar_Get( "con_mapfilter", "1", CVAR_ARCHIVE, "when true show only maps in game folder" );
// content control
Cvar_Get( "violence_hgibs", "1", CVAR_ARCHIVE, "show human gib entities" );

View File

@ -63,6 +63,25 @@ int NearestPOW( int value, qboolean roundDown )
return n;
}
// remap a value in the range [A,B] to [C,D].
float RemapVal( float val, float A, float B, float C, float D )
{
return C + (D - C) * (val - A) / (B - A);
}
float ApproachVal( float target, float value, float speed )
{
float delta = target - value;
if( delta > speed )
value += speed;
else if( delta < -speed )
value -= speed;
else value = target;
return value;
}
/*
=================
rsqrt

View File

@ -119,6 +119,8 @@ float RadiusFromBounds( const vec3_t mins, const vec3_t maxs );
void AngleQuaternion( const vec3_t angles, vec4_t q );
void QuaternionSlerp( const vec4_t p, vec4_t q, float t, vec4_t qt );
float RemapVal( float val, float A, float B, float C, float D );
float ApproachVal( float target, float value, float speed );
//
// matrixlib.c

View File

@ -1753,7 +1753,6 @@ static void Mod_LoadBrushModel( model_t *mod, const void *buffer, qboolean *load
{
msurface_t *surf = mod->surfaces + mod->firstmodelsurface + j;
mextrasurf_t *info = SURF_INFO( surf, mod );
vec3_t normal, vup = { 0, 0, 1 };
if( surf->flags & SURF_CONVEYOR )
mod->flags |= MODEL_CONVEYOR;
@ -1761,10 +1760,6 @@ static void Mod_LoadBrushModel( model_t *mod, const void *buffer, qboolean *load
// kill water backplanes for submodels (half-life rules)
if( surf->flags & SURF_DRAWTURB )
{
if( surf->flags & SURF_PLANEBACK )
VectorNegate( surf->plane->normal, normal );
else VectorCopy( surf->plane->normal, normal );
if( surf->plane->type == PLANE_Z )
{
// kill bottom plane too
@ -1872,8 +1867,10 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
// store modelname to show error
Q_strncpy( tempname, mod->name, sizeof( tempname ));
COM_FixSlashes( tempname );
buf = FS_LoadFile( tempname, NULL, false );
buf = COM_LoadFile( mod->name, 0, NULL );
if( !buf )
{
Q_memset( mod, 0, sizeof( model_t ));

View File

@ -160,6 +160,7 @@ typedef struct ui_enginefuncs_s
void (*pfnSetCursor)( void *hCursor ); // change cursor
int (*pfnIsMapValid)( char *filename );
void (*pfnProcessImage)( int texnum, float gamma, int topColor, int bottomColor );
int (*pfnCompareFileTime)( char *filename1, char *filename2, int *iCompare );
} ui_enginefuncs_t;
typedef struct

View File

@ -1661,8 +1661,8 @@ void SV_Pause_f( sv_client_t *cl )
return;
}
if( !sv.paused ) Q_snprintf( message, MAX_STRING, "^2%s^7 paused the game", cl->name );
else Q_snprintf( message, MAX_STRING, "^2%s^7 unpaused the game", cl->name );
if( !sv.paused ) Q_snprintf( message, MAX_STRING, "^2%s^7 paused the game\n", cl->name );
else Q_snprintf( message, MAX_STRING, "^2%s^7 unpaused the game\n", cl->name );
SV_TogglePause( message );
}

View File

@ -1034,18 +1034,18 @@ void pfnChangeLevel( const char* s1, const char* s2 )
if( !s1 || s1[0] <= ' ' || sv.background )
return;
// make sure we don't issue two changelevels at one time
if( svs.changelevel_next_time > host.realtime )
return;
svs.changelevel_next_time = host.realtime + 0.5f; // rest 1 secs if failed
// make sure we don't issue two changelevels
if( svs.spawncount == last_spawncount )
return;
last_spawncount = svs.spawncount;
// make sure we don't issue two changelevels at one time
if( svs.changelevel_next_time > host.realtime )
return;
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
@ -3102,33 +3102,6 @@ float pfnTime( void )
return (float)Sys_DoubleTime();
}
/*
=============
pfnCompareFileTime
=============
*/
int pfnCompareFileTime( const char *filename1, const char *filename2, int *iCompare )
{
int bRet = 0;
*iCompare = 0;
if( filename1 && filename2 )
{
long ft1 = FS_FileTime( filename1, false );
long ft2 = FS_FileTime( filename2, false );
// one of files is missing
if( ft1 == -1 || ft2 == -1 )
return bRet;
*iCompare = Host_CompareFileTime( ft1, ft2 );
bRet = 1;
}
return bRet;
}
/*
=============
pfnStaticDecal
@ -4258,7 +4231,7 @@ static enginefuncs_t gEngfuncs =
COM_LoadFileForMe,
COM_FreeFile,
pfnEndSection,
pfnCompareFileTime,
COM_CompareFileTime,
pfnGetGameDir,
Cvar_RegisterVariable,
pfnFadeClientVolume,

View File

@ -182,6 +182,7 @@ char *SV_EntityScript( void )
{
string entfilename;
char *ents;
size_t ft1, ft2;
if( !sv.worldmodel )
return NULL;
@ -191,10 +192,21 @@ char *SV_EntityScript( void )
FS_StripExtension( entfilename );
FS_DefaultExtension( entfilename, ".ent" );
if(( ents = FS_LoadFile( entfilename, NULL, true )))
// make sure what entity patch is never than bsp
ft1 = FS_FileTime( sv.worldmodel->name, false );
ft2 = FS_FileTime( entfilename, true );
if( ft2 != -1 )
{
MsgDev( D_INFO, "^2Read entity patch:^7 %s\n", entfilename );
return ents;
if( ft1 > ft2 )
{
MsgDev( D_INFO, "^1Entity patch is older than bsp. Ignored.\n", entfilename );
}
else if(( ents = FS_LoadFile( entfilename, NULL, true )))
{
MsgDev( D_INFO, "^2Read entity patch:^7 %s\n", entfilename );
return ents;
}
}
// use internal entities

View File

@ -1444,7 +1444,6 @@ int UI_VidInit( void )
uiStatic.cursorY = ScreenHeight >> 1;
uiStatic.outlineWidth = 4;
uiStatic.sliderWidth = 6;
uiStatic.space_draw_width = 8;
// all menu buttons have the same view sizes
uiStatic.buttons_draw_width = UI_BUTTONS_WIDTH;
@ -1453,7 +1452,6 @@ int UI_VidInit( void )
UI_ScaleCoords( NULL, NULL, &uiStatic.outlineWidth, NULL );
UI_ScaleCoords( NULL, NULL, &uiStatic.sliderWidth, NULL );
UI_ScaleCoords( NULL, NULL, &uiStatic.buttons_draw_width, &uiStatic.buttons_draw_height );
UI_ScaleCoords( NULL, NULL, &uiStatic.space_draw_width, NULL );
// trying to load colors.lst
UI_ApplyCustomColors ();

View File

@ -370,7 +370,6 @@ typedef struct
int buttons_draw_width; // scaled image what we drawing
int buttons_draw_height;
int space_draw_width; // scaled space width
} uiStatic_t;
extern uiStatic_t uiStatic;

View File

@ -173,9 +173,10 @@ inline void TextMessageSetColor( int r, int g, int b, int alpha = 255 )
#define DrawConsoleString (*g_engfuncs.pfnDrawConsoleString)
#define GetConsoleStringSize (*g_engfuncs.pfnDrawConsoleStringLen)
#define ConsoleSetColor (*g_engfuncs.pfnSetConsoleDefaultColor)
#define PIC_SetFlags (*g_engfuncs.pfnPIC_SetFlags)
#define RANDOM_LONG (*g_engfuncs.pfnRandomLong)
#define RANDOM_FLOAT (*g_engfuncs.pfnRandomFloat)
#define COMPARE_FILE_TIME (*g_engfuncs.pfnCompareFileTime)
#endif//ENGINECALLBACKS_H

View File

@ -34,6 +34,8 @@ GNU General Public License for more details.
#define bound( min, num, max ) ((num) >= (min) ? ((num) < (max) ? (num) : (max)) : (min))
typedef int (*cmpfunc)( const void *a, const void *b );
#include "menu_int.h"
#endif//EXTDLL_H

View File

@ -34,8 +34,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define ID_CANCEL 5
#define ID_KEYLIST 6
#define ID_TABLEHINT 7
#define ID_MSGBOX 8
#define ID_MSGTEXT 9
#define ID_MSGBOX1 8
#define ID_MSGBOX2 9
#define ID_MSGTEXT 10
#define ID_PROMPT 11
#define ID_YES 130
#define ID_NO 131
#define MAX_KEYS 256
#define CMD_LENGTH 38
@ -60,8 +64,12 @@ typedef struct
menuPicButton_s cancel;
// redefine key wait dialog
menuAction_s msgBox;
menuAction_s msgBox1; // small msgbox
menuAction_s msgBox2; // large msgbox
menuAction_s dlgMessage;
menuAction_s promptMessage;
menuPicButton_s yes;
menuPicButton_s no;
menuScrollList_s keysList;
menuAction_s hintMessage;
@ -73,6 +81,23 @@ typedef struct
static uiControls_t uiControls;
extern bool hold_button_stack;
static void UI_ResetToDefaultsDialog( void )
{
// toggle main menu between active\inactive
// show\hide reset to defaults dialog
uiControls.defaults.generic.flags ^= QMF_INACTIVE;
uiControls.advanced.generic.flags ^= QMF_INACTIVE;
uiControls.done.generic.flags ^= QMF_INACTIVE;
uiControls.cancel.generic.flags ^= QMF_INACTIVE;
uiControls.keysList.generic.flags ^= QMF_INACTIVE;
uiControls.msgBox2.generic.flags ^= QMF_HIDDEN;
uiControls.promptMessage.generic.flags ^= QMF_HIDDEN;
uiControls.yes.generic.flags ^= QMF_HIDDEN;
uiControls.no.generic.flags ^= QMF_HIDDEN;
}
/*
=================
UI_Controls_GetKeyBindings
@ -215,9 +240,10 @@ static void UI_PromptDialog( void )
uiControls.advanced.generic.flags ^= QMF_INACTIVE;
uiControls.done.generic.flags ^= QMF_INACTIVE;
uiControls.cancel.generic.flags ^= QMF_INACTIVE;
uiControls.keysList.generic.flags ^= QMF_INACTIVE;
uiControls.msgBox.generic.flags ^= QMF_HIDDEN;
uiControls.msgBox1.generic.flags ^= QMF_HIDDEN;
uiControls.dlgMessage.generic.flags ^= QMF_HIDDEN;
}
@ -288,6 +314,15 @@ UI_Controls_KeyFunc
static const char *UI_Controls_KeyFunc( int key, int down )
{
char cmd[128];
if( uiControls.msgBox1.generic.flags & QMF_HIDDEN )
{
if( down && key == K_ESCAPE && uiControls.defaults.generic.flags & QMF_INACTIVE )
{
UI_ResetToDefaultsDialog();
return uiSoundNull;
}
}
if( down )
{
@ -383,6 +418,10 @@ static void UI_Controls_Callback( void *self, int event )
UI_PopMenu();
break;
case ID_DEFAULTS:
case ID_NO:
UI_ResetToDefaultsDialog ();
break;
case ID_YES:
UI_Controls_ResetKeysList ();
break;
case ID_ADVANCED:
@ -491,14 +530,23 @@ static void UI_Controls_Init( void )
UI_Controls_ParseKeysList();
uiControls.msgBox.generic.id = ID_MSGBOX;
uiControls.msgBox.generic.type = QMTYPE_ACTION;
uiControls.msgBox.generic.flags = QMF_INACTIVE|QMF_HIDDEN;
uiControls.msgBox.generic.ownerdraw = UI_MsgBox_Ownerdraw; // just a fill rectangle
uiControls.msgBox.generic.x = 192;
uiControls.msgBox.generic.y = 256;
uiControls.msgBox.generic.width = 640;
uiControls.msgBox.generic.height = 128;
uiControls.msgBox1.generic.id = ID_MSGBOX1;
uiControls.msgBox1.generic.type = QMTYPE_ACTION;
uiControls.msgBox1.generic.flags = QMF_INACTIVE|QMF_HIDDEN;
uiControls.msgBox1.generic.ownerdraw = UI_MsgBox_Ownerdraw; // just a fill rectangle
uiControls.msgBox1.generic.x = 192;
uiControls.msgBox1.generic.y = 256;
uiControls.msgBox1.generic.width = 640;
uiControls.msgBox1.generic.height = 128;
uiControls.msgBox2.generic.id = ID_MSGBOX2;
uiControls.msgBox2.generic.type = QMTYPE_ACTION;
uiControls.msgBox2.generic.flags = QMF_INACTIVE|QMF_HIDDEN;
uiControls.msgBox2.generic.ownerdraw = UI_MsgBox_Ownerdraw; // just a fill rectangle
uiControls.msgBox2.generic.x = 192;
uiControls.msgBox2.generic.y = 256;
uiControls.msgBox2.generic.width = 640;
uiControls.msgBox2.generic.height = 256;
uiControls.dlgMessage.generic.id = ID_MSGTEXT;
uiControls.dlgMessage.generic.type = QMTYPE_ACTION;
@ -507,6 +555,33 @@ static void UI_Controls_Init( void )
uiControls.dlgMessage.generic.x = 320;
uiControls.dlgMessage.generic.y = 280;
uiControls.promptMessage.generic.id = ID_PROMPT;
uiControls.promptMessage.generic.type = QMTYPE_ACTION;
uiControls.promptMessage.generic.flags = QMF_INACTIVE|QMF_DROPSHADOW|QMF_HIDDEN;
uiControls.promptMessage.generic.name = "Reset buttons to default?";
uiControls.promptMessage.generic.x = 290;
uiControls.promptMessage.generic.y = 280;
uiControls.yes.generic.id = ID_YES;
uiControls.yes.generic.type = QMTYPE_BM_BUTTON;
uiControls.yes.generic.flags = QMF_HIGHLIGHTIFFOCUS|QMF_DROPSHADOW|QMF_HIDDEN;
uiControls.yes.generic.name = "Ok";
uiControls.yes.generic.x = 380;
uiControls.yes.generic.y = 460;
uiControls.yes.generic.callback = UI_Controls_Callback;
UI_UtilSetupPicButton( &uiControls.yes, PC_OK );
uiControls.no.generic.id = ID_NO;
uiControls.no.generic.type = QMTYPE_BM_BUTTON;
uiControls.no.generic.flags = QMF_HIGHLIGHTIFFOCUS|QMF_DROPSHADOW|QMF_HIDDEN;
uiControls.no.generic.name = "Cancel";
uiControls.no.generic.x = 530;
uiControls.no.generic.y = 460;
uiControls.no.generic.callback = UI_Controls_Callback;
UI_UtilSetupPicButton( &uiControls.no, PC_CANCEL );
UI_AddItem( &uiControls.menu, (void *)&uiControls.background );
UI_AddItem( &uiControls.menu, (void *)&uiControls.banner );
UI_AddItem( &uiControls.menu, (void *)&uiControls.defaults );
@ -515,8 +590,12 @@ static void UI_Controls_Init( void )
UI_AddItem( &uiControls.menu, (void *)&uiControls.cancel );
UI_AddItem( &uiControls.menu, (void *)&uiControls.hintMessage );
UI_AddItem( &uiControls.menu, (void *)&uiControls.keysList );
UI_AddItem( &uiControls.menu, (void *)&uiControls.msgBox );
UI_AddItem( &uiControls.menu, (void *)&uiControls.msgBox1 );
UI_AddItem( &uiControls.menu, (void *)&uiControls.msgBox2 );
UI_AddItem( &uiControls.menu, (void *)&uiControls.dlgMessage );
UI_AddItem( &uiControls.menu, (void *)&uiControls.promptMessage );
UI_AddItem( &uiControls.menu, (void *)&uiControls.no );
UI_AddItem( &uiControls.menu, (void *)&uiControls.yes );
}
/*

View File

@ -133,6 +133,9 @@ static void UI_LoadGame_GetGameList( void )
filenames = FS_SEARCH( "save/*.sav", &numFiles, TRUE );
// sort the saves in reverse order (oldest past at the end)
qsort( filenames, numFiles, sizeof( char* ), (cmpfunc)COM_CompareSaves );
for ( i = 0; i < numFiles; i++ )
{
if( i >= UI_MAXGAMES ) break;

View File

@ -134,6 +134,9 @@ static void UI_SaveGame_GetGameList( void )
filenames = FS_SEARCH( "save/*.sav", &numFiles, TRUE );
// sort the saves in reverse order (oldest past at the end)
qsort( filenames, numFiles, sizeof( char* ), (cmpfunc)COM_CompareSaves );
if ( CL_IsActive() && !gpGlobals->demoplayback )
{
// create new entry for current save game

View File

@ -107,6 +107,25 @@ char *StringCopy( const char *input )
return out;
}
/*
============
COM_CompareSaves
============
*/
int COM_CompareSaves( const void **a, const void **b )
{
char *file1, *file2;
file1 = (char *)*a;
file2 = (char *)*b;
int bResult;
COMPARE_FILE_TIME( file2, file1, &bResult );
return bResult;
}
/*
============
COM_FileBase

View File

@ -123,6 +123,7 @@ extern void StringConcat( char *dst, const char *src, size_t size ); // strncat
extern char *Info_ValueForKey( const char *s, const char *key );
extern int KEY_GetKey( const char *binding ); // ripped out from engine
extern char *StringCopy( const char *input ); // copy string into new memory
extern int COM_CompareSaves( const void **a, const void **b );
extern void UI_LoadCustomStrings( void );