diff --git a/common/const.h b/common/const.h index b885e44e..d29816e6 100644 --- a/common/const.h +++ b/common/const.h @@ -110,7 +110,9 @@ #define EF_NOINTERP 32 // don't interpolate the next frame #define EF_LIGHT 64 // rocket flare glow sprite #define EF_NODRAW 128 // don't draw entity - +#define EF_NIGHTVISION 256 // player nightvision +#define EF_SNIPERLASER 512 // sniper laser effect +#define EF_FIBERCAMERA 1024 // fiber camera #define EF_NOREFLECT (1<<24) // Entity won't reflecting in mirrors @@ -531,6 +533,7 @@ #define TEFIRE_FLAG_LOOP 4 // if set, sprite plays at 15 fps, otherwise plays at whatever rate stretches the animation over the sprite's duration. #define TEFIRE_FLAG_ALPHA 8 // if set, sprite is rendered alpha blended at 50% else, opaque #define TEFIRE_FLAG_PLANAR 16 // if set, all fire sprites have same initial Z instead of randomly filling a cube. +#define TEFIRE_FLAG_ADDITIVE 32 // if set, sprite is rendered non-opaque with additive #define TE_PLAYERATTACHMENT 124 // attaches a TENT to a player (this is a high-priority tent) // byte (entity index of player) @@ -621,8 +624,9 @@ #define CHAN_BODY 4 #define CHAN_STREAM 5 // allocate stream channel from the static or dynamic area #define CHAN_STATIC 6 // allocate channel from the static area -#define CHAN_NETWORKVOICE_BASE 7 // voice data coming across the network +#define CHAN_NETWORKVOICE_BASE 7 // voice data coming across the network #define CHAN_NETWORKVOICE_END 500 // network voice data reserves slots (CHAN_NETWORKVOICE_BASE through CHAN_NETWORKVOICE_END). +#define CHAN_BOT 501 // channel used for bot chatter. // attenuation values #define ATTN_NONE 0 @@ -724,7 +728,8 @@ enum kRenderFxDeadPlayer, // kRenderAmt is the player index kRenderFxExplode, // Scale up really big! kRenderFxGlowShell, // Glowing Shell - kRenderFxClampMinScale // Keep this sprite from getting very small (SPRITES only!) + kRenderFxClampMinScale, // Keep this sprite from getting very small (SPRITES only!) + kRenderFxLightMultiplier //CTM !!!CZERO added to tell the studiorender that the value in iuser2 is a lightmultiplier }; typedef unsigned int func_t; diff --git a/common/cvardef.h b/common/cvardef.h index f822cc7a..c57b97a7 100644 --- a/common/cvardef.h +++ b/common/cvardef.h @@ -24,6 +24,7 @@ #define FCVAR_SPONLY (1<<6) // This cvar cannot be changed by clients connected to a multiplayer server. #define FCVAR_PRINTABLEONLY (1<<7) // This cvar's string cannot contain unprintable characters ( e.g., used for player name etc ). #define FCVAR_UNLOGGED (1<<8) // If this is a FCVAR_SERVER, don't log changes to the log file / console if we are creating a log +#define FCVAR_NOEXTRAWHITEPACE (1<<9) // strip trailing/leading white space from this cvar typedef struct cvar_s { @@ -34,4 +35,4 @@ typedef struct cvar_s struct cvar_s *next; } cvar_t; -#endif//CVARDEF_H \ No newline at end of file +#endif//CVARDEF_H diff --git a/dlls/buttons.cpp b/dlls/buttons.cpp index 7b050add..3027f10e 100644 --- a/dlls/buttons.cpp +++ b/dlls/buttons.cpp @@ -1045,7 +1045,11 @@ void CMomentaryRotButton::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, US pev->ideal_yaw = CBaseToggle::AxisDelta( pev->spawnflags, pev->angles, m_start ) / m_flMoveDistance; UpdateAllButtons( pev->ideal_yaw, 1 ); - UpdateTarget( pev->ideal_yaw ); + + // Calculate destination angle and use it to predict value, this prevents sending target in wrong direction on retriggering + Vector dest = pev->angles + pev->avelocity * ( pev->nextthink - pev->ltime ); + float value1 = CBaseToggle::AxisDelta( pev->spawnflags, dest, m_start ) / m_flMoveDistance; + UpdateTarget( value1 ); } void CMomentaryRotButton::UpdateAllButtons( float value, int start ) diff --git a/dlls/cbase.h b/dlls/cbase.h index 47ce7595..617bbab9 100644 --- a/dlls/cbase.h +++ b/dlls/cbase.h @@ -280,8 +280,8 @@ public: #ifdef _DEBUG void FunctionCheck( void *pFunction, char *name ) { - if( pFunction && !NAME_FOR_FUNCTION( (unsigned long)( pFunction ) ) ) - ALERT( at_error, "No EXPORT: %s:%s (%08lx)\n", STRING( pev->classname ), name, (unsigned long)pFunction ); + if( pFunction && !NAME_FOR_FUNCTION( (size_t)( pFunction ) ) ) + ALERT( at_error, "No EXPORT: %s:%s (%08lx)\n", STRING( pev->classname ), name, (size_t)pFunction ); } BASEPTR ThinkSet( BASEPTR func, char *name ) diff --git a/dlls/client.cpp b/dlls/client.cpp index 5fb7c221..74be0ea3 100644 --- a/dlls/client.cpp +++ b/dlls/client.cpp @@ -48,6 +48,8 @@ extern void CopyToBodyQue( entvars_t* pev ); extern int giPrecacheGrunt; extern int gmsgSayText; +extern cvar_t allow_spectators; + extern int g_teamplay; void LinkUserMessages( void ); @@ -204,6 +206,97 @@ void ClientPutInServer( edict_t *pEntity ) #include "voice_gamemgr.h" extern CVoiceGameMgr g_VoiceGameMgr; #endif + +//----------------------------------------------------------------------------- +// Purpose: determine if a uchar32 represents a valid Unicode code point +//----------------------------------------------------------------------------- +bool Q_IsValidUChar32( unsigned int uVal ) +{ + // Values > 0x10FFFF are explicitly invalid; ditto for UTF-16 surrogate halves, + // values ending in FFFE or FFFF, or values in the 0x00FDD0-0x00FDEF reserved range + return ( uVal < 0x110000u ) && ( ( uVal - 0x00D800u ) > 0x7FFu ) && ( ( uVal & 0xFFFFu ) < 0xFFFEu ) && ( ( uVal - 0x00FDD0u ) > 0x1Fu ); +} + +// Decode one character from a UTF-8 encoded string. Treats 6-byte CESU-8 sequences +// as a single character, as if they were a correctly-encoded 4-byte UTF-8 sequence. +int Q_UTF8ToUChar32( const char *pUTF8_, unsigned int &uValueOut, bool &bErrorOut ) +{ + const unsigned char *pUTF8 = (const unsigned char*)pUTF8_; + + int nBytes = 1; + unsigned int uValue = pUTF8[0]; + unsigned int uMinValue = 0; + + // 0....... single byte + if( uValue < 0x80 ) + goto decodeFinishedNoCheck; + + // Expecting at least a two-byte sequence with 0xC0 <= first <= 0xF7 (110...... and 11110...) + if( ( uValue - 0xC0u ) > 0x37u || ( pUTF8[1] & 0xC0 ) != 0x80 ) + goto decodeError; + + uValue = ( uValue << 6 ) - ( 0xC0 << 6 ) + pUTF8[1] - 0x80; + nBytes = 2; + uMinValue = 0x80; + + // 110..... two-byte lead byte + if( !( uValue & ( 0x20 << 6 ) ) ) + goto decodeFinished; + + // Expecting at least a three-byte sequence + if( ( pUTF8[2] & 0xC0 ) != 0x80 ) + goto decodeError; + + uValue = ( uValue << 6 ) - ( 0x20 << 12 ) + pUTF8[2] - 0x80; + nBytes = 3; + uMinValue = 0x800; + + // 1110.... three-byte lead byte +decodeFinished: + if( uValue >= uMinValue && Q_IsValidUChar32( uValue ) ) + { +decodeFinishedNoCheck: + uValueOut = uValue; + bErrorOut = false; + return nBytes; + } +decodeError: + uValueOut = '?'; + bErrorOut = true; + return nBytes; + +decodeFinishedMaybeCESU8: + // Do we have a full UTF-16 surrogate pair that's been UTF-8 encoded afterwards? + // That is, do we have 0xD800-0xDBFF followed by 0xDC00-0xDFFF? If so, decode it all. + if( ( uValue - 0xD800u ) < 0x400u && pUTF8[3] == 0xED && (unsigned char)( pUTF8[4] - 0xB0 ) < 0x10 && ( pUTF8[5] & 0xC0 ) == 0x80 ) + { + uValue = 0x10000 + ( ( uValue - 0xD800u ) << 10 ) + ( (unsigned char)( pUTF8[4] - 0xB0 ) << 6 ) + pUTF8[5] - 0x80; + nBytes = 6; + uMinValue = 0x10000; + } + goto decodeFinished; +} + +//----------------------------------------------------------------------------- +// Purpose: Returns true if UTF-8 string contains invalid sequences. +//----------------------------------------------------------------------------- +bool Q_UnicodeValidate( const char *pUTF8 ) +{ + bool bError = false; + while( *pUTF8 ) + { + unsigned int uVal; + // Our UTF-8 decoder silently fixes up 6-byte CESU-8 (improperly re-encoded UTF-16) sequences. + // However, these are technically not valid UTF-8. So if we eat 6 bytes at once, it's an error. + int nCharSize = Q_UTF8ToUChar32( pUTF8, uVal, bError ); + if( bError || nCharSize == 6 ) + return false; + pUTF8 += nCharSize; + } + return true; +} + + //// HOST_SAY // String comes in as // say blah blah blah @@ -265,20 +358,13 @@ void Host_Say( edict_t *pEntity, int teamonly ) p[strlen( p ) - 1] = 0; } - // make sure the text has content - for( pc = p; pc != NULL && *pc != 0; pc++ ) - { - if( !isspace( *pc ) ) - { - pc = NULL; // we've found an alphanumeric character, so text is valid - break; - } - } - if( pc != NULL ) + if( !p || !p[0] || !Q_UnicodeValidate ( p ) ) return; // no character found, so say nothing // turn on color set 2 (color on, no sound) - if( teamonly ) + if( player->IsObserver() && ( teamonly ) ) + sprintf( text, "%c(SPEC) %s: ", 2, STRING( pEntity->v.netname ) ); + else if( teamonly ) sprintf( text, "%c(TEAM) %s: ", 2, STRING( pEntity->v.netname ) ); else sprintf( text, "%c%s: ", 2, STRING( pEntity->v.netname ) ); @@ -313,9 +399,14 @@ void Host_Say( edict_t *pEntity, int teamonly ) if( g_VoiceGameMgr.PlayerHasBlockedPlayer( client, player ) ) continue; #endif - if( teamonly && g_pGameRules->PlayerRelationship( client, CBaseEntity::Instance( pEntity ) ) != GR_TEAMMATE ) + if( !player->IsObserver() && teamonly && g_pGameRules->PlayerRelationship( client, CBaseEntity::Instance( pEntity ) ) != GR_TEAMMATE ) continue; + // Spectators can only talk to other specs + if( player->IsObserver() && teamonly ) + if ( !client->IsObserver() ) + continue; + MESSAGE_BEGIN( MSG_ONE, gmsgSayText, NULL, client->pev ); WRITE_BYTE( ENTINDEX( pEntity ) ); WRITE_STRING( text ); @@ -459,12 +550,40 @@ void ClientCommand( edict_t *pEntity ) { GetClassPtr( (CBasePlayer *)pev )->SelectLastItem(); } - else if( FStrEq( pcmd, "spectate" ) && ( pev->flags & FL_PROXY ) ) // added for proxy support + else if( FStrEq( pcmd, "spectate" ) // clients wants to become a spectator { - CBasePlayer * pPlayer = GetClassPtr( (CBasePlayer *)pev ); + // always allow proxies to become a spectator + if( ( pev->flags & FL_PROXY ) || allow_spectators.value ) + { + CBasePlayer *pPlayer = GetClassPtr( (CBasePlayer *)pev ); - edict_t *pentSpawnSpot = g_pGameRules->GetPlayerSpawnSpot( pPlayer ); - pPlayer->StartObserver( pev->origin, VARS( pentSpawnSpot )->angles ); + edict_t *pentSpawnSpot = g_pGameRules->GetPlayerSpawnSpot( pPlayer ); + pPlayer->StartObserver( pev->origin, VARS( pentSpawnSpot )->angles ); + + // notify other clients of player switching to spectator mode + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, UTIL_VarArgs( "%s switched to spectator mode\n", + ( pev->netname && STRING(pev->netname)[0] != 0 ) ? STRING(pev->netname) : "unconnected" ) ); + } + else + ClientPrint( pev, HUD_PRINTCONSOLE, "Spectator mode is disabled.\n" ); + } + else if( FStrEq( pcmd, "specmode" ) ) // new spectator mode + { + CBasePlayer *pPlayer = GetClassPtr( (CBasePlayer *)pev ); + + if( pPlayer->IsObserver() ) + pPlayer->Observer_SetMode( atoi( CMD_ARGV( 1 ) ) ); + } + else if( FStrEq( pcmd, "closemenus" ) ) + { + // just ignore it + } + else if( FStrEq( pcmd, "follownext" ) ) // follow next player + { + CBasePlayer *pPlayer = GetClassPtr( (CBasePlayer *)pev ); + + if( pPlayer->IsObserver() ) + pPlayer->Observer_FindNextPlayer( atoi( CMD_ARGV( 1 ) ) ? true : false ); } else if( g_pGameRules->ClientCommand( GetClassPtr( (CBasePlayer *)pev ), pcmd ) ) { @@ -524,12 +643,15 @@ void ClientUserInfoChanged( edict_t *pEntity, char *infobuffer ) // Set the name g_engfuncs.pfnSetClientKeyValue( ENTINDEX( pEntity ), infobuffer, "name", sName ); - char text[256]; - snprintf( text, 256, "* %s changed name to %s\n", STRING( pEntity->v.netname ), g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ) ); - MESSAGE_BEGIN( MSG_ALL, gmsgSayText, NULL ); - WRITE_BYTE( ENTINDEX( pEntity ) ); - WRITE_STRING( text ); - MESSAGE_END(); + if( gpGlobals->maxClients > 1 ) + { + char text[256]; + snprintf( text, 256, "* %s changed name to %s\n", STRING( pEntity->v.netname ), g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ) ); + MESSAGE_BEGIN( MSG_ALL, gmsgSayText, NULL ); + WRITE_BYTE( ENTINDEX( pEntity ) ); + WRITE_STRING( text ); + MESSAGE_END(); + } // team match? if( g_teamplay ) @@ -983,7 +1105,7 @@ int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *h int i; // don't send if flagged for NODRAW and it's not the host getting the message - if( ( ent->v.effects == EF_NODRAW ) && ( ent != host ) ) + if( ( ent->v.effects & EF_NODRAW ) && ( ent != host ) ) return 0; // Ignore ents without valid / visible models @@ -1553,41 +1675,67 @@ engine sets cd to 0 before calling. */ void UpdateClientData( const struct edict_s *ent, int sendweapons, struct clientdata_s *cd ) { - cd->flags = ent->v.flags; - cd->health = ent->v.health; + if( !ent || !ent->pvPrivateData ) + return; + entvars_t *pev = (entvars_t *)&ent->v; + CBasePlayer *pl = (CBasePlayer *)( CBasePlayer::Instance( pev ) ); + entvars_t *pevOrg = NULL; - cd->viewmodel = MODEL_INDEX( STRING( ent->v.viewmodel ) ); + // if user is spectating different player in First person, override some vars + if( pl && pl->pev->iuser1 == OBS_IN_EYE ) + { + if( pl->m_hObserverTarget ) + { + pevOrg = pev; + pev = pl->m_hObserverTarget->pev; + pl = (CBasePlayer *)(CBasePlayer::Instance( pev ) ); + } + } - cd->waterlevel = ent->v.waterlevel; - cd->watertype = ent->v.watertype; - cd->weapons = ent->v.weapons; + cd->flags = pev->flags; + cd->health = pev->health; + + cd->viewmodel = MODEL_INDEX( STRING( pev->viewmodel ) ); + + cd->waterlevel = pev->waterlevel; + cd->watertype = pev->watertype; + cd->weapons = pev->weapons; // Vectors - cd->origin = ent->v.origin; - cd->velocity = ent->v.velocity; - cd->view_ofs = ent->v.view_ofs; - cd->punchangle = ent->v.punchangle; + cd->origin = pev->origin; + cd->velocity = pev->velocity; + cd->view_ofs = pev->view_ofs; + cd->punchangle = pev->punchangle; - cd->bInDuck = ent->v.bInDuck; - cd->flTimeStepSound = ent->v.flTimeStepSound; - cd->flDuckTime = ent->v.flDuckTime; - cd->flSwimTime = ent->v.flSwimTime; - cd->waterjumptime = ent->v.teleport_time; + cd->bInDuck = pev->bInDuck; + cd->flTimeStepSound = pev->flTimeStepSound; + cd->flDuckTime = pev->flDuckTime; + cd->flSwimTime = pev->flSwimTime; + cd->waterjumptime = pev->teleport_time; strcpy( cd->physinfo, ENGINE_GETPHYSINFO( ent ) ); - cd->maxspeed = ent->v.maxspeed; - cd->fov = ent->v.fov; - cd->weaponanim = ent->v.weaponanim; + cd->maxspeed = pev->maxspeed; + cd->fov = pev->fov; + cd->weaponanim = pev->weaponanim; - cd->pushmsec = ent->v.pushmsec; + cd->pushmsec = pev->pushmsec; + // Spectator mode + if( pevOrg != NULL ) + { + // don't use spec vars from chased player + cd->iuser1 = pevOrg->iuser1; + cd->iuser2 = pevOrg->iuser2; + } + else + { + cd->iuser1 = pev->iuser1; + cd->iuser2 = pev->iuser2; + } #if defined( CLIENT_WEAPONS ) if( sendweapons ) { - entvars_t *pev = (entvars_t *)&ent->v; - CBasePlayer *pl = (CBasePlayer *)CBasePlayer::Instance( pev ); - if( pl ) { cd->m_flNextAttack = pl->m_flNextAttack; diff --git a/dlls/crossbow.cpp b/dlls/crossbow.cpp index 45fd922c..7a4686e7 100644 --- a/dlls/crossbow.cpp +++ b/dlls/crossbow.cpp @@ -353,7 +353,7 @@ void CCrossbow::PrimaryAttack( void ) // this function only gets called in multiplayer void CCrossbow::FireSniperBolt() { - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.75; + m_flNextPrimaryAttack = GetNextAttackDelay( 0.75 ); if( m_iClip == 0 ) { @@ -451,7 +451,7 @@ void CCrossbow::FireBolt() // HEV suit - indicate out of ammo condition m_pPlayer->SetSuitUpdate( "!HEV_AMO0", FALSE, 0 ); - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.75; + m_flNextPrimaryAttack = GetNextAttackDelay( 0.75 ); m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.75; diff --git a/dlls/crowbar.cpp b/dlls/crowbar.cpp index 94f0066b..80a18d65 100644 --- a/dlls/crowbar.cpp +++ b/dlls/crowbar.cpp @@ -27,7 +27,7 @@ LINK_ENTITY_TO_CLASS( weapon_crowbar, CCrowbar ) -enum gauss_e +enum crowbar_e { CROWBAR_IDLE = 0, CROWBAR_DRAW, @@ -40,8 +40,7 @@ enum gauss_e CROWBAR_ATTACK3HIT }; - -void CCrowbar::Spawn( ) +void CCrowbar::Spawn() { Precache(); m_iId = WEAPON_CROWBAR; @@ -191,7 +190,7 @@ int CCrowbar::Swing( int fFirst ) if( fFirst ) { // miss - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; + m_flNextPrimaryAttack = GetNextAttackDelay( 0.5 ); // player "shoot" animation m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); @@ -297,7 +296,7 @@ int CCrowbar::Swing( int fFirst ) m_pPlayer->m_iWeaponVolume = flVol * CROWBAR_WALLHIT_VOLUME; #endif - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.25; + m_flNextPrimaryAttack = GetNextAttackDelay( 0.25 ); SetThink( &CCrowbar::Smack ); pev->nextthink = UTIL_WeaponTimeBase() + 0.2; diff --git a/dlls/doors.cpp b/dlls/doors.cpp index bf7205ee..bdc82f06 100644 --- a/dlls/doors.cpp +++ b/dlls/doors.cpp @@ -1100,19 +1100,22 @@ void CMomentaryDoor::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYP Vector move = m_vecPosition1 + ( value * ( m_vecPosition2 - m_vecPosition1 ) ); Vector delta = move - pev->origin; - float speed = delta.Length() * 10; + //float speed = delta.Length() * 10; + float speed = delta.Length() / 0.1; // move there in 0.1 sec if( speed != 0 ) { // This entity only thinks when it moves, so if it's thinking, it's in the process of moving - // play the sound when it starts moving + // play the sound when it starts moving(not yet thinking) if( pev->nextthink < pev->ltime || pev->nextthink == 0 ) EMIT_SOUND( ENT( pev ), CHAN_STATIC, (char*)STRING( pev->noiseMoving ), 1, ATTN_NORM ); + // If we already moving to designated point, return + else if( move == m_vecFinalDest ) + return; LinearMove( move, speed ); SetMoveDone( &CMomentaryDoor::MomentaryMoveDone ); } - } void CMomentaryDoor::MomentaryMoveDone( void ) diff --git a/dlls/extdll.h b/dlls/extdll.h index cbc7ebb9..58349e32 100644 --- a/dlls/extdll.h +++ b/dlls/extdll.h @@ -44,7 +44,7 @@ #else // _WIN32 #define FALSE 0 #define TRUE (!FALSE) -typedef unsigned long ULONG; +typedef unsigned int ULONG; typedef unsigned char BYTE; typedef int BOOL; #define MAX_PATH PATH_MAX diff --git a/dlls/game.cpp b/dlls/game.cpp index 3aec1810..fb247903 100644 --- a/dlls/game.cpp +++ b/dlls/game.cpp @@ -39,6 +39,8 @@ cvar_t teamoverride = { "mp_teamoverride","1" }; cvar_t defaultteam = { "mp_defaultteam","0" }; cvar_t allowmonsters = { "mp_allowmonsters","0", FCVAR_SERVER }; +cvar_t allow_spectators = { "allow_spectators", "0", FCVAR_SERVER }; // 0 prevents players from being spectators + cvar_t mp_chattime = { "mp_chattime","10", FCVAR_SERVER }; // Engine Cvars diff --git a/dlls/gauss.cpp b/dlls/gauss.cpp index 14aac39b..10149202 100644 --- a/dlls/gauss.cpp +++ b/dlls/gauss.cpp @@ -145,7 +145,7 @@ void CGauss::PrimaryAttack() if( m_pPlayer->pev->waterlevel == 3 ) { PlayEmptySound(); - m_flNextSecondaryAttack = m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15; + m_flNextSecondaryAttack = m_flNextPrimaryAttack = GetNextAttackDelay( 0.15 ); return; } @@ -183,7 +183,7 @@ void CGauss::SecondaryAttack() PlayEmptySound(); } - m_flNextSecondaryAttack = m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; + m_flNextSecondaryAttack = m_flNextPrimaryAttack = GetNextAttackDelay( 0.5 ); return; } diff --git a/dlls/handgrenade.cpp b/dlls/handgrenade.cpp index 063b2886..96119b6b 100644 --- a/dlls/handgrenade.cpp +++ b/dlls/handgrenade.cpp @@ -170,7 +170,7 @@ void CHandGrenade::WeaponIdle( void ) m_flReleaseThrow = 0; m_flStartThrow = 0; - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; + m_flNextPrimaryAttack = GetNextAttackDelay( 0.5 ); m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; @@ -180,7 +180,7 @@ void CHandGrenade::WeaponIdle( void ) // just threw last grenade // set attack times in the future, and weapon idle in the future so we can see the whole throw // animation, weapon idle will automatically retire the weapon for us. - m_flTimeWeaponIdle = m_flNextSecondaryAttack = m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5;// ensure that the animation can finish playing + m_flTimeWeaponIdle = m_flNextSecondaryAttack = m_flNextPrimaryAttack = GetNextAttackDelay( 0.5 );// ensure that the animation can finish playing } return; } diff --git a/dlls/mp5.cpp b/dlls/mp5.cpp index 7d05d5e1..7131f888 100644 --- a/dlls/mp5.cpp +++ b/dlls/mp5.cpp @@ -177,7 +177,7 @@ void CMP5::PrimaryAttack() // HEV suit - indicate out of ammo condition m_pPlayer->SetSuitUpdate( "!HEV_AMO0", FALSE, 0 ); - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.1; + m_flNextPrimaryAttack = GetNextAttackDelay( 0.1 ); if( m_flNextPrimaryAttack < UTIL_WeaponTimeBase() ) m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.1; @@ -227,7 +227,7 @@ void CMP5::SecondaryAttack( void ) #endif PLAYBACK_EVENT( flags, m_pPlayer->edict(), m_usMP52 ); - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1; + m_flNextPrimaryAttack = GetNextAttackDelay( 1 ); m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1; m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 5;// idle pretty soon after shooting. diff --git a/dlls/multiplay_gamerules.cpp b/dlls/multiplay_gamerules.cpp index 929c2bf6..ebef51de 100644 --- a/dlls/multiplay_gamerules.cpp +++ b/dlls/multiplay_gamerules.cpp @@ -92,7 +92,7 @@ CHalfLifeMultiplay::CHalfLifeMultiplay() if( IS_DEDICATED_SERVER() ) { // dedicated server - char *servercfgfile = (char *)CVAR_GET_STRING( "servercfgfile" ); + /*char *servercfgfile = (char *)CVAR_GET_STRING( "servercfgfile" ); if( servercfgfile && servercfgfile[0] ) { @@ -102,6 +102,8 @@ CHalfLifeMultiplay::CHalfLifeMultiplay() sprintf( szCommand, "exec %s\n", servercfgfile ); SERVER_COMMAND( szCommand ); } + */ + // this code has been moved into engine, to only run server.cfg once } else { diff --git a/dlls/nihilanth.cpp b/dlls/nihilanth.cpp index 58317b3c..ba1c6192 100644 --- a/dlls/nihilanth.cpp +++ b/dlls/nihilanth.cpp @@ -1185,8 +1185,22 @@ void CNihilanth::CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_ case USE_OFF: { CBaseEntity *pTouch = UTIL_FindEntityByTargetname( NULL, m_szDeadTouch ); - if( pTouch && m_hEnemy != NULL ) - pTouch->Touch( m_hEnemy ); + if( pTouch ) + { + if( m_hEnemy != NULL ) + { + pTouch->Touch( m_hEnemy ); + } + // if the player is using "notarget", the ending sequence won't fire unless we catch it here + else + { + CBaseEntity *pEntity = UTIL_FindEntityByClassname( NULL, "player" ); + if( pEntity != NULL && pEntity->IsAlive() ) + { + pTouch->Touch( pEntity ); + } + } + } } break; case USE_ON: diff --git a/dlls/player.cpp b/dlls/player.cpp index 2f097072..7d7363b5 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -34,6 +34,7 @@ #include "decals.h" #include "gamerules.h" #include "game.h" +#include "pm_shared.h" #include "hltv.h" // #define DUCKFIX @@ -201,7 +202,8 @@ void LinkUserMessages( void ) gmsgDamage = REG_USER_MSG( "Damage", 12 ); gmsgBattery = REG_USER_MSG( "Battery", 2); gmsgTrain = REG_USER_MSG( "Train", 1 ); - gmsgHudText = REG_USER_MSG( "HudText", -1 ); + //gmsgHudText = REG_USER_MSG( "HudTextPro", -1 ); + gmsgHudText = REG_USER_MSG( "HudText", -1 ); // we don't use the message but 3rd party addons may! gmsgSayText = REG_USER_MSG( "SayText", -1 ); gmsgTextMsg = REG_USER_MSG( "TextMsg", -1 ); gmsgWeaponList = REG_USER_MSG( "WeaponList", -1 ); @@ -785,6 +787,12 @@ void CBasePlayer::RemoveAllItems( BOOL removeSuit ) m_pLastItem = NULL; + if( m_pTank != NULL ) + { + m_pTank->Use( this, this, USE_OFF, 0 ); + m_pTank = NULL; + } + int i; CBasePlayerItem *pPendingItem; for( i = 0; i < MAX_ITEM_TYPES; i++ ) @@ -1297,6 +1305,9 @@ void CBasePlayer::PlayerDeathThink( void ) StartDeathCam(); } + if( pev->iuser1 ) // player is in spectator mode + return; + // wait for any button down, or mp_forcerespawn is set and the respawn time is up if( !fAnyButtonDown && !( g_pGameRules->IsMultiplayer() && forcerespawn.value > 0 && ( gpGlobals->time > ( m_fDeadTime + 5 ) ) ) ) return; @@ -1345,7 +1356,9 @@ void CBasePlayer::StartDeathCam( void ) } CopyToBodyQue( pev ); - StartObserver( pSpot->v.origin, pSpot->v.v_angle ); + + UTIL_SetOrigin( pev, pSpot->v.origin ); + pev->angles = pev->v_angle = pSpot->v.v_angle; } else { @@ -1353,23 +1366,89 @@ void CBasePlayer::StartDeathCam( void ) TraceResult tr; CopyToBodyQue( pev ); UTIL_TraceLine( pev->origin, pev->origin + Vector( 0, 0, 128 ), ignore_monsters, edict(), &tr ); - StartObserver( tr.vecEndPos, UTIL_VecToAngles( tr.vecEndPos - pev->origin ) ); - return; + + UTIL_SetOrigin( pev, tr.vecEndPos ); + pev->angles = pev->v_angle = UTIL_VecToAngles( tr.vecEndPos - pev->origin ); } + + // start death cam + m_afPhysicsFlags |= PFLAG_OBSERVER; + pev->view_ofs = g_vecZero; + pev->fixangle = TRUE; + pev->solid = SOLID_NOT; + pev->takedamage = DAMAGE_NO; + pev->movetype = MOVETYPE_NONE; + pev->modelindex = 0; } void CBasePlayer::StartObserver( Vector vecPosition, Vector vecViewAngle ) { - m_afPhysicsFlags |= PFLAG_OBSERVER; + // clear any clientside entities attached to this player + MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin ); + WRITE_BYTE( TE_KILLPLAYERATTACHMENTS ); + WRITE_BYTE( (BYTE)entindex() ); + MESSAGE_END(); + // Holster weapon immediately, to allow it to cleanup + if( m_pActiveItem ) + m_pActiveItem->Holster(); + + if( m_pTank != NULL ) + { + m_pTank->Use( this, this, USE_OFF, 0 ); + m_pTank = NULL; + } + + // clear out the suit message cache so we don't keep chattering + SetSuitUpdate( NULL, FALSE, 0 ); + + // Tell Ammo Hud that the player is dead + MESSAGE_BEGIN( MSG_ONE, gmsgCurWeapon, NULL, pev ); + WRITE_BYTE( 0 ); + WRITE_BYTE( 0XFF ); + WRITE_BYTE( 0xFF ); + MESSAGE_END(); + + // reset FOV + m_iFOV = m_iClientFOV = 0; + pev->fov = m_iFOV; + MESSAGE_BEGIN( MSG_ONE, gmsgSetFOV, NULL, pev ); + WRITE_BYTE( 0 ); + MESSAGE_END(); + + // Setup flags + m_iHideHUD = ( HIDEHUD_HEALTH | HIDEHUD_WEAPONS ); + m_afPhysicsFlags |= PFLAG_OBSERVER; + pev->effects = EF_NODRAW; pev->view_ofs = g_vecZero; pev->angles = pev->v_angle = vecViewAngle; pev->fixangle = TRUE; pev->solid = SOLID_NOT; pev->takedamage = DAMAGE_NO; pev->movetype = MOVETYPE_NONE; - pev->modelindex = 0; + ClearBits( m_afPhysicsFlags, PFLAG_DUCKING ); + ClearBits( pev->flags, FL_DUCKING ); + pev->deadflag = DEAD_RESPAWNABLE; + pev->health = 1; + + // Clear out the status bar + m_fInitHUD = TRUE; + + pev->team = 0; + MESSAGE_BEGIN( MSG_ALL, gmsgTeamInfo ); + WRITE_BYTE( ENTINDEX(edict()) ); + WRITE_STRING( "" ); + MESSAGE_END(); + + // Remove all the player's stuff + RemoveAllItems( FALSE ); + + // Move them to the new position UTIL_SetOrigin( pev, vecPosition ); + + // Find a player to watch + m_flNextObserverInput = 0; + Observer_SetMode( m_iObserverLastMode ); } // @@ -1379,6 +1458,9 @@ void CBasePlayer::StartObserver( Vector vecPosition, Vector vecViewAngle ) void CBasePlayer::PlayerUse( void ) { + if( IsObserver() ) + return; + // Was use pressed or released? if( !( ( pev->button | m_afButtonPressed | m_afButtonReleased) & IN_USE ) ) return; @@ -1747,6 +1829,16 @@ void CBasePlayer::PreThink( void ) CheckSuitUpdate(); + // Observer Button Handling + if( IsObserver() ) + { + Observer_HandleButtons(); + Observer_CheckTarget(); + Observer_CheckProperties(); + pev->impulse = 0; + return; + } + if( pev->deadflag >= DEAD_DYING ) { PlayerDeathThink(); @@ -3767,6 +3859,9 @@ void CBasePlayer::UpdateClientData( void ) g_pGameRules->InitHUD( this ); m_fGameHUDInitialized = TRUE; + + m_iObserverLastMode = OBS_ROAMING; + if( g_pGameRules->IsMultiplayer() ) { FireTargets( "game_playerjoin", this, this, USE_TOGGLE, 0 ); @@ -3807,7 +3902,10 @@ void CBasePlayer::UpdateClientData( void ) if( pev->health != m_iClientHealth ) { - int iHealth = max( pev->health, 0 ); // make sure that no negative health values are sent +#define clamp( val, min, max ) ( ((val) > (max)) ? (max) : ( ((val) < (min)) ? (min) : (val) ) ) + int iHealth = clamp( pev->health, 0, 255 ); // make sure that no negative health values are sent + if( pev->health > 0.0f && pev->health <= 1.0f ) + iHealth = 1; // send "health" update message MESSAGE_BEGIN( MSG_ONE, gmsgHealth, NULL, pev ); @@ -4336,7 +4434,8 @@ void CBasePlayer::DropPlayerItem( char *pszItemName ) // item we want to drop and hit a BREAK; pWeapon is the item. if( pWeapon ) { - g_pGameRules->GetNextBestWeapon( this, pWeapon ); + if( !g_pGameRules->GetNextBestWeapon( this, pWeapon ) ) + return; // can't drop the item they asked for, may be our last item or something we can't holster UTIL_MakeVectors( pev->angles ); diff --git a/dlls/player.h b/dlls/player.h index e75787ee..cb2bddf8 100644 --- a/dlls/player.h +++ b/dlls/player.h @@ -86,6 +86,18 @@ enum sbar_data class CBasePlayer : public CBaseMonster { public: + // Spectator camera + void Observer_FindNextPlayer( bool bReverse ); + void Observer_HandleButtons(); + void Observer_SetMode( int iMode ); + void Observer_CheckTarget(); + void Observer_CheckProperties(); + EHANDLE m_hObserverTarget; + float m_flNextObserverInput; + int m_iObserverWeapon; // weapon of current tracked target + int m_iObserverLastMode;// last used observer mode + int IsObserver() { return pev->iuser1; }; + int random_seed; // See that is shared between client & server for shared weapons code int m_iPlayerSound;// the index of the sound list slot reserved for this player diff --git a/dlls/rpg.cpp b/dlls/rpg.cpp index 1fec5cf1..95c9132a 100644 --- a/dlls/rpg.cpp +++ b/dlls/rpg.cpp @@ -297,7 +297,7 @@ void CRpg::Reload( void ) // Set the next attack time into the future so that WeaponIdle will get called more often // than reload, allowing the RPG LTD to be updated - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; + m_flNextPrimaryAttack = GetNextAttackDelay( 0.5 ); if( m_cActiveRockets && m_fSpotActive ) { @@ -463,7 +463,7 @@ void CRpg::PrimaryAttack() m_iClip--; - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.5; + m_flNextPrimaryAttack = GetNextAttackDelay( 1.5 ); m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.5; } else diff --git a/dlls/satchel.cpp b/dlls/satchel.cpp index 48ec5b9a..05d1fc8c 100644 --- a/dlls/satchel.cpp +++ b/dlls/satchel.cpp @@ -354,7 +354,7 @@ void CSatchel::PrimaryAttack() } m_chargeReady = 2; - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; + m_flNextPrimaryAttack = GetNextAttackDelay( 0.5 ); m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; break; @@ -401,7 +401,7 @@ void CSatchel::Throw( void ) m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.0; + m_flNextPrimaryAttack = GetNextAttackDelay( 1.0 ); m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; } } @@ -442,7 +442,7 @@ void CSatchel::WeaponIdle( void ) // use tripmine animations strcpy( m_pPlayer->m_szAnimExtention, "trip" ); - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; + m_flNextPrimaryAttack = GetNextAttackDelay( 0.5 ); m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; m_chargeReady = 0; break; diff --git a/dlls/saverestore.h b/dlls/saverestore.h index f76613e8..a9ad2c54 100644 --- a/dlls/saverestore.h +++ b/dlls/saverestore.h @@ -59,7 +59,7 @@ public: void WriteVector( const char *pname, const float *value, int count ); // Save a vector void WritePositionVector( const char *pname, const Vector &value ); // Offset for landmark if necessary void WritePositionVector( const char *pname, const float *value, int count ); // array of pos vectors - void WriteFunction( const char *pname, const int *value, int count ); // Save a function pointer + void WriteFunction( const char *pname, void **value, int count ); // Save a function pointer int WriteEntVars( const char *pname, entvars_t *pev ); // Save entvars_t (entvars_t) int WriteFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ); diff --git a/dlls/shotgun.cpp b/dlls/shotgun.cpp index 8c96e99c..595561e2 100644 --- a/dlls/shotgun.cpp +++ b/dlls/shotgun.cpp @@ -119,7 +119,7 @@ void CShotgun::PrimaryAttack() if( m_pPlayer->pev->waterlevel == 3 ) { PlayEmptySound(); - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15; + m_flNextPrimaryAttack = GetNextAttackDelay( 0.15 ); return; } @@ -172,7 +172,7 @@ void CShotgun::PrimaryAttack() if( m_iClip != 0 ) m_flPumpTime = gpGlobals->time + 0.5; - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.75; + m_flNextPrimaryAttack = GetNextAttackDelay( 0.75 ); m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.75; if( m_iClip != 0 ) m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 5.0; @@ -187,7 +187,7 @@ void CShotgun::SecondaryAttack( void ) if( m_pPlayer->pev->waterlevel == 3 ) { PlayEmptySound(); - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15; + m_flNextPrimaryAttack = GetNextAttackDelay( 0.15 ); return; } @@ -243,7 +243,7 @@ void CShotgun::SecondaryAttack( void ) if( m_iClip != 0 ) m_flPumpTime = gpGlobals->time + 0.95; - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.5; + m_flNextPrimaryAttack = GetNextAttackDelay( 1.5 ); m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.5; if( m_iClip != 0 ) m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 6.0; @@ -269,7 +269,7 @@ void CShotgun::Reload( void ) m_fInSpecialReload = 1; m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.6; m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.6; - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.0; + m_flNextPrimaryAttack = GetNextAttackDelay( 1.0 ); m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0; return; } diff --git a/dlls/squeakgrenade.cpp b/dlls/squeakgrenade.cpp index 22200b74..30ddda62 100644 --- a/dlls/squeakgrenade.cpp +++ b/dlls/squeakgrenade.cpp @@ -533,7 +533,7 @@ void CSqueak::PrimaryAttack() m_fJustThrown = 1; - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.3; + m_flNextPrimaryAttack = GetNextAttackDelay( 0.3 ); m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0; } } diff --git a/dlls/subs.cpp b/dlls/subs.cpp index bc7baf18..5ebe757b 100644 --- a/dlls/subs.cpp +++ b/dlls/subs.cpp @@ -415,6 +415,14 @@ After moving, set origin to exact final destination, call "move done" function */ void CBaseToggle::LinearMoveDone( void ) { + Vector delta = m_vecFinalDest - pev->origin; + float error = delta.Length(); + if( error > 0.03125 ) + { + LinearMove( m_vecFinalDest, 100 ); + return; + } + UTIL_SetOrigin( pev, m_vecFinalDest ); pev->velocity = g_vecZero; pev->nextthink = -1; diff --git a/dlls/triggers.cpp b/dlls/triggers.cpp index d7f9483c..958f899f 100644 --- a/dlls/triggers.cpp +++ b/dlls/triggers.cpp @@ -688,7 +688,7 @@ void PlayCDTrack( int iTrack ) if( iTrack == -1 ) { - CLIENT_COMMAND( pClient, "cd pause\n" ); + CLIENT_COMMAND( pClient, "cd stop\n" ); } else { diff --git a/dlls/tripmine.cpp b/dlls/tripmine.cpp index f04d906a..e2ed0817 100644 --- a/dlls/tripmine.cpp +++ b/dlls/tripmine.cpp @@ -470,7 +470,7 @@ void CTripmine::PrimaryAttack( void ) }*/ - m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.3; + m_flNextPrimaryAttack = GetNextAttackDelay( 0.3 ); m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); } diff --git a/dlls/util.cpp b/dlls/util.cpp index d1fceb0a..4fc0d51a 100644 --- a/dlls/util.cpp +++ b/dlls/util.cpp @@ -1886,7 +1886,7 @@ void CSave::WritePositionVector( const char *pname, const float *value, int coun } } -void CSave::WriteFunction( const char *pname, const int *data, int count ) +void CSave::WriteFunction( const char *pname, void **data, int count ) { const char *functionName; @@ -2042,7 +2042,7 @@ int CSave::WriteFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *pFi WriteInt( pTest->fieldName, (int *)(char *)pOutputData, pTest->fieldSize ); break; case FIELD_FUNCTION: - WriteFunction( pTest->fieldName, (int *)pOutputData, pTest->fieldSize ); + WriteFunction( pTest->fieldName, (void **)pOutputData, pTest->fieldSize ); break; default: ALERT( at_error, "Bad field type\n" ); diff --git a/dlls/util.h b/dlls/util.h index e8aee878..f8ae0b6a 100644 --- a/dlls/util.h +++ b/dlls/util.h @@ -37,7 +37,7 @@ extern globalvars_t *gpGlobals; #define STRING(offset) (const char *)(gpGlobals->pStringBase + (int)offset) #if !defined __amd64__ || defined(CLIENT_DLL) -#define MAKE_STRING(str) ((int)(size_t)str - (int)(size_t)STRING(0)) +#define MAKE_STRING(str) ((size_t)str - (size_t)STRING(0)) #else #define MAKE_STRING ALLOC_STRING #endif diff --git a/dlls/weapons.cpp b/dlls/weapons.cpp index ff03bbfc..ee2a8547 100644 --- a/dlls/weapons.cpp +++ b/dlls/weapons.cpp @@ -612,6 +612,11 @@ void CBasePlayerWeapon::ItemPostFrame( void ) m_fInReload = FALSE; } + if( !(m_pPlayer->pev->button & IN_ATTACK ) ) + { + m_flLastFireTime = 0.0f; + } + if( ( m_pPlayer->pev->button & IN_ATTACK2 ) && CanAttack( m_flNextSecondaryAttack, gpGlobals->time, UseDecrement() ) ) { if( pszAmmo2() && !m_pPlayer->m_rgAmmo[SecondaryAmmoIndex()] ) @@ -943,6 +948,7 @@ BOOL CBasePlayerWeapon::DefaultDeploy( char *szViewModel, char *szWeaponModel, i m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0; + m_flLastFireTime = 0.0f; return TRUE; } @@ -1130,6 +1136,36 @@ void CBasePlayerWeapon::RetireWeapon( void ) g_pGameRules->GetNextBestWeapon( m_pPlayer, this ); } +//========================================================================= +// GetNextAttackDelay - An accurate way of calcualting the next attack time. +//========================================================================= +float CBasePlayerWeapon::GetNextAttackDelay( float delay ) +{ + if( m_flLastFireTime == 0 || m_flNextPrimaryAttack == -1 ) + { + // At this point, we are assuming that the client has stopped firing + // and we are going to reset our book keeping variables. + m_flLastFireTime = gpGlobals->time; + m_flPrevPrimaryAttack = delay; + } + // calculate the time between this shot and the previous + float flTimeBetweenFires = gpGlobals->time - m_flLastFireTime; + float flCreep = 0.0f; + if( flTimeBetweenFires > 0 ) + flCreep = flTimeBetweenFires - m_flPrevPrimaryAttack; // postive or negative + + // save the last fire time + m_flLastFireTime = gpGlobals->time; + + float flNextAttack = UTIL_WeaponTimeBase() + delay - flCreep; + // we need to remember what the m_flNextPrimaryAttack time is set to for each shot, + // store it as m_flPrevPrimaryAttack. + m_flPrevPrimaryAttack = flNextAttack - UTIL_WeaponTimeBase(); + //char szMsg[256]; + //_snprintf( szMsg, sizeof(szMsg), "next attack time: %0.4f\n", gpGlobals->time + flNextAttack ); + //OutputDebugString( szMsg ); + return flNextAttack; +} //********************************************************* // weaponbox code: //********************************************************* diff --git a/dlls/weapons.h b/dlls/weapons.h index 5112254a..3e6fc5ce 100644 --- a/dlls/weapons.h +++ b/dlls/weapons.h @@ -331,6 +331,7 @@ public: void PrintState( void ); virtual CBasePlayerItem *GetWeaponPtr( void ) { return (CBasePlayerItem *)this; }; + float GetNextAttackDelay( float delay ); float m_flPumpTime; int m_fInSpecialReload; // Are we in the middle of a reload for the shotguns @@ -345,6 +346,10 @@ public: int m_fInReload; // Are we in the middle of a reload; int m_iDefaultAmmo;// how much ammo you get when you pick up this weapon as placed by a level designer. + + // hle time creep vars + float m_flPrevPrimaryAttack; + float m_flLastFireTime; }; class CBasePlayerAmmo : public CBaseEntity diff --git a/dlls/zombie.cpp b/dlls/zombie.cpp index 7fe416c7..b20293c1 100644 --- a/dlls/zombie.cpp +++ b/dlls/zombie.cpp @@ -169,13 +169,15 @@ void CZombie::IdleSound( void ) int pitch = 95 + RANDOM_LONG( 0, 9 ); // Play a random idle sound - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, pIdleSounds[RANDOM_LONG( 0, ARRAYSIZE( pIdleSounds ) -1 )], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG( -5, 5 ) ); + EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, pIdleSounds[RANDOM_LONG( 0, ARRAYSIZE( pIdleSounds ) -1 )], 1.0, ATTN_NORM, 0, pitch ); } void CZombie::AttackSound( void ) { + int pitch = 95 + RANDOM_LONG( 0, 9 ); + // Play a random attack sound - EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, pAttackSounds[RANDOM_LONG( 0, ARRAYSIZE( pAttackSounds ) - 1 )], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG( -5, 5 ) ); + EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, pAttackSounds[RANDOM_LONG( 0, ARRAYSIZE( pAttackSounds ) - 1 )], 1.0, ATTN_NORM, 0, pitch ); } //========================================================= diff --git a/engine/eiface.h b/engine/eiface.h index 903451f5..3419e5bd 100644 --- a/engine/eiface.h +++ b/engine/eiface.h @@ -57,7 +57,8 @@ 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_model_specifybounds, // For model files only, the geometry must fit in the specified bbox + force_model_specifybounds_if_avail // For Steam model files only, the geometry must fit in the specified bbox (if the file is available) } FORCE_TYPE; // Returned by TraceLine @@ -88,7 +89,7 @@ typedef struct int fPlayTrack; } CDStatus; -typedef unsigned long CRC32_t; +typedef unsigned int CRC32_t; // Engine hands this to DLLs for functionality callbacks typedef struct enginefuncs_s @@ -156,7 +157,7 @@ typedef struct enginefuncs_s void (*pfnCVarSetString)( const char *szVarName, const char *szValue ); void (*pfnAlertMessage)( ALERT_TYPE atype, char *szFmt, ... ); void (*pfnEngineFprintf)( FILE *pfile, char *szFmt, ... ); - void* (*pfnPvAllocEntPrivateData)( edict_t *pEdict, long cb ); + void* (*pfnPvAllocEntPrivateData)( edict_t *pEdict, int cb ); void* (*pfnPvEntPrivateData)( edict_t *pEdict ); void (*pfnFreeEntPrivateData)( edict_t *pEdict ); const char *(*pfnSzFromIndex)( int iString ); @@ -171,8 +172,8 @@ typedef struct enginefuncs_s int (*pfnRegUserMsg)( const char *pszName, int iSize ); void (*pfnAnimationAutomove)( const edict_t* pEdict, float flTime ); void (*pfnGetBonePosition)( const edict_t* pEdict, int iBone, float *rgflOrigin, float *rgflAngles ); - unsigned long (*pfnFunctionFromName)( const char *pName ); - const char *(*pfnNameForFunction)( unsigned long function ); + unsigned int (*pfnFunctionFromName)( const char *pName ); + const char *(*pfnNameForFunction)( unsigned int function ); void (*pfnClientPrintf)( edict_t* pEdict, PRINT_TYPE ptype, const char *szMsg ); // JOHN: engine callbacks so game DLL can print messages to individual clients void (*pfnServerPrint)( const char *szMsg ); const char *(*pfnCmd_Args)( void ); // these 3 added @@ -183,7 +184,7 @@ typedef struct enginefuncs_s void (*pfnCRC32_ProcessBuffer)( CRC32_t *pulCRC, void *p, int len ); void (*pfnCRC32_ProcessByte)( CRC32_t *pulCRC, unsigned char ch ); CRC32_t (*pfnCRC32_Final)( CRC32_t pulCRC ); - long (*pfnRandomLong)( long lLow, long lHigh ); + int (*pfnRandomLong)( int lLow, int lHigh ); float (*pfnRandomFloat)( float flLow, float flHigh ); void (*pfnSetView)( const edict_t *pClient, const edict_t *pViewent ); float (*pfnTime)( void ); @@ -276,7 +277,7 @@ typedef struct KeyValueData_s char *szClassName; // in: entity classname char *szKeyName; // in: name of key char *szValue; // in: value of key - long fHandled; // out: DLL sets to true if key-value pair was understood + int fHandled; // out: DLL sets to true if key-value pair was understood } KeyValueData; @@ -354,7 +355,7 @@ typedef enum _fieldtypes FIELD_TYPECOUNT // MUST BE LAST } FIELDTYPE; -#ifndef offsetof +#if !defined(offsetof) && !defined(GNUC) #define offsetof(s,m) (size_t)&(((s *)0)->m) #endif diff --git a/engine/shake.h b/engine/shake.h index c644a476..b2e88a33 100644 --- a/engine/shake.h +++ b/engine/shake.h @@ -36,7 +36,7 @@ extern int gmsgFade; #define FFADE_OUT 0x0001 // Fade out (not in) #define FFADE_MODULATE 0x0002 // Modulate (don't blend) #define FFADE_STAYOUT 0x0004 // ignores the duration, stays faded out until new ScreenFade message received - +#define FFADE_LONGFADE 0x0008 // used to indicate the fade can be longer than 16 seconds (added for czero) // This structure is sent over the net to describe a screen fade event typedef struct @@ -47,4 +47,4 @@ typedef struct byte r, g, b, a; // fade to color ( max alpha ) } ScreenFade; -#endif // SHAKE_H \ No newline at end of file +#endif // SHAKE_H diff --git a/engine/studio.h b/engine/studio.h index b5b709bb..cd572419 100644 --- a/engine/studio.h +++ b/engine/studio.h @@ -33,14 +33,14 @@ Studio models are position independent, so the cache manager can move them. // studio limits #define MAXSTUDIOTRIANGLES 32768 // max triangles per model #define MAXSTUDIOVERTS 4096 // max vertices per submodel -#define MAXSTUDIOSEQUENCES 256 // total animation sequences +#define MAXSTUDIOSEQUENCES 2048 // total animation sequences #define MAXSTUDIOSKINS 256 // total textures #define MAXSTUDIOSRCBONES 512 // bones allowed at source movement #define MAXSTUDIOBONES 128 // total bones actually used #define MAXSTUDIOMODELS 32 // sub-models per model #define MAXSTUDIOBODYPARTS 32 // body parts per submodel #define MAXSTUDIOGROUPS 16 // sequence groups (e.g. barney01.mdl, barney02.mdl, e.t.c) -#define MAXSTUDIOANIMATIONS 512 // max frames per sequence +#define MAXSTUDIOANIMATIONS 2048 // max frames per sequence #define MAXSTUDIOMESHES 256 // max textures per model #define MAXSTUDIOEVENTS 1024 // events per model #define MAXSTUDIOPIVOTS 256 // pivot points @@ -214,10 +214,8 @@ typedef struct { char label[32]; // textual name char name[64]; // file name - cache_user_t cache; // cache index pointer -#ifndef __amd64 - int data; // hack for group 0 -#endif + int unused1; // // was "cache" - index pointer + int unused2; // was "data" - hack for group 0 } mstudioseqgroup_t; // sequence descriptions diff --git a/pm_shared/pm_defs.h b/pm_shared/pm_defs.h index d29bff19..cd17ce54 100644 --- a/pm_shared/pm_defs.h +++ b/pm_shared/pm_defs.h @@ -201,7 +201,7 @@ typedef struct playermove_s pmtrace_t (*PM_PlayerTrace)( float *start, float *end, int traceFlags, int ignore_pe ); #endif struct pmtrace_s *(*PM_TraceLine)( float *start, float *end, int flags, int usehulll, int ignore_pe ); - long (*RandomLong)( long lLow, long lHigh ); + int (*RandomLong)( int lLow, int lHigh ); float (*RandomFloat)( float flLow, float flHigh ); int (*PM_GetModelType)( struct model_s *mod ); void (*PM_GetModelBounds)( struct model_s *mod, float *mins, float *maxs ); diff --git a/pm_shared/pm_materials.h b/pm_shared/pm_materials.h index cd1051d2..e625b4fc 100644 --- a/pm_shared/pm_materials.h +++ b/pm_shared/pm_materials.h @@ -28,4 +28,5 @@ #define CHAR_TEX_COMPUTER 'P' #define CHAR_TEX_GLASS 'Y' #define CHAR_TEX_FLESH 'F' +#define CHAR_TEX_SNOW 'N' #endif//PM_MATERIALS_H diff --git a/pm_shared/pm_shared.c b/pm_shared/pm_shared.c index de855a50..7a1fb966 100644 --- a/pm_shared/pm_shared.c +++ b/pm_shared/pm_shared.c @@ -87,6 +87,8 @@ playermove_t *pmove = NULL; #define PLAYER_LONGJUMP_SPEED 350 // how fast we longjump +#define PLAYER_DUCKING_MULTIPLIER 0.333 + // double to float warning #pragma warning(disable : 4244) #define max(a, b) (((a) > (b)) ? (a) : (b)) @@ -2017,9 +2019,9 @@ void PM_Duck( void ) if( pmove->flags & FL_DUCKING ) { - pmove->cmd.forwardmove *= 0.333; - pmove->cmd.sidemove *= 0.333; - pmove->cmd.upmove *= 0.333; + pmove->cmd.forwardmove *= PLAYER_DUCKING_MULTIPLIER; + pmove->cmd.sidemove *= PLAYER_DUCKING_MULTIPLIER; + pmove->cmd.upmove *= PLAYER_DUCKING_MULTIPLIER; } if( ( pmove->cmd.buttons & IN_DUCK ) || ( pmove->bInDuck ) || ( pmove->flags & FL_DUCKING ) ) @@ -2110,16 +2112,24 @@ void PM_LadderMove( physent_t *pLadder ) { float forward = 0, right = 0; vec3_t vpn, v_right; + float flSpeed = MAX_CLIMB_SPEED; + + // they shouldn't be able to move faster than their maxspeed + if( flSpeed > pmove->maxspeed ) + flSpeed = pmove->maxspeed; AngleVectors( pmove->angles, vpn, v_right, NULL ); + + if( pmove->flags & FL_DUCKING ) + flSpeed *= PLAYER_DUCKING_MULTIPLIER; if( pmove->cmd.buttons & IN_BACK ) - forward -= MAX_CLIMB_SPEED; + forward -= flSpeed; if( pmove->cmd.buttons & IN_FORWARD ) - forward += MAX_CLIMB_SPEED; + forward += flSpeed; if( pmove->cmd.buttons & IN_MOVELEFT ) - right -= MAX_CLIMB_SPEED; + right -= flSpeed; if( pmove->cmd.buttons & IN_MOVERIGHT ) - right += MAX_CLIMB_SPEED; + right += flSpeed; if( pmove->cmd.buttons & IN_JUMP ) {