diff options
Diffstat (limited to 'game/shared/sdk')
30 files changed, 4578 insertions, 0 deletions
diff --git a/game/shared/sdk/sdk_basegrenade_projectile.cpp b/game/shared/sdk/sdk_basegrenade_projectile.cpp new file mode 100644 index 0000000..567f7e7 --- /dev/null +++ b/game/shared/sdk/sdk_basegrenade_projectile.cpp @@ -0,0 +1,263 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "sdk_basegrenade_projectile.h" + +float GetCurrentGravity( void ); + + +#ifdef CLIENT_DLL + + #include "c_sdk_player.h" + +#else + + #include "soundent.h" + + BEGIN_DATADESC( CBaseGrenadeProjectile ) + DEFINE_THINKFUNC( DangerSoundThink ), + END_DATADESC() + +#endif + + +IMPLEMENT_NETWORKCLASS_ALIASED( BaseGrenadeProjectile, DT_BaseGrenadeProjectile ) + +BEGIN_NETWORK_TABLE( CBaseGrenadeProjectile, DT_BaseGrenadeProjectile ) + #ifdef CLIENT_DLL + RecvPropVector( RECVINFO( m_vInitialVelocity ) ) + #else + SendPropVector( SENDINFO( m_vInitialVelocity ), + 20, // nbits + 0, // flags + -3000, // low value + 3000 // high value + ) + #endif +END_NETWORK_TABLE() + + +#ifdef CLIENT_DLL + + + void CBaseGrenadeProjectile::PostDataUpdate( DataUpdateType_t type ) + { + BaseClass::PostDataUpdate( type ); + + if ( type == DATA_UPDATE_CREATED ) + { + // Now stick our initial velocity into the interpolation history + CInterpolatedVar< Vector > &interpolator = GetOriginInterpolator(); + + interpolator.ClearHistory(); + float changeTime = GetLastChangeTime( LATCH_SIMULATION_VAR ); + + // Add a sample 1 second back. + Vector vCurOrigin = GetLocalOrigin() - m_vInitialVelocity; + interpolator.AddToHead( changeTime - 1.0, &vCurOrigin, false ); + + // Add the current sample. + vCurOrigin = GetLocalOrigin(); + interpolator.AddToHead( changeTime, &vCurOrigin, false ); + } + } + + int CBaseGrenadeProjectile::DrawModel( int flags ) + { + // During the first half-second of our life, don't draw ourselves if he's + // still playing his throw animation. + // (better yet, we could draw ourselves in his hand). + if ( GetThrower() != C_BasePlayer::GetLocalPlayer() ) + { + if ( gpGlobals->curtime - m_flSpawnTime < 0.5 ) + { + C_SDKPlayer *pPlayer = dynamic_cast<C_SDKPlayer*>( GetThrower() ); + if ( pPlayer && pPlayer->m_PlayerAnimState->IsThrowingGrenade() ) + { + return 0; + } + } + } + + return BaseClass::DrawModel( flags ); + } + + void CBaseGrenadeProjectile::Spawn() + { + m_flSpawnTime = gpGlobals->curtime; + BaseClass::Spawn(); + } + +#else + + void CBaseGrenadeProjectile::Spawn( void ) + { + BaseClass::Spawn(); + + SetSolidFlags( FSOLID_NOT_STANDABLE ); + SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_CUSTOM ); + SetSolid( SOLID_BBOX ); // So it will collide with physics props! + + // smaller, cube bounding box so we rest on the ground + SetSize( Vector ( -2, -2, -2 ), Vector ( 2, 2, 2 ) ); + } + + void CBaseGrenadeProjectile::DangerSoundThink( void ) + { + if (!IsInWorld()) + { + Remove( ); + return; + } + + if( gpGlobals->curtime > m_flDetonateTime ) + { + Detonate(); + return; + } + + CSoundEnt::InsertSound ( SOUND_DANGER, GetAbsOrigin() + GetAbsVelocity() * 0.5, GetAbsVelocity().Length( ), 0.2 ); + + SetNextThink( gpGlobals->curtime + 0.2 ); + + if (GetWaterLevel() != 0) + { + SetAbsVelocity( GetAbsVelocity() * 0.5 ); + } + } + + //Sets the time at which the grenade will explode + void CBaseGrenadeProjectile::SetDetonateTimerLength( float timer ) + { + m_flDetonateTime = gpGlobals->curtime + timer; + } + + void CBaseGrenadeProjectile::ResolveFlyCollisionCustom( trace_t &trace, Vector &vecVelocity ) + { + //Assume all surfaces have the same elasticity + float flSurfaceElasticity = 1.0; + + //Don't bounce off of players with perfect elasticity + if( trace.m_pEnt && trace.m_pEnt->IsPlayer() ) + { + flSurfaceElasticity = 0.3; + } + + // if its breakable glass and we kill it, don't bounce. + // give some damage to the glass, and if it breaks, pass + // through it. + bool breakthrough = false; + + if( trace.m_pEnt && FClassnameIs( trace.m_pEnt, "func_breakable" ) ) + { + breakthrough = true; + } + + if( trace.m_pEnt && FClassnameIs( trace.m_pEnt, "func_breakable_surf" ) ) + { + breakthrough = true; + } + + if (breakthrough) + { + CTakeDamageInfo info( this, this, 10, DMG_CLUB ); + trace.m_pEnt->DispatchTraceAttack( info, GetAbsVelocity(), &trace ); + + ApplyMultiDamage(); + + if( trace.m_pEnt->m_iHealth <= 0 ) + { + // slow our flight a little bit + Vector vel = GetAbsVelocity(); + + vel *= 0.4; + + SetAbsVelocity( vel ); + return; + } + } + + float flTotalElasticity = GetElasticity() * flSurfaceElasticity; + flTotalElasticity = clamp( flTotalElasticity, 0.0f, 0.9f ); + + // NOTE: A backoff of 2.0f is a reflection + Vector vecAbsVelocity; + PhysicsClipVelocity( GetAbsVelocity(), trace.plane.normal, vecAbsVelocity, 2.0f ); + vecAbsVelocity *= flTotalElasticity; + + // Get the total velocity (player + conveyors, etc.) + VectorAdd( vecAbsVelocity, GetBaseVelocity(), vecVelocity ); + float flSpeedSqr = DotProduct( vecVelocity, vecVelocity ); + + // Stop if on ground. + if ( trace.plane.normal.z > 0.7f ) // Floor + { + // Verify that we have an entity. + CBaseEntity *pEntity = trace.m_pEnt; + Assert( pEntity ); + + SetAbsVelocity( vecAbsVelocity ); + + if ( flSpeedSqr < ( 30 * 30 ) ) + { + if ( pEntity->IsStandable() ) + { + SetGroundEntity( pEntity ); + } + + // Reset velocities. + SetAbsVelocity( vec3_origin ); + SetLocalAngularVelocity( vec3_angle ); + + //align to the ground so we're not standing on end + QAngle angle; + VectorAngles( trace.plane.normal, angle ); + + // rotate randomly in yaw + angle[1] = random->RandomFloat( 0, 360 ); + + // TODO: rotate around trace.plane.normal + + SetAbsAngles( angle ); + } + else + { + Vector vecDelta = GetBaseVelocity() - vecAbsVelocity; + Vector vecBaseDir = GetBaseVelocity(); + VectorNormalize( vecBaseDir ); + float flScale = vecDelta.Dot( vecBaseDir ); + + VectorScale( vecAbsVelocity, ( 1.0f - trace.fraction ) * gpGlobals->frametime, vecVelocity ); + VectorMA( vecVelocity, ( 1.0f - trace.fraction ) * gpGlobals->frametime, GetBaseVelocity() * flScale, vecVelocity ); + PhysicsPushEntity( vecVelocity, &trace ); + } + } + else + { + // If we get *too* slow, we'll stick without ever coming to rest because + // we'll get pushed down by gravity faster than we can escape from the wall. + if ( flSpeedSqr < ( 30 * 30 ) ) + { + // Reset velocities. + SetAbsVelocity( vec3_origin ); + SetLocalAngularVelocity( vec3_angle ); + } + else + { + SetAbsVelocity( vecAbsVelocity ); + } + } + + BounceSound(); + } + + void CBaseGrenadeProjectile::SetupInitialTransmittedGrenadeVelocity( const Vector &velocity ) + { + m_vInitialVelocity = velocity; + } + +#endif diff --git a/game/shared/sdk/sdk_basegrenade_projectile.h b/game/shared/sdk/sdk_basegrenade_projectile.h new file mode 100644 index 0000000..6838f2b --- /dev/null +++ b/game/shared/sdk/sdk_basegrenade_projectile.h @@ -0,0 +1,78 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef BASECSGRENADE_PROJECTILE_H +#define BASECSGRENADE_PROJECTILE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "basegrenade_shared.h" + + +#ifdef CLIENT_DLL + #define CBaseGrenadeProjectile C_BaseGrenadeProjectile +#endif + + +class CBaseGrenadeProjectile : public CBaseGrenade +{ +public: + DECLARE_CLASS( CBaseGrenadeProjectile, CBaseGrenade ); + DECLARE_NETWORKCLASS(); + + virtual void Spawn(); + + +public: + + // This gets sent to the client and placed in the client's interpolation history + // so the projectile starts out moving right off the bat. + CNetworkVector( m_vInitialVelocity ); + + +#ifdef CLIENT_DLL + CBaseGrenadeProjectile() {} + CBaseGrenadeProjectile( const CBaseGrenadeProjectile& ) {} + virtual int DrawModel( int flags ); + virtual void PostDataUpdate( DataUpdateType_t type ); + + float m_flSpawnTime; +#else + DECLARE_DATADESC(); + + //Constants for all CS Grenades + static inline float GetGrenadeGravity() { return 0.4f; } + static inline const float GetGrenadeFriction() { return 0.2f; } + static inline const float GetGrenadeElasticity() { return 0.45f; } + + //Think function to emit danger sounds for the AI + void DangerSoundThink( void ); + + virtual float GetShakeAmplitude( void ) { return 0.0f; } + + // Specify what velocity we want the grenade to have on the client immediately. + // Without this, the entity wouldn't have an interpolation history initially, so it would + // sit still until it had gotten a few updates from the server. + void SetupInitialTransmittedGrenadeVelocity( const Vector &velocity ); + +protected: + + //Set the time to detonate ( now + timer ) + void SetDetonateTimerLength( float timer ); + +private: + + //Custom collision to allow for constant elasticity on hit surfaces + virtual void ResolveFlyCollisionCustom( trace_t &trace, Vector &vecVelocity ); + + float m_flDetonateTime; +#endif +}; + + +#endif // BASECSGRENADE_PROJECTILE_H diff --git a/game/shared/sdk/sdk_fx_shared.cpp b/game/shared/sdk/sdk_fx_shared.cpp new file mode 100644 index 0000000..e7ceb02 --- /dev/null +++ b/game/shared/sdk/sdk_fx_shared.cpp @@ -0,0 +1,224 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "sdk_fx_shared.h" +#include "weapon_sdkbase.h" + +#ifndef CLIENT_DLL + #include "ilagcompensationmanager.h" +#endif + +#ifdef CLIENT_DLL + +#include "fx_impact.h" +#include "c_sdk_player.h" + + // this is a cheap ripoff from CBaseCombatWeapon::WeaponSound(): + void FX_WeaponSound( + int iPlayerIndex, + WeaponSound_t sound_type, + const Vector &vOrigin, + CSDKWeaponInfo *pWeaponInfo ) + { + + // If we have some sounds from the weapon classname.txt file, play a random one of them + const char *shootsound = pWeaponInfo->aShootSounds[ sound_type ]; + if ( !shootsound || !shootsound[0] ) + return; + + CBroadcastRecipientFilter filter; // this is client side only + if ( !te->CanPredict() ) + return; + + CBaseEntity::EmitSound( filter, iPlayerIndex, shootsound, &vOrigin ); + } + + class CGroupedSound + { + public: + string_t m_SoundName; + Vector m_vPos; + }; + + CUtlVector<CGroupedSound> g_GroupedSounds; + + + // Called by the ImpactSound function. + void ShotgunImpactSoundGroup( const char *pSoundName, const Vector &vEndPos ) + { + // Don't play the sound if it's too close to another impact sound. + for ( int i=0; i < g_GroupedSounds.Count(); i++ ) + { + CGroupedSound *pSound = &g_GroupedSounds[i]; + + if ( vEndPos.DistToSqr( pSound->m_vPos ) < 300*300 ) + { + if ( Q_stricmp( pSound->m_SoundName, pSoundName ) == 0 ) + return; + } + } + + // Ok, play the sound and add it to the list. + CLocalPlayerFilter filter; + C_BaseEntity::EmitSound( filter, NULL, pSoundName, &vEndPos ); + + int j = g_GroupedSounds.AddToTail(); + g_GroupedSounds[j].m_SoundName = pSoundName; + g_GroupedSounds[j].m_vPos = vEndPos; + } + + + void StartGroupingSounds() + { + Assert( g_GroupedSounds.Count() == 0 ); + SetImpactSoundRoute( ShotgunImpactSoundGroup ); + } + + + void EndGroupingSounds() + { + g_GroupedSounds.Purge(); + SetImpactSoundRoute( NULL ); + } + +#else + + #include "sdk_player.h" + #include "te_firebullets.h" + + // Server doesn't play sounds anyway. + void StartGroupingSounds() {} + void EndGroupingSounds() {} + void FX_WeaponSound ( int iPlayerIndex, + WeaponSound_t sound_type, + const Vector &vOrigin, + CSDKWeaponInfo *pWeaponInfo ) {}; + +#endif + + + +// This runs on both the client and the server. +// On the server, it only does the damage calculations. +// On the client, it does all the effects. +void FX_FireBullets( + int iPlayerIndex, + const Vector &vOrigin, + const QAngle &vAngles, + int iWeaponID, + int iMode, + int iSeed, + float flSpread + ) +{ + bool bDoEffects = true; + +#ifdef CLIENT_DLL + C_SDKPlayer *pPlayer = ToSDKPlayer( ClientEntityList().GetBaseEntity( iPlayerIndex ) ); +#else + CSDKPlayer *pPlayer = ToSDKPlayer( UTIL_PlayerByIndex( iPlayerIndex) ); +#endif + + const char * weaponAlias = WeaponIDToAlias( iWeaponID ); + + if ( !weaponAlias ) + { + DevMsg("FX_FireBullets: weapon alias for ID %i not found\n", iWeaponID ); + return; + } + + char wpnName[128]; + Q_snprintf( wpnName, sizeof( wpnName ), "weapon_%s", weaponAlias ); + WEAPON_FILE_INFO_HANDLE hWpnInfo = LookupWeaponInfoSlot( wpnName ); + + if ( hWpnInfo == GetInvalidWeaponInfoHandle() ) + { + DevMsg("FX_FireBullets: LookupWeaponInfoSlot failed for weapon %s\n", wpnName ); + return; + } + + CSDKWeaponInfo *pWeaponInfo = static_cast< CSDKWeaponInfo* >( GetFileWeaponInfoFromHandle( hWpnInfo ) ); + +#ifdef CLIENT_DLL + // Do the firing animation event. + if ( pPlayer && !pPlayer->IsDormant() ) + { + if ( iMode == Primary_Mode ) + pPlayer->m_PlayerAnimState->DoAnimationEvent( PLAYERANIMEVENT_FIRE_GUN_PRIMARY ); + else + pPlayer->m_PlayerAnimState->DoAnimationEvent( PLAYERANIMEVENT_FIRE_GUN_SECONDARY ); + } +#else + // if this is server code, send the effect over to client as temp entity + // Dispatch one message for all the bullet impacts and sounds. + TE_FireBullets( + iPlayerIndex, + vOrigin, + vAngles, + iWeaponID, + iMode, + iSeed, + flSpread + ); + + bDoEffects = false; // no effects on server +#endif + + iSeed++; + + int iDamage = pWeaponInfo->m_iDamage; + int iAmmoType = pWeaponInfo->iAmmoType; + + WeaponSound_t sound_type = SINGLE; + + if ( bDoEffects) + { + FX_WeaponSound( iPlayerIndex, sound_type, vOrigin, pWeaponInfo ); + } + + + // Fire bullets, calculate impacts & effects + + if ( !pPlayer ) + return; + + StartGroupingSounds(); + +#if !defined (CLIENT_DLL) + // Move other players back to history positions based on local player's lag + lagcompensation->StartLagCompensation( pPlayer, pPlayer->GetCurrentCommand() ); +#endif + + for ( int iBullet=0; iBullet < pWeaponInfo->m_iBullets; iBullet++ ) + { + RandomSeed( iSeed ); // init random system with this seed + + // Get circular gaussian spread. + float x, y; + x = RandomFloat( -0.5, 0.5 ) + RandomFloat( -0.5, 0.5 ); + y = RandomFloat( -0.5, 0.5 ) + RandomFloat( -0.5, 0.5 ); + + iSeed++; // use new seed for next bullet + + pPlayer->FireBullet( + vOrigin, + vAngles, + flSpread, + iDamage, + iAmmoType, + pPlayer, + bDoEffects, + x,y ); + } + +#if !defined (CLIENT_DLL) + lagcompensation->FinishLagCompensation( pPlayer ); +#endif + + EndGroupingSounds(); +} + diff --git a/game/shared/sdk/sdk_fx_shared.h b/game/shared/sdk/sdk_fx_shared.h new file mode 100644 index 0000000..2437909 --- /dev/null +++ b/game/shared/sdk/sdk_fx_shared.h @@ -0,0 +1,27 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef FX_CS_SHARED_H +#define FX_CS_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + +// This runs on both the client and the server. +// On the server, it only does the damage calculations. +// On the client, it does all the effects. +void FX_FireBullets( + int iPlayer, + const Vector &vOrigin, + const QAngle &vAngles, + int iWeaponID, + int iMode, + int iSeed, + float flSpread + ); + + +#endif // FX_CS_SHARED_H diff --git a/game/shared/sdk/sdk_gamemovement.cpp b/game/shared/sdk/sdk_gamemovement.cpp new file mode 100644 index 0000000..7134e13 --- /dev/null +++ b/game/shared/sdk/sdk_gamemovement.cpp @@ -0,0 +1,53 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +//========= Copyright � 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= +#include "cbase.h" +#include "gamemovement.h" +#include "sdk_gamerules.h" +#include "sdk_shareddefs.h" +#include "in_buttons.h" +#include "movevars_shared.h" + + +#ifdef CLIENT_DLL + #include "c_sdk_player.h" +#else + #include "sdk_player.h" +#endif + + +class CSDKGameMovement : public CGameMovement +{ +public: + DECLARE_CLASS( CSDKGameMovement, CGameMovement ); + + CSDKGameMovement(); +}; + + +// Expose our interface. +static CSDKGameMovement g_GameMovement; +IGameMovement *g_pGameMovement = ( IGameMovement * )&g_GameMovement; + +EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CGameMovement, IGameMovement,INTERFACENAME_GAMEMOVEMENT, g_GameMovement ); + + +// ---------------------------------------------------------------------------------------- // +// CSDKGameMovement. +// ---------------------------------------------------------------------------------------- // + +CSDKGameMovement::CSDKGameMovement() +{ + //m_vecViewOffsetNormal = SDK_PLAYER_VIEW_OFFSET; +} + diff --git a/game/shared/sdk/sdk_gamerules.cpp b/game/shared/sdk/sdk_gamerules.cpp new file mode 100644 index 0000000..7aff040 --- /dev/null +++ b/game/shared/sdk/sdk_gamerules.cpp @@ -0,0 +1,369 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: The TF Game rules +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "sdk_gamerules.h" +#include "ammodef.h" +#include "KeyValues.h" +#include "weapon_sdkbase.h" + + +#ifdef CLIENT_DLL + + +#else + + #include "voice_gamemgr.h" + #include "team.h" + +#endif + + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +#ifndef CLIENT_DLL +LINK_ENTITY_TO_CLASS(info_player_terrorist, CPointEntity); +LINK_ENTITY_TO_CLASS(info_player_counterterrorist,CPointEntity); +#endif + +REGISTER_GAMERULES_CLASS( CSDKGameRules ); + + +BEGIN_NETWORK_TABLE_NOBASE( CSDKGameRules, DT_SDKGameRules ) +END_NETWORK_TABLE() + + +LINK_ENTITY_TO_CLASS( sdk_gamerules, CSDKGameRulesProxy ); +IMPLEMENT_NETWORKCLASS_ALIASED( SDKGameRulesProxy, DT_SDKGameRulesProxy ) + + +#ifdef CLIENT_DLL + void RecvProxy_SDKGameRules( const RecvProp *pProp, void **pOut, void *pData, int objectID ) + { + CSDKGameRules *pRules = SDKGameRules(); + Assert( pRules ); + *pOut = pRules; + } + + BEGIN_RECV_TABLE( CSDKGameRulesProxy, DT_SDKGameRulesProxy ) + RecvPropDataTable( "sdk_gamerules_data", 0, 0, &REFERENCE_RECV_TABLE( DT_SDKGameRules ), RecvProxy_SDKGameRules ) + END_RECV_TABLE() +#else + void *SendProxy_SDKGameRules( const SendProp *pProp, const void *pStructBase, const void *pData, CSendProxyRecipients *pRecipients, int objectID ) + { + CSDKGameRules *pRules = SDKGameRules(); + Assert( pRules ); + pRecipients->SetAllRecipients(); + return pRules; + } + + BEGIN_SEND_TABLE( CSDKGameRulesProxy, DT_SDKGameRulesProxy ) + SendPropDataTable( "sdk_gamerules_data", 0, &REFERENCE_SEND_TABLE( DT_SDKGameRules ), SendProxy_SDKGameRules ) + END_SEND_TABLE() +#endif + + +#ifdef CLIENT_DLL + + +#else + + // --------------------------------------------------------------------------------------------------- // + // Voice helper + // --------------------------------------------------------------------------------------------------- // + + class CVoiceGameMgrHelper : public IVoiceGameMgrHelper + { + public: + virtual bool CanPlayerHearPlayer( CBasePlayer *pListener, CBasePlayer *pTalker ) + { + // Dead players can only be heard by other dead team mates + if ( pTalker->IsAlive() == false ) + { + if ( pListener->IsAlive() == false ) + return ( pListener->InSameTeam( pTalker ) ); + + return false; + } + + return ( pListener->InSameTeam( pTalker ) ); + } + }; + CVoiceGameMgrHelper g_VoiceGameMgrHelper; + IVoiceGameMgrHelper *g_pVoiceGameMgrHelper = &g_VoiceGameMgrHelper; + + + + // --------------------------------------------------------------------------------------------------- // + // Globals. + // --------------------------------------------------------------------------------------------------- // + + // NOTE: the indices here must match TEAM_TERRORIST, TEAM_CT, TEAM_SPECTATOR, etc. + char *sTeamNames[] = + { + "Unassigned", + "Spectator", + "Terrorist", + "Counter-Terrorist" + }; + + + // --------------------------------------------------------------------------------------------------- // + // Global helper functions. + // --------------------------------------------------------------------------------------------------- // + + // World.cpp calls this but we don't use it in SDK. + void InitBodyQue() + { + } + + + // --------------------------------------------------------------------------------------------------- // + // CSDKGameRules implementation. + // --------------------------------------------------------------------------------------------------- // + + CSDKGameRules::CSDKGameRules() + { + // Create the team managers + for ( int i = 0; i < ARRAYSIZE( sTeamNames ); i++ ) + { + CTeam *pTeam = static_cast<CTeam*>(CreateEntityByName( "sdk_team_manager" )); + pTeam->Init( sTeamNames[i], i ); + + g_Teams.AddToTail( pTeam ); + } + } + + //----------------------------------------------------------------------------- + // Purpose: + //----------------------------------------------------------------------------- + CSDKGameRules::~CSDKGameRules() + { + // Note, don't delete each team since they are in the gEntList and will + // automatically be deleted from there, instead. + g_Teams.Purge(); + } + + //----------------------------------------------------------------------------- + // Purpose: TF2 Specific Client Commands + // Input : + // Output : + //----------------------------------------------------------------------------- + bool CSDKGameRules::ClientCommand( CBaseEntity *pEdict, const CCommand &args ) + { + return BaseClass::ClientCommand( pEdict, args ); + } + + //----------------------------------------------------------------------------- + // Purpose: Player has just spawned. Equip them. + //----------------------------------------------------------------------------- + + void CSDKGameRules::RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrcIn, float flRadius, int iClassIgnore ) + { + RadiusDamage( info, vecSrcIn, flRadius, iClassIgnore, false ); + } + + // Add the ability to ignore the world trace + void CSDKGameRules::RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrcIn, float flRadius, int iClassIgnore, bool bIgnoreWorld ) + { + CBaseEntity *pEntity = NULL; + trace_t tr; + float flAdjustedDamage, falloff; + Vector vecSpot; + Vector vecToTarget; + Vector vecEndPos; + + Vector vecSrc = vecSrcIn; + + if ( flRadius ) + falloff = info.GetDamage() / flRadius; + else + falloff = 1.0; + + int bInWater = (UTIL_PointContents ( vecSrc ) & MASK_WATER) ? true : false; + + vecSrc.z += 1;// in case grenade is lying on the ground + + // iterate on all entities in the vicinity. + for ( CEntitySphereQuery sphere( vecSrc, flRadius ); ( pEntity = sphere.GetCurrentEntity() ) != NULL; sphere.NextEntity() ) + { + if ( pEntity->m_takedamage != DAMAGE_NO ) + { + // UNDONE: this should check a damage mask, not an ignore + if ( iClassIgnore != CLASS_NONE && pEntity->Classify() == iClassIgnore ) + {// houndeyes don't hurt other houndeyes with their attack + continue; + } + + // blast's don't tavel into or out of water + if (bInWater && pEntity->GetWaterLevel() == 0) + continue; + if (!bInWater && pEntity->GetWaterLevel() == 3) + continue; + + // radius damage can only be blocked by the world + vecSpot = pEntity->BodyTarget( vecSrc ); + + + + bool bHit = false; + + if( bIgnoreWorld ) + { + vecEndPos = vecSpot; + bHit = true; + } + else + { + UTIL_TraceLine( vecSrc, vecSpot, MASK_SOLID_BRUSHONLY, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); + + if (tr.startsolid) + { + // if we're stuck inside them, fixup the position and distance + tr.endpos = vecSrc; + tr.fraction = 0.0; + } + + vecEndPos = tr.endpos; + + if( tr.fraction == 1.0 || tr.m_pEnt == pEntity ) + { + bHit = true; + } + } + + if ( bHit ) + { + // the explosion can 'see' this entity, so hurt them! + //vecToTarget = ( vecSrc - vecEndPos ); + vecToTarget = ( vecEndPos - vecSrc ); + + // decrease damage for an ent that's farther from the bomb. + flAdjustedDamage = vecToTarget.Length() * falloff; + flAdjustedDamage = info.GetDamage() - flAdjustedDamage; + + if ( flAdjustedDamage > 0 ) + { + CTakeDamageInfo adjustedInfo = info; + adjustedInfo.SetDamage( flAdjustedDamage ); + + Vector dir = vecToTarget; + VectorNormalize( dir ); + + // If we don't have a damage force, manufacture one + if ( adjustedInfo.GetDamagePosition() == vec3_origin || adjustedInfo.GetDamageForce() == vec3_origin ) + { + CalculateExplosiveDamageForce( &adjustedInfo, dir, vecSrc, 1.5 /* explosion scale! */ ); + } + else + { + // Assume the force passed in is the maximum force. Decay it based on falloff. + float flForce = adjustedInfo.GetDamageForce().Length() * falloff; + adjustedInfo.SetDamageForce( dir * flForce ); + adjustedInfo.SetDamagePosition( vecSrc ); + } + + pEntity->TakeDamage( adjustedInfo ); + + // Now hit all triggers along the way that respond to damage... + pEntity->TraceAttackToTriggers( adjustedInfo, vecSrc, vecEndPos, dir ); + } + } + } + } + } + + void CSDKGameRules::Think() + { + BaseClass::Think(); + } + +#endif + + +bool CSDKGameRules::ShouldCollide( int collisionGroup0, int collisionGroup1 ) +{ + if ( collisionGroup0 > collisionGroup1 ) + { + // swap so that lowest is always first + swap(collisionGroup0,collisionGroup1); + } + + //Don't stand on COLLISION_GROUP_WEAPON + if( collisionGroup0 == COLLISION_GROUP_PLAYER_MOVEMENT && + collisionGroup1 == COLLISION_GROUP_WEAPON ) + { + return false; + } + + return BaseClass::ShouldCollide( collisionGroup0, collisionGroup1 ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Init CS ammo definitions +//----------------------------------------------------------------------------- + +// shared ammo definition +// JAY: Trying to make a more physical bullet response +#define BULLET_MASS_GRAINS_TO_LB(grains) (0.002285*(grains)/16.0f) +#define BULLET_MASS_GRAINS_TO_KG(grains) lbs2kg(BULLET_MASS_GRAINS_TO_LB(grains)) + +// exaggerate all of the forces, but use real numbers to keep them consistent +#define BULLET_IMPULSE_EXAGGERATION 1 + +// convert a velocity in ft/sec and a mass in grains to an impulse in kg in/s +#define BULLET_IMPULSE(grains, ftpersec) ((ftpersec)*12*BULLET_MASS_GRAINS_TO_KG(grains)*BULLET_IMPULSE_EXAGGERATION) + + +CAmmoDef* GetAmmoDef() +{ + static CAmmoDef def; + static bool bInitted = false; + + if ( !bInitted ) + { + bInitted = true; + + // def.AddAmmoType( BULLET_PLAYER_50AE, DMG_BULLET, TRACER_LINE, 0, 0, "ammo_50AE_max", 2400, 0, 10, 14 ); + def.AddAmmoType( AMMO_GRENADE, DMG_BLAST, TRACER_LINE, 0, 0, 1/*max carry*/, 1, 0 ); + def.AddAmmoType( AMMO_BULLETS, DMG_BULLET, TRACER_LINE, 0, 0, 1/*max carry*/, 1, 0 ); + } + + return &def; +} + + +#ifndef CLIENT_DLL + +const char *CSDKGameRules::GetChatPrefix( bool bTeamOnly, CBasePlayer *pPlayer ) +{ + return "(chat prefix)"; +} + +#endif + +//----------------------------------------------------------------------------- +// Purpose: Find the relationship between players (teamplay vs. deathmatch) +//----------------------------------------------------------------------------- +int CSDKGameRules::PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ) +{ +#ifndef CLIENT_DLL + // half life multiplay has a simple concept of Player Relationships. + // you are either on another player's team, or you are not. + if ( !pPlayer || !pTarget || !pTarget->IsPlayer() || IsTeamplay() == false ) + return GR_NOTTEAMMATE; + + if ( (*GetTeamID(pPlayer) != '\0') && (*GetTeamID(pTarget) != '\0') && !stricmp( GetTeamID(pPlayer), GetTeamID(pTarget) ) ) + return GR_TEAMMATE; + +#endif + + return GR_NOTTEAMMATE; +} diff --git a/game/shared/sdk/sdk_gamerules.h b/game/shared/sdk/sdk_gamerules.h new file mode 100644 index 0000000..df1b79b --- /dev/null +++ b/game/shared/sdk/sdk_gamerules.h @@ -0,0 +1,88 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: The TF Game rules object +// +// $Workfile: $ +// $Date: $ +// $NoKeywords: $ +//=============================================================================// + +#ifndef SDK_GAMERULES_H +#define SDK_GAMERULES_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "teamplay_gamerules.h" +#include "convar.h" +#include "gamevars_shared.h" + +#ifdef CLIENT_DLL + #include "c_baseplayer.h" +#else + #include "player.h" +#endif + + +#ifdef CLIENT_DLL + #define CSDKGameRules C_SDKGameRules + #define CSDKGameRulesProxy C_SDKGameRulesProxy +#endif + + +class CSDKGameRulesProxy : public CGameRulesProxy +{ +public: + DECLARE_CLASS( CSDKGameRulesProxy, CGameRulesProxy ); + DECLARE_NETWORKCLASS(); +}; + + +class CSDKGameRules : public CTeamplayRules +{ +public: + DECLARE_CLASS( CSDKGameRules, CTeamplayRules ); + + virtual bool ShouldCollide( int collisionGroup0, int collisionGroup1 ); + + virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ); + virtual bool IsTeamplay( void ) { return false; } + +#ifdef CLIENT_DLL + + DECLARE_CLIENTCLASS_NOBASE(); // This makes datatables able to access our private vars. + +#else + + DECLARE_SERVERCLASS_NOBASE(); // This makes datatables able to access our private vars. + + CSDKGameRules(); + virtual ~CSDKGameRules(); + + virtual bool ClientCommand( CBaseEntity *pEdict, const CCommand &args ); + virtual void RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrcIn, float flRadius, int iClassIgnore ); + virtual void Think(); + + virtual const char *GetChatPrefix( bool bTeamOnly, CBasePlayer *pPlayer ); + +private: + + void RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrcIn, float flRadius, int iClassIgnore, bool bIgnoreWorld ); + + +#endif +}; + +//----------------------------------------------------------------------------- +// Gets us at the team fortress game rules +//----------------------------------------------------------------------------- + +inline CSDKGameRules* SDKGameRules() +{ + return static_cast<CSDKGameRules*>(g_pGameRules); +} + + +#endif // SDK_GAMERULES_H diff --git a/game/shared/sdk/sdk_player_shared.cpp b/game/shared/sdk/sdk_player_shared.cpp new file mode 100644 index 0000000..f9b4911 --- /dev/null +++ b/game/shared/sdk/sdk_player_shared.cpp @@ -0,0 +1,160 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" + +#ifdef CLIENT_DLL + + #include "c_sdk_player.h" + +#else + + #include "sdk_player.h" + +#endif + +#include "gamevars_shared.h" +#include "takedamageinfo.h" +#include "effect_dispatch_data.h" +#include "engine/ivdebugoverlay.h" + +ConVar sv_showimpacts("sv_showimpacts", "0", FCVAR_REPLICATED, "Shows client (red) and server (blue) bullet impact point" ); + +void DispatchEffect( const char *pName, const CEffectData &data ); + +CWeaponSDKBase* CSDKPlayer::SDKAnim_GetActiveWeapon() +{ + return GetActiveSDKWeapon(); +} + +bool CSDKPlayer::SDKAnim_CanMove() +{ + return true; +} + +void CSDKPlayer::FireBullet( + Vector vecSrc, // shooting postion + const QAngle &shootAngles, //shooting angle + float vecSpread, // spread vector + int iDamage, // base damage + int iBulletType, // ammo type + CBaseEntity *pevAttacker, // shooter + bool bDoEffects, // create impact effect ? + float x, // spread x factor + float y // spread y factor + ) +{ + float fCurrentDamage = iDamage; // damage of the bullet at it's current trajectory + float flCurrentDistance = 0.0; //distance that the bullet has traveled so far + + Vector vecDirShooting, vecRight, vecUp; + AngleVectors( shootAngles, &vecDirShooting, &vecRight, &vecUp ); + + if ( !pevAttacker ) + pevAttacker = this; // the default attacker is ourselves + + // add the spray + Vector vecDir = vecDirShooting + + x * vecSpread * vecRight + + y * vecSpread * vecUp; + + VectorNormalize( vecDir ); + + float flMaxRange = 8000; + + Vector vecEnd = vecSrc + vecDir * flMaxRange; // max bullet range is 10000 units + + trace_t tr; // main enter bullet trace + + UTIL_TraceLine( vecSrc, vecEnd, MASK_SOLID|CONTENTS_DEBRIS|CONTENTS_HITBOX, this, COLLISION_GROUP_NONE, &tr ); + + if ( tr.fraction == 1.0f ) + return; // we didn't hit anything, stop tracing shoot + + if ( sv_showimpacts.GetBool() ) + { +#ifdef CLIENT_DLL + // draw red client impact markers + debugoverlay->AddBoxOverlay( tr.endpos, Vector(-2,-2,-2), Vector(2,2,2), QAngle( 0, 0, 0), 255,0,0,127, 4 ); + + if ( tr.m_pEnt && tr.m_pEnt->IsPlayer() ) + { + C_BasePlayer *player = ToBasePlayer( tr.m_pEnt ); + player->DrawClientHitboxes( 4, true ); + } +#else + // draw blue server impact markers + NDebugOverlay::Box( tr.endpos, Vector(-2,-2,-2), Vector(2,2,2), 0,0,255,127, 4 ); + + if ( tr.m_pEnt && tr.m_pEnt->IsPlayer() ) + { + CBasePlayer *player = ToBasePlayer( tr.m_pEnt ); + player->DrawServerHitboxes( 4, true ); + } +#endif + } + + //calculate the damage based on the distance the bullet travelled. + flCurrentDistance += tr.fraction * flMaxRange; + + // damage get weaker of distance + fCurrentDamage *= pow ( 0.85f, (flCurrentDistance / 500)); + + int iDamageType = DMG_BULLET | DMG_NEVERGIB; + + if( bDoEffects ) + { + // See if the bullet ended up underwater + started out of the water + if ( enginetrace->GetPointContents( tr.endpos ) & (CONTENTS_WATER|CONTENTS_SLIME) ) + { + trace_t waterTrace; + UTIL_TraceLine( vecSrc, tr.endpos, (MASK_SHOT|CONTENTS_WATER|CONTENTS_SLIME), this, COLLISION_GROUP_NONE, &waterTrace ); + + if( waterTrace.allsolid != 1 ) + { + CEffectData data; + data.m_vOrigin = waterTrace.endpos; + data.m_vNormal = waterTrace.plane.normal; + data.m_flScale = random->RandomFloat( 8, 12 ); + + if ( waterTrace.contents & CONTENTS_SLIME ) + { + data.m_fFlags |= FX_WATER_IN_SLIME; + } + + DispatchEffect( "gunshotsplash", data ); + } + } + else + { + //Do Regular hit effects + + // Don't decal nodraw surfaces + if ( !( tr.surface.flags & (SURF_SKY|SURF_NODRAW|SURF_HINT|SURF_SKIP) ) ) + { + CBaseEntity *pEntity = tr.m_pEnt; + if ( !( !friendlyfire.GetBool() && pEntity && pEntity->IsPlayer() && pEntity->GetTeamNumber() == GetTeamNumber() ) ) + { + UTIL_ImpactTrace( &tr, iDamageType ); + } + } + } + } // bDoEffects + + // add damage to entity that we hit + +#ifdef GAME_DLL + ClearMultiDamage(); + + CTakeDamageInfo info( pevAttacker, pevAttacker, fCurrentDamage, iDamageType ); + CalculateBulletDamageForce( &info, iBulletType, vecDir, tr.endpos ); + tr.m_pEnt->DispatchTraceAttack( info, vecDir, &tr ); + + TraceAttackToTriggers( info, tr.startpos, tr.endpos, vecDir ); + + ApplyMultiDamage(); +#endif +} diff --git a/game/shared/sdk/sdk_player_shared.h b/game/shared/sdk/sdk_player_shared.h new file mode 100644 index 0000000..f745fc8 --- /dev/null +++ b/game/shared/sdk/sdk_player_shared.h @@ -0,0 +1,136 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Shared Player Variables / Functions and variables that may or may not be networked +// +//===========================================================================================// + +#ifndef SDK_PLAYER_SHARED_H +#define SDK_PLAYER_SHARED_H +#ifdef _WIN32 +#pragma once +#endif + +#include "networkvar.h" +#include "weapon_sdkbase.h" + +#ifdef CLIENT_DLL +class C_SDKPlayer; +#else +class CSDKPlayer; +#endif + +class CSDKPlayerShared +{ +public: + +#ifdef CLIENT_DLL + friend class C_SDKPlayer; + typedef C_SDKPlayer OuterClass; + DECLARE_PREDICTABLE(); +#else + friend class CSDKPlayer; + typedef CSDKPlayer OuterClass; +#endif + + DECLARE_EMBEDDED_NETWORKVAR() + DECLARE_CLASS_NOBASE( CSDKPlayerShared ); + + CSDKPlayerShared(); + ~CSDKPlayerShared(); + +#if defined ( SDK_USE_STAMINA ) || defined ( SDK_USE_SPRINTING ) + void SetStamina( float stamina ); + float GetStamina( void ) { return m_flStamina; } +#endif // SDK_USE_STAMINA || SDK_USE_SPRINTING + + void Init( OuterClass *pOuter ); + + bool IsSniperZoomed( void ) const; + bool IsDucking( void ) const; + +#if defined ( SDK_USE_PLAYERCLASSES ) + void SetDesiredPlayerClass( int playerclass ); + int DesiredPlayerClass( void ); + + void SetPlayerClass( int playerclass ); + int PlayerClass( void ); +#endif + + CWeaponSDKBase* GetActiveSDKWeapon() const; + +#if defined ( SDK_USE_PRONE ) + void StartGoingProne( void ); + void StandUpFromProne( void ); + bool IsProne() const; + bool IsGettingUpFromProne() const; + bool IsGoingProne() const; + void SetProne( bool bProne, bool bNoAnimation = false ); + bool CanChangePosition( void ); +#endif + + bool IsJumping( void ) { return m_bJumping; } + void SetJumping( bool bJumping ); + + void ForceUnzoom( void ); + +#ifdef SDK_USE_SPRINTING + bool IsSprinting( void ) { return m_bIsSprinting; } + + void SetSprinting( bool bSprinting ); + void StartSprinting( void ); + void StopSprinting( void ); + + void ResetSprintPenalty( void ); +#endif + + void ComputeWorldSpaceSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs ); + +private: + +#if defined ( SDK_USE_PRONE ) + CNetworkVar( bool, m_bProne ); +#endif + +#if defined ( SDK_USE_PLAYERCLASSES ) + CNetworkVar( int, m_iPlayerClass ); + CNetworkVar( int, m_iDesiredPlayerClass ); +#endif + + +#if defined ( SDK_USE_SPRINTING ) + CNetworkVar( bool, m_bIsSprinting ); + bool m_bGaveSprintPenalty; +#endif + +#if defined ( SDK_USE_STAMINA ) || defined ( SDK_USE_SPRINTING ) + CNetworkVar( float, m_flStamina ); +#endif // SDK_USE_STAMINA || SDK_USE_SPRINTING + +public: + +#ifdef SDK_USE_PRONE + float m_flNextProneCheck; // Prevent it switching their prone state constantly. + + CNetworkVar( float, m_flUnProneTime ); + CNetworkVar( float, m_flGoProneTime ); + CNetworkVar( bool, m_bForceProneChange ); +#endif + + bool m_bJumping; + + float m_flLastViewAnimationTime; + + //Tony; player speeds; at spawn server and client update both of these based on class (if any) + float m_flRunSpeed; + float m_flSprintSpeed; + float m_flProneSpeed; + +private: + + OuterClass *m_pOuter; +}; + + + + +#endif //SDK_PLAYER_SHARED_H
\ No newline at end of file diff --git a/game/shared/sdk/sdk_playeranimstate.cpp b/game/shared/sdk/sdk_playeranimstate.cpp new file mode 100644 index 0000000..6effe3e --- /dev/null +++ b/game/shared/sdk/sdk_playeranimstate.cpp @@ -0,0 +1,621 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "base_playeranimstate.h" +#include "tier0/vprof.h" +#include "animation.h" +#include "studio.h" +#include "apparent_velocity_helper.h" +#include "utldict.h" + +#include "sdk_playeranimstate.h" +#include "weapon_sdkbase.h" +#include "weapon_basesdkgrenade.h" + +#ifdef CLIENT_DLL + #include "c_sdk_player.h" + #include "bone_setup.h" + #include "interpolatedvar.h" +#else + #include "sdk_player.h" +#endif + +#define ANIM_TOPSPEED_WALK 100 +#define ANIM_TOPSPEED_RUN 250 +#define ANIM_TOPSPEED_RUN_CROUCH 85 + +#define DEFAULT_IDLE_NAME "idle_upper_" +#define DEFAULT_CROUCH_IDLE_NAME "crouch_idle_upper_" +#define DEFAULT_CROUCH_WALK_NAME "crouch_walk_upper_" +#define DEFAULT_WALK_NAME "walk_upper_" +#define DEFAULT_RUN_NAME "run_upper_" + +#define DEFAULT_FIRE_IDLE_NAME "idle_shoot_" +#define DEFAULT_FIRE_CROUCH_NAME "crouch_idle_shoot_" +#define DEFAULT_FIRE_CROUCH_WALK_NAME "crouch_walk_shoot_" +#define DEFAULT_FIRE_WALK_NAME "walk_shoot_" +#define DEFAULT_FIRE_RUN_NAME "run_shoot_" + + +#define FIRESEQUENCE_LAYER (AIMSEQUENCE_LAYER+NUM_AIMSEQUENCE_LAYERS) +#define RELOADSEQUENCE_LAYER (FIRESEQUENCE_LAYER + 1) +#define GRENADESEQUENCE_LAYER (RELOADSEQUENCE_LAYER + 1) +#define NUM_LAYERS_WANTED (GRENADESEQUENCE_LAYER + 1) + + + +// ------------------------------------------------------------------------------------------------ // +// CSDKPlayerAnimState declaration. +// ------------------------------------------------------------------------------------------------ // + +class CSDKPlayerAnimState : public CBasePlayerAnimState, public ISDKPlayerAnimState +{ +public: + DECLARE_CLASS( CSDKPlayerAnimState, CBasePlayerAnimState ); + friend ISDKPlayerAnimState* CreatePlayerAnimState( CBaseAnimatingOverlay *pEntity, ISDKPlayerAnimStateHelpers *pHelpers, LegAnimType_t legAnimType, bool bUseAimSequences ); + + CSDKPlayerAnimState(); + + virtual void DoAnimationEvent( PlayerAnimEvent_t event, int nData ); + virtual bool IsThrowingGrenade(); + virtual int CalcAimLayerSequence( float *flCycle, float *flAimSequenceWeight, bool bForceIdle ); + virtual void ClearAnimationState(); + virtual bool CanThePlayerMove(); + virtual float GetCurrentMaxGroundSpeed(); + virtual Activity CalcMainActivity(); + virtual void DebugShowAnimState( int iStartLine ); + virtual void ComputeSequences( CStudioHdr *pStudioHdr ); + virtual void ClearAnimationLayers(); + + + void InitSDK( CBaseAnimatingOverlay *pPlayer, ISDKPlayerAnimStateHelpers *pHelpers, LegAnimType_t legAnimType, bool bUseAimSequences ); + +protected: + + int CalcFireLayerSequence(PlayerAnimEvent_t event); + void ComputeFireSequence(CStudioHdr *pStudioHdr); + + void ComputeReloadSequence(CStudioHdr *pStudioHdr); + int CalcReloadLayerSequence(); + + bool IsOuterGrenadePrimed(); + void ComputeGrenadeSequence( CStudioHdr *pStudioHdr ); + int CalcGrenadePrimeSequence(); + int CalcGrenadeThrowSequence(); + int GetOuterGrenadeThrowCounter(); + + const char* GetWeaponSuffix(); + bool HandleJumping(); + + void UpdateLayerSequenceGeneric( CStudioHdr *pStudioHdr, int iLayer, bool &bEnabled, float &flCurCycle, int &iSequence, bool bWaitAtEnd ); + +private: + + // Current state variables. + bool m_bJumping; // Set on a jump event. + float m_flJumpStartTime; + bool m_bFirstJumpFrame; + + // Aim sequence plays reload while this is on. + bool m_bReloading; + float m_flReloadCycle; + int m_iReloadSequence; + + // This is set to true if ANY animation is being played in the fire layer. + bool m_bFiring; // If this is on, then it'll continue the fire animation in the fire layer + // until it completes. + int m_iFireSequence; // (For any sequences in the fire layer, including grenade throw). + float m_flFireCycle; + + // These control grenade animations. + bool m_bThrowingGrenade; + bool m_bPrimingGrenade; + float m_flGrenadeCycle; + int m_iGrenadeSequence; + int m_iLastThrowGrenadeCounter; // used to detect when the guy threw the grenade. + + ISDKPlayerAnimStateHelpers *m_pHelpers; +}; + + +ISDKPlayerAnimState* CreatePlayerAnimState( CBaseAnimatingOverlay *pEntity, ISDKPlayerAnimStateHelpers *pHelpers, LegAnimType_t legAnimType, bool bUseAimSequences ) +{ + CSDKPlayerAnimState *pRet = new CSDKPlayerAnimState; + pRet->InitSDK( pEntity, pHelpers, legAnimType, bUseAimSequences ); + return pRet; +} + +// ------------------------------------------------------------------------------------------------ // +// CSDKPlayerAnimState implementation. +// ------------------------------------------------------------------------------------------------ // + +CSDKPlayerAnimState::CSDKPlayerAnimState() +{ + m_pOuter = NULL; + m_bReloading = false; +} + + +void CSDKPlayerAnimState::InitSDK( CBaseAnimatingOverlay *pEntity, ISDKPlayerAnimStateHelpers *pHelpers, LegAnimType_t legAnimType, bool bUseAimSequences ) +{ + CModAnimConfig config; + config.m_flMaxBodyYawDegrees = 90; + config.m_LegAnimType = legAnimType; + config.m_bUseAimSequences = bUseAimSequences; + + m_pHelpers = pHelpers; + + BaseClass::Init( pEntity, config ); +} + + +void CSDKPlayerAnimState::ClearAnimationState() +{ + m_bJumping = false; + m_bFiring = false; + m_bReloading = false; + m_bThrowingGrenade = m_bPrimingGrenade = false; + m_iLastThrowGrenadeCounter = GetOuterGrenadeThrowCounter(); + + BaseClass::ClearAnimationState(); +} + + +void CSDKPlayerAnimState::DoAnimationEvent( PlayerAnimEvent_t event, int nData ) +{ + Assert( event != PLAYERANIMEVENT_THROW_GRENADE ); + + if ( event == PLAYERANIMEVENT_FIRE_GUN_PRIMARY || + event == PLAYERANIMEVENT_FIRE_GUN_SECONDARY ) + { + // Regardless of what we're doing in the fire layer, restart it. + m_flFireCycle = 0; + m_iFireSequence = CalcFireLayerSequence( event ); + m_bFiring = m_iFireSequence != -1; + } + else if ( event == PLAYERANIMEVENT_JUMP ) + { + // Play the jump animation. + m_bJumping = true; + m_bFirstJumpFrame = true; + m_flJumpStartTime = gpGlobals->curtime; + } + else if ( event == PLAYERANIMEVENT_RELOAD ) + { + m_iReloadSequence = CalcReloadLayerSequence(); + if ( m_iReloadSequence != -1 ) + { + m_bReloading = true; + m_flReloadCycle = 0; + } + } + else + { + Assert( !"CSDKPlayerAnimState::DoAnimationEvent" ); + } +} + + +float g_flThrowGrenadeFraction = 0.25; +bool CSDKPlayerAnimState::IsThrowingGrenade() +{ + if ( m_bThrowingGrenade ) + { + // An animation event would be more appropriate here. + return m_flGrenadeCycle < g_flThrowGrenadeFraction; + } + else + { + bool bThrowPending = (m_iLastThrowGrenadeCounter != GetOuterGrenadeThrowCounter()); + return bThrowPending || IsOuterGrenadePrimed(); + } +} + + +int CSDKPlayerAnimState::CalcReloadLayerSequence() +{ + const char *pSuffix = GetWeaponSuffix(); + if ( !pSuffix ) + return -1; + + CWeaponSDKBase *pWeapon = m_pHelpers->SDKAnim_GetActiveWeapon(); + if ( !pWeapon ) + return -1; + + // First, look for reload_<weapon name>. + char szName[512]; + Q_snprintf( szName, sizeof( szName ), "reload_%s", pSuffix ); + int iReloadSequence = m_pOuter->LookupSequence( szName ); + if ( iReloadSequence != -1 ) + return iReloadSequence; + + //SDKTODO +/* + // Ok, look for generic categories.. pistol, shotgun, rifle, etc. + if ( pWeapon->GetSDKWpnData().m_WeaponType == WEAPONTYPE_PISTOL ) + { + Q_snprintf( szName, sizeof( szName ), "reload_pistol" ); + iReloadSequence = m_pOuter->LookupSequence( szName ); + if ( iReloadSequence != -1 ) + return iReloadSequence; + } + */ + + // Fall back to reload_m4. + iReloadSequence = CalcSequenceIndex( "reload_m4" ); + if ( iReloadSequence > 0 ) + return iReloadSequence; + + return -1; +} + + +#ifdef CLIENT_DLL + void CSDKPlayerAnimState::UpdateLayerSequenceGeneric( CStudioHdr *pStudioHdr, int iLayer, bool &bEnabled, float &flCurCycle, int &iSequence, bool bWaitAtEnd ) + { + if ( !bEnabled ) + return; + + // Increment the fire sequence's cycle. + flCurCycle += m_pOuter->GetSequenceCycleRate( pStudioHdr, iSequence ) * gpGlobals->frametime; + if ( flCurCycle > 1 ) + { + if ( bWaitAtEnd ) + { + flCurCycle = 1; + } + else + { + // Not firing anymore. + bEnabled = false; + iSequence = 0; + return; + } + } + + // Now dump the state into its animation layer. + C_AnimationLayer *pLayer = m_pOuter->GetAnimOverlay( iLayer ); + + pLayer->m_flCycle = flCurCycle; + pLayer->m_nSequence = iSequence; + + pLayer->m_flPlaybackRate = 1.0; + pLayer->m_flWeight = 1.0f; + pLayer->m_nOrder = iLayer; + } +#endif + + + +bool CSDKPlayerAnimState::IsOuterGrenadePrimed() +{ + CBaseCombatCharacter *pChar = m_pOuter->MyCombatCharacterPointer(); + if ( pChar ) + { + CBaseSDKGrenade *pGren = dynamic_cast<CBaseSDKGrenade*>( pChar->GetActiveWeapon() ); + return pGren && pGren->IsPinPulled(); + } + else + { + return NULL; + } +} + + +void CSDKPlayerAnimState::ComputeGrenadeSequence( CStudioHdr *pStudioHdr ) +{ +#ifdef CLIENT_DLL + if ( m_bThrowingGrenade ) + { + UpdateLayerSequenceGeneric( pStudioHdr, GRENADESEQUENCE_LAYER, m_bThrowingGrenade, m_flGrenadeCycle, m_iGrenadeSequence, false ); + } + else + { + // Priming the grenade isn't an event.. we just watch the player for it. + // Also play the prime animation first if he wants to throw the grenade. + bool bThrowPending = (m_iLastThrowGrenadeCounter != GetOuterGrenadeThrowCounter()); + if ( IsOuterGrenadePrimed() || bThrowPending ) + { + if ( !m_bPrimingGrenade ) + { + // If this guy just popped into our PVS, and he's got his grenade primed, then + // let's assume that it's all the way primed rather than playing the prime + // animation from the start. + if ( TimeSinceLastAnimationStateClear() < 0.4f ) + m_flGrenadeCycle = 1; + else + m_flGrenadeCycle = 0; + + m_iGrenadeSequence = CalcGrenadePrimeSequence(); + } + + m_bPrimingGrenade = true; + UpdateLayerSequenceGeneric( pStudioHdr, GRENADESEQUENCE_LAYER, m_bPrimingGrenade, m_flGrenadeCycle, m_iGrenadeSequence, true ); + + // If we're waiting to throw and we're done playing the prime animation... + if ( bThrowPending && m_flGrenadeCycle == 1 ) + { + m_iLastThrowGrenadeCounter = GetOuterGrenadeThrowCounter(); + + // Now play the throw animation. + m_iGrenadeSequence = CalcGrenadeThrowSequence(); + if ( m_iGrenadeSequence != -1 ) + { + // Configure to start playing + m_bThrowingGrenade = true; + m_bPrimingGrenade = false; + m_flGrenadeCycle = 0; + } + } + } + else + { + m_bPrimingGrenade = false; + } + } +#endif +} + + +int CSDKPlayerAnimState::CalcGrenadePrimeSequence() +{ + return CalcSequenceIndex( "idle_shoot_gren1" ); +} + + +int CSDKPlayerAnimState::CalcGrenadeThrowSequence() +{ + return CalcSequenceIndex( "idle_shoot_gren2" ); +} + + +int CSDKPlayerAnimState::GetOuterGrenadeThrowCounter() +{ + CSDKPlayer *pPlayer = dynamic_cast<CSDKPlayer*>( m_pOuter ); + if ( pPlayer ) + return pPlayer->m_iThrowGrenadeCounter; + else + return 0; +} + + +void CSDKPlayerAnimState::ComputeReloadSequence( CStudioHdr *pStudioHdr ) +{ +#ifdef CLIENT_DLL + UpdateLayerSequenceGeneric( pStudioHdr, RELOADSEQUENCE_LAYER, m_bReloading, m_flReloadCycle, m_iReloadSequence, false ); +#else + // Server doesn't bother with different fire sequences. +#endif +} + + +int CSDKPlayerAnimState::CalcAimLayerSequence( float *flCycle, float *flAimSequenceWeight, bool bForceIdle ) +{ + const char *pSuffix = GetWeaponSuffix(); + if ( !pSuffix ) + return 0; + + if ( bForceIdle ) + { + switch ( GetCurrentMainSequenceActivity() ) + { + case ACT_CROUCHIDLE: + return CalcSequenceIndex( "%s%s", DEFAULT_CROUCH_IDLE_NAME, pSuffix ); + + default: + return CalcSequenceIndex( "%s%s", DEFAULT_IDLE_NAME, pSuffix ); + } + } + else + { + switch ( GetCurrentMainSequenceActivity() ) + { + case ACT_RUN: + return CalcSequenceIndex( "%s%s", DEFAULT_RUN_NAME, pSuffix ); + + case ACT_WALK: + case ACT_RUNTOIDLE: + case ACT_IDLETORUN: + return CalcSequenceIndex( "%s%s", DEFAULT_WALK_NAME, pSuffix ); + + case ACT_CROUCHIDLE: + return CalcSequenceIndex( "%s%s", DEFAULT_CROUCH_IDLE_NAME, pSuffix ); + + case ACT_RUN_CROUCH: + return CalcSequenceIndex( "%s%s", DEFAULT_CROUCH_WALK_NAME, pSuffix ); + + case ACT_IDLE: + default: + return CalcSequenceIndex( "%s%s", DEFAULT_IDLE_NAME, pSuffix ); + } + } +} + + +const char* CSDKPlayerAnimState::GetWeaponSuffix() +{ + // Figure out the weapon suffix. + CWeaponSDKBase *pWeapon = m_pHelpers->SDKAnim_GetActiveWeapon(); + if ( !pWeapon ) + return "Pistol"; + + const char *pSuffix = pWeapon->GetSDKWpnData().m_szAnimExtension; + + return pSuffix; +} + + +int CSDKPlayerAnimState::CalcFireLayerSequence(PlayerAnimEvent_t event) +{ + // Figure out the weapon suffix. + CWeaponSDKBase *pWeapon = m_pHelpers->SDKAnim_GetActiveWeapon(); + if ( !pWeapon ) + return 0; + + const char *pSuffix = GetWeaponSuffix(); + if ( !pSuffix ) + return 0; + + // Don't rely on their weapon here because the player has usually switched to their + // pistol or rifle by the time the PLAYERANIMEVENT_THROW_GRENADE message gets to the client. + if ( event == PLAYERANIMEVENT_THROW_GRENADE ) + { + pSuffix = "Gren"; + } + + switch ( GetCurrentMainSequenceActivity() ) + { + case ACT_PLAYER_RUN_FIRE: + case ACT_RUN: + return CalcSequenceIndex( "%s%s", DEFAULT_FIRE_RUN_NAME, pSuffix ); + + case ACT_PLAYER_WALK_FIRE: + case ACT_WALK: + return CalcSequenceIndex( "%s%s", DEFAULT_FIRE_WALK_NAME, pSuffix ); + + case ACT_PLAYER_CROUCH_FIRE: + case ACT_CROUCHIDLE: + return CalcSequenceIndex( "%s%s", DEFAULT_FIRE_CROUCH_NAME, pSuffix ); + + case ACT_PLAYER_CROUCH_WALK_FIRE: + case ACT_RUN_CROUCH: + return CalcSequenceIndex( "%s%s", DEFAULT_FIRE_CROUCH_WALK_NAME, pSuffix ); + + default: + case ACT_PLAYER_IDLE_FIRE: + return CalcSequenceIndex( "%s%s", DEFAULT_FIRE_IDLE_NAME, pSuffix ); + } +} + + +bool CSDKPlayerAnimState::CanThePlayerMove() +{ + return m_pHelpers->SDKAnim_CanMove(); +} + + +float CSDKPlayerAnimState::GetCurrentMaxGroundSpeed() +{ + Activity currentActivity = m_pOuter->GetSequenceActivity( m_pOuter->GetSequence() ); + if ( currentActivity == ACT_WALK || currentActivity == ACT_IDLE ) + return ANIM_TOPSPEED_WALK; + else if ( currentActivity == ACT_RUN ) + return ANIM_TOPSPEED_RUN; + else if ( currentActivity == ACT_RUN_CROUCH ) + return ANIM_TOPSPEED_RUN_CROUCH; + else + return 0; +} + + +bool CSDKPlayerAnimState::HandleJumping() +{ + if ( m_bJumping ) + { + if ( m_bFirstJumpFrame ) + { + m_bFirstJumpFrame = false; + RestartMainSequence(); // Reset the animation. + } + + // Don't check if he's on the ground for a sec.. sometimes the client still has the + // on-ground flag set right when the message comes in. + if ( gpGlobals->curtime - m_flJumpStartTime > 0.2f ) + { + if ( m_pOuter->GetFlags() & FL_ONGROUND ) + { + m_bJumping = false; + RestartMainSequence(); // Reset the animation. + } + } + } + + // Are we still jumping? If so, keep playing the jump animation. + return m_bJumping; +} + + +Activity CSDKPlayerAnimState::CalcMainActivity() +{ + float flOuterSpeed = GetOuterXYSpeed(); + + if ( HandleJumping() ) + { + return ACT_HOP; + } + else + { + Activity idealActivity = ACT_IDLE; + + if ( m_pOuter->GetFlags() & FL_DUCKING ) + { + if ( flOuterSpeed > MOVING_MINIMUM_SPEED ) + idealActivity = ACT_RUN_CROUCH; + else + idealActivity = ACT_CROUCHIDLE; + } + else + { + if ( flOuterSpeed > MOVING_MINIMUM_SPEED ) + { + if ( flOuterSpeed > ARBITRARY_RUN_SPEED ) + idealActivity = ACT_RUN; + else + idealActivity = ACT_WALK; + } + else + { + idealActivity = ACT_IDLE; + } + } + + return idealActivity; + } +} + + +void CSDKPlayerAnimState::DebugShowAnimState( int iStartLine ) +{ +#ifdef CLIENT_DLL + engine->Con_NPrintf( iStartLine++, "fire : %s, cycle: %.2f\n", m_bFiring ? GetSequenceName( m_pOuter->GetModelPtr(), m_iFireSequence ) : "[not firing]", m_flFireCycle ); + engine->Con_NPrintf( iStartLine++, "reload: %s, cycle: %.2f\n", m_bReloading ? GetSequenceName( m_pOuter->GetModelPtr(), m_iReloadSequence ) : "[not reloading]", m_flReloadCycle ); + BaseClass::DebugShowAnimState( iStartLine ); +#endif +} + + +void CSDKPlayerAnimState::ComputeSequences( CStudioHdr *pStudioHdr ) +{ + BaseClass::ComputeSequences( pStudioHdr ); + + ComputeFireSequence( pStudioHdr ); + ComputeReloadSequence( pStudioHdr ); + ComputeGrenadeSequence( pStudioHdr ); +} + + +void CSDKPlayerAnimState::ClearAnimationLayers() +{ + if ( !m_pOuter ) + return; + + m_pOuter->SetNumAnimOverlays( NUM_LAYERS_WANTED ); + for ( int i=0; i < m_pOuter->GetNumAnimOverlays(); i++ ) + { + m_pOuter->GetAnimOverlay( i )->SetOrder( CBaseAnimatingOverlay::MAX_OVERLAYS ); + } +} + + +void CSDKPlayerAnimState::ComputeFireSequence( CStudioHdr *pStudioHdr ) +{ +#ifdef CLIENT_DLL + UpdateLayerSequenceGeneric( pStudioHdr, FIRESEQUENCE_LAYER, m_bFiring, m_flFireCycle, m_iFireSequence, false ); +#else + // Server doesn't bother with different fire sequences. +#endif +} diff --git a/game/shared/sdk/sdk_playeranimstate.h b/game/shared/sdk/sdk_playeranimstate.h new file mode 100644 index 0000000..46ca04c --- /dev/null +++ b/game/shared/sdk/sdk_playeranimstate.h @@ -0,0 +1,76 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef SDK_PLAYERANIMSTATE_H +#define SDK_PLAYERANIMSTATE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "convar.h" +#include "iplayeranimstate.h" +#include "base_playeranimstate.h" + + +#ifdef CLIENT_DLL + class C_BaseAnimatingOverlay; + class C_WeaponSDKBase; + #define CBaseAnimatingOverlay C_BaseAnimatingOverlay + #define CWeaponSDKBase C_WeaponSDKBase + #define CSDKPlayer C_SDKPlayer +#else + class CBaseAnimatingOverlay; + class CWeaponSDKBase; + class CSDKPlayer; +#endif + + +// When moving this fast, he plays run anim. +#define ARBITRARY_RUN_SPEED 175.0f + + +enum PlayerAnimEvent_t +{ + PLAYERANIMEVENT_FIRE_GUN_PRIMARY=0, + PLAYERANIMEVENT_FIRE_GUN_SECONDARY, + PLAYERANIMEVENT_THROW_GRENADE, + PLAYERANIMEVENT_JUMP, + PLAYERANIMEVENT_RELOAD, + + PLAYERANIMEVENT_COUNT +}; + + +class ISDKPlayerAnimState : virtual public IPlayerAnimState +{ +public: + // This is called by both the client and the server in the same way to trigger events for + // players firing, jumping, throwing grenades, etc. + virtual void DoAnimationEvent( PlayerAnimEvent_t event, int nData = 0 ) = 0; + + // Returns true if we're playing the grenade prime or throw animation. + virtual bool IsThrowingGrenade() = 0; +}; + + +// This abstracts the differences between SDK players and hostages. +class ISDKPlayerAnimStateHelpers +{ +public: + virtual CWeaponSDKBase* SDKAnim_GetActiveWeapon() = 0; + virtual bool SDKAnim_CanMove() = 0; +}; + + +ISDKPlayerAnimState* CreatePlayerAnimState( CBaseAnimatingOverlay *pEntity, ISDKPlayerAnimStateHelpers *pHelpers, LegAnimType_t legAnimType, bool bUseAimSequences ); + +// If this is set, then the game code needs to make sure to send player animation events +// to the local player if he's the one being watched. +extern ConVar cl_showanimstate; + + +#endif // SDK_PLAYERANIMSTATE_H diff --git a/game/shared/sdk/sdk_playerclass_info_parse.cpp b/game/shared/sdk/sdk_playerclass_info_parse.cpp new file mode 100644 index 0000000..ec42763 --- /dev/null +++ b/game/shared/sdk/sdk_playerclass_info_parse.cpp @@ -0,0 +1,137 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "sdk_playerclass_info_parse.h" +#include "weapon_sdkbase.h" +#include <KeyValues.h> + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//Tony; due to the nature of the base code.. I must do this ! + +FilePlayerClassInfo_t* CreatePlayerClassInfo() +{ +#if defined ( SDK_USE_PLAYERCLASSES ) + return new CSDKPlayerClassInfo; +#else + return new FilePlayerClassInfo_t; +#endif +} + +#if defined ( SDK_USE_PLAYERCLASSES ) + +CSDKPlayerClassInfo::CSDKPlayerClassInfo() +{ + m_iTeam= TEAM_UNASSIGNED; + + m_iPrimaryWeapon= WEAPON_NONE; + m_iSecondaryWeapon= WEAPON_NONE; + m_iMeleeWeapon= WEAPON_NONE; + + m_iNumGrensType1 = 0; + m_iGrenType1 = WEAPON_NONE; + + m_iNumGrensType2 = 0; + m_iGrenType2 = WEAPON_NONE; + + m_szLimitCvar[0] = '\0'; + m_flRunSpeed = SDK_DEFAULT_PLAYER_RUNSPEED; + m_flSprintSpeed = SDK_DEFAULT_PLAYER_RUNSPEED; + m_flProneSpeed = SDK_DEFAULT_PLAYER_RUNSPEED; + + m_iArmor = 0; +} + +void CSDKPlayerClassInfo::Parse( KeyValues *pKeyValuesData, const char *szWeaponName ) +{ + BaseClass::Parse( pKeyValuesData, szWeaponName ); + + m_iTeam= pKeyValuesData->GetInt( "team", TEAM_UNASSIGNED ); + + // Figure out what team can have this player class + m_iTeam = TEAM_UNASSIGNED; + +//Tony; don't check for teams unless we're using teams. You could do a free for all, but class / character based game if you wanted. +#ifdef SDK_USE_TEAMS + const char *pTeam = pKeyValuesData->GetString( "team", NULL ); + if ( pTeam ) + { + if ( Q_stricmp( pTeam, "BLUE" ) == 0 ) + { + m_iTeam = SDK_TEAM_BLUE; + } + else if ( Q_stricmp( pTeam, "RED" ) == 0 ) + { + m_iTeam = SDK_TEAM_RED; + } + else + { + Assert( false ); + } + } + else + { + Assert( false ); + } +#endif + + const char *pszPrimaryWeapon = pKeyValuesData->GetString( "primaryweapon", NULL ); + m_iPrimaryWeapon = AliasToWeaponID( pszPrimaryWeapon ); + Assert( m_iPrimaryWeapon != WEAPON_NONE ); // require player to have a primary weapon + + const char *pszSecondaryWeapon = pKeyValuesData->GetString( "secondaryweapon", NULL ); + + if ( pszSecondaryWeapon ) + { + m_iSecondaryWeapon = AliasToWeaponID( pszSecondaryWeapon ); +// Assert( m_iSecondaryWeapon != WEAPON_NONE ); + } + else + m_iSecondaryWeapon = WEAPON_NONE; + + const char *pszMeleeWeapon = pKeyValuesData->GetString( "meleeweapon", NULL ); + if ( pszMeleeWeapon ) + { + m_iMeleeWeapon = AliasToWeaponID( pszMeleeWeapon ); +// Assert( m_iMeleeWeapon != WEAPON_NONE ); + } + else + m_iMeleeWeapon = WEAPON_NONE; + + m_iNumGrensType1 = pKeyValuesData->GetInt( "numgrens", 0 ); + if ( m_iNumGrensType1 > 0 ) + { + const char *pszGrenType1 = pKeyValuesData->GetString( "grenadetype", NULL ); + m_iGrenType1 = AliasToWeaponID( pszGrenType1 ); +// Assert( m_iGrenType1 != WEAPON_NONE ); + } + + m_iNumGrensType2 = pKeyValuesData->GetInt( "numgrens2", 0 ); + if ( m_iNumGrensType2 > 0 ) + { + const char *pszGrenType2 = pKeyValuesData->GetString( "grenadetype2", NULL ); + m_iGrenType2 = AliasToWeaponID( pszGrenType2 ); +// Assert( m_iGrenType2 != WEAPON_NONE ); + } + + Q_strncpy( m_szLimitCvar, pKeyValuesData->GetString( "limitcvar", "!! Missing limit cvar on Player Class" ), sizeof(m_szLimitCvar) ); + + Assert( Q_strlen( m_szLimitCvar ) > 0 && "Every class must specify a limitcvar" ); + + // HUD player status health images (when the player is hurt) + Q_strncpy( m_szClassImage, pKeyValuesData->GetString( "classimage", "white" ), sizeof( m_szClassImage ) ); + Q_strncpy( m_szClassImageBG, pKeyValuesData->GetString( "classimagebg", "white" ), sizeof( m_szClassImageBG ) ); + + m_flRunSpeed = pKeyValuesData->GetFloat( "RunSpeed", SDK_DEFAULT_PLAYER_RUNSPEED ); + m_flSprintSpeed = pKeyValuesData->GetFloat( "SprintSpeed", SDK_DEFAULT_PLAYER_RUNSPEED ); + m_flProneSpeed = pKeyValuesData->GetFloat( "ProneSpeed", SDK_DEFAULT_PLAYER_RUNSPEED ); + + m_iArmor = pKeyValuesData->GetInt( "armor", 0 ); + +} +#endif // SDK_USE_PLAYERCLASSES
\ No newline at end of file diff --git a/game/shared/sdk/sdk_playerclass_info_parse.h b/game/shared/sdk/sdk_playerclass_info_parse.h new file mode 100644 index 0000000..2e15f34 --- /dev/null +++ b/game/shared/sdk/sdk_playerclass_info_parse.h @@ -0,0 +1,53 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef SDK_PLAYERCLASS_INFO_PARSE_H +#define SDK_PLAYERCLASS_INFO_PARSE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "playerclass_info_parse.h" +#include "networkvar.h" + +#if defined ( SDK_USE_PLAYERCLASSES ) +//-------------------------------------------------------------------------------------------------------- +class CSDKPlayerClassInfo : public FilePlayerClassInfo_t +{ +public: + DECLARE_CLASS_GAMEROOT( CSDKPlayerClassInfo, FilePlayerClassInfo_t ); + + CSDKPlayerClassInfo(); + + virtual void Parse( ::KeyValues *pKeyValuesData, const char *szWeaponName ); + + int m_iTeam; //which team. 2 == team 1, 3 == team 2 + + int m_iPrimaryWeapon; + int m_iSecondaryWeapon; + int m_iMeleeWeapon; + + int m_iNumGrensType1; + int m_iGrenType1; + + int m_iNumGrensType2; + int m_iGrenType2; + + char m_szLimitCvar[64]; //which cvar controls the class limit for this class + + char m_szClassImage[SDK_PLAYERCLASS_IMAGE_LENGTH]; + char m_szClassImageBG[SDK_PLAYERCLASS_IMAGE_LENGTH]; + + float m_flRunSpeed; + float m_flSprintSpeed; + float m_flProneSpeed; + + int m_iArmor; +}; +#endif // SDK_USE_PLAYERCLASSES + +#endif // DOD_PLAYERCLASS_INFO_PARSE_H diff --git a/game/shared/sdk/sdk_shareddefs.cpp b/game/shared/sdk/sdk_shareddefs.cpp new file mode 100644 index 0000000..001f273 --- /dev/null +++ b/game/shared/sdk/sdk_shareddefs.cpp @@ -0,0 +1,116 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=====================================================================================// + +#include "cbase.h" +#include "weapon_sdkbase.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +// the 1 / 2 / 3 respectively are all identical in our template mod to start, I've made the base ones (pc_class1, pc_class2, pc_class3) and then duplicated them for the teams. +//Tony; for our template we have two versions. +#if defined ( SDK_USE_PLAYERCLASSES ) && defined ( SDK_USE_TEAMS ) +const char *pszTeamBlueClasses[] = +{ + "blue_class1", + "blue_class2", + "blue_class3", + NULL +}; + +const char *pszTeamRedClasses[] = +{ + "red_class1", + "red_class2", + "red_class3", + NULL +}; +ConVar mp_limit_blue_class1( "mp_limit_blue_class1", "-1", FCVAR_REPLICATED, "Class limit for Blue class 1" ); +ConVar mp_limit_blue_class2( "mp_limit_blue_class2", "-1", FCVAR_REPLICATED, "Class limit for Blue class 2" ); +ConVar mp_limit_blue_class3( "mp_limit_blue_class3", "-1", FCVAR_REPLICATED, "Class limit for Blue class 3" ); + +ConVar mp_limit_red_class1( "mp_limit_red_class1", "-1", FCVAR_REPLICATED, "Class limit for Red class 1" ); +ConVar mp_limit_red_class2( "mp_limit_red_class2", "-1", FCVAR_REPLICATED, "Class limit for Red class 2" ); +ConVar mp_limit_red_class3( "mp_limit_red_class3", "-1", FCVAR_REPLICATED, "Class limit for Red class 3" ); + +//Tony; not using teams, but we are using classes +#elif defined ( SDK_USE_PLAYERCLASSES ) && !defined( SDK_USE_TEAMS ) +const char *pszPlayerClasses[] = +{ + "pc_class1", + "pc_class2", + "pc_class3", + NULL +}; +ConVar mp_limit_pc_class1( "mp_limit_pc_class1", "-1", FCVAR_REPLICATED, "Class limit for class 1" ); +ConVar mp_limit_pc_class2( "mp_limit_pc_class2", "-1", FCVAR_REPLICATED, "Class limit for class 2" ); +ConVar mp_limit_pc_class3( "mp_limit_pc_class3", "-1", FCVAR_REPLICATED, "Class limit for class 3" ); +#endif + +const char *pszTeamNames[] = +{ + "#SDK_Team_Unassigned", + "#SDK_Team_Spectator", +#if defined ( SDK_USE_TEAMS ) + "#SDK_Team_Blue", + "#SDK_Team_Red", +#endif +}; + +//Tony; We need to precache all possible player models that we're going to use +const char *pszPossiblePlayerModels[] = +{ + SDK_PLAYER_MODEL, + "models/player/american_rifleman.mdl", + "models/player/german_rifleman.mdl", + NULL +}; + +// ----------------------------------------------------------------------------- // +// Global Weapon Definitions +// ----------------------------------------------------------------------------- // + +//-------------------------------------------------------------------------------------------------------- +static const char * s_WeaponAliasInfo[] = +{ + "none", // WEAPON_NONE + "mp5", // SDK_WEAPON_MP5 + "shotgun", // SDK_WEAPON_SHOTGUN + "grenade", // SDK_WEAPON_GRENADE + "pistol", // SDK_WEAPON_PISTOL + "crowbar", // SDK_WEAPON_CROWBAR + NULL, // WEAPON_NONE +}; + +//-------------------------------------------------------------------------------------------------------- +// +// Given an alias, return the associated weapon ID +// +int AliasToWeaponID( const char *alias ) +{ + if (alias) + { + for( int i=0; s_WeaponAliasInfo[i] != NULL; ++i ) + if (!Q_stricmp( s_WeaponAliasInfo[i], alias )) + return i; + } + + return WEAPON_NONE; +} + +//-------------------------------------------------------------------------------------------------------- +// +// Given a weapon ID, return its alias +// +const char *WeaponIDToAlias( int id ) +{ + if ( (id >= WEAPON_MAX) || (id < 0) ) + return NULL; + + return s_WeaponAliasInfo[id]; +} + + diff --git a/game/shared/sdk/sdk_shareddefs.h b/game/shared/sdk/sdk_shareddefs.h new file mode 100644 index 0000000..ef3acfe --- /dev/null +++ b/game/shared/sdk/sdk_shareddefs.h @@ -0,0 +1,208 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef SDK_SHAREDDEFS_H +#define SDK_SHAREDDEFS_H +#ifdef _WIN32 +#pragma once +#endif + +//========================= +// GAMEPLAY RELATED OPTIONS +//========================= +// NOTES: The Wizard automatically replaces these strings! If you extract the source as is, you will have to add the defines manually! +// +// Will your mod be team based? +// define SDK_USE_TEAMS +#define SDK_USE_TEAMS + +// +// Do you use player classes? +// define SDK_USE_PLAYERCLASSES +#define SDK_USE_PLAYERCLASSES + +//================================ +// PLAYER MOVEMENT RELATED OPTIONS +//================================ + +// +// Do your players have stamina? - this is a pre-requisite for sprinting, if you define sprinting, and don't uncomment this, it will be included anyway. +// define SDK_USE_STAMINA +#define SDK_USE_STAMINA + +// +// Are your players able to sprint? +// define SDK_USE_SPRINTING +#define SDK_USE_SPRINTING + +//Tony; stamina is a pre-requisite to sprinting, if you don't declare stamina but you do declare sprinting +//stamina needs to be included. +#if defined ( SDK_USE_SPRINTING ) && !defined( SDK_USE_STAMINA ) +#define SDK_USE_STAMINA +#endif +// +// Can your players go prone? +// define SDK_USE_PRONE +#define SDK_USE_PRONE + +//===================== +// EXTRA WEAPON OPTIONS +//===================== + +// +// If you're allowing sprinting, do you want to be able to shoot while sprinting? +// define SDK_SHOOT_WHILE_SPRINTING +#define SDK_SHOOT_WHILE_SPRINTING + +// +// Do you want your players to be able to shoot while climing ladders? +// define SDK_SHOOT_ON_LADDERS +#define SDK_SHOOT_ON_LADDERS + +// +// Do you want your players to be able to shoot while jumping? +// define SDK_SHOOT_WHILE_JUMPING +#define SDK_SHOOT_WHILE_JUMPING + + + +#define SDK_GAME_DESCRIPTION "SDK Template mod v1" + +//================================================================================ +// Most elements below here are specific to the options above. +//================================================================================ + +#if defined ( SDK_USE_TEAMS ) + +enum sdkteams_e + { + SDK_TEAM_BLUE = LAST_SHARED_TEAM+1, + SDK_TEAM_RED, + }; + +#endif // SDK_USE_TEAMS + +#if defined ( SDK_USE_PRONE ) + + #define TIME_TO_PRONE 1.2f + #define VEC_PRONE_HULL_MIN SDKGameRules()->GetSDKViewVectors()->m_vProneHullMin + #define VEC_PRONE_HULL_MAX SDKGameRules()->GetSDKViewVectors()->m_vProneHullMax + #define VEC_PRONE_VIEW SDKGameRules()->GetSDKViewVectors()->m_vProneView + +#endif // SDK_USE_PRONE + +#if defined ( SDK_USE_SPRINTING ) + + #define INITIAL_SPRINT_STAMINA_PENALTY 15 + #define LOW_STAMINA_THRESHOLD 35 + +#endif // SDK_USE_SPRINTING + +#if defined ( SDK_USE_PLAYERCLASSES ) + #define SDK_NUM_PLAYERCLASSES 3 //Tony; our template sample has 3 player classes. + #define SDK_PLAYERCLASS_IMAGE_LENGTH 64 + + #define PLAYERCLASS_RANDOM -2 + #define PLAYERCLASS_UNDEFINED -1 + + #if defined ( SDK_USE_TEAMS ) + //Tony; using teams with classes, so make sure the team class panel names are defined. + #define PANEL_CLASS_BLUE "class_blue" + #define PANEL_CLASS_RED "class_red" + + extern const char *pszTeamBlueClasses[]; + extern const char *pszTeamRedClasses[]; + #else + #define PANEL_CLASS_NOTEAMS "class_noteams" + extern const char *pszPlayerClasses[]; + #endif // SDK_USE_TEAMS + +#endif // SDK_USE_PLAYERCLASSES + +#define SDK_PLAYER_MODEL "models/player/american_rifleman.mdl" + +//Tony; We need to precache all possible player models that we're going to use +extern const char *pszPossiblePlayerModels[]; + +extern const char *pszTeamNames[]; + +//Tony; these defines handle the default speeds for all of these - all are listed regardless of which option is enabled. +#define SDK_DEFAULT_PLAYER_RUNSPEED 220 +#define SDK_DEFAULT_PLAYER_SPRINTSPEED 330 +#define SDK_DEFAULT_PLAYER_PRONESPEED 50 + +//-------------------------------------------------------------------------------------------------------- +// +// Weapon IDs for all SDK Game weapons +// +typedef enum +{ + WEAPON_NONE = 0, + + SDK_WEAPON_NONE = WEAPON_NONE, + SDK_WEAPON_MP5, + SDK_WEAPON_SHOTGUN, + SDK_WEAPON_GRENADE, + SDK_WEAPON_PISTOL, + SDK_WEAPON_CROWBAR, + + + WEAPON_MAX, // number of weapons weapon index +} SDKWeaponID; + +typedef enum +{ + FM_AUTOMATIC = 0, + FM_SEMIAUTOMATIC, + FM_BURST, + +} SDK_Weapon_Firemodes; + +const char *WeaponIDToAlias( int id ); +int AliasToWeaponID( const char *alias ); + + +// The various states the player can be in during the join game process. +enum SDKPlayerState +{ + // Happily running around in the game. + // You can't move though if CSGameRules()->IsFreezePeriod() returns true. + // This state can jump to a bunch of other states like STATE_PICKINGCLASS or STATE_DEATH_ANIM. + STATE_ACTIVE=0, + + // This is the state you're in when you first enter the server. + // It's switching between intro cameras every few seconds, and there's a level info + // screen up. + STATE_WELCOME, // Show the level intro screen. + + // During these states, you can either be a new player waiting to join, or + // you can be a live player in the game who wants to change teams. + // Either way, you can't move while choosing team or class (or while any menu is up). +#if defined ( SDK_USE_TEAMS ) + STATE_PICKINGTEAM, // Choosing team. +#endif +#if defined ( SDK_USE_PLAYERCLASSES ) + STATE_PICKINGCLASS, // Choosing class. +#endif + + STATE_DEATH_ANIM, // Playing death anim, waiting for that to finish. + STATE_OBSERVER_MODE, // Noclipping around, watching players, etc. + + NUM_PLAYER_STATES +}; +#define SDK_PLAYER_DEATH_TIME 5.0f //Minimum Time before respawning + +// Special Damage types +enum +{ + SDK_DMG_CUSTOM_NONE = 0, + SDK_DMG_CUSTOM_SUICIDE, +}; + +// Player avoidance +#define PUSHAWAY_THINK_INTERVAL (1.0f / 20.0f) + +#endif // SDK_SHAREDDEFS_H diff --git a/game/shared/sdk/sdk_usermessages.cpp b/game/shared/sdk/sdk_usermessages.cpp new file mode 100644 index 0000000..e42267a --- /dev/null +++ b/game/shared/sdk/sdk_usermessages.cpp @@ -0,0 +1,49 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "usermessages.h" +#include "shake.h" +#include "voice_gamemgr.h" + +void RegisterUserMessages() +{ + usermessages->Register( "Geiger", 1 ); // geiger info data + usermessages->Register( "Train", 1 ); // train control data + usermessages->Register( "HudText", -1 ); + usermessages->Register( "SayText", -1 ); + usermessages->Register( "TextMsg", -1 ); + usermessages->Register( "HudMsg", -1 ); + usermessages->Register( "ResetHUD", 1 ); // called every respawn + usermessages->Register( "GameTitle", 0 ); // show game title + usermessages->Register( "ItemPickup", -1 ); // for item history on screen + usermessages->Register( "ShowMenu", -1 ); // show hud menu + usermessages->Register( "Shake", 13 ); // shake view + usermessages->Register( "Fade", 10 ); // fade HUD in/out + usermessages->Register( "VGUIMenu", -1 ); // Show VGUI menu + usermessages->Register( "CloseCaption", -1 ); // Show a caption (by string id number)(duration in 10th of a second) + + usermessages->Register( "SendAudio", -1 ); // play radion command + + usermessages->Register( "VoiceMask", VOICE_MAX_PLAYERS_DW*4 * 2 + 1 ); + usermessages->Register( "RequestState", 0 ); + + usermessages->Register( "BarTime", -1 ); // For the C4 progress bar. + usermessages->Register( "Damage", -1 ); // for HUD damage indicators + usermessages->Register( "RadioText", -1 ); // for HUD damage indicators + usermessages->Register( "HintText", -1 ); // Displays hint text display + usermessages->Register( "KeyHintText", -1 ); // Displays hint text display + + usermessages->Register( "ReloadEffect", 2 ); // a player reloading.. + usermessages->Register( "PlayerAnimEvent", -1 ); // jumping, firing, reload, etc. + + usermessages->Register( "AmmoDenied", 2 ); + usermessages->Register( "UpdateRadar", -1 ); + + // Used to send a sample HUD message + usermessages->Register( "GameMessage", -1 ); +} + diff --git a/game/shared/sdk/sdk_weapon_melee.cpp b/game/shared/sdk/sdk_weapon_melee.cpp new file mode 100644 index 0000000..0a92f21 --- /dev/null +++ b/game/shared/sdk/sdk_weapon_melee.cpp @@ -0,0 +1,363 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Base code for any melee based weapon +// +//=====================================================================================// + +#include "cbase.h" + +#include "weapon_sdkbase.h" +#include "sdk_weapon_melee.h" + +#include "sdk_gamerules.h" +#include "ammodef.h" +#include "mathlib/mathlib.h" +#include "in_buttons.h" +#include "animation.h" + +#if defined( CLIENT_DLL ) + #include "c_sdk_player.h" +#else + #include "sdk_player.h" + #include "ndebugoverlay.h" + #include "te_effect_dispatch.h" + #include "ilagcompensationmanager.h" +#endif + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +IMPLEMENT_NETWORKCLASS_ALIASED( WeaponSDKMelee, DT_WeaponSDKMelee ) + +BEGIN_NETWORK_TABLE( CWeaponSDKMelee, DT_WeaponSDKMelee ) +END_NETWORK_TABLE() + +BEGIN_PREDICTION_DATA( CWeaponSDKMelee ) +END_PREDICTION_DATA() + +#define MELEE_HULL_DIM 16 + +static const Vector g_meleeMins(-MELEE_HULL_DIM,-MELEE_HULL_DIM,-MELEE_HULL_DIM); +static const Vector g_meleeMaxs(MELEE_HULL_DIM,MELEE_HULL_DIM,MELEE_HULL_DIM); + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CWeaponSDKMelee::CWeaponSDKMelee() +{ + m_bFiresUnderwater = true; +} + +//----------------------------------------------------------------------------- +// Purpose: Spawn the weapon +//----------------------------------------------------------------------------- +void CWeaponSDKMelee::Spawn( void ) +{ + m_fMinRange1 = 0; + m_fMinRange2 = 0; + m_fMaxRange1 = 64; + m_fMaxRange2 = 64; + //Call base class first + BaseClass::Spawn(); +} + +//----------------------------------------------------------------------------- +// Purpose: Precache the weapon +//----------------------------------------------------------------------------- +void CWeaponSDKMelee::Precache( void ) +{ + //Call base class first + BaseClass::Precache(); +} + +//------------------------------------------------------------------------------ +// Purpose : Update weapon +//------------------------------------------------------------------------------ +void CWeaponSDKMelee::ItemPostFrame( void ) +{ + CSDKPlayer *pPlayer = GetPlayerOwner(); + if ( pPlayer == NULL ) + return; + + if ( (pPlayer->m_nButtons & IN_ATTACK) && (m_flNextPrimaryAttack <= gpGlobals->curtime) && pPlayer->CanAttack() ) + { + PrimaryAttack(); + } + else if ( (pPlayer->m_nButtons & IN_ATTACK2) && (m_flNextSecondaryAttack <= gpGlobals->curtime) && pPlayer->CanAttack() ) + { + SecondaryAttack(); + } + else + { + WeaponIdle(); + } +} + +//------------------------------------------------------------------------------ +// Purpose : +// Input : +// Output : +//------------------------------------------------------------------------------ +void CWeaponSDKMelee::PrimaryAttack() +{ + +#ifndef CLIENT_DLL + CSDKPlayer *pPlayer = ToSDKPlayer( GetPlayerOwner() ); + // Move other players back to history positions based on local player's lag + lagcompensation->StartLagCompensation( pPlayer, pPlayer->GetCurrentCommand() ); +#endif + Swing( false ); +#ifndef CLIENT_DLL + // Move other players back to history positions based on local player's lag + lagcompensation->FinishLagCompensation( pPlayer ); +#endif + +} + +//------------------------------------------------------------------------------ +// Purpose : +// Input : +// Output : +//------------------------------------------------------------------------------ +void CWeaponSDKMelee::SecondaryAttack() +{ + Swing( true ); +} + + +//------------------------------------------------------------------------------ +// Purpose: Implement impact function +//------------------------------------------------------------------------------ +void CWeaponSDKMelee::Hit( trace_t &traceHit, Activity nHitActivity ) +{ + CSDKPlayer *pPlayer = ToSDKPlayer( GetOwner() ); + + //Do view kick +// AddViewKick(); + + CBaseEntity *pHitEntity = traceHit.m_pEnt; + + //Apply damage to a hit target + if ( pHitEntity != NULL ) + { + Vector hitDirection; + pPlayer->EyeVectors( &hitDirection, NULL, NULL ); + VectorNormalize( hitDirection ); + +#ifndef CLIENT_DLL + CTakeDamageInfo info( GetOwner(), GetOwner(), GetDamageForActivity( nHitActivity ), DMG_CLUB ); + + if( pPlayer && pHitEntity->IsNPC() ) + { + // If bonking an NPC, adjust damage. + info.AdjustPlayerDamageInflictedForSkillLevel(); + } + + CalculateMeleeDamageForce( &info, hitDirection, traceHit.endpos ); + + pHitEntity->DispatchTraceAttack( info, hitDirection, &traceHit ); + ApplyMultiDamage(); + + // Now hit all triggers along the ray that... + TraceAttackToTriggers( info, traceHit.startpos, traceHit.endpos, hitDirection ); +#endif + WeaponSound( MELEE_HIT ); + } + + // Apply an impact effect + ImpactEffect( traceHit ); +} + +Activity CWeaponSDKMelee::ChooseIntersectionPointAndActivity( trace_t &hitTrace, const Vector &mins, const Vector &maxs, CSDKPlayer *pOwner ) +{ + int i, j, k; + float distance; + const float *minmaxs[2] = {mins.Base(), maxs.Base()}; + trace_t tmpTrace; + Vector vecHullEnd = hitTrace.endpos; + Vector vecEnd; + + distance = 1e6f; + Vector vecSrc = hitTrace.startpos; + + vecHullEnd = vecSrc + ((vecHullEnd - vecSrc)*2); + UTIL_TraceLine( vecSrc, vecHullEnd, MASK_SHOT_HULL, pOwner, COLLISION_GROUP_NONE, &tmpTrace ); + if ( tmpTrace.fraction == 1.0 ) + { + for ( i = 0; i < 2; i++ ) + { + for ( j = 0; j < 2; j++ ) + { + for ( k = 0; k < 2; k++ ) + { + vecEnd.x = vecHullEnd.x + minmaxs[i][0]; + vecEnd.y = vecHullEnd.y + minmaxs[j][1]; + vecEnd.z = vecHullEnd.z + minmaxs[k][2]; + + UTIL_TraceLine( vecSrc, vecEnd, MASK_SHOT_HULL, pOwner, COLLISION_GROUP_NONE, &tmpTrace ); + if ( tmpTrace.fraction < 1.0 ) + { + float thisDistance = (tmpTrace.endpos - vecSrc).Length(); + if ( thisDistance < distance ) + { + hitTrace = tmpTrace; + distance = thisDistance; + } + } + } + } + } + } + else + { + hitTrace = tmpTrace; + } + + + return ACT_VM_HITCENTER; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &traceHit - +//----------------------------------------------------------------------------- +bool CWeaponSDKMelee::ImpactWater( const Vector &start, const Vector &end ) +{ + //FIXME: This doesn't handle the case of trying to splash while being underwater, but that's not going to look good + // right now anyway... + + // We must start outside the water + if ( UTIL_PointContents( start ) & (CONTENTS_WATER|CONTENTS_SLIME)) + return false; + + // We must end inside of water + if ( !(UTIL_PointContents( end ) & (CONTENTS_WATER|CONTENTS_SLIME))) + return false; + + trace_t waterTrace; + + UTIL_TraceLine( start, end, (CONTENTS_WATER|CONTENTS_SLIME), GetOwner(), COLLISION_GROUP_NONE, &waterTrace ); + + if ( waterTrace.fraction < 1.0f ) + { +#ifndef CLIENT_DLL + CEffectData data; + + data.m_fFlags = 0; + data.m_vOrigin = waterTrace.endpos; + data.m_vNormal = waterTrace.plane.normal; + data.m_flScale = 8.0f; + + // See if we hit slime + if ( waterTrace.contents & CONTENTS_SLIME ) + { + data.m_fFlags |= FX_WATER_IN_SLIME; + } + + DispatchEffect( "watersplash", data ); +#endif + } + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponSDKMelee::ImpactEffect( trace_t &traceHit ) +{ + // See if we hit water (we don't do the other impact effects in this case) + if ( ImpactWater( traceHit.startpos, traceHit.endpos ) ) + return; + + //FIXME: need new decals + UTIL_ImpactTrace( &traceHit, DMG_CLUB ); +} + + +//------------------------------------------------------------------------------ +// Purpose : Starts the swing of the weapon and determines the animation +// Input : bIsSecondary - is this a secondary attack? +//------------------------------------------------------------------------------ +void CWeaponSDKMelee::Swing( int bIsSecondary ) +{ + trace_t traceHit; + + // Try a ray + CSDKPlayer *pOwner = ToSDKPlayer( GetOwner() ); + if ( !pOwner ) + return; + + Vector swingStart = pOwner->Weapon_ShootPosition( ); + Vector forward; + + pOwner->EyeVectors( &forward, NULL, NULL ); + + Vector swingEnd = swingStart + forward * GetRange(); + UTIL_TraceLine( swingStart, swingEnd, MASK_SHOT_HULL, pOwner, COLLISION_GROUP_NONE, &traceHit ); + Activity nHitActivity = ACT_VM_HITCENTER; + +#ifndef CLIENT_DLL + // Like bullets, melee traces have to trace against triggers. + CTakeDamageInfo triggerInfo( GetOwner(), GetOwner(), GetDamageForActivity( nHitActivity ), DMG_CLUB ); + TraceAttackToTriggers( triggerInfo, traceHit.startpos, traceHit.endpos, vec3_origin ); +#endif + + if ( traceHit.fraction == 1.0 ) + { + float meleeHullRadius = 1.732f * MELEE_HULL_DIM; // hull is +/- 16, so use cuberoot of 2 to determine how big the hull is from center to the corner point + + // Back off by hull "radius" + swingEnd -= forward * meleeHullRadius; + + UTIL_TraceHull( swingStart, swingEnd, g_meleeMins, g_meleeMaxs, MASK_SHOT_HULL, pOwner, COLLISION_GROUP_NONE, &traceHit ); + if ( traceHit.fraction < 1.0 && traceHit.m_pEnt ) + { + Vector vecToTarget = traceHit.m_pEnt->GetAbsOrigin() - swingStart; + VectorNormalize( vecToTarget ); + + float dot = vecToTarget.Dot( forward ); + + // YWB: Make sure they are sort of facing the guy at least... + if ( dot < 0.70721f ) + { + // Force amiss + traceHit.fraction = 1.0f; + } + else + { + nHitActivity = ChooseIntersectionPointAndActivity( traceHit, g_meleeMins, g_meleeMaxs, pOwner ); + } + } + } + + WeaponSound( SINGLE ); + + // ------------------------- + // Miss + // ------------------------- + if ( traceHit.fraction == 1.0f ) + { + nHitActivity = bIsSecondary ? ACT_VM_MISSCENTER2 : ACT_VM_MISSCENTER; + + // We want to test the first swing again + Vector testEnd = swingStart + forward * GetRange(); + + // See if we happened to hit water + ImpactWater( swingStart, testEnd ); + } + else + { + Hit( traceHit, nHitActivity ); + } + + // Send the anim + SendWeaponAnim( nHitActivity ); + + pOwner->DoAnimationEvent( PLAYERANIMEVENT_ATTACK_PRIMARY ); + + //Setup our next attack times + m_flNextPrimaryAttack = gpGlobals->curtime + GetFireRate(); + m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration(); +} + diff --git a/game/shared/sdk/sdk_weapon_melee.h b/game/shared/sdk/sdk_weapon_melee.h new file mode 100644 index 0000000..be9d75d --- /dev/null +++ b/game/shared/sdk/sdk_weapon_melee.h @@ -0,0 +1,60 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Base code for any melee based weapon +// +//=====================================================================================// + +#ifndef SDK_WEAPON_MELEE_H +#define SDK_WEAPON_MELEE_H + +#ifdef _WIN32 +#pragma once +#endif + + +#if defined( CLIENT_DLL ) +#define CWeaponSDKMelee C_WeaponSDKMelee +#endif + +//========================================================= +// CBaseHLBludgeonWeapon +//========================================================= +class CWeaponSDKMelee : public CWeaponSDKBase +{ + DECLARE_CLASS( CWeaponSDKMelee, CWeaponSDKBase ); +public: + CWeaponSDKMelee(); + + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + + virtual void Spawn( void ); + virtual void Precache( void ); + + //Attack functions + virtual void PrimaryAttack( void ); + virtual void SecondaryAttack( void ); + + virtual void ItemPostFrame( void ); + + //Functions to select animation sequences + virtual Activity GetPrimaryAttackActivity( void ) { return ACT_VM_HITCENTER; } + virtual Activity GetSecondaryAttackActivity( void ) { return ACT_VM_HITCENTER2; } + + virtual float GetRange( void ) { return 32.0f; } + virtual float GetDamageForActivity( Activity hitActivity ) { return GetSDKWpnData().m_iDamage; } + + CWeaponSDKMelee( const CWeaponSDKMelee & ); + +protected: + virtual void ImpactEffect( trace_t &trace ); + +private: + bool ImpactWater( const Vector &start, const Vector &end ); + void Swing( int bIsSecondary ); + void Hit( trace_t &traceHit, Activity nHitActivity ); + Activity ChooseIntersectionPointAndActivity( trace_t &hitTrace, const Vector &mins, const Vector &maxs, CSDKPlayer *pOwner ); +}; + + +#endif // SDK_WEAPON_MELEE_H
\ No newline at end of file diff --git a/game/shared/sdk/sdk_weapon_parse.cpp b/game/shared/sdk/sdk_weapon_parse.cpp new file mode 100644 index 0000000..69303d3 --- /dev/null +++ b/game/shared/sdk/sdk_weapon_parse.cpp @@ -0,0 +1,35 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include <KeyValues.h> +#include "sdk_weapon_parse.h" + + +FileWeaponInfo_t* CreateWeaponInfo() +{ + return new CSDKWeaponInfo; +} + + +CSDKWeaponInfo::CSDKWeaponInfo() +{ +} + + +void CSDKWeaponInfo::Parse( KeyValues *pKeyValuesData, const char *szWeaponName ) +{ + BaseClass::Parse( pKeyValuesData, szWeaponName ); + + m_iDamage = pKeyValuesData->GetInt( "Damage", 42 ); // Douglas Adams 1952 - 2001 + m_iBullets = pKeyValuesData->GetInt( "Bullets", 1 ); + m_flCycleTime = pKeyValuesData->GetFloat( "CycleTime", 0.15 ); + + const char *pAnimEx = pKeyValuesData->GetString( "PlayerAnimationExtension", "mp5" ); + Q_strncpy( m_szAnimExtension, pAnimEx, sizeof( m_szAnimExtension ) ); +} + + diff --git a/game/shared/sdk/sdk_weapon_parse.h b/game/shared/sdk/sdk_weapon_parse.h new file mode 100644 index 0000000..dfa0992 --- /dev/null +++ b/game/shared/sdk/sdk_weapon_parse.h @@ -0,0 +1,37 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef SDK_WEAPON_PARSE_H +#define SDK_WEAPON_PARSE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "weapon_parse.h" +#include "networkvar.h" + + +//-------------------------------------------------------------------------------------------------------- +class CSDKWeaponInfo : public FileWeaponInfo_t +{ +public: + DECLARE_CLASS_GAMEROOT( CSDKWeaponInfo, FileWeaponInfo_t ); + + CSDKWeaponInfo(); + + virtual void Parse( ::KeyValues *pKeyValuesData, const char *szWeaponName ); + + char m_szAnimExtension[16]; // string used to generate player animations with this weapon + + // Parameters for FX_FireBullets: + int m_iDamage; + int m_iBullets; + float m_flCycleTime; +}; + + +#endif // SDK_WEAPON_PARSE_H diff --git a/game/shared/sdk/weapon_basesdkgrenade.cpp b/game/shared/sdk/weapon_basesdkgrenade.cpp new file mode 100644 index 0000000..441fd60 --- /dev/null +++ b/game/shared/sdk/weapon_basesdkgrenade.cpp @@ -0,0 +1,363 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "weapon_sdkbase.h" +#include "gamerules.h" +#include "npcevent.h" +#include "engine/IEngineSound.h" +#include "weapon_basesdkgrenade.h" +#include "in_buttons.h" + + +#ifdef CLIENT_DLL + + #include "c_sdk_player.h" + +#else + + #include "sdk_player.h" + #include "items.h" + +#endif + + +#define GRENADE_TIMER 1.5f //Seconds + + +IMPLEMENT_NETWORKCLASS_ALIASED( BaseSDKGrenade, DT_BaseSDKGrenade ) + +BEGIN_NETWORK_TABLE(CBaseSDKGrenade, DT_BaseSDKGrenade) + +#ifndef CLIENT_DLL + SendPropBool( SENDINFO(m_bRedraw) ), + SendPropBool( SENDINFO(m_bPinPulled) ), + SendPropFloat( SENDINFO(m_fThrowTime), 0, SPROP_NOSCALE ), +#else + RecvPropBool( RECVINFO(m_bRedraw) ), + RecvPropBool( RECVINFO(m_bPinPulled) ), + RecvPropFloat( RECVINFO(m_fThrowTime) ), +#endif + +END_NETWORK_TABLE() + +#ifdef CLIENT_DLL +BEGIN_PREDICTION_DATA( CBaseSDKGrenade ) + DEFINE_PRED_FIELD( m_bRedraw, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), + DEFINE_PRED_FIELD( m_bRedraw, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), +END_PREDICTION_DATA() +#endif + +LINK_ENTITY_TO_CLASS( weapon_basesdkgrenade, CBaseSDKGrenade ); + + +CBaseSDKGrenade::CBaseSDKGrenade() +{ + m_bRedraw = false; + m_bPinPulled = false; + m_fThrowTime = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CBaseSDKGrenade::Precache() +{ + BaseClass::Precache(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CBaseSDKGrenade::Deploy() +{ + m_bRedraw = false; + m_bPinPulled = false; + m_fThrowTime = 0; + + return BaseClass::Deploy(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CBaseSDKGrenade::Holster( CBaseCombatWeapon *pSwitchingTo ) +{ + m_bRedraw = false; + m_bPinPulled = false; // when this is holstered make sure the pin isn�t pulled. + m_fThrowTime = 0; + +#ifndef CLIENT_DLL + // If they attempt to switch weapons before the throw animation is done, + // allow it, but kill the weapon if we have to. + CSDKPlayer *pPlayer = GetPlayerOwner(); + + if( pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0 ) + { + CBaseCombatCharacter *pOwner = (CBaseCombatCharacter *)pPlayer; + pOwner->Weapon_Drop( this ); + UTIL_Remove(this); + } +#endif + + return BaseClass::Holster( pSwitchingTo ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CBaseSDKGrenade::PrimaryAttack() +{ + if ( m_bRedraw || m_bPinPulled ) + return; + + CSDKPlayer *pPlayer = GetPlayerOwner(); + if ( !pPlayer || pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 ) + return; + + // The pull pin animation has to finish, then we wait until they aren't holding the primary + // attack button, then throw the grenade. + SendWeaponAnim( ACT_VM_PULLPIN ); + m_bPinPulled = true; + + // Don't let weapon idle interfere in the middle of a throw! + SetWeaponIdleTime( gpGlobals->curtime + SequenceDuration() ); + + m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CBaseSDKGrenade::SecondaryAttack() +{ + if ( m_bRedraw ) + return; + + CSDKPlayer *pPlayer = GetPlayerOwner(); + + if ( pPlayer == NULL ) + return; + + //See if we're ducking + if ( pPlayer->GetFlags() & FL_DUCKING ) + { + //Send the weapon animation + SendWeaponAnim( ACT_VM_SECONDARYATTACK ); + } + else + { + //Send the weapon animation + SendWeaponAnim( ACT_VM_HAULBACK ); + } + + // Don't let weapon idle interfere in the middle of a throw! + SetWeaponIdleTime( gpGlobals->curtime + SequenceDuration() ); + + m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CBaseSDKGrenade::Reload() +{ + if ( ( m_bRedraw ) && ( m_flNextPrimaryAttack <= gpGlobals->curtime ) && ( m_flNextSecondaryAttack <= gpGlobals->curtime ) ) + { + //Redraw the weapon + SendWeaponAnim( ACT_VM_DRAW ); + + //Update our times + m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration(); + m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration(); + + SetWeaponIdleTime( gpGlobals->curtime + SequenceDuration() ); + } + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CBaseSDKGrenade::ItemPostFrame() +{ + CSDKPlayer *pPlayer = GetPlayerOwner(); + if ( !pPlayer ) + return; + + CBaseViewModel *vm = pPlayer->GetViewModel( m_nViewModelIndex ); + if ( !vm ) + return; + + // If they let go of the fire button, they want to throw the grenade. + if ( m_bPinPulled && !(pPlayer->m_nButtons & IN_ATTACK) ) + { + pPlayer->DoAnimationEvent( PLAYERANIMEVENT_THROW_GRENADE ); + + StartGrenadeThrow(); + + DecrementAmmo( pPlayer ); + + m_bPinPulled = false; + SendWeaponAnim( ACT_VM_THROW ); + SetWeaponIdleTime( gpGlobals->curtime + SequenceDuration() ); + } + else if ((m_fThrowTime > 0) && (m_fThrowTime < gpGlobals->curtime)) + { + ThrowGrenade(); + } + else if( m_bRedraw ) + { + // Has the throw animation finished playing + if( m_flTimeWeaponIdle < gpGlobals->curtime ) + { +#ifdef GAME_DLL + // if we're officially out of grenades, ditch this weapon + if( pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0 ) + { + pPlayer->Weapon_Drop( this, NULL, NULL ); + UTIL_Remove(this); + } + else + { + pPlayer->SwitchToNextBestWeapon( this ); + } +#endif + return; //don't animate this grenade any more! + } + } + else if( !m_bRedraw ) + { + BaseClass::ItemPostFrame(); + } +} + + + +#ifdef CLIENT_DLL + + void CBaseSDKGrenade::DecrementAmmo( CBaseCombatCharacter *pOwner ) + { + } + + void CBaseSDKGrenade::DropGrenade() + { + m_bRedraw = true; + m_fThrowTime = 0.0f; + } + + void CBaseSDKGrenade::ThrowGrenade() + { + m_bRedraw = true; + m_fThrowTime = 0.0f; + } + + void CBaseSDKGrenade::StartGrenadeThrow() + { + m_fThrowTime = gpGlobals->curtime + 0.1f; + } + +#else + + BEGIN_DATADESC( CBaseSDKGrenade ) + DEFINE_FIELD( m_bRedraw, FIELD_BOOLEAN ), + END_DATADESC() + + int CBaseSDKGrenade::CapabilitiesGet() + { + return bits_CAP_WEAPON_RANGE_ATTACK1; + } + + //----------------------------------------------------------------------------- + // Purpose: + // Input : *pOwner - + //----------------------------------------------------------------------------- + void CBaseSDKGrenade::DecrementAmmo( CBaseCombatCharacter *pOwner ) + { + pOwner->RemoveAmmo( 1, m_iPrimaryAmmoType ); + } + + void CBaseSDKGrenade::StartGrenadeThrow() + { + m_fThrowTime = gpGlobals->curtime + 0.1f; + } + + void CBaseSDKGrenade::ThrowGrenade() + { + CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + if ( !pPlayer ) + { + Assert( false ); + return; + } + + QAngle angThrow = pPlayer->LocalEyeAngles(); + + Vector vForward, vRight, vUp; + + if (angThrow.x < 90 ) + angThrow.x = -10 + angThrow.x * ((90 + 10) / 90.0); + else + { + angThrow.x = 360.0f - angThrow.x; + angThrow.x = -10 + angThrow.x * -((90 - 10) / 90.0); + } + + float flVel = (90 - angThrow.x) * 6; + + if (flVel > 750) + flVel = 750; + + AngleVectors( angThrow, &vForward, &vRight, &vUp ); + + Vector vecSrc = pPlayer->GetAbsOrigin() + pPlayer->GetViewOffset(); + + vecSrc += vForward * 16; + + Vector vecThrow = vForward * flVel + pPlayer->GetAbsVelocity(); + + EmitGrenade( vecSrc, vec3_angle, vecThrow, AngularImpulse(600,random->RandomInt(-1200,1200),0), pPlayer ); + + m_bRedraw = true; + m_fThrowTime = 0.0f; + } + + void CBaseSDKGrenade::DropGrenade() + { + CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + if ( !pPlayer ) + { + Assert( false ); + return; + } + + Vector vForward; + pPlayer->EyeVectors( &vForward ); + Vector vecSrc = pPlayer->GetAbsOrigin() + pPlayer->GetViewOffset() + vForward * 16; + + Vector vecVel = pPlayer->GetAbsVelocity(); + + EmitGrenade( vecSrc, vec3_angle, vecVel, AngularImpulse(600,random->RandomInt(-1200,1200),0), pPlayer ); + + m_bRedraw = true; + m_fThrowTime = 0.0f; + } + + void CBaseSDKGrenade::EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel, AngularImpulse angImpulse, CBasePlayer *pPlayer ) + { + Assert( 0 && "CBaseSDKGrenade::EmitGrenade should not be called. Make sure to implement this in your subclass!\n" ); + } + + bool CBaseSDKGrenade::AllowsAutoSwitchFrom( void ) const + { + return !m_bPinPulled; + } + +#endif + diff --git a/game/shared/sdk/weapon_basesdkgrenade.h b/game/shared/sdk/weapon_basesdkgrenade.h new file mode 100644 index 0000000..3eaa26c --- /dev/null +++ b/game/shared/sdk/weapon_basesdkgrenade.h @@ -0,0 +1,79 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef WEAPON_BASESDKGRENADE_H +#define WEAPON_BASESDKGRENADE_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "weapon_sdkbase.h" + + +#ifdef CLIENT_DLL + + #define CBaseSDKGrenade C_BaseSDKGrenade + +#endif + + +class CBaseSDKGrenade : public CWeaponSDKBase +{ +public: + DECLARE_CLASS( CBaseSDKGrenade, CWeaponSDKBase ); + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + + CBaseSDKGrenade(); + + virtual void Precache(); + + bool Deploy(); + bool Holster( CBaseCombatWeapon *pSwitchingTo ); + + void PrimaryAttack(); + void SecondaryAttack(); + + bool Reload(); + + virtual void ItemPostFrame(); + + void DecrementAmmo( CBaseCombatCharacter *pOwner ); + virtual void StartGrenadeThrow(); + virtual void ThrowGrenade(); + virtual void DropGrenade(); + + bool IsPinPulled() const; + +#ifndef CLIENT_DLL + DECLARE_DATADESC(); + + virtual bool AllowsAutoSwitchFrom( void ) const; + + int CapabilitiesGet(); + + // Each derived grenade class implements this. + virtual void EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel, AngularImpulse angImpulse, CBasePlayer *pPlayer ); +#endif + +protected: + CNetworkVar( bool, m_bRedraw ); // Draw the weapon again after throwing a grenade + CNetworkVar( bool, m_bPinPulled ); // Set to true when the pin has been pulled but the grenade hasn't been thrown yet. + CNetworkVar( float, m_fThrowTime ); // the time at which the grenade will be thrown. If this value is 0 then the time hasn't been set yet. + +private: + CBaseSDKGrenade( const CBaseSDKGrenade & ) {} +}; + + +inline bool CBaseSDKGrenade::IsPinPulled() const +{ + return m_bPinPulled; +} + + +#endif // WEAPON_BASESDKGRENADE_H diff --git a/game/shared/sdk/weapon_crowbar.cpp b/game/shared/sdk/weapon_crowbar.cpp new file mode 100644 index 0000000..2443cdd --- /dev/null +++ b/game/shared/sdk/weapon_crowbar.cpp @@ -0,0 +1,78 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=====================================================================================// + +#include "cbase.h" +#include "weapon_sdkbase.h" +#include "sdk_weapon_melee.h" + +#if defined( CLIENT_DLL ) + + #define CWeaponCrowbar C_WeaponCrowbar + #include "c_sdk_player.h" + +#else + + #include "sdk_player.h" + +#endif + + +class CWeaponCrowbar : public CWeaponSDKMelee +{ +public: + DECLARE_CLASS( CWeaponCrowbar, CWeaponSDKMelee ); + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + DECLARE_ACTTABLE(); + + CWeaponCrowbar(); + + virtual SDKWeaponID GetWeaponID( void ) const { return SDK_WEAPON_CROWBAR; } + virtual float GetRange( void ) { return 64.0f; } //Tony; let the crowbar swing further. + virtual bool CanWeaponBeDropped() const { return false; } + +private: + + CWeaponCrowbar( const CWeaponCrowbar & ); +}; + +IMPLEMENT_NETWORKCLASS_ALIASED( WeaponCrowbar, DT_WeaponCrowbar ) + +BEGIN_NETWORK_TABLE( CWeaponCrowbar, DT_WeaponCrowbar ) +END_NETWORK_TABLE() + +BEGIN_PREDICTION_DATA( CWeaponCrowbar ) +END_PREDICTION_DATA() + +LINK_ENTITY_TO_CLASS( weapon_crowbar, CWeaponCrowbar ); +PRECACHE_WEAPON_REGISTER( weapon_crowbar ); + + + +CWeaponCrowbar::CWeaponCrowbar() +{ +} + +//Tony; todo; add ACT_MP_PRONE* activities, so we have them. +acttable_t CWeaponCrowbar::m_acttable[] = +{ + { ACT_MP_STAND_IDLE, ACT_DOD_STAND_AIM_SPADE, false }, + { ACT_MP_CROUCH_IDLE, ACT_DOD_CROUCH_AIM_SPADE, false }, + { ACT_MP_PRONE_IDLE, ACT_DOD_PRONE_AIM_SPADE, false }, + + { ACT_MP_RUN, ACT_DOD_RUN_AIM_SPADE, false }, + { ACT_MP_WALK, ACT_DOD_WALK_AIM_SPADE, false }, + { ACT_MP_CROUCHWALK, ACT_DOD_CROUCHWALK_AIM_SPADE, false }, + { ACT_MP_PRONE_CRAWL, ACT_DOD_PRONEWALK_AIM_SPADE, false }, + { ACT_SPRINT, ACT_DOD_SPRINT_AIM_SPADE, false }, + + { ACT_MP_ATTACK_STAND_PRIMARYFIRE, ACT_DOD_PRIMARYATTACK_SPADE, false }, + { ACT_MP_ATTACK_CROUCH_PRIMARYFIRE, ACT_DOD_PRIMARYATTACK_SPADE, false }, + { ACT_MP_ATTACK_PRONE_PRIMARYFIRE, ACT_DOD_PRIMARYATTACK_PRONE_SPADE, false }, +}; + +IMPLEMENT_ACTTABLE( CWeaponCrowbar ); + diff --git a/game/shared/sdk/weapon_grenade.cpp b/game/shared/sdk/weapon_grenade.cpp new file mode 100644 index 0000000..428acc0 --- /dev/null +++ b/game/shared/sdk/weapon_grenade.cpp @@ -0,0 +1,114 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "weapon_sdkbase.h" +#include "gamerules.h" +#include "npcevent.h" +#include "engine/IEngineSound.h" +#include "weapon_grenade.h" + + +#ifdef CLIENT_DLL + +#else + + #include "sdk_player.h" + #include "items.h" + #include "sdk_basegrenade_projectile.h" + +#endif + + +#define GRENADE_TIMER 3.0f //Seconds + +IMPLEMENT_NETWORKCLASS_ALIASED( SDKGrenade, DT_SDKGrenade ) + +BEGIN_NETWORK_TABLE(CSDKGrenade, DT_SDKGrenade) +END_NETWORK_TABLE() + +BEGIN_PREDICTION_DATA( CSDKGrenade ) +END_PREDICTION_DATA() + +LINK_ENTITY_TO_CLASS( weapon_grenade, CSDKGrenade ); +PRECACHE_WEAPON_REGISTER( weapon_grenade ); + + +#ifdef GAME_DLL + +#define GRENADE_MODEL "models/Weapons/w_eq_fraggrenade_thrown.mdl" + +class CGrenadeProjectile : public CBaseGrenadeProjectile +{ +public: + DECLARE_CLASS( CGrenadeProjectile, CBaseGrenadeProjectile ); + + + // Overrides. +public: + virtual void Spawn() + { + SetModel( GRENADE_MODEL ); + BaseClass::Spawn(); + } + + virtual void Precache() + { + PrecacheModel( GRENADE_MODEL ); + BaseClass::Precache(); + } + + // Grenade stuff. +public: + + static CGrenadeProjectile* Create( + const Vector &position, + const QAngle &angles, + const Vector &velocity, + const AngularImpulse &angVelocity, + CBaseCombatCharacter *pOwner, + float timer ) + { + CGrenadeProjectile *pGrenade = (CGrenadeProjectile*)CBaseEntity::Create( "grenade_projectile", position, angles, pOwner ); + + // Set the timer for 1 second less than requested. We're going to issue a SOUND_DANGER + // one second before detonation. + + pGrenade->SetDetonateTimerLength( 1.5 ); + pGrenade->SetAbsVelocity( velocity ); + pGrenade->SetupInitialTransmittedGrenadeVelocity( velocity ); + pGrenade->SetThrower( pOwner ); + + pGrenade->SetGravity( BaseClass::GetGrenadeGravity() ); + pGrenade->SetFriction( BaseClass::GetGrenadeFriction() ); + pGrenade->SetElasticity( BaseClass::GetGrenadeElasticity() ); + + pGrenade->m_flDamage = 100; + pGrenade->m_DmgRadius = pGrenade->m_flDamage * 3.5f; + pGrenade->ChangeTeam( pOwner->GetTeamNumber() ); + pGrenade->ApplyLocalAngularVelocityImpulse( angVelocity ); + + // make NPCs afaid of it while in the air + pGrenade->SetThink( &CGrenadeProjectile::DangerSoundThink ); + pGrenade->SetNextThink( gpGlobals->curtime ); + + return pGrenade; + } +}; + +LINK_ENTITY_TO_CLASS( grenade_projectile, CGrenadeProjectile ); +PRECACHE_WEAPON_REGISTER( grenade_projectile ); + +BEGIN_DATADESC( CSDKGrenade ) +END_DATADESC() + +void CSDKGrenade::EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel, AngularImpulse angImpulse, CBasePlayer *pPlayer ) +{ + CGrenadeProjectile::Create( vecSrc, vecAngles, vecVel, angImpulse, pPlayer, GRENADE_TIMER ); +} + +#endif + diff --git a/game/shared/sdk/weapon_grenade.h b/game/shared/sdk/weapon_grenade.h new file mode 100644 index 0000000..9d8434b --- /dev/null +++ b/game/shared/sdk/weapon_grenade.h @@ -0,0 +1,49 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef WEAPON_GRENADE_H +#define WEAPON_GRENADE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "weapon_basesdkgrenade.h" + + +#ifdef CLIENT_DLL + + #define CSDKGrenade C_SDKGrenade + +#endif + +//----------------------------------------------------------------------------- +// Fragmentation grenades +//----------------------------------------------------------------------------- +class CSDKGrenade : public CBaseSDKGrenade +{ +public: + DECLARE_CLASS( CSDKGrenade, CBaseSDKGrenade ); + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + + CSDKGrenade() {} + + virtual SDKWeaponID GetWeaponID( void ) const { return WEAPON_GRENADE; } + +#ifdef CLIENT_DLL + +#else + DECLARE_DATADESC(); + + virtual void EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel, AngularImpulse angImpulse, CBasePlayer *pPlayer ); + +#endif + + CSDKGrenade( const CSDKGrenade & ) {} +}; + + +#endif // WEAPON_GRENADE_H diff --git a/game/shared/sdk/weapon_mp5.cpp b/game/shared/sdk/weapon_mp5.cpp new file mode 100644 index 0000000..691f1a9 --- /dev/null +++ b/game/shared/sdk/weapon_mp5.cpp @@ -0,0 +1,168 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "weapon_sdkbase.h" +#include "sdk_fx_shared.h" + + +#if defined( CLIENT_DLL ) + + #define CWeaponMP5 C_WeaponMP5 + #include "c_sdk_player.h" + +#else + + #include "sdk_player.h" + +#endif + + +class CWeaponMP5 : public CWeaponSDKBase +{ +public: + DECLARE_CLASS( CWeaponMP5, CWeaponSDKBase ); + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + + CWeaponMP5(); + + virtual void PrimaryAttack(); + virtual bool Deploy(); + virtual bool Reload(); + virtual void WeaponIdle(); + + virtual SDKWeaponID GetWeaponID( void ) const { return WEAPON_MP5; } + + +private: + + CWeaponMP5( const CWeaponMP5 & ); + + void Fire( float flSpread ); +}; + +IMPLEMENT_NETWORKCLASS_ALIASED( WeaponMP5, DT_WeaponMP5 ) + +BEGIN_NETWORK_TABLE( CWeaponMP5, DT_WeaponMP5 ) +END_NETWORK_TABLE() + +BEGIN_PREDICTION_DATA( CWeaponMP5 ) +END_PREDICTION_DATA() + +LINK_ENTITY_TO_CLASS( weapon_mp5, CWeaponMP5 ); +PRECACHE_WEAPON_REGISTER( weapon_mp5 ); + + + +CWeaponMP5::CWeaponMP5() +{ +} + +bool CWeaponMP5::Deploy( ) +{ + CSDKPlayer *pPlayer = GetPlayerOwner(); + pPlayer->m_iShotsFired = 0; + + return BaseClass::Deploy(); +} + +bool CWeaponMP5::Reload( ) +{ + CSDKPlayer *pPlayer = GetPlayerOwner(); + + if (pPlayer->GetAmmoCount( GetPrimaryAmmoType() ) <= 0) + return false; + + int iResult = DefaultReload( GetMaxClip1(), GetMaxClip2(), ACT_VM_RELOAD ); + if ( !iResult ) + return false; + + pPlayer->SetAnimation( PLAYER_RELOAD ); + +#ifndef CLIENT_DLL + if ((iResult) && (pPlayer->GetFOV() != pPlayer->GetDefaultFOV())) + { + pPlayer->SetFOV( pPlayer, pPlayer->GetDefaultFOV() ); + } +#endif + + pPlayer->m_iShotsFired = 0; + + return true; +} + +void CWeaponMP5::PrimaryAttack( void ) +{ + const CSDKWeaponInfo &pWeaponInfo = GetSDKWpnData(); + CSDKPlayer *pPlayer = GetPlayerOwner(); + + float flCycleTime = pWeaponInfo.m_flCycleTime; + + bool bPrimaryMode = true; + + float flSpread = 0.01f; + + // more spread when jumping + if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) ) + flSpread = 0.05f; + + pPlayer->m_iShotsFired++; + + // Out of ammo? + if ( m_iClip1 <= 0 ) + { + if (m_bFireOnEmpty) + { + PlayEmptySound(); + m_flNextPrimaryAttack = gpGlobals->curtime + 0.2; + } + } + + SendWeaponAnim( ACT_VM_PRIMARYATTACK ); + + m_iClip1--; + + // player "shoot" animation + pPlayer->SetAnimation( PLAYER_ATTACK1 ); + + FX_FireBullets( + pPlayer->entindex(), + pPlayer->Weapon_ShootPosition(), + pPlayer->EyeAngles() + pPlayer->GetPunchAngle(), + GetWeaponID(), + bPrimaryMode?Primary_Mode:Secondary_Mode, + CBaseEntity::GetPredictionRandomSeed() & 255, + flSpread ); + + pPlayer->DoMuzzleFlash(); + + m_flNextPrimaryAttack = m_flNextSecondaryAttack = gpGlobals->curtime + flCycleTime; + + if (!m_iClip1 && pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0) + { + // HEV suit - indicate out of ammo condition + pPlayer->SetSuitUpdate("!HEV_AMO0", false, 0); + } + + // start idle animation in 5 seconds + SetWeaponIdleTime( gpGlobals->curtime + 5.0 ); +} + +void CWeaponMP5::WeaponIdle() +{ + if (m_flTimeWeaponIdle > gpGlobals->curtime) + return; + + // only idle if the slid isn't back + if ( m_iClip1 != 0 ) + { + SetWeaponIdleTime( gpGlobals->curtime + 5.0f ); + SendWeaponAnim( ACT_VM_IDLE ); + } +} + + diff --git a/game/shared/sdk/weapon_pistol.cpp b/game/shared/sdk/weapon_pistol.cpp new file mode 100644 index 0000000..1791d67 --- /dev/null +++ b/game/shared/sdk/weapon_pistol.cpp @@ -0,0 +1,80 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=====================================================================================// + +#include "cbase.h" +#include "weapon_sdkbase.h" + +#if defined( CLIENT_DLL ) + + #define CWeaponPistol C_WeaponPistol + #include "c_sdk_player.h" + +#else + + #include "sdk_player.h" + +#endif + + +class CWeaponPistol : public CWeaponSDKBase +{ +public: + DECLARE_CLASS( CWeaponPistol, CWeaponSDKBase ); + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + DECLARE_ACTTABLE(); + + CWeaponPistol(); + + virtual SDKWeaponID GetWeaponID( void ) const { return SDK_WEAPON_PISTOL; } + virtual int GetFireMode() const { return FM_SEMIAUTOMATIC; } + +private: + + CWeaponPistol( const CWeaponPistol & ); +}; + +IMPLEMENT_NETWORKCLASS_ALIASED( WeaponPistol, DT_WeaponPistol ) + +BEGIN_NETWORK_TABLE( CWeaponPistol, DT_WeaponPistol ) +END_NETWORK_TABLE() + +BEGIN_PREDICTION_DATA( CWeaponPistol ) +END_PREDICTION_DATA() + +LINK_ENTITY_TO_CLASS( weapon_pistol, CWeaponPistol ); +PRECACHE_WEAPON_REGISTER( weapon_pistol ); + + + +CWeaponPistol::CWeaponPistol() +{ +} + +//Tony; todo; add ACT_MP_PRONE* activities, so we have them. +acttable_t CWeaponPistol::m_acttable[] = +{ + { ACT_MP_STAND_IDLE, ACT_DOD_STAND_IDLE_PISTOL, false }, + { ACT_MP_CROUCH_IDLE, ACT_DOD_CROUCH_IDLE_PISTOL, false }, + { ACT_MP_PRONE_IDLE, ACT_DOD_PRONE_AIM_PISTOL, false }, + + { ACT_MP_RUN, ACT_DOD_RUN_AIM_PISTOL, false }, + { ACT_MP_WALK, ACT_DOD_WALK_AIM_PISTOL, false }, + { ACT_MP_CROUCHWALK, ACT_DOD_CROUCHWALK_AIM_PISTOL, false }, + { ACT_MP_PRONE_CRAWL, ACT_DOD_PRONEWALK_IDLE_PISTOL, false }, + { ACT_SPRINT, ACT_DOD_SPRINT_IDLE_PISTOL, false }, + + { ACT_MP_ATTACK_STAND_PRIMARYFIRE, ACT_DOD_PRIMARYATTACK_PISTOL, false }, + { ACT_MP_ATTACK_CROUCH_PRIMARYFIRE, ACT_DOD_PRIMARYATTACK_PISTOL, false }, + { ACT_MP_ATTACK_PRONE_PRIMARYFIRE, ACT_DOD_PRIMARYATTACK_PRONE_PISTOL, false }, + + { ACT_MP_RELOAD_STAND, ACT_DOD_RELOAD_PISTOL, false }, + { ACT_MP_RELOAD_CROUCH, ACT_DOD_RELOAD_CROUCH_PISTOL, false }, + { ACT_MP_RELOAD_PRONE, ACT_DOD_RELOAD_PRONE_PISTOL, false }, +}; + +IMPLEMENT_ACTTABLE( CWeaponPistol ); + diff --git a/game/shared/sdk/weapon_sdkbase.cpp b/game/shared/sdk/weapon_sdkbase.cpp new file mode 100644 index 0000000..f6e5929 --- /dev/null +++ b/game/shared/sdk/weapon_sdkbase.cpp @@ -0,0 +1,163 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "in_buttons.h" +#include "takedamageinfo.h" +#include "weapon_sdkbase.h" +#include "ammodef.h" + + +#if defined( CLIENT_DLL ) + + #include "c_sdk_player.h" + +#else + + #include "sdk_player.h" + +#endif + + +// ----------------------------------------------------------------------------- // +// Global functions. +// ----------------------------------------------------------------------------- // + +//-------------------------------------------------------------------------------------------------------- +static const char * s_WeaponAliasInfo[] = +{ + "none", // WEAPON_NONE + "mp5", // WEAPON_MP5 + "shotgun", // WEAPON_SHOTGUN + "grenade", // WEAPON_GRENADE + NULL, // WEAPON_NONE +}; + +//-------------------------------------------------------------------------------------------------------- +// +// Given an alias, return the associated weapon ID +// +int AliasToWeaponID( const char *alias ) +{ + if (alias) + { + for( int i=0; s_WeaponAliasInfo[i] != NULL; ++i ) + if (!Q_stricmp( s_WeaponAliasInfo[i], alias )) + return i; + } + + return WEAPON_NONE; +} + +//-------------------------------------------------------------------------------------------------------- +// +// Given a weapon ID, return its alias +// +const char *WeaponIDToAlias( int id ) +{ + if ( (id >= WEAPON_MAX) || (id < 0) ) + return NULL; + + return s_WeaponAliasInfo[id]; +} + +// ----------------------------------------------------------------------------- // +// CWeaponSDKBase tables. +// ----------------------------------------------------------------------------- // + +IMPLEMENT_NETWORKCLASS_ALIASED( WeaponSDKBase, DT_WeaponSDKBase ) + +BEGIN_NETWORK_TABLE( CWeaponSDKBase, DT_WeaponSDKBase ) +#ifdef CLIENT_DLL + +#else + // world weapon models have no animations + SendPropExclude( "DT_AnimTimeMustBeFirst", "m_flAnimTime" ), + SendPropExclude( "DT_BaseAnimating", "m_nSequence" ), +#endif +END_NETWORK_TABLE() + +#ifdef CLIENT_DLL +BEGIN_PREDICTION_DATA( CWeaponSDKBase ) + DEFINE_PRED_FIELD( m_flTimeWeaponIdle, FIELD_FLOAT, FTYPEDESC_OVERRIDE | FTYPEDESC_NOERRORCHECK ), +END_PREDICTION_DATA() +#endif + +LINK_ENTITY_TO_CLASS( weapon_sdk_base, CWeaponSDKBase ); + + +#ifdef GAME_DLL + + BEGIN_DATADESC( CWeaponSDKBase ) + + // New weapon Think and Touch Functions go here.. + + END_DATADESC() + +#endif + +// ----------------------------------------------------------------------------- // +// CWeaponCSBase implementation. +// ----------------------------------------------------------------------------- // +CWeaponSDKBase::CWeaponSDKBase() +{ + SetPredictionEligible( true ); + + AddSolidFlags( FSOLID_TRIGGER ); // Nothing collides with these but it gets touches. +} + +const CSDKWeaponInfo &CWeaponSDKBase::GetSDKWpnData() const +{ + const FileWeaponInfo_t *pWeaponInfo = &GetWpnData(); + const CSDKWeaponInfo *pSDKInfo; + + #ifdef _DEBUG + pSDKInfo = dynamic_cast< const CSDKWeaponInfo* >( pWeaponInfo ); + Assert( pSDKInfo ); + #else + pSDKInfo = static_cast< const CSDKWeaponInfo* >( pWeaponInfo ); + #endif + + return *pSDKInfo; +} + +bool CWeaponSDKBase::PlayEmptySound() +{ + CPASAttenuationFilter filter( this ); + filter.UsePredictionRules(); + + EmitSound( filter, entindex(), "Default.ClipEmpty_Rifle" ); + + return 0; +} + +CSDKPlayer* CWeaponSDKBase::GetPlayerOwner() const +{ + return dynamic_cast< CSDKPlayer* >( GetOwner() ); +} + +#ifdef GAME_DLL + +void CWeaponSDKBase::SendReloadEvents() +{ + CSDKPlayer *pPlayer = dynamic_cast< CSDKPlayer* >( GetOwner() ); + if ( !pPlayer ) + return; + + // Send a message to any clients that have this entity to play the reload. + CPASFilter filter( pPlayer->GetAbsOrigin() ); + filter.RemoveRecipient( pPlayer ); + + UserMessageBegin( filter, "ReloadEffect" ); + WRITE_SHORT( pPlayer->entindex() ); + MessageEnd(); + + // Make the player play his reload animation. + pPlayer->DoAnimationEvent( PLAYERANIMEVENT_RELOAD ); +} + +#endif
\ No newline at end of file diff --git a/game/shared/sdk/weapon_sdkbase.h b/game/shared/sdk/weapon_sdkbase.h new file mode 100644 index 0000000..b91ff88 --- /dev/null +++ b/game/shared/sdk/weapon_sdkbase.h @@ -0,0 +1,85 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef WEAPON_SDKBASE_H +#define WEAPON_SDKBASE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "sdk_playeranimstate.h" +#include "sdk_weapon_parse.h" + +#if defined( CLIENT_DLL ) + #define CWeaponSDKBase C_WeaponSDKBase +#endif + +class CSDKPlayer; + +// These are the names of the ammo types that the weapon script files reference. +#define AMMO_BULLETS "AMMO_BULLETS" +#define AMMO_ROCKETS "AMMO_ROCKETS" +#define AMMO_GRENADE "AMMO_GRENADE" + +//-------------------------------------------------------------------------------------------------------- +// +// Weapon IDs for all SDK Game weapons +// +typedef enum +{ + WEAPON_NONE = 0, + + WEAPON_MP5, + WEAPON_SHOTGUN, + WEAPON_GRENADE, + + WEAPON_MAX, // number of weapons weapon index +} SDKWeaponID; + +typedef enum +{ + Primary_Mode = 0, + Secondary_Mode, +} SDKWeaponMode; + +const char *WeaponIDToAlias( int id ); + +class CWeaponSDKBase : public CBaseCombatWeapon +{ +public: + DECLARE_CLASS( CWeaponSDKBase, CBaseCombatWeapon ); + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + + CWeaponSDKBase(); + + #ifdef GAME_DLL + DECLARE_DATADESC(); + #endif + + // All predicted weapons need to implement and return true + virtual bool IsPredicted() const { return true; } + virtual SDKWeaponID GetWeaponID( void ) const { return WEAPON_NONE; } + + // Get SDK weapon specific weapon data. + CSDKWeaponInfo const &GetSDKWpnData() const; + + // Get a pointer to the player that owns this weapon + CSDKPlayer* GetPlayerOwner() const; + + // override to play custom empty sounds + virtual bool PlayEmptySound(); + +#ifdef GAME_DLL + virtual void SendReloadEvents(); +#endif + +private: + CWeaponSDKBase( const CWeaponSDKBase & ); +}; + + +#endif // WEAPON_SDKBASE_H diff --git a/game/shared/sdk/weapon_shotgun.cpp b/game/shared/sdk/weapon_shotgun.cpp new file mode 100644 index 0000000..b4cd059 --- /dev/null +++ b/game/shared/sdk/weapon_shotgun.cpp @@ -0,0 +1,246 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "weapon_sdkbase.h" +#include "sdk_fx_shared.h" + + +#if defined( CLIENT_DLL ) + + #define CWeaponShotgun C_WeaponShotgun + #include "c_sdk_player.h" + +#else + + #include "sdk_player.h" + #include "te_firebullets.h" + +#endif + + +class CWeaponShotgun : public CWeaponSDKBase +{ +public: + DECLARE_CLASS( CWeaponShotgun, CWeaponSDKBase ); + DECLARE_NETWORKCLASS(); + DECLARE_PREDICTABLE(); + + CWeaponShotgun(); + + virtual void PrimaryAttack(); + virtual bool Reload(); + virtual void WeaponIdle(); + + virtual SDKWeaponID GetWeaponID( void ) const { return WEAPON_SHOTGUN; } + + +private: + + CWeaponShotgun( const CWeaponShotgun & ); + + float m_flPumpTime; + CNetworkVar( int, m_fInSpecialReload ); + +}; + +IMPLEMENT_NETWORKCLASS_ALIASED( WeaponShotgun, DT_WeaponShotgun ) + +BEGIN_NETWORK_TABLE( CWeaponShotgun, DT_WeaponShotgun ) + + #ifdef CLIENT_DLL + RecvPropInt( RECVINFO( m_fInSpecialReload ) ) + #else + SendPropInt( SENDINFO( m_fInSpecialReload ), 2, SPROP_UNSIGNED ) + #endif + +END_NETWORK_TABLE() + +BEGIN_PREDICTION_DATA( CWeaponShotgun ) +END_PREDICTION_DATA() + +LINK_ENTITY_TO_CLASS( weapon_shotgun, CWeaponShotgun ); +PRECACHE_WEAPON_REGISTER( weapon_shotgun ); + + + +CWeaponShotgun::CWeaponShotgun() +{ + m_flPumpTime = 0; +} + +void CWeaponShotgun::PrimaryAttack() +{ + CSDKPlayer *pPlayer = GetPlayerOwner(); + if ( !pPlayer ) + return; + + // don't fire underwater + if (pPlayer->GetWaterLevel() == 3) + { + PlayEmptySound( ); + m_flNextPrimaryAttack = gpGlobals->curtime + 0.15; + return; + } + + // Out of ammo? + if ( m_iClip1 <= 0 ) + { + Reload(); + if ( m_iClip1 == 0 ) + { + PlayEmptySound(); + m_flNextPrimaryAttack = gpGlobals->curtime + 0.2; + } + + return; + } + + SendWeaponAnim( ACT_VM_PRIMARYATTACK ); + + m_iClip1--; + pPlayer->DoMuzzleFlash(); + + // player "shoot" animation + pPlayer->SetAnimation( PLAYER_ATTACK1 ); + + // Dispatch the FX right away with full accuracy. + FX_FireBullets( + pPlayer->entindex(), + pPlayer->Weapon_ShootPosition(), + pPlayer->EyeAngles() + 2.0f * pPlayer->GetPunchAngle(), + GetWeaponID(), + Primary_Mode, + CBaseEntity::GetPredictionRandomSeed() & 255, // wrap it for network traffic so it's the same between client and server + 0.0675 ); + + if (!m_iClip1 && pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0) + { + // HEV suit - indicate out of ammo condition + pPlayer->SetSuitUpdate("!HEV_AMO0", false, 0); + } + + if (m_iClip1 != 0) + m_flPumpTime = gpGlobals->curtime + 0.5; + + m_flNextPrimaryAttack = gpGlobals->curtime + 0.875; + m_flNextSecondaryAttack = gpGlobals->curtime + 0.875; + if (m_iClip1 != 0) + SetWeaponIdleTime( gpGlobals->curtime + 2.5 ); + else + SetWeaponIdleTime( gpGlobals->curtime + 0.875 ); + m_fInSpecialReload = 0; + + // Update punch angles. + QAngle angle = pPlayer->GetPunchAngle(); + + if ( pPlayer->GetFlags() & FL_ONGROUND ) + { + angle.x -= SharedRandomInt( "ShotgunPunchAngleGround", 4, 6 ); + } + else + { + angle.x -= SharedRandomInt( "ShotgunPunchAngleAir", 8, 11 ); + } + + pPlayer->SetPunchAngle( angle ); +} + + +bool CWeaponShotgun::Reload() +{ + CSDKPlayer *pPlayer = GetPlayerOwner(); + + if (pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 || m_iClip1 == GetMaxClip1()) + return true; + + // don't reload until recoil is done + if (m_flNextPrimaryAttack > gpGlobals->curtime) + return true; + + // check to see if we're ready to reload + if (m_fInSpecialReload == 0) + { + pPlayer->SetAnimation( PLAYER_RELOAD ); + + SendWeaponAnim( ACT_SHOTGUN_RELOAD_START ); + m_fInSpecialReload = 1; + pPlayer->m_flNextAttack = gpGlobals->curtime + 0.5; + m_flNextPrimaryAttack = gpGlobals->curtime + 0.5; + m_flNextSecondaryAttack = gpGlobals->curtime + 0.5; + SetWeaponIdleTime( gpGlobals->curtime + 0.5 ); + return true; + } + else if (m_fInSpecialReload == 1) + { + if (m_flTimeWeaponIdle > gpGlobals->curtime) + return true; + // was waiting for gun to move to side + m_fInSpecialReload = 2; + + SendWeaponAnim( ACT_VM_RELOAD ); + SetWeaponIdleTime( gpGlobals->curtime + 0.45 ); + } + else + { + // Add them to the clip + m_iClip1 += 1; + +#ifdef GAME_DLL + SendReloadEvents(); +#endif + + CSDKPlayer *pPlayer = GetPlayerOwner(); + + if ( pPlayer ) + pPlayer->RemoveAmmo( 1, m_iPrimaryAmmoType ); + + m_fInSpecialReload = 1; + } + + return true; +} + + +void CWeaponShotgun::WeaponIdle() +{ + CSDKPlayer *pPlayer = GetPlayerOwner(); + + if (m_flPumpTime && m_flPumpTime < gpGlobals->curtime) + { + // play pumping sound + m_flPumpTime = 0; + } + + if (m_flTimeWeaponIdle < gpGlobals->curtime) + { + if (m_iClip1 == 0 && m_fInSpecialReload == 0 && pPlayer->GetAmmoCount( m_iPrimaryAmmoType )) + { + Reload( ); + } + else if (m_fInSpecialReload != 0) + { + if (m_iClip1 != 8 && pPlayer->GetAmmoCount( m_iPrimaryAmmoType )) + { + Reload( ); + } + else + { + // reload debounce has timed out + //MIKETODO: shotgun anims + SendWeaponAnim( ACT_SHOTGUN_RELOAD_FINISH ); + + // play cocking sound + m_fInSpecialReload = 0; + SetWeaponIdleTime( gpGlobals->curtime + 1.5 ); + } + } + else + { + SendWeaponAnim( ACT_VM_IDLE ); + } + } +} |