This commit is contained in:
FluorescentCIAAfricanAmerican
2020-04-22 12:56:21 -04:00
commit 3bf9df6b27
15370 changed files with 5489726 additions and 0 deletions
+583
View File
@@ -0,0 +1,583 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "baseobject_shared.h"
#include <KeyValues.h>
#include "tf_shareddefs.h"
#include "engine/ivmodelinfo.h"
//-----------------------------------------------------------------------------
// Purpose: Parse our model and create the buildpoints in it
//-----------------------------------------------------------------------------
void CBaseObject::CreateBuildPoints( void )
{
// Clear out any existing build points
m_BuildPoints.RemoveAll();
KeyValues * modelKeyValues = new KeyValues("");
if ( !modelKeyValues->LoadFromBuffer( modelinfo->GetModelName( GetModel() ), modelinfo->GetModelKeyValueText( GetModel() ) ) )
{
return;
}
// Do we have a build point section?
KeyValues *pkvAllBuildPoints = modelKeyValues->FindKey("build_points");
if ( pkvAllBuildPoints )
{
KeyValues *pkvBuildPoint = pkvAllBuildPoints->GetFirstSubKey();
while ( pkvBuildPoint )
{
// Find the attachment first
const char *sAttachment = pkvBuildPoint->GetName();
int iAttachmentNumber = LookupAttachment( sAttachment );
if ( iAttachmentNumber )
{
AddAndParseBuildPoint( iAttachmentNumber, pkvBuildPoint );
}
else
{
Msg( "ERROR: Model %s specifies buildpoint %s, but has no attachment named %s.\n", STRING(GetModelName()), pkvBuildPoint->GetString(), pkvBuildPoint->GetString() );
}
pkvBuildPoint = pkvBuildPoint->GetNextKey();
}
}
// Any virtual build points (build points that aren't on an attachment)?
pkvAllBuildPoints = modelKeyValues->FindKey("virtual_build_points");
if ( pkvAllBuildPoints )
{
KeyValues *pkvBuildPoint = pkvAllBuildPoints->GetFirstSubKey();
while ( pkvBuildPoint )
{
AddAndParseBuildPoint( -1, pkvBuildPoint );
pkvBuildPoint = pkvBuildPoint->GetNextKey();
}
}
modelKeyValues->deleteThis();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseObject::AddAndParseBuildPoint( int iAttachmentNumber, KeyValues *pkvBuildPoint )
{
int iPoint = AddBuildPoint( iAttachmentNumber );
m_BuildPoints[iPoint].m_bPutInAttachmentSpace = (pkvBuildPoint->GetInt( "PutInAttachmentSpace", 0 ) != 0);
// Now see if we've got a set of valid objects specified
KeyValues *pkvValidObjects = pkvBuildPoint->FindKey( "valid_objects" );
if ( pkvValidObjects )
{
KeyValues *pkvObject = pkvValidObjects->GetFirstSubKey();
while ( pkvObject )
{
const char *pSpecifiedObject = pkvObject->GetName();
int iLenObjName = Q_strlen( pSpecifiedObject );
// Find the object index for the name
for ( int i = 0; i < OBJ_LAST; i++ )
{
if ( !Q_strncmp( GetObjectInfo( i )->m_pClassName, pSpecifiedObject, iLenObjName) )
{
AddValidObjectToBuildPoint( iPoint, i );
break;
}
}
pkvObject = pkvObject->GetNextKey();
}
}
SetBuildPointPassenger( iPoint, pkvBuildPoint->GetInt( "passenger", -1 ) );
}
//-----------------------------------------------------------------------------
// Purpose: Add a new buildpoint to my list of buildpoints
//-----------------------------------------------------------------------------
int CBaseObject::AddBuildPoint( int iAttachmentNum )
{
// Make a new buildpoint
BuildPoint_t sNewPoint;
sNewPoint.m_hObject = NULL;
sNewPoint.m_iAttachmentNum = iAttachmentNum;
sNewPoint.m_iPassenger = -1;
sNewPoint.m_bPutInAttachmentSpace = false;
Q_memset( sNewPoint.m_bValidObjects, 0, sizeof( sNewPoint.m_bValidObjects ) );
// Insert it into our list
return m_BuildPoints.AddToTail( sNewPoint );
}
//-----------------------------------------------------------------------------
// Purpose: Indicate which passenger position this build point is associated with
//-----------------------------------------------------------------------------
void CBaseObject::SetBuildPointPassenger( int iPoint, int iPassenger )
{
m_BuildPoints[iPoint].m_iPassenger = iPassenger;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CBaseObject::GetBuildPointPassenger( int iPoint ) const
{
return m_BuildPoints[iPoint].m_iPassenger;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseObject::AddValidObjectToBuildPoint( int iPoint, int iObjectType )
{
Assert( iPoint <= GetNumBuildPoints() );
m_BuildPoints[iPoint].m_bValidObjects[ iObjectType ] = true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CBaseObject::GetNumBuildPoints( void ) const
{
return m_BuildPoints.Size();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CBaseObject* CBaseObject::GetBuildPointObject( int iPoint )
{
Assert( iPoint >= 0 && iPoint <= GetNumBuildPoints() );
return m_BuildPoints[iPoint].m_hObject;
}
//-----------------------------------------------------------------------------
// Purpose: Return true if the specified object type can be built on this point
//-----------------------------------------------------------------------------
bool CBaseObject::CanBuildObjectOnBuildPoint( int iPoint, int iObjectType )
{
Assert( iPoint >= 0 && iPoint <= GetNumBuildPoints() );
// Allowed to build here?
if ( !m_BuildPoints[iPoint].m_bValidObjects[ iObjectType ] )
return false;
// Buildpoint empty?
return ( m_BuildPoints[iPoint].m_hObject == NULL );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CBaseObject::GetBuildPoint( int iPoint, Vector &vecOrigin, QAngle &vecAngles )
{
Assert( iPoint >= 0 && iPoint <= GetNumBuildPoints() );
int iAttachmentNum = m_BuildPoints[iPoint].m_iAttachmentNum;
if ( iAttachmentNum == -1 )
{
vecOrigin = GetAbsOrigin();
vecAngles = GetAbsAngles();
return true;
}
else
{
return GetAttachment( m_BuildPoints[iPoint].m_iAttachmentNum, vecOrigin, vecAngles );
}
}
int CBaseObject::GetBuildPointAttachmentIndex( int iPoint ) const
{
Assert( iPoint >= 0 && iPoint <= GetNumBuildPoints() );
if ( m_BuildPoints[iPoint].m_bPutInAttachmentSpace )
{
return m_BuildPoints[iPoint].m_iAttachmentNum;
}
else
{
return 0;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseObject::SetObjectOnBuildPoint( int iPoint, CBaseObject *pObject )
{
Assert( iPoint >= 0 && iPoint <= GetNumBuildPoints() );
m_BuildPoints[iPoint].m_hObject = pObject;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float CBaseObject::GetMaxSnapDistance( int iPoint )
{
Assert( iPoint >= 0 && iPoint <= GetNumBuildPoints() );
if ( m_BuildPoints[iPoint].m_iAttachmentNum == -1 )
{
// Virtual build points need some more space since they represent an upgrade to the whole object.
return 128;
}
else
{
return 128;
}
}
//-----------------------------------------------------------------------------
// Purpose: Return the number of objects on my build points
//-----------------------------------------------------------------------------
int CBaseObject::GetNumObjectsOnMe( void )
{
int iObjects = 0;
for ( int i = 0; i < GetNumBuildPoints(); i++ )
{
if ( m_BuildPoints[i].m_hObject )
{
iObjects++;
}
}
return iObjects;
}
//-----------------------------------------------------------------------------
// Purpose: Return the first object build on this object
//-----------------------------------------------------------------------------
CBaseEntity *CBaseObject::GetFirstObjectOnMe( void )
{
for ( int i = 0; i < GetNumBuildPoints(); i++ )
{
if ( m_BuildPoints[i].m_hObject )
return m_BuildPoints[i].m_hObject;
}
return NULL;
}
//-----------------------------------------------------------------------------
// I've finished building the specified object on the specified build point
//-----------------------------------------------------------------------------
int CBaseObject::FindObjectOnBuildPoint( CBaseObject *pObject )
{
for (int i = m_BuildPoints.Count(); --i >= 0; )
{
if (m_BuildPoints[i].m_hObject == pObject)
return i;
}
return -1;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CBaseObject *CBaseObject::GetObjectOfTypeOnMe( int iObjectType )
{
for ( int iObject = 0; iObject < GetNumObjectsOnMe(); ++iObject )
{
CBaseObject *pObject = dynamic_cast<CBaseObject*>( m_BuildPoints[iObject].m_hObject.Get() );
if ( pObject )
{
if ( pObject->GetType() == iObjectType )
return pObject;
}
}
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseObject::RemoveAllObjects( void )
{
for ( int i = 0; i < GetNumBuildPoints(); i++ )
{
if ( m_BuildPoints[i].m_hObject )
{
#ifndef CLIENT_DLL
UTIL_Remove( m_BuildPoints[i].m_hObject );
#endif
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CBaseObject *CBaseObject::GetParentObject( void )
{
if ( GetMoveParent() )
return dynamic_cast<CBaseObject*>(GetMoveParent());
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose: Return true if I ever accept this powerup type
//-----------------------------------------------------------------------------
bool CBaseObject::CanPowerupEver( int iPowerup )
{
Assert( iPowerup >= 0 && iPowerup < MAX_POWERUPS );
// Un-repairable objects can't be boosted
switch( iPowerup )
{
#ifndef CLIENT_DLL
case POWERUP_BOOST:
if ( !m_flRepairMultiplier )
return false;
break;
#endif
case POWERUP_POWER:
// Do we use power?
if ( m_fObjectFlags & OF_DOESNT_NEED_POWER )
return false;
// Objects on vehicles never need power
if ( IsBuiltOnAttachment() )
{
if ( GetParentObject() && GetParentObject()->IsAVehicle() )
return false;
}
// Ok, I'll be needing some juice
return true;
default:
break;
}
// Don't accept any powerups if we're placing
if ( IsPlacing() )
return false;
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Return true if I can be powered by this powerup right now
//-----------------------------------------------------------------------------
bool CBaseObject::CanPowerupNow( int iPowerup )
{
Assert( iPowerup >= 0 && iPowerup < MAX_POWERUPS );
if ( !CanPowerupEver(iPowerup) )
return false;
// Un-repairable objects can't be boosted
switch( iPowerup )
{
case POWERUP_POWER:
// If I have power, I don't need it
if ( IsPowered() )
return false;
return true;
default:
break;
}
// Don't accept any powerups if we're placing
if ( IsPlacing() )
return false;
#ifdef CLIENT_DLL
return true;
#else
return BaseClass::CanPowerupEver( iPowerup );
#endif
}
//-----------------------------------------------------------------------------
// Purpose: Return true if this object has power
//-----------------------------------------------------------------------------
bool CBaseObject::IsPowered( void )
{
if ( !CanPowerupEver( POWERUP_POWER ) )
return true;
#ifdef CLIENT_DLL
return ( HasPowerup(POWERUP_POWER) );
#else
return ( HasPowerup(POWERUP_POWER) || m_hPowerPack );
#endif
};
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float CBaseObject::GetSapperAttachTime( void )
{
return GetObjectInfo( GetType() )->m_flSapperAttachTime;
}
static ConVar sv_ignore_hitboxes( "sv_ignore_hitboxes", "0", FCVAR_REPLICATED, "Disable hitboxes" );
bool CBaseObject::TestHitboxes( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr )
{
bool bReturn = BaseClass::TestHitboxes( ray, fContentsMask, tr );
if( !sv_ignore_hitboxes.GetBool() )
return bReturn;
if( !bReturn )
{
return false;
}
if( tr.fraction == 1.f && !tr.allsolid && !tr.startsolid )
{
return false;
}
return bReturn;
}
//-----------------------------------------------------------------------------
// Purpose: Return true if this object should be active
//-----------------------------------------------------------------------------
bool CBaseObject::ShouldBeActive( void )
{
// Placing and/or constructing objects shouldn't be active
if ( IsPlacing() || IsBuilding() )
return false;
// Powered? Or don't need it
if ( CanPowerupEver(POWERUP_POWER) && !HasPowerup( POWERUP_POWER ) )
return false;
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Set the object's type
//-----------------------------------------------------------------------------
void CBaseObject::SetType( int iObjectType )
{
m_iObjectType = iObjectType;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : act -
//-----------------------------------------------------------------------------
void CBaseObject::SetActivity( Activity act )
{
// Allow any model swapping, etc. to occur
OnActivityChanged( act );
// Hrm, it's not actually a studio model...
if ( !GetModelPtr() )
return;
int sequence = SelectWeightedSequence( act );
if ( sequence != ACTIVITY_NOT_AVAILABLE )
{
m_Activity = act;
SetObjectSequence( sequence );
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Activity
//-----------------------------------------------------------------------------
Activity CBaseObject::GetActivity( ) const
{
return m_Activity;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : act -
//-----------------------------------------------------------------------------
void CBaseObject::OnActivityChanged( Activity act )
{
// Nothing
}
//-----------------------------------------------------------------------------
// Purpose: Thin wrapper over CBaseAnimating::SetSequence to do bookkeeping.
// Input : sequence -
//-----------------------------------------------------------------------------
void CBaseObject::SetObjectSequence( int sequence )
{
ResetSequence( sequence );
SetCycle( 0 );
#if !defined( CLIENT_DLL )
if ( IsUsingClientSideAnimation() )
{
ResetClientsideFrame();
}
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseObject::AttemptToGoActive( void )
{
// Go active if we can
if ( ShouldBeActive() )
{
OnGoActive();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseObject::OnGoActive( void )
{
#ifndef CLIENT_DLL
// Play startup animation
PlayStartupAnimation();
// Switch to the on state
if ( GetModelPtr() )
{
int index = FindBodygroupByName( "powertoggle" );
if ( index >= 0 )
{
SetBodygroup( index, 1 );
}
}
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseObject::OnGoInactive( void )
{
#ifndef CLIENT_DLL
if ( GetModelPtr() )
{
// Switch to the off state
int index = FindBodygroupByName( "powertoggle" );
if ( index >= 0 )
{
SetBodygroup( index, 0 );
}
}
#endif
}
+49
View File
@@ -0,0 +1,49 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef BASEOBJECT_SHARED_H
#define BASEOBJECT_SHARED_H
#ifdef _WIN32
#pragma once
#endif
#include "tf_shareddefs.h"
#if defined( CLIENT_DLL )
#define CBaseObject C_BaseObject
#endif
class CBaseObject;
typedef CHandle<CBaseObject> ObjectHandle;
struct BuildPoint_t
{
// If this is true, then objects are parented to the attachment point instead of
// parented to the entity's abs origin + angles. That way, they'll move if the
// attachment point animates.
bool m_bPutInAttachmentSpace;
int m_iAttachmentNum;
ObjectHandle m_hObject;
int m_iPassenger;
bool m_bValidObjects[ OBJ_LAST ];
};
struct VulnerablePoint_t
{
float m_fDamageMultiplier;
int m_nSet;
int m_nBox;
};
// Shared header file for players
#if defined( CLIENT_DLL )
#include "c_baseobject.h"
#else
#include "tf_obj.h"
#endif
#endif // BASEOBJECT_SHARED_H
@@ -0,0 +1,497 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "basetfplayer_shared.h"
#include "basetfcombatweapon_shared.h"
#include "weapon_twohandedcontainer.h"
#if !defined( CLIENT_DLL )
#include "soundent.h"
#else
#include "functionproxy.h"
#include "ivrenderview.h"
#include "cl_animevent.h"
#include "fx.h"
#endif
CBaseTFCombatWeapon::CBaseTFCombatWeapon ( void )
{
m_bReflectViewModelAnimations = false;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseTFCombatWeapon::Precache( void )
{
BaseClass::Precache();
#if !defined( CLIENT_DLL )
// Connect to my CVars
m_pDamageCVar = cvar->FindVar( UTIL_VarArgs( "%s_damage", GetClassname() ) );
m_pRangeCVar = cvar->FindVar( UTIL_VarArgs( "%s_range", GetClassname() ) );
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CBaseTFCombatWeapon::GetPrimaryAmmo( void )
{
// Get the local player
CBasePlayer *pPlayer = ToBaseTFPlayer( GetOwner() );
if ( pPlayer == NULL )
return 0;
return pPlayer->GetAmmoCount( m_iPrimaryAmmoType );
}
//-----------------------------------------------------------------------------
// Purpose: Checks if the owner is EMPed
//-----------------------------------------------------------------------------
bool CBaseTFCombatWeapon::IsOwnerEMPed()
{
CBaseTFPlayer *pPlayer = ToBaseTFPlayer( GetOwner() );
if ((!pPlayer) || (!pPlayer->GetPlayerClass()))
return false;
return ( pPlayer->HasPowerup(POWERUP_EMP) );
}
//-----------------------------------------------------------------------------
// Purpose: Temporarily remove disguise
//-----------------------------------------------------------------------------
void CBaseTFCombatWeapon::CheckRemoveDisguise( void )
{
#if !defined( CLIENT_DLL )
CBaseTFPlayer *player = static_cast< CBaseTFPlayer * >( GetOwner());
if ( player )
{
// Always remove camo
player->ClearCamouflage();
}
#endif
}
//-----------------------------------------------------------------------------
// Purpose: Factor in the player's anim speed to the sequence duration for weapons
//-----------------------------------------------------------------------------
float CBaseTFCombatWeapon::SequenceDuration( int iSequence )
{
float flDuration = BaseClass::SequenceDuration( iSequence );
CBaseTFPlayer *pOwner = (CBaseTFPlayer *)GetOwner();
if ( pOwner )
{
flDuration /= pOwner->GetDefaultAnimSpeed();
}
return flDuration;
}
//-----------------------------------------------------------------------------
// Purpose: Override weapon sound. TF doesn't use ATTN_GUNFIRE for it's weapon attenuations.
//-----------------------------------------------------------------------------
void CBaseTFCombatWeapon::WeaponSound( WeaponSound_t shoot_type, float soundtime /*= 0.0f*/ )
{
#if !defined( CLIENT_DLL )
// HACKHACK: Force a combat sound to alert NPCs, for antlion prototype
CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), 600, 0.1 );
#endif
BaseClass::WeaponSound( shoot_type, soundtime );
}
//-----------------------------------------------------------------------------
// Purpose: Get the point from which to create the weapon's tracer
//-----------------------------------------------------------------------------
Vector CBaseTFCombatWeapon::GetTracerSrc( Vector &vecSrc, Vector &vecFireDir )
{
QAngle vecAngles;
VectorAngles( vecFireDir, vecAngles );
Vector right;
AngleVectors( vecAngles, NULL, &right, NULL );
return (vecSrc + Vector ( 0,0,-4 ) + right * 2 + vecFireDir * 16);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : activity -
//-----------------------------------------------------------------------------
void CBaseTFCombatWeapon::PlayAttackAnimation( int activity )
{
SendWeaponAnim( activity );
CBaseTFPlayer *pPlayer = ToBaseTFPlayer( GetOwner() );
if ( pPlayer )
{
pPlayer->SetAnimation( PLAYER_ATTACK1 );
pPlayer->SetLastAttackTime( gpGlobals->curtime );
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : sequence -
//-----------------------------------------------------------------------------
bool CBaseTFCombatWeapon::SendWeaponAnim( int iActivity )
{
CBaseTFPlayer *pPlayer = ToBaseTFPlayer( GetOwner() );
if ( !pPlayer )
return false;
CBaseTFCombatWeapon *pOther = NULL;
// See if we are wielding multiple weapons
CWeaponTwoHandedContainer *pContainer = dynamic_cast< CWeaponTwoHandedContainer * >( pPlayer->GetActiveWeapon() );
if ( pContainer )
{
// Make sure they exist
CBaseTFCombatWeapon *left = static_cast< CBaseTFCombatWeapon * >( pContainer->GetLeftWeapon() );
CBaseTFCombatWeapon *right = static_cast< CBaseTFCombatWeapon * >( pContainer->GetRightWeapon() );
if ( !left || !right )
return false;
// Make sure one of them is this!!!
if ( left != this && right != this )
return false;
// Get pointer to other one
pOther = left;
if ( left == this )
{
pOther = right;
}
Assert(pOther);
// Now ask our other weapon if it would like to stomp my animation attempt
iActivity = pOther->ReplaceOtherWeaponsActivity( iActivity );
if ( iActivity == -1 )
return false;
}
// Always pass through to base
BaseClass::SendWeaponAnim( iActivity );
if ( !IsReflectingAnimations() )
return false;
// See if we are wielding multiple weapons
if ( !pContainer )
return false;
Assert(pOther);
// Send our other weapon the activity code
iActivity = GetOtherWeaponsActivity( iActivity );
if ( iActivity != -1 )
{
pOther->SendWeaponAnim( iActivity );
// Remember it for weapon switching
m_iLastReflectedActivity = iActivity;
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : reflect -
//-----------------------------------------------------------------------------
void CBaseTFCombatWeapon::SetReflectViewModelAnimations( bool reflect )
{
m_bReflectViewModelAnimations = reflect;
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CBaseTFCombatWeapon::IsReflectingAnimations( void ) const
{
return m_bReflectViewModelAnimations;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CBaseTFCombatWeapon::IsCamouflaged( void )
{
CBaseTFPlayer *pPlayer = (CBaseTFPlayer *)GetOwner();
if ( pPlayer && pPlayer->IsCamouflaged() )
return true;
return false;
}
#if defined( CLIENT_DLL )
static ConVar cl_bobcycle( "cl_bobcycle","0.8" );
static ConVar cl_bob( "cl_bob","0.002" );
static ConVar cl_bobup( "cl_bobup","0.5" );
// Register these cvars if needed for easy tweaking
static ConVar v_iyaw_cycle( "v_iyaw_cycle", "2"/*, FCVAR_UNREGISTERED*/ );
static ConVar v_iroll_cycle( "v_iroll_cycle", "0.5"/*, FCVAR_UNREGISTERED*/ );
static ConVar v_ipitch_cycle( "v_ipitch_cycle", "1"/*, FCVAR_UNREGISTERED*/ );
static ConVar v_iyaw_level( "v_iyaw_level", "0.3"/*, FCVAR_UNREGISTERED*/ );
static ConVar v_iroll_level( "v_iroll_level", "0.1"/*, FCVAR_UNREGISTERED*/ );
static ConVar v_ipitch_level( "v_ipitch_level", "0.3"/*, FCVAR_UNREGISTERED*/ );
//-----------------------------------------------------------------------------
// Purpose:
// Output : float
//-----------------------------------------------------------------------------
float CBaseTFCombatWeapon::CalcViewmodelBob( void )
{
static double bobtime;
static float bob;
float cycle;
CBasePlayer *player = ToBasePlayer( GetOwner() );
if ( !player )
return 0.0f;
if ( ( player->GetGroundEntity() == NULL ) || !gpGlobals->frametime )
{
return bob; // just use old value
}
bobtime += gpGlobals->frametime;
cycle = bobtime - (int)(bobtime/cl_bobcycle.GetFloat())*cl_bobcycle.GetFloat();
cycle /= cl_bobcycle.GetFloat();
if (cycle < cl_bobup.GetFloat())
{
cycle = M_PI * cycle / cl_bobup.GetFloat();
}
else
{
cycle = M_PI + M_PI*(cycle-cl_bobup.GetFloat())/(1.0 - cl_bobup.GetFloat());
}
// bob is proportional to simulated velocity in the xy plane
// (don't count Z, or jumping messes it up)
bob = player->GetAbsVelocity().Length2D() * cl_bob.GetFloat();
bob = bob*0.3 + bob*0.7*sin(cycle);
bob = MIN( 4.0, bob );
bob = MAX( -7.0, bob );
return bob;
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : float
//-----------------------------------------------------------------------------
void CBaseTFCombatWeapon::AddViewmodelBob( CBaseViewModel *viewmodel, Vector &origin, QAngle &angles )
{
float fIdleScale = 2.0f;
// Bias so view models aren't all synced to each other
//float curtime = gpGlobals->curtime + ( viewmodelindex * 2 * M_PI / GetViewModelCount() );
float curtime = gpGlobals->curtime + ( viewmodel->entindex() * 2 * M_PI );
origin[ROLL] -= fIdleScale * sin(curtime*v_iroll_cycle.GetFloat()) * v_iroll_level.GetFloat();
origin[PITCH] -= fIdleScale * sin(curtime*v_ipitch_cycle.GetFloat()) * (v_ipitch_level.GetFloat() * 0.5);
origin[YAW] -= fIdleScale * sin(curtime*v_iyaw_cycle.GetFloat()) * v_iyaw_level.GetFloat();
Vector forward;
AngleVectors( angles, &forward, NULL, NULL );
float flBob = CalcViewmodelBob();
// Apply bob, but scaled down to 40%
VectorMA( origin, flBob * 0.4, forward, origin );
// Z bob a bit more
origin[2] += flBob;
// throw in a little tilt.
angles[ YAW ] -= flBob * 0.6;
angles[ ROLL ] -= flBob * 0.5;
angles[ PITCH ] -= flBob * 0.4;
}
//-----------------------------------------------------------------------------
// Purpose: TF specific weapon anim events
//-----------------------------------------------------------------------------
bool CBaseTFCombatWeapon::OnFireEvent( C_BaseViewModel *pViewModel, const Vector& origin, const QAngle& angles, int event, const char *options )
{
switch( event )
{
case CL_EVENT_MUZZLEFLASH0:
case CL_EVENT_MUZZLEFLASH1:
case CL_EVENT_MUZZLEFLASH2:
case CL_EVENT_MUZZLEFLASH3:
{
int iAttachment = -1;
Vector attachOrigin;
QAngle attachAngles;
// First person muzzle flashes
switch (event)
{
case CL_EVENT_MUZZLEFLASH0:
iAttachment = 0;
break;
case CL_EVENT_MUZZLEFLASH1:
iAttachment = 1;
break;
case CL_EVENT_MUZZLEFLASH2:
iAttachment = 2;
break;
case CL_EVENT_MUZZLEFLASH3:
iAttachment = 3;
break;
}
// Did we find it?
if ( pViewModel->GetAttachment( iAttachment+1, attachOrigin, attachAngles ) )
{
//int iType = atoi( options );
// Is our owner boosted?
CBasePlayer *pPlayer = ToBaseTFPlayer( GetOwner() );
if ( pPlayer && pPlayer->HasPowerup(POWERUP_BOOST) )
{
unsigned char color[3];
color[0] = 50;
color[1] = 255;
color[2] = 50;
FX_MuzzleEffect( attachOrigin, attachAngles, 1.0, GetRefEHandle(), &color[0] );
}
else
{
FX_MuzzleEffect( attachOrigin, attachAngles, 1.0, GetRefEHandle() );
}
return true;
}
}
break;
default:
break;
}
return false;
}
//============================================================================================================
// OWNER BOOSTED PROXY FOR WEAPONS / PLAYERS
//============================================================================================================
class CPlayerBoostedProxy : public CResultProxy
{
public:
bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
void OnBind( void *pC_BaseEntity );
private:
CFloatInput m_Factor;
};
bool CPlayerBoostedProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
{
if (!CResultProxy::Init( pMaterial, pKeyValues ))
return false;
if (!m_Factor.Init( pMaterial, pKeyValues, "scale", 1 ))
return false;
return true;
}
void CPlayerBoostedProxy::OnBind( void *pRenderable )
{
// Find the view angle between the player and this entity....
IClientRenderable *pRend = (IClientRenderable *)pRenderable;
C_BaseEntity *pEntity = pRend->GetIClientUnknown()->GetBaseEntity();
CBaseTFPlayer *pPlayer = NULL;
C_BaseViewModel *pViewModel = dynamic_cast<C_BaseViewModel*>(pEntity);
if ( pViewModel )
{
pPlayer = C_BaseTFPlayer::GetLocalPlayer();
}
else
{
CBaseTFCombatWeapon *pWeapon = dynamic_cast<CBaseTFCombatWeapon*>(pEntity);
if ( pWeapon )
{
pPlayer = ToBaseTFPlayer( pWeapon->GetOwner() );
}
else
{
pPlayer = dynamic_cast<CBaseTFPlayer*>(pEntity);
}
}
// Find him?
if ( pPlayer )
{
float flBoosted = (int)pPlayer->HasPowerup( POWERUP_BOOST );
SetFloatResult( flBoosted * m_Factor.GetFloat() );
}
}
EXPOSE_INTERFACE( CPlayerBoostedProxy, IMaterialProxy, "PlayerBoosted" IMATERIAL_PROXY_INTERFACE_VERSION );
#else
//-----------------------------------------------------------------------------
// Purpose:
// Output : float
//-----------------------------------------------------------------------------
float CBaseTFCombatWeapon::CalcViewmodelBob( void )
{
return 0.0f;
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : float
//-----------------------------------------------------------------------------
void CBaseTFCombatWeapon::AddViewmodelBob( CBaseViewModel *viewmodel, Vector &origin, QAngle &angles )
{
}
#endif
LINK_ENTITY_TO_CLASS( basetfcombatweapon, CBaseTFCombatWeapon );
IMPLEMENT_NETWORKCLASS_ALIASED( BaseTFCombatWeapon , DT_BaseTFCombatWeapon )
BEGIN_NETWORK_TABLE( CBaseTFCombatWeapon , DT_BaseTFCombatWeapon )
#if !defined( CLIENT_DLL )
// Don't network any animation stuff to client
SendPropExclude( "DT_AnimTimeMustBeFirst", "m_flAnimTime" ),
SendPropExclude( "DT_BaseAnimating", "m_flCycle" ),
SendPropInt( SENDINFO( m_bReflectViewModelAnimations ), 1, SPROP_UNSIGNED ),
#else
RecvPropInt( RECVINFO( m_bReflectViewModelAnimations ) ),
#endif
END_NETWORK_TABLE()
BEGIN_PREDICTION_DATA( CBaseTFCombatWeapon )
// If true, reflect and weapon animations to all view models
DEFINE_PRED_FIELD( m_bReflectViewModelAnimations, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
DEFINE_FIELD( m_iLastReflectedActivity, FIELD_INTEGER )
END_PREDICTION_DATA()
+152
View File
@@ -0,0 +1,152 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef BASETFCOMBATWEAPON_SHARED_H
#define BASETFCOMBATWEAPON_SHARED_H
#ifdef _WIN32
#pragma once
#endif
#include "baseplayer_shared.h"
#include "basetfplayer_shared.h"
#include "basecombatweapon_shared.h"
#if defined( CLIENT_DLL )
#define CBaseTFCombatWeapon C_BaseTFCombatWeapon
#endif
//-----------------------------------------------------------------------------
// Purpose: Client side rep of CBaseTFCombatWeapon
//-----------------------------------------------------------------------------
class CBaseTFCombatWeapon : public CBaseCombatWeapon
{
DECLARE_CLASS( CBaseTFCombatWeapon, CBaseCombatWeapon );
public:
DECLARE_NETWORKCLASS();
DECLARE_PREDICTABLE();
CBaseTFCombatWeapon ();
virtual void Precache( void );
bool IsCamouflaged( void );
virtual Vector GetTracerSrc( Vector &vecSrc, Vector &vecFireDir );
// Check if the owner is being EMP'd and if we can't fire, play an appropriate
// failure sound
// Default is to allow firing no matter what
virtual bool ComputeEMPFireState( void ) { return true; }
virtual void CheckRemoveDisguise( void );
virtual int GetImpactScale( void ) { return 1; };
// FIXME: why are these virtual?
virtual float SequenceDuration( int iSequence );
virtual float SequenceDuration( void ) { return SequenceDuration( GetSequence() ); }
virtual void WeaponSound( WeaponSound_t sound_type, float soundtime = 0.0f );
virtual void PlayAttackAnimation( int activity );
virtual bool SendWeaponAnim( int iActivity );
virtual void SetReflectViewModelAnimations( bool reflect );
virtual bool IsReflectingAnimations( void ) const;
virtual int GetLastReflectedActivity( void ) { return m_iLastReflectedActivity; };
virtual int GetOtherWeaponsActivity( int iActivity ) { return iActivity; }
virtual int ReplaceOtherWeaponsActivity( int iActivity ) { return iActivity; }
virtual bool SupportsTwoHanded( void ) { return false; };
virtual void CleanupOnActStart( void ) { return; }
bool IsOwnerEMPed();
virtual void BulletWasFired( const Vector &vecStart, const Vector &vecEnd ) { return; };
// Technology handling
virtual void GainedNewTechnology( CBaseTechnology *pTechnology ) { return; };
/*
// All predicted weapons need to implement and return true
virtual bool IsPredicted( void ) const
{
return true;
}
*/
virtual int GetPrimaryAmmo( void );
virtual void AddViewmodelBob( CBaseViewModel *viewmodel, Vector &origin, QAngle &angles );
virtual float CalcViewmodelBob( void );
#if defined( CLIENT_DLL )
virtual bool ShouldPredict( void )
{
if ( GetOwner() &&
GetOwner() == C_BasePlayer::GetLocalPlayer() )
return true;
return BaseClass::ShouldPredict();
}
// Camo
virtual int GetFxBlend( void );
virtual bool IsTransparent( void );
virtual int GetSecondaryAmmo( void );
virtual int DrawModel( int flags );
virtual void DrawAmmo( void );
virtual void DrawMiniAmmo( void );
virtual bool ShouldDrawPickup( void );
virtual void OnDataChanged( DataUpdateType_t updateType );
virtual const char *GetPrintName( void );
virtual bool ShouldShowUsageHint( void );
static void CreateCrosshairPanels( void );
static void DestroyCrosshairPanels( void );
virtual bool OnFireEvent( C_BaseViewModel *pViewModel, const Vector& origin, const QAngle& angles, int event, const char *options );
protected:
static vgui::Label *m_pCrosshairAmmo;
private:
// Share crosshair stuff among all weapons
static bool m_bCrosshairInitialized;
// Create/destroy shared crosshair object
static void InitializeCrosshairPanels( void );
private:
CBaseTFCombatWeapon ( const CBaseTFCombatWeapon & );
#else
virtual void AddAssociatedObject( CBaseObject *pObject ) { }
virtual void RemoveAssociatedObject( CBaseObject *pObject ) { }
protected:
// CVars that contain my damage details
const ConVar *m_pDamageCVar;
const ConVar *m_pRangeCVar;
#endif
protected:
// If true, reflect and weapon animations to all view models
CNetworkVar( bool, m_bReflectViewModelAnimations );
int m_iLastReflectedActivity;
float bobtime;
float bob;
};
#endif // BASETFCOMBATWEAPON_SHARED_H
+825
View File
@@ -0,0 +1,825 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: TF2's player object, code shared between client & server.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "basetfplayer_shared.h"
#include "weapon_combatshield.h"
#include "weapon_objectselection.h"
#include "weapon_twohandedcontainer.h"
#ifdef CLIENT_DLL
#include "c_weapon_builder.h"
#else
#include "weapon_builder.h"
#include "basegrenade_shared.h"
#include "grenade_objectsapper.h"
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CBaseTFPlayer::IsClass( TFClass iClass )
{
if ( !GetPlayerClass() )
{
// Special case for undecided players
if ( iClass == TFCLASS_UNDECIDED )
return true;
return false;
}
return ( PlayerClass() == iClass );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CWeaponCombatShield *CBaseTFPlayer::GetCombatShield( void )
{
if ( !m_hWeaponCombatShield )
{
if ( GetTeamNumber() == TEAM_ALIENS )
{
m_hWeaponCombatShield = static_cast< CWeaponCombatShield * >( Weapon_OwnsThisType( "weapon_combat_shield_alien" ) );
#ifndef CLIENT_DLL
if ( !m_hWeaponCombatShield )
{
m_hWeaponCombatShield = static_cast< CWeaponCombatShield * >( GiveNamedItem( "weapon_combat_shield_alien" ) );
}
#endif
}
else
{
m_hWeaponCombatShield = static_cast< CWeaponCombatShield * >( Weapon_OwnsThisType( "weapon_combat_shield" ) );
#ifndef CLIENT_DLL
if ( !m_hWeaponCombatShield )
{
m_hWeaponCombatShield = static_cast< CWeaponCombatShield * >( GiveNamedItem( "weapon_combat_shield" ) );
}
#endif
}
}
return m_hWeaponCombatShield;
}
//-----------------------------------------------------------------------------
// Purpose: Check to see if the shot is blocked by the player's handheld shield
//-----------------------------------------------------------------------------
bool CBaseTFPlayer::IsHittingShield( const Vector &vecVelocity, float *flDamage )
{
if (!IsParrying() && !IsBlocking())
return false;
Vector2D vecDelta = vecVelocity.AsVector2D();
Vector2DNormalize( vecDelta );
Vector forward;
AngleVectors( GetLocalAngles(), &forward );
Vector2DNormalize( forward.AsVector2D() );
float flDot = DotProduct2D( vecDelta, forward.AsVector2D() );
// This gives us a little more than a 90 degree protection angle
if (flDot < -0.67f)
{
// We've hit the players handheld shield, see if the shield can do anything about it
if ( flDamage && GetCombatShield() )
{
// Return true if the shield blocked it all
*flDamage = GetCombatShield()->AttemptToBlock( *flDamage );
return ( !(*flDamage) );
}
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose: Play a sound to show we've been hurt
//-----------------------------------------------------------------------------
void CBaseTFPlayer::PainSound( void )
{
char *sSoundName = NULL;
if ( GetTeamNumber() == TEAM_HUMANS )
{
sSoundName = "Humans.Pain";
}
else if ( GetTeamNumber() == TEAM_ALIENS )
{
switch( PlayerClass() )
{
case TFCLASS_COMMANDO:
sSoundName = "AlienCommando.Pain";
break;
case TFCLASS_MEDIC:
sSoundName = "AlienMedic.Pain";
break;
case TFCLASS_DEFENDER:
sSoundName = "AlienDefender.Pain";
break;
case TFCLASS_ESCORT:
sSoundName = "AlienEscort.Pain";
break;
default:
break;
}
}
if ( !sSoundName )
return;
CPASAttenuationFilter filter( this, sSoundName );
EmitSound( filter, entindex(), sSoundName );
}
//-----------------------------------------------------------------------------
// Purpose: Return true if we should record our last weapon when switching between the two specified weapons
//-----------------------------------------------------------------------------
bool CBaseTFPlayer::Weapon_ShouldSetLast( CBaseCombatWeapon *pOldWeapon, CBaseCombatWeapon *pNewWeapon )
{
// Don't record last weapons when switching to an object
if ( dynamic_cast< CWeaponObjectSelection* >( pNewWeapon ) )
{
// Store this weapon off so we can switch back to it
// Don't store it if it's also an object
CBaseCombatWeapon *pLast = pOldWeapon->GetLastWeapon();
#ifdef CLIENT_DLL
if ( !dynamic_cast< C_WeaponBuilder* >( pLast ) )
#else
if ( !dynamic_cast< CWeaponBuilder* >( pLast ) )
#endif
{
m_hLastWeaponBeforeObject = pLast;
}
return false;
}
// Don't record last weapons when switching from the builder
// If the old weapon is a twohanded container, check the left weapon
CWeaponTwoHandedContainer *pContainer = dynamic_cast< CWeaponTwoHandedContainer * >( pOldWeapon );
if ( pContainer )
{
pOldWeapon = dynamic_cast< CBaseTFCombatWeapon * >( pContainer->GetLeftWeapon() );
}
#ifdef CLIENT_DLL
if ( dynamic_cast< C_WeaponBuilder* >( pOldWeapon ) )
return false;
#else
if ( dynamic_cast< CWeaponBuilder* >( pOldWeapon ) )
return false;
#endif
return BaseClass::Weapon_ShouldSetLast( pOldWeapon, pNewWeapon );
}
//-----------------------------------------------------------------------------
// Purpose: Return true if we should allow selection of the specified item
//-----------------------------------------------------------------------------
bool CBaseTFPlayer::Weapon_ShouldSelectItem( CBaseCombatWeapon *pWeapon )
{
CBaseCombatWeapon *pActiveWeapon = GetActiveWeapon();
// If the old weapon is a twohanded container, check the left weapon
CWeaponTwoHandedContainer *pContainer = dynamic_cast< CWeaponTwoHandedContainer * >( pActiveWeapon );
if ( pContainer )
{
pActiveWeapon = pContainer->GetLeftWeapon();
}
return ( pWeapon != pActiveWeapon );
}
#ifndef CLIENT_DLL
// Sapper handling is all here because it'll soon be shared Client / Server
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CBaseTFPlayer::IsAttachingSapper( void )
{
return ( m_TFLocal.m_bAttachingSapper );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float CBaseTFPlayer::GetSapperAttachmentTime( void )
{
return (gpGlobals->curtime - m_flSapperAttachmentStartTime);
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseTFPlayer::StartAttachingSapper( CBaseObject *pObject, CGrenadeObjectSapper *pSapper )
{
Assert( pSapper );
m_TFLocal.m_bAttachingSapper = true;
m_TFLocal.m_flSapperAttachmentFrac = 0.0f;
m_hSappedObject = pObject;
m_flSapperAttachmentStartTime = gpGlobals->curtime;
m_flSapperAttachmentFinishTime = gpGlobals->curtime + m_hSappedObject->GetSapperAttachTime();
m_hSapper = pSapper;
m_hSapper->SetArmed( false );
CPASAttenuationFilter filter( m_hSapper, "WeaponObjectSapper.Attach" );
EmitSound( filter, m_hSapper->entindex(), "WeaponObjectSapper.Attach" );
// Drop the player's weapon
if ( GetActiveWeapon() )
{
GetActiveWeapon()->Holster();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseTFPlayer::CheckSapperAttaching( void )
{
// Did we stop attaching?
if ( !m_TFLocal.m_bAttachingSapper )
{
if ( m_TFLocal.m_flSapperAttachmentFrac )
{
StopAttaching();
}
return;
}
// Object gone?
if ( m_hSappedObject == NULL )
{
StopAttaching();
return;
}
// Sapper gone?
if ( m_hSapper == NULL )
{
StopAttaching();
return;
}
// Make sure I'm still looking at the target
trace_t tr;
Vector vecAiming;
Vector vecSrc = EyePosition();
EyeVectors( &vecAiming );
UTIL_TraceLine( vecSrc, vecSrc + (vecAiming * 128), MASK_SOLID, this, TFCOLLISION_GROUP_WEAPON, &tr );
if ( tr.fraction == 1.0 || tr.m_pEnt != m_hSappedObject )
{
StopAttaching();
return;
}
// Finished?
if ( m_flSapperAttachmentFinishTime >= gpGlobals->curtime )
{
float dt = m_flSapperAttachmentFinishTime - m_flSapperAttachmentStartTime;
if ( dt > 0.0f )
{
m_TFLocal.m_flSapperAttachmentFrac = ( gpGlobals->curtime - m_flSapperAttachmentStartTime ) / dt;
m_TFLocal.m_flSapperAttachmentFrac = clamp( m_TFLocal.m_flSapperAttachmentFrac, 0.0f, 1.0f );
}
else
{
m_TFLocal.m_flSapperAttachmentFrac = 0.0f;
}
return;
}
FinishAttaching();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseTFPlayer::CleanupAfterAttaching( void )
{
Assert( m_TFLocal.m_bAttachingSapper );
m_TFLocal.m_bAttachingSapper = false;
m_flSapperAttachmentFinishTime = -1;
m_flSapperAttachmentStartTime = -1;
m_TFLocal.m_flSapperAttachmentFrac = 0.0f;
// Restore the player's weapon
m_flNextAttack = gpGlobals->curtime;
if ( GetActiveWeapon() )
{
GetActiveWeapon()->Deploy();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseTFPlayer::StopAttaching( void )
{
CleanupAfterAttaching();
if ( m_hSapper != NULL )
{
CPASAttenuationFilter filter( m_hSapper, "WeaponObjectSapper.AttachFail" );
EmitSound( filter, m_hSapper->entindex(), "WeaponObjectSapper.AttachFail" );
m_hSapper->SetTargetObject( NULL );
m_hSapper->Remove( );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseTFPlayer::FinishAttaching( void )
{
CleanupAfterAttaching();
if ( m_hSapper != NULL )
{
m_hSapper->SetTargetObject( m_hSappedObject );
m_hSapper->SetArmed( true );
}
}
#endif
// Below this many degrees, slow down turning rate linearly
#define FADE_TURN_DEGREES 45.0f
// After this, need to start turning feet
#define MAX_TORSO_ANGLE 90.0f
// Below this amount, don't play a turning animation/perform IK
#define MIN_TURN_ANGLE_REQUIRING_TURN_ANIMATION 15.0f
static ConVar tf2_feetyawrunscale( "tf2_feetyawrunscale", "2", FCVAR_REPLICATED, "Multiplier on tf2_feetyawrate to allow turning faster when running." );
extern ConVar sv_backspeed;
extern ConVar mp_feetyawrate;
extern ConVar mp_facefronttime;
extern ConVar mp_ik;
CPlayerAnimState::CPlayerAnimState( CBaseTFPlayer *outer )
: m_pOuter( outer )
{
m_flGaitYaw = 0.0f;
m_flGoalFeetYaw = 0.0f;
m_flCurrentFeetYaw = 0.0f;
m_flCurrentTorsoYaw = 0.0f;
m_flLastYaw = 0.0f;
m_flLastTurnTime = 0.0f;
};
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CPlayerAnimState::Update()
{
m_angRender = GetOuter()->GetLocalAngles();
ComputePoseParam_BodyYaw();
ComputePoseParam_BodyPitch( GetOuter()->GetModelPtr() );
ComputePoseParam_BodyLookYaw();
ComputePlaybackRate();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CPlayerAnimState::ComputePlaybackRate()
{
// Determine ideal playback rate
Vector vel;
GetOuterAbsVelocity( vel );
float speed = vel.Length2D();
bool isMoving = ( speed > 0.5f ) ? true : false;
Activity currentActivity = GetOuter()->GetSequenceActivity( GetOuter()->GetSequence() );
switch ( currentActivity )
{
case ACT_WALK:
case ACT_RUN:
case ACT_IDLE:
{
float maxspeed = GetOuter()->MaxSpeed();
if ( isMoving && ( maxspeed > 0.0f ) )
{
float flFactor = 1.0f;
// HACK HACK:: Defender backward animation is animated at 0.6 times speed, so scale up animation for this class
// if he's running backward.
// Not sure if we're really going to do all classes this way.
if ( GetOuter()->IsClass( TFCLASS_DEFENDER ) ||
GetOuter()->IsClass( TFCLASS_MEDIC ) )
{
Vector facing;
Vector moving;
moving = vel;
AngleVectors( GetOuter()->GetLocalAngles(), &facing );
VectorNormalize( moving );
float dot = moving.Dot( facing );
if ( dot < 0.0f )
{
float backspeed = sv_backspeed.GetFloat();
flFactor = 1.0f - fabs( dot ) * (1.0f - backspeed);
if ( flFactor > 0.0f )
{
flFactor = 1.0f / flFactor;
}
}
}
// Note this gets set back to 1.0 if sequence changes due to ResetSequenceInfo below
GetOuter()->SetPlaybackRate( ( speed * flFactor ) / maxspeed );
// BUG BUG:
// This stuff really should be m_flPlaybackRate = speed / m_flGroundSpeed
}
else
{
GetOuter()->SetPlaybackRate( 1.0f );
}
}
break;
default:
{
GetOuter()->SetPlaybackRate( 1.0f );
}
break;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : CBasePlayer
//-----------------------------------------------------------------------------
CBaseTFPlayer *CPlayerAnimState::GetOuter()
{
return m_pOuter;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : dt -
//-----------------------------------------------------------------------------
void CPlayerAnimState::EstimateYaw( void )
{
float dt = gpGlobals->frametime;
if ( !dt )
{
return;
}
Vector est_velocity;
QAngle angles;
GetOuterAbsVelocity( est_velocity );
angles = GetOuter()->GetLocalAngles();
if ( est_velocity[1] == 0 && est_velocity[0] == 0 )
{
float flYawDiff = angles[YAW] - m_flGaitYaw;
flYawDiff = flYawDiff - (int)(flYawDiff / 360) * 360;
if (flYawDiff > 180)
flYawDiff -= 360;
if (flYawDiff < -180)
flYawDiff += 360;
if (dt < 0.25)
flYawDiff *= dt * 4;
else
flYawDiff *= dt;
m_flGaitYaw += flYawDiff;
m_flGaitYaw = m_flGaitYaw - (int)(m_flGaitYaw / 360) * 360;
}
else
{
m_flGaitYaw = (atan2(est_velocity[1], est_velocity[0]) * 180 / M_PI);
if (m_flGaitYaw > 180)
m_flGaitYaw = 180;
else if (m_flGaitYaw < -180)
m_flGaitYaw = -180;
}
}
//-----------------------------------------------------------------------------
// Purpose: Override for backpeddling
// Input : dt -
//-----------------------------------------------------------------------------
void CPlayerAnimState::ComputePoseParam_BodyYaw( void )
{
int iYaw = GetOuter()->LookupPoseParameter( "move_yaw" );
if ( iYaw < 0 )
return;
// view direction relative to movement
float flYaw;
EstimateYaw();
QAngle angles = GetOuter()->GetLocalAngles();
float ang = angles[ YAW ];
if ( ang > 180.0f )
{
ang -= 360.0f;
}
else if ( ang < -180.0f )
{
ang += 360.0f;
}
// calc side to side turning
flYaw = ang - m_flGaitYaw;
// Invert for mapping into 8way blend
flYaw = -flYaw;
flYaw = flYaw - (int)(flYaw / 360) * 360;
if (flYaw < -180)
{
flYaw = flYaw + 360;
}
else if (flYaw > 180)
{
flYaw = flYaw - 360;
}
GetOuter()->SetPoseParameter( iYaw, flYaw );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CPlayerAnimState::ComputePoseParam_BodyPitch( CStudioHdr *pStudioHdr )
{
// Get pitch from v_angle
float flPitch = GetOuter()->GetLocalAngles()[ PITCH ];
if ( flPitch > 180.0f )
{
flPitch -= 360.0f;
}
flPitch = clamp( flPitch, -90, 90 );
QAngle absangles = GetOuter()->GetAbsAngles();
absangles.x = 0.0f;
m_angRender = absangles;
// See if we have a blender for pitch
int pitch = GetOuter()->LookupPoseParameter( pStudioHdr, "body_pitch" );
if ( pitch < 0 )
return;
GetOuter()->SetPoseParameter( pStudioHdr, pitch, flPitch );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : goal -
// maxrate -
// dt -
// current -
// Output : int
//-----------------------------------------------------------------------------
int CPlayerAnimState::ConvergeAngles( float goal,float maxrate, float dt, float& current )
{
int direction = TURN_NONE;
float anglediff = goal - current;
float anglediffabs = fabs( anglediff );
anglediff = AngleNormalize( anglediff );
float scale = 1.0f;
if ( anglediffabs <= FADE_TURN_DEGREES )
{
scale = anglediffabs / FADE_TURN_DEGREES;
// Always do at least a bit of the turn ( 1% )
scale = clamp( scale, 0.01f, 1.0f );
}
float maxmove = maxrate * dt * scale;
if ( fabs( anglediff ) < maxmove )
{
current = goal;
}
else
{
if ( anglediff > 0 )
{
current += maxmove;
direction = TURN_LEFT;
}
else
{
current -= maxmove;
direction = TURN_RIGHT;
}
}
current = AngleNormalize( current );
return direction;
}
void CPlayerAnimState::ComputePoseParam_BodyLookYaw( void )
{
QAngle absangles = GetOuter()->GetAbsAngles();
absangles.y = AngleNormalize( absangles.y );
m_angRender = absangles;
// See if we even have a blender for pitch
int upper_body_yaw = GetOuter()->LookupPoseParameter( "body_yaw" );
if ( upper_body_yaw < 0 )
{
return;
}
// Assume upper and lower bodies are aligned and that we're not turning
float flGoalTorsoYaw = 0.0f;
int turning = TURN_NONE;
float turnrate = mp_feetyawrate.GetFloat();
Vector vel;
GetOuterAbsVelocity( vel );
bool isMoving = ( vel.Length() > 0.0f ) ? true : false;
if ( !isMoving )
{
// Just stopped moving, try and clamp feet
if ( m_flLastTurnTime <= 0.0f )
{
m_flLastTurnTime = gpGlobals->curtime;
m_flLastYaw = GetOuter()->GetAbsAngles().y;
// Snap feet to be perfectly aligned with torso/eyes
m_flGoalFeetYaw = GetOuter()->GetAbsAngles().y;
m_flCurrentFeetYaw = m_flGoalFeetYaw;
m_nTurningInPlace = TURN_NONE;
}
// If rotating in place, update stasis timer
if ( m_flLastYaw != GetOuter()->GetAbsAngles().y )
{
m_flLastTurnTime = gpGlobals->curtime;
m_flLastYaw = GetOuter()->GetAbsAngles().y;
}
if ( m_flGoalFeetYaw != m_flCurrentFeetYaw )
{
m_flLastTurnTime = gpGlobals->curtime;
}
turning = ConvergeAngles( m_flGoalFeetYaw, turnrate, gpGlobals->frametime, m_flCurrentFeetYaw );
// See how far off current feetyaw is from true yaw
float yawdelta = GetOuter()->GetAbsAngles().y - m_flCurrentFeetYaw;
yawdelta = AngleNormalize( yawdelta );
bool rotated_too_far = false;
float yawmagnitude = fabs( yawdelta );
// If too far, then need to turn in place
if ( yawmagnitude > MAX_TORSO_ANGLE )
{
rotated_too_far = true;
}
// Standing still for a while, rotate feet around to face forward
// Or rotated too far
// FIXME: Play an in place turning animation
if ( rotated_too_far ||
( gpGlobals->curtime > m_flLastTurnTime + mp_facefronttime.GetFloat() ) )
{
m_flGoalFeetYaw = GetOuter()->GetAbsAngles().y;
m_flLastTurnTime = gpGlobals->curtime;
float yd = m_flCurrentFeetYaw - m_flGoalFeetYaw;
if ( yd > 0 )
{
m_nTurningInPlace = TURN_RIGHT;
}
else if ( yd < 0 )
{
m_nTurningInPlace = TURN_LEFT;
}
else
{
m_nTurningInPlace = TURN_NONE;
}
turning = ConvergeAngles( m_flGoalFeetYaw, turnrate, gpGlobals->frametime, m_flCurrentFeetYaw );
yawdelta = GetOuter()->GetAbsAngles().y - m_flCurrentFeetYaw;
}
// Snap upper body into position since the delta is already smoothed for the feet
flGoalTorsoYaw = yawdelta;
m_flCurrentTorsoYaw = flGoalTorsoYaw;
}
else
{
m_flLastTurnTime = 0.0f;
m_nTurningInPlace = TURN_NONE;
m_flGoalFeetYaw = GetOuter()->GetAbsAngles().y;
flGoalTorsoYaw = 0.0f;
turning = ConvergeAngles( m_flGoalFeetYaw, turnrate, gpGlobals->frametime, m_flCurrentFeetYaw );
m_flCurrentTorsoYaw = GetOuter()->GetAbsAngles().y - m_flCurrentFeetYaw;
}
if ( turning == TURN_NONE )
{
m_nTurningInPlace = turning;
}
if ( m_nTurningInPlace != TURN_NONE )
{
// If we're close to finishing the turn, then turn off the turning animation
if ( fabs( m_flCurrentFeetYaw - m_flGoalFeetYaw ) < MIN_TURN_ANGLE_REQUIRING_TURN_ANIMATION )
{
m_nTurningInPlace = TURN_NONE;
}
}
// Counter rotate upper body as needed
ConvergeAngles( flGoalTorsoYaw, turnrate, gpGlobals->frametime, m_flCurrentTorsoYaw );
// Rotate entire body into position
absangles = GetOuter()->GetAbsAngles();
absangles.y = m_flCurrentFeetYaw;
m_angRender = absangles;
GetOuter()->SetPoseParameter( upper_body_yaw, clamp( m_flCurrentTorsoYaw, -90.0f, 90.0f ) );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : activity -
// Output : Activity
//-----------------------------------------------------------------------------
Activity CPlayerAnimState::BodyYawTranslateActivity( Activity activity )
{
// Not even standing still, sigh
if ( activity != ACT_IDLE )
return activity;
// Not turning
switch ( m_nTurningInPlace )
{
default:
case TURN_NONE:
return activity;
/*
case TURN_RIGHT:
return ACT_TURNRIGHT45;
case TURN_LEFT:
return ACT_TURNLEFT45;
*/
case TURN_RIGHT:
case TURN_LEFT:
return mp_ik.GetBool() ? ACT_TURN : activity;
}
Assert( 0 );
return activity;
}
const QAngle& CPlayerAnimState::GetRenderAngles()
{
return m_angRender;
}
void CPlayerAnimState::GetOuterAbsVelocity( Vector& vel )
{
#if defined( CLIENT_DLL )
GetOuter()->EstimateAbsVelocity( vel );
#else
vel = GetOuter()->GetAbsVelocity();
#endif
}
+22
View File
@@ -0,0 +1,22 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef BASETFPLAYER_SHARED_H
#define BASETFPLAYER_SHARED_H
#ifdef _WIN32
#pragma once
#endif
// Shared header file for players
#if defined( CLIENT_DLL )
#define CBaseTFPlayer C_BaseTFPlayer
#include "c_basetfplayer.h"
#else
#include "tf_player.h"
#endif
#endif // BASETFPLAYER_SHARED_H
File diff suppressed because it is too large Load Diff
+272
View File
@@ -0,0 +1,272 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: A base vehicle class
//
//=============================================================================//
#ifndef BASETFVEHICLE_H
#define BASETFVEHICLE_H
#ifdef _WIN32
#pragma once
#endif
#include "basetfplayer_shared.h"
#include "baseobject_shared.h"
#include "tf_obj_basedrivergun_shared.h"
#if defined( CLIENT_DLL )
#include "iclientvehicle.h"
#else
#include "IServerVehicle.h"
#endif
class CMoveData;
class CUserCmd;
class CBasePlayer;
#if defined( CLIENT_DLL )
#define CBaseTFVehicle C_BaseTFVehicle
#endif
class CBaseTFVehicle;
class CBaseObjectDriverGun;
struct VehicleBaseMoveData_t
{
CBaseTFVehicle *m_pVehicle;
};
// ------------------------------------------------------------------------ //
// The base class that all vehicles in tf2 will derive from
// ------------------------------------------------------------------------ //
#if defined( CLIENT_DLL )
class CBaseTFVehicle : public CBaseObject, public IClientVehicle
#else
class CBaseTFVehicle : public CBaseObject, public IServerVehicle
#endif
{
DECLARE_CLASS( CBaseTFVehicle, CBaseObject );
public:
DECLARE_NETWORKCLASS();
DECLARE_PREDICTABLE();
CBaseTFVehicle();
#if !defined (CLIENT_DLL)
// CBaseEntity overrides
virtual void FinishedBuilding( void );
virtual void DestroyObject( );
virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
virtual bool UseAttachedItem( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
virtual void GetVectors(Vector* pForward, Vector* pRight, Vector* pUp) const;
virtual bool ClientCommand( CBaseTFPlayer *pPlayer, const CCommand &args );
// IVehicle overrides
virtual IServerVehicle* GetServerVehicle() { return this; }
virtual CBaseEntity* GetVehicleEnt();
// Get and set the current driver.
virtual void SetPassenger( int nRole, CBasePlayer *pEnt );
// Where do we get out of the vehicle?
virtual bool GetPassengerExitPoint( int nRole, Vector *pExitPoint, QAngle *pAngles );
virtual Class_T ClassifyPassenger( CBasePlayer *pPassenger, Class_T defaultClassification ) { return defaultClassification; }
virtual float DamageModifier ( CTakeDamageInfo &info ) { return 1.0; }
virtual const vehicleparams_t *GetVehicleParams( void ) { return NULL; }
virtual bool IsVehicleUpright( void ) { return true; }
virtual bool IsPassengerEntering( void ) { Assert( 0 ); return true; }
virtual bool IsPassengerExiting( void ) { Assert( 0 ); return true; }
// NPC Driving
virtual bool NPC_CanDrive( void ) { return true; }
virtual void NPC_SetDriver( CNPC_VehicleDriver *pDriver ) { return; }
virtual void NPC_DriveVehicle( void ) { return; }
virtual void NPC_ThrottleCenter( void ) { return; }
virtual void NPC_ThrottleReverse( void ) { return; }
virtual void NPC_ThrottleForward( void ) { return; }
virtual void NPC_Brake( void ) { return; }
virtual void NPC_TurnLeft( float flDegrees ) { return; }
virtual void NPC_TurnRight( float flDegrees ) { return; }
virtual void NPC_TurnCenter( void ) { return; }
virtual void NPC_PrimaryFire( void ) { return; }
virtual void NPC_SecondaryFire( void ) { return; }
virtual bool NPC_HasPrimaryWeapon( void ) { return false; }
virtual bool NPC_HasSecondaryWeapon( void ) { return false; }
virtual void NPC_AimPrimaryWeapon( Vector vecTarget ) { return; }
virtual void NPC_AimSecondaryWeapon( Vector vecTarget ) { return; }
// Weapon handling
virtual void Weapon_PrimaryRanges( float *flMinRange, float *flMaxRange ) { *flMinRange = 0; *flMaxRange = 0; }
virtual void Weapon_SecondaryRanges( float *flMinRange, float *flMaxRange ) { *flMinRange = 0; *flMaxRange = 0; }
virtual float Weapon_PrimaryCanFireAt( void ) { return gpGlobals->curtime; } // Return the time at which this vehicle's primary weapon can fire again
virtual float Weapon_SecondaryCanFireAt( void ) { return gpGlobals->curtime; } // Return the time at which this vehicle's secondary weapon can fire again
// Vehicles dont want to attach to anything they're built upon
virtual bool ShouldAttachToParent( void ) { return false; }
virtual bool MustNotBeBuiltInConstructionYard( void ) const { return false; }
// Purpose: Try to board the vehicle
void AttemptToBoardVehicle( CBaseTFPlayer *pPlayer );
// Figure out which role of a parent vehicle this vehicle is sitting in..
int GetParentVehicleRole();
// Purpose:
void GetPassengerExitPoint( CBasePlayer *pPlayer, int nRole, Vector *pAbsPosition, QAngle *pAbsAngles );
int GetEntryAnimForPoint( const Vector &vecPoint );
int GetExitAnimToUse( Vector &vecEyeExitEndpoint, bool &bAllPointsBlocked );
void HandleEntryExitFinish( bool bExitAnimOn, bool bResetAnim );
void HandlePassengerEntry( CBasePlayer *pPlayer, bool bAllowEntryOutsideZone = false );
bool HandlePassengerExit( CBasePlayer *pPlayer );
// Deterioration
void VehicleDeteriorationThink( void );
void VehiclePassengerThink( void );
#endif
bool IsReadyToDrive( void );
virtual bool IsAVehicle( void ) { return true; }
// Get a position in *local space* inside the vehicle for the player to start at
virtual void GetPassengerStartPoint( int nRole, Vector *pPoint, QAngle *pAngles );
#if defined( CLIENT_DLL )
// C_BaseEntity overrides
virtual IClientVehicle* GetClientVehicle() { return this; }
virtual C_BaseEntity *GetVehicleEnt();
virtual void ClientThink();
// Fills in the unperterbed view position for a particular role.
// Prediction
virtual bool ShouldPredict( void );
virtual bool IsPredicted( void ) const { return true; }
// IClientVehicle
// Called at time player enters vehicle
virtual void GetVehicleFOV( float &flFOV ) { return; }
virtual void DrawHudElements( void );
// Get the angles that a player in the specified role should be using for visuals
virtual QAngle GetPassengerAngles( QAngle angCurrent, int nRole );
// Allows the vehicle to restrict view angles
virtual void UpdateViewAngles( C_BasePlayer *pLocalPlayer, CUserCmd *pCmd ) {}
virtual void GetVehicleClipPlanes( float &flZNear, float &flZFar ) const {}
bool IsBoostable( void ) { return m_bBoostUpgrade; }
// Hud
virtual void DrawHudBoostData( void );
virtual void SetupCrosshair( void );
#endif
int LocateEntryPoint( CBaseTFPlayer *pPlayer, float* fBest2dDistanceSqr= NULL );
// This lets the object decide whether or not it wants to use the ThirdPersonCameraOrigin attachment for its view.
// The manned guns use first-person when they're on the ground and third-person when they're in a vehicle.
virtual bool ShouldUseThirdPersonVehicleView();
virtual void GetVehicleViewPosition( int nRole, Vector *pOrigin, QAngle *pAngles, float *pFOV = NULL );
virtual bool GetRoleViewPosition( int nRole, Vector *pVehicleEyeOrigin, QAngle *pVehicleEyeAngles );
virtual bool GetRoleAbsViewPosition( int nRole, Vector *pAbsVehicleEyeOrigin, QAngle *pAbsVehicleEyeAngles );
// Can a given passenger take damage?
virtual bool IsPassengerDamagable( int nRole ) { return (nRole != VEHICLE_DRIVER); }
virtual void Spawn();
virtual void SetupMove( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move );
virtual void ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMove ) {}
virtual void FinishMove( CBasePlayer *player, CUserCmd *ucmd, CMoveData *move );
virtual void ItemPostFrame( CBasePlayer *pPassenger );
virtual CBasePlayer* GetPassenger( int nRole = VEHICLE_DRIVER );
virtual int GetPassengerRole( CBasePlayer *pEnt );
// Does the player use his normal weapons while in this mode?
virtual bool IsPassengerUsingStandardWeapons( int nRole = VEHICLE_DRIVER ) { return false; }
virtual Vector GetSoundEmissionOrigin() const;
// Returns the driver as a tfplayer pointer
CBaseTFPlayer *GetDriverPlayer();
int GetMaxPassengerCount() const;
int GetPassengerCount() const;
// Is a particular player in the vehicle?
bool IsPlayerInVehicle( CBaseTFPlayer *pPlayer );
void ResetDeteriorationTime( void );
// Driver controlled guns
void SetDriverGun( CBaseObjectDriverGun *pGun );
void VehicleDriverGunThink( void );
protected:
enum
{
MAX_PASSENGERS = 4,
MAX_PASSENGER_BITS = 3
};
// Can we get into the vehicle?
virtual bool CanGetInVehicle( CBaseTFPlayer *pPlayer );
// Here's where we deal with weapons
virtual void OnItemPostFrame( CBaseTFPlayer *pDriver );
// Specify the number of roles we can have
void SetMaxPassengerCount( int nMaxPassengers );
bool IsValidExitPoint( int nRole, Vector *pExitPoint, QAngle *pAngles );
int GetEmptyRole( void );
private:
#if !defined (CLIENT_DLL)
// Get the parent vehicle of this vehicle..
CBaseTFVehicle *GetParentVehicle();
// Get a position in *world space* inside the vehicle for the player to exit at
void GetInitialPassengerExitPoint( int nRole, Vector *pAbsPoint, QAngle *pAbsAngles );
// Figure out which role of a vehicle a child vehicle is sitting in..
int GetChildVehicleRole( CBaseTFVehicle *pChild );
#endif
private:
typedef CHandle<CBaseTFPlayer> CPlayerHandle;
CNetworkArray( CPlayerHandle, m_hPassengers, MAX_PASSENGERS );
CNetworkVar( int, m_nMaxPassengers );
// Driver controlled gun
CNetworkHandle( CBaseObjectDriverGun, m_hDriverGun );
#if defined( CLIENT_DLL )
CHudTexture *m_pIconDefaultCrosshair;
bool m_bBoostUpgrade;
int m_nBoostTimeLeft;
private:
CBaseTFVehicle( const CBaseTFVehicle & ); // not defined, not accessible
#endif
};
#endif // BASETFVEHICLE_H
+328
View File
@@ -0,0 +1,328 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Entity used to highlight laser designation points to clients
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "basetfplayer_shared.h"
#include "tf_obj_manned_plasmagun.h"
#include "env_laserdesignation.h"
#if !defined( CLIENT_DLL )
#include "tf_vehicle_tank.h"
#include "tf_obj_manned_missilelauncher.h"
#endif
extern ConVar weapon_grenade_rocket_track_range_mod;
extern ConVar vehicle_tank_range;
extern ConVar weapon_rocket_launcher_range;
extern ConVar obj_manned_missilelauncher_range_off;
//-----------------------------------------------------------------------------
// Stores a list of all laser designations
//-----------------------------------------------------------------------------
CUtlVector< EHANDLE > CEnvLaserDesignation::m_LaserDesignatorsTeam1;
CUtlVector< EHANDLE > CEnvLaserDesignation::m_LaserDesignatorsTeam2;
IMPLEMENT_NETWORKCLASS_ALIASED( EnvLaserDesignation, DT_EnvLaserDesignation )
BEGIN_NETWORK_TABLE( CEnvLaserDesignation, DT_EnvLaserDesignation )
#if !defined( CLIENT_DLL )
SendPropInt( SENDINFO( m_bActive ), 1, SPROP_UNSIGNED ),
#else
RecvPropInt( RECVINFO( m_bActive ) ),
#endif
END_NETWORK_TABLE()
BEGIN_PREDICTION_DATA( CEnvLaserDesignation )
DEFINE_PRED_FIELD( m_bActive, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
END_PREDICTION_DATA()
LINK_ENTITY_TO_CLASS( env_laserdesignation, CEnvLaserDesignation );
PRECACHE_REGISTER( env_laserdesignation );
//-----------------------------------------------------------------------------
// Purpose: Create a laser designation
//-----------------------------------------------------------------------------
CEnvLaserDesignation *CEnvLaserDesignation::Create( CBasePlayer *pOwner )
{
CEnvLaserDesignation *pDesignation = (CEnvLaserDesignation*)CreateEntityByName("env_laserdesignation");
pDesignation->Spawn();
pDesignation->SetOwnerEntity( pOwner );
pDesignation->ChangeTeam( pOwner->GetTeamNumber() );
pDesignation->SetActive( false );
return pDesignation;
}
//-----------------------------------------------------------------------------
// Purpose: Create a laser designation
//-----------------------------------------------------------------------------
CEnvLaserDesignation *CEnvLaserDesignation::CreatePredicted( CBasePlayer *pOwner )
{
#if !defined( NO_ENTITY_PREDICTION )
CEnvLaserDesignation *pDesignation = (CEnvLaserDesignation*)CREATE_PREDICTED_ENTITY("env_laserdesignation");
if ( pDesignation )
{
pDesignation->Spawn();
pDesignation->SetOwnerEntity( pOwner );
pDesignation->SetPlayerSimulated( pOwner );
pDesignation->ChangeTeam( pOwner->GetTeamNumber() );
pDesignation->SetActive( false );
}
return pDesignation;
#else
return NULL;
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CEnvLaserDesignation::CEnvLaserDesignation( void )
{
m_bActive = -1; // So the first setactive will take effect
m_bPrevActive = false;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CEnvLaserDesignation::~CEnvLaserDesignation( void )
{
EHANDLE hLaser;
hLaser = this;
if ( GetTeamNumber() == 1 )
{
m_LaserDesignatorsTeam1.FindAndRemove( hLaser );
}
else if ( GetTeamNumber() == 2 )
{
m_LaserDesignatorsTeam2.FindAndRemove( hLaser );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvLaserDesignation::Spawn( void )
{
SetModel( "models/projectiles/grenade_limpet.mdl" );
SetMoveType( MOVETYPE_NONE );
SetSolid( SOLID_NONE );
SetSize( vec3_origin, vec3_origin );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvLaserDesignation::ChangeTeam( int iTeamNum )
{
Assert( iTeamNum > 0 && iTeamNum < MAX_TF_TEAMS );
EHANDLE hLaser;
hLaser = this;
if ( iTeamNum == 1 )
{
m_LaserDesignatorsTeam1.AddToTail( hLaser );
}
else if ( iTeamNum == 2 )
{
m_LaserDesignatorsTeam2.AddToTail( hLaser );
}
BaseClass::ChangeTeam( iTeamNum );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvLaserDesignation::SetActive( bool bActive )
{
if ( bActive == m_bActive )
return;
if ( !bActive )
{
AddEffects( EF_NODRAW );
}
else
{
IncrementInterpolationFrame();
RemoveEffects( EF_NODRAW );
}
#if defined( CLIENT_DLL )
ENTITY_PANEL_ACTIVATE( "laserdesignation", bActive );
#endif
m_bActive = bActive;
}
#if !defined( CLIENT_DLL )
int CEnvLaserDesignation::UpdateTransmitState()
{
return SetTransmitState( FL_EDICT_FULLCHECK );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CEnvLaserDesignation::ShouldTransmit( const CCheckTransmitInfo *pInfo )
{
// Only transmit to players who care about laser designation:
// - Player designating
// - Players in tanks
// - Commandos
CBaseEntity* pRecipientEntity = CBaseEntity::Instance( pInfo->m_pClientEnt );
if ( pRecipientEntity->IsPlayer() )
{
CBaseTFPlayer *pPlayer = (CBaseTFPlayer*)pRecipientEntity;
// Designating player?
if ( pPlayer == GetOwnerEntity() )
return SetTransmitState( FL_EDICT_ALWAYS );
if ( !InSameTeam( pPlayer ) )
return FL_EDICT_DONTSEND;
// In a tank?
if ( pPlayer->IsInAVehicle() )
{
CBaseEntity *pVehicle = pPlayer->GetVehicle()->GetVehicleEnt();
if ( dynamic_cast<CVehicleTank*>(pVehicle) )
{
// Make sure it's within range of the tank's fire
static float flTankRange = 0;
if ( !flTankRange )
{
flTankRange = vehicle_tank_range.GetFloat() * weapon_grenade_rocket_track_range_mod.GetFloat();
flTankRange *= flTankRange;
}
float flDistanceSqr = ( GetAbsOrigin() - pPlayer->GetAbsOrigin() ).LengthSqr();
if ( flDistanceSqr < flTankRange )
return FL_EDICT_ALWAYS;
}
else if ( dynamic_cast<CObjectMannedMissileLauncher*>(pVehicle) )
{
// Make sure it's within range of the manned missile launcher's fire
static float flGunRange = 0;
if ( !flGunRange )
{
flGunRange = obj_manned_missilelauncher_range_off.GetFloat() * weapon_grenade_rocket_track_range_mod.GetFloat();
flGunRange *= flGunRange;
}
float flDistanceSqr = ( GetAbsOrigin() - pPlayer->GetAbsOrigin() ).LengthSqr();
if ( flDistanceSqr < flGunRange )
return FL_EDICT_ALWAYS;
}
}
// Is the player a commando?
if ( pPlayer->PlayerClass() == TFCLASS_COMMANDO )
{
// Make sure it's within range of the commando's rockets
static float flCommandoRange = 0;
if ( !flCommandoRange )
{
flCommandoRange = weapon_rocket_launcher_range.GetFloat() * weapon_grenade_rocket_track_range_mod.GetFloat();
flCommandoRange *= flCommandoRange;
}
float flDistanceSqr = ( GetAbsOrigin() - pPlayer->GetAbsOrigin() ).LengthSqr();
if ( flDistanceSqr < flCommandoRange )
return FL_EDICT_ALWAYS;
}
}
return FL_EDICT_DONTSEND;
}
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CEnvLaserDesignation::GetNumLaserDesignators( int iTeamNumber )
{
Assert( iTeamNumber > 0 && iTeamNumber < MAX_TF_TEAMS );
if ( iTeamNumber == 1 )
return m_LaserDesignatorsTeam1.Count();
return m_LaserDesignatorsTeam2.Count();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CEnvLaserDesignation::GetLaserDesignation( int iTeamNumber, int iDesignator, Vector *vecOrigin )
{
Assert( iTeamNumber > 0 && iTeamNumber < MAX_TF_TEAMS );
CHandle<CEnvLaserDesignation> hLaser;
if ( iTeamNumber == 1 )
{
Assert( iDesignator < m_LaserDesignatorsTeam1.Count() );
hLaser = m_LaserDesignatorsTeam1[iDesignator];
}
else
{
Assert( iDesignator < m_LaserDesignatorsTeam2.Count() );
hLaser = m_LaserDesignatorsTeam2[iDesignator];
}
// Active?
if ( !hLaser.Get() || !hLaser->IsActive() )
return false;
*vecOrigin = hLaser->GetAbsOrigin();
return true;
}
#if defined( CLIENT_DLL )
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CEnvLaserDesignation::DrawModel( int flags )
{
return false;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : updateType -
//-----------------------------------------------------------------------------
void CEnvLaserDesignation::OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
if ( m_bActive != m_bPrevActive )
{
ENTITY_PANEL_ACTIVATE( "laserdesignation", m_bActive );
}
m_bPrevActive = m_bActive.Get();
}
//-----------------------------------------------------------------------------
// Add, remove object from the panel
//-----------------------------------------------------------------------------
void CEnvLaserDesignation::SetDormant( bool bDormant )
{
BaseClass::SetDormant( bDormant );
ENTITY_PANEL_ACTIVATE( "laserdesignation", (!bDormant && m_bActive) );
}
#endif
+80
View File
@@ -0,0 +1,80 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef ENV_LASERDESIGNATION_H
#define ENV_LASERDESIGNATION_H
#pragma once
#if defined( CLIENT_DLL )
#define CEnvLaserDesignation C_EnvLaserDesignation
#endif
//-----------------------------------------------------------------------------
// Purpose: A laser designation point
//-----------------------------------------------------------------------------
class CEnvLaserDesignation : public CBaseAnimating
{
public:
DECLARE_NETWORKCLASS();
DECLARE_PREDICTABLE();
DECLARE_CLASS( CEnvLaserDesignation, CBaseAnimating );
CEnvLaserDesignation( void );
~CEnvLaserDesignation( void );
virtual void Spawn( void );
virtual void ChangeTeam( int iTeamNum );
// Designation
void SetActive( bool bActive );
bool IsActive( void ) { return m_bActive; }
// All predicted weapons need to implement and return true
virtual bool IsPredicted( void ) const
{
return true;
}
#if defined( CLIENT_DLL )
virtual bool ShouldPredict( void )
{
if ( GetOwnerEntity() == C_BasePlayer::GetLocalPlayer() )
return true;
return BaseClass::ShouldPredict();
}
DECLARE_ENTITY_PANEL();
virtual void OnDataChanged( DataUpdateType_t updateType );
virtual void SetDormant( bool bDormant );
virtual int DrawModel( int flags );
#else
virtual int UpdateTransmitState();
virtual int ShouldTransmit( const CCheckTransmitInfo *pInfo );
#endif
// Global Designator access
static CEnvLaserDesignation *Create( CBasePlayer *pOwner );
static CEnvLaserDesignation *CreatePredicted( CBasePlayer *pOwner );
static int GetNumLaserDesignators( int iTeamNumber );
static bool GetLaserDesignation( int iTeamNumber, int iDesignator, Vector *vecOrigin );
protected:
static CUtlVector< EHANDLE > m_LaserDesignatorsTeam1;
static CUtlVector< EHANDLE > m_LaserDesignatorsTeam2;
CNetworkVar( bool, m_bActive );
bool m_bPrevActive;
private:
CEnvLaserDesignation( const CEnvLaserDesignation& src );
};
#endif // ENV_LASERDESIGNATION_H
+40
View File
@@ -0,0 +1,40 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef GASOLINE_SHARED_H
#define GASOLINE_SHARED_H
#ifdef _WIN32
#pragma once
#endif
#define PYRO_AMMO_TYPE "Gasoline"
// Radius in inches of each gasoline blob. They should render to about this size.
#define GASOLINE_BLOB_RADIUS 30
// Blobs start to attract each other when their centerpoints get this close.
#define GASOLINE_ATTRACT_START_DISTANCE (GASOLINE_BLOB_RADIUS + 20)
// Blobs expire after this long whether they are lit or not.
#define MAX_LIT_GASOLINE_BLOB_LIFETIME 5.0
#define MAX_UNLIT_GASOLINE_BLOB_LIFETIME 20.0
// Heat per second given off by fire.
#define FIRE_DAMAGE_PER_SEC 85
#define BLOBFLAG_LIT 0x01 // This blob is on fire.
#define BLOBFLAG_STOPPED 0x02 // This means it has hit a surface and stopped moving.
#define BLOBFLAG_USE_GRAVITY 0x04
#define NUM_BLOB_FLAGS 3
#endif // GASOLINE_SHARED_H
+211
View File
@@ -0,0 +1,211 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "tf_player.h"
#include "tf_basecombatweapon.h"
#include "basegrenade_shared.h"
#include "engine/IEngineSound.h"
#include "tf_shareddefs.h"
#include "IEffects.h"
#include "Sprite.h"
#include "grenade_antipersonnel.h"
// Damage CVars
ConVar weapon_antipersonnel_grenade_damage( "weapon_antipersonnel_grenade_damage","0", FCVAR_NONE, "Anti-personnel grenade maximum damage" );
ConVar weapon_antipersonnel_grenade_radius( "weapon_antipersonnel_grenade_radius","0", FCVAR_NONE, "Anti-personnel grenade splash radius" );
#if !defined( CLIENT_DLL )
// Server Only
ConVar weapon_antipersonnel_grenade_force( "weapon_antipersonnel_grenade_force","225.0", FCVAR_NONE, "Grenade explosive force modifier." );
#endif
IMPLEMENT_SERVERCLASS_ST(CGrenadeAntiPersonnel, DT_GrenadeAntiPersonnel)
END_SEND_TABLE()
LINK_ENTITY_TO_CLASS( grenade_antipersonnel, CGrenadeAntiPersonnel );
PRECACHE_WEAPON_REGISTER(grenade_antipersonnel);
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CGrenadeAntiPersonnel::CGrenadeAntiPersonnel()
{
UseClientSideAnimation();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGrenadeAntiPersonnel::Precache( void )
{
BaseClass::Precache( );
PrecacheModel( "models/weapons/w_grenade.mdl" );
PrecacheModel( "sprites/redglow1.vmt" );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGrenadeAntiPersonnel::Spawn( void )
{
Precache();
SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE );
SetSolid( SOLID_BBOX );
SetGravity( 1.0 );
SetFriction( 0.9 );
SetElasticity( 2.0f );
SetModel( "models/weapons/w_grenade.mdl" );
UTIL_SetSize(this, vec3_origin, vec3_origin);
SetTouch( BounceTouch );
SetCollisionGroup( TFCOLLISION_GROUP_GRENADE );
m_flDetonateTime = gpGlobals->curtime + 3.0;
SetThink( TumbleThink );
SetNextThink( gpGlobals->curtime + 0.1f );
// Set my damages to the cvar values
SetDamage( weapon_antipersonnel_grenade_damage.GetFloat() );
SetDamageRadius( weapon_antipersonnel_grenade_radius.GetFloat() );
// Create a green light
m_pLiveSprite = CSprite::SpriteCreate( "sprites/redglow1.vmt", GetLocalOrigin() + Vector(0,0,1), false );
m_pLiveSprite->SetTransparency( kRenderGlow, 0, 255, 0, 128, kRenderFxNoDissipation );
m_pLiveSprite->SetBrightness( 255 );
m_pLiveSprite->SetScale( 1 );
m_pLiveSprite->SetAttachment( this, 0 );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGrenadeAntiPersonnel::UpdateOnRemove( void )
{
// Remove our live sprite
if ( m_pLiveSprite )
{
UTIL_Remove( m_pLiveSprite );
m_pLiveSprite = NULL;
}
// Chain at end to mimic destructor unwind order
BaseClass::UpdateOnRemove();
}
//-----------------------------------------------------------------------------
// Purpose: Allow shield parry's
//-----------------------------------------------------------------------------
void CGrenadeAntiPersonnel::BounceTouch( CBaseEntity *pOther )
{
// Don't blow up on trigger brushes
Assert( pOther );
if ( !pOther->IsSolid() )
return;
if ( pOther->GetCollisionGroup() == TFCOLLISION_GROUP_SHIELD )
{
// Move away from the shield...
// Fling it out a little extra along the plane normal
Vector vecCenter;
AngleVectors( pOther->GetAbsAngles(), &vecCenter );
// Bounce off the ground if it's on the ground...
Vector vecNewVelocity = GetAbsVelocity();
VectorMultiply( vecCenter, 400.0f, vecNewVelocity );
if ((GetFlags() & FL_ONGROUND) && vecNewVelocity.z <= 100.0f)
{
vecNewVelocity.z = 100.0f;
}
SetAbsVelocity( vecNewVelocity );
}
// If we're set to explode on contact, and we just hit an enemy, go kaboom
if ( m_bExplodeOnContact && !InSameTeam(pOther) && pOther->m_takedamage != DAMAGE_NO )
{
Detonate();
return;
}
BaseClass::BounceTouch( pOther );
}
//-----------------------------------------------------------------------------
// Purpose: Return the radius for the screenshake
//-----------------------------------------------------------------------------
float CGrenadeAntiPersonnel::GetShakeRadius( void )
{
return (m_DmgRadius * 2);
}
//-----------------------------------------------------------------------------
// Purpose: Create a missile
//-----------------------------------------------------------------------------
void CGrenadeAntiPersonnel::Detonate( void )
{
BaseClass::Detonate();
// iterate on all entities in the vicinity and find vehicles
CBaseEntity *pEntity = NULL;
for ( CEntitySphereQuery sphere( GetAbsOrigin(), m_DmgRadius ); ( pEntity = sphere.GetCurrentEntity() ) != NULL; sphere.NextEntity() )
{
// Check team.
if ( pEntity->GetTeam() == GetTeam() )
continue;
if ( pEntity->GetServerVehicle() )
{
IPhysicsObject *pPhysObject = pEntity->VPhysicsGetObject();
if ( pPhysObject )
{
// Rocket the vehicle in the direction of the incoming rocket.
Vector vecForceDir = pEntity->GetAbsOrigin() - GetAbsOrigin();
float flDistance = VectorNormalize( vecForceDir );
if ( flDistance >= 0.0f && flDistance < m_DmgRadius )
{
vecForceDir.z = 1.0f;
VectorNormalize( vecForceDir );
float flForce = pPhysObject->GetMass();
flForce += ( 4 * 500.0f ); // Wheels
flForce *= weapon_antipersonnel_grenade_force.GetFloat();
flForce *= ( 1.0f - ( flDistance / m_DmgRadius ) );
vecForceDir *= flForce;
pPhysObject->ApplyForceOffset( vecForceDir, GetAbsOrigin() );
}
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Create a missile
//-----------------------------------------------------------------------------
CGrenadeAntiPersonnel *CGrenadeAntiPersonnel::Create( const Vector &vecOrigin, const Vector &vecForward, CBasePlayer *pOwner )
{
CGrenadeAntiPersonnel *pGrenade = (CGrenadeAntiPersonnel*)CreateEntityByName("grenade_antipersonnel");
UTIL_SetOrigin( pGrenade, vecOrigin );
pGrenade->Spawn();
pGrenade->ChangeTeam( pOwner->GetTeamNumber() );
pGrenade->SetOwnerEntity( pOwner );
pGrenade->SetThrower( pOwner );
pGrenade->SetAbsVelocity( vecForward );
QAngle angles;
VectorAngles( vecForward, angles );
pGrenade->SetLocalAngles( angles );
pGrenade->SetLocalAngularVelocity( RandomAngle(-500,500) );
return pGrenade;
}
+50
View File
@@ -0,0 +1,50 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef GRENADE_ANTIPERSONNEL_H
#define GRENADE_ANTIPERSONNEL_H
#ifdef _WIN32
#pragma once
#endif
class CSprite;
#include "grenade_base_empable.h"
//-----------------------------------------------------------------------------
// Purpose: Antipersonnel grenade
//-----------------------------------------------------------------------------
class CGrenadeAntiPersonnel : public CBaseEMPableGrenade
{
DECLARE_CLASS( CGrenadeAntiPersonnel, CBaseEMPableGrenade );
public:
CGrenadeAntiPersonnel();
DECLARE_SERVERCLASS();
virtual void Spawn( void );
virtual void Precache( void );
virtual void UpdateOnRemove( void );
virtual void BounceTouch( CBaseEntity *pOther );
// virtual void BounceSound( void );
virtual float GetShakeRadius( void );
virtual void Detonate( void );
// Damage type accessors
virtual int GetDamageType() const { return DMG_BLAST; }
static CGrenadeAntiPersonnel *CGrenadeAntiPersonnel::Create( const Vector &vecOrigin, const Vector &vecAngles, CBasePlayer *pOwner );
void SetExplodeOnContact( bool bExplode ) { m_bExplodeOnContact = bExplode; }
private:
CSprite *m_pLiveSprite;
bool m_bExplodeOnContact;
};
#endif // GRENADE_ANTIPERSONNEL_H
+89
View File
@@ -0,0 +1,89 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "basegrenade_shared.h"
#include "engine/IEngineSound.h"
#include "grenade_base_empable.h"
#include "IEffects.h"
#if !defined( CLIENT_DLL )
// Global Savedata
BEGIN_DATADESC( CBaseEMPableGrenade )
// Function Pointers
DEFINE_THINKFUNC( FizzleThink ),
END_DATADESC()
#endif
IMPLEMENT_NETWORKCLASS_ALIASED( BaseEMPableGrenade, DT_BaseEMPableGrenade )
BEGIN_NETWORK_TABLE( CBaseEMPableGrenade, DT_BaseEMPableGrenade )
#if !defined( CLIENT_DLL )
SendPropFloat( SENDINFO( m_flFizzleDuration ), 10, SPROP_ROUNDDOWN, 0.0, 256.0f ),
#else
RecvPropFloat( RECVINFO( m_flFizzleDuration ) ),
#endif
END_NETWORK_TABLE()
LINK_ENTITY_TO_CLASS( base_empable_grenade, CBaseEMPableGrenade );
BEGIN_PREDICTION_DATA( CBaseEMPableGrenade )
DEFINE_PRED_FIELD( m_flFizzleDuration, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
END_PREDICTION_DATA()
#define GRENADE_FIZZLE_DURATION 0.5
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CBaseEMPableGrenade::CBaseEMPableGrenade( void )
{
m_flFizzleDuration = 0;
}
//-----------------------------------------------------------------------------
// Purpose: Apply EMP damage to class
//-----------------------------------------------------------------------------
bool CBaseEMPableGrenade::TakeEMPDamage( float duration )
{
// If we're fizzling already, ignore extra EMP damage
if ( m_flFizzleDuration )
return true;
// Fizzle away in a couple of seconds
m_flFizzleDuration = gpGlobals->curtime + MIN( duration, GRENADE_FIZZLE_DURATION );
SetThink( FizzleThink );
SetNextThink( gpGlobals->curtime + 0.1f );
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Fizzle out and remove self from the world.
//-----------------------------------------------------------------------------
void CBaseEMPableGrenade::FizzleThink( void )
{
float flDeltaTime = m_flFizzleDuration - gpGlobals->curtime;
// Keep fizzling until it's time to go
if ( flDeltaTime > 0.0f )
{
// Emit a fizzle sound
EmitSound( "BaseEMPableGrenade.Fizzle" );
// Smoke & Spark
g_pEffects->Sparks( GetAbsOrigin() );
UTIL_Smoke( GetAbsOrigin(), random->RandomInt( 4, 7), 10 );
}
else
{
Remove( );
return;
}
SetNextThink( gpGlobals->curtime + 0.1f );
}
+50
View File
@@ -0,0 +1,50 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef GRENADE_BASE_EMPABLE_H
#define GRENADE_BASE_EMPABLE_H
#ifdef _WIN32
#pragma once
#endif
#include "basegrenade_shared.h"
#if defined( CLIENT_DLL )
#define CBaseEMPableGrenade C_BaseEMPableGrenade
#endif
//-----------------------------------------------------------------------------
// Purpose: EMP grenade
//-----------------------------------------------------------------------------
class CBaseEMPableGrenade : public CBaseGrenade
{
DECLARE_CLASS( CBaseEMPableGrenade, CBaseGrenade );
public:
DECLARE_PREDICTABLE();
DECLARE_NETWORKCLASS();
#if !defined( CLIENT_DLL )
DECLARE_DATADESC();
#endif
CBaseEMPableGrenade();
virtual bool CanTakeEMPDamage( void ) { return true; }
virtual bool TakeEMPDamage( float duration );
void FizzleThink( void );
private:
CNetworkVar( float, m_flFizzleDuration );
private:
CBaseEMPableGrenade( const CBaseEMPableGrenade & ); // not defined, not accessible
};
#endif // GRENADE_BASE_EMPABLE_H
+343
View File
@@ -0,0 +1,343 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "basetfplayer_shared.h"
#include "basegrenade_shared.h"
#include "engine/IEngineSound.h"
#include "tf_shareddefs.h"
#include "Sprite.h"
#include "grenade_emp.h"
#include "tf_gamerules.h"
#if defined( CLIENT_DLL )
#include "particles_simple.h"
#else
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
int g_iEMPPulseEffectIndex = 0;
// Damage CVars
ConVar weapon_emp_grenade_duration( "weapon_emp_grenade_duration","5", FCVAR_REPLICATED, "Duration of the EMP grenade's effect." );
ConVar weapon_emp_grenade_object_duration( "weapon_emp_grenade_object_duration","5", FCVAR_REPLICATED, "Duration of the EMP grenade's effect on objects." );
ConVar weapon_emp_grenade_radius( "weapon_emp_grenade_radius","256", FCVAR_REPLICATED, "EMP grenade splash radius" );
IMPLEMENT_NETWORKCLASS_ALIASED( GrenadeEMP, DT_GrenadeEMP );
BEGIN_NETWORK_TABLE( CGrenadeEMP, DT_GrenadeEMP )
#if !defined( CLIENT_DLL )
SendPropEHandle( SENDINFO( m_hLiveSprite ) ),
#else
RecvPropEHandle( RECVINFO( m_hLiveSprite ) ),
#endif
END_NETWORK_TABLE()
BEGIN_PREDICTION_DATA( CGrenadeEMP )
DEFINE_PRED_FIELD( m_hLiveSprite, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ),
END_PREDICTION_DATA()
LINK_ENTITY_TO_CLASS( grenade_emp, CGrenadeEMP );
PRECACHE_REGISTER(grenade_emp);
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CGrenadeEMP::CGrenadeEMP()
{
SetPredictionEligible( true );
#if defined( CLIENT_DLL )
m_ParticleEvent.Init( 100 );
#else
UseClientSideAnimation();
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGrenadeEMP::Precache( void )
{
BaseClass::Precache( );
PrecacheModel( "models/weapons/w_grenade.mdl" );
PrecacheModel( "sprites/redglow1.vmt" );
g_iEMPPulseEffectIndex = PrecacheModel( "sprites/lgtning.spr" );
PrecacheScriptSound( "GrenadeEMP.Bounce" );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGrenadeEMP::Spawn( void )
{
Precache();
SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE );
SetSolid( SOLID_BBOX );
//m_flGravity = 1.0;
SetFriction( 0.75 );
SetModel( "models/weapons/w_grenade.mdl" );
SetSize( Vector( -4, -4, -4), Vector(4, 4, 4) );
SetTouch( BounceTouch );
SetCollisionGroup( TFCOLLISION_GROUP_GRENADE );
m_flDetonateTime = gpGlobals->curtime + 4.0;
SetThink( TumbleThink );
SetNextThink( gpGlobals->curtime + 0.1f );
// Set my damages to the cvar values
SetDamage( weapon_emp_grenade_duration.GetFloat() );
SetDamageRadius( weapon_emp_grenade_radius.GetFloat() );
// Create a white light
CBasePlayer *player = ToBasePlayer( GetOwnerEntity() );
if ( player )
{
m_hLiveSprite = SPRITE_CREATE_PREDICTABLE( "sprites/chargeball2.vmt", GetLocalOrigin() + Vector(0,0,1), false );
if ( m_hLiveSprite )
{
m_hLiveSprite->SetOwnerEntity( player );
m_hLiveSprite->SetPlayerSimulated( player );
m_hLiveSprite->SetTransparency( kRenderGlow, 255, 255, 255, 128, kRenderFxNoDissipation );
m_hLiveSprite->SetBrightness( 255 );
m_hLiveSprite->SetScale( 0.15, 5.0f );
m_hLiveSprite->SetAttachment( this, 0 );
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGrenadeEMP::UpdateOnRemove( void )
{
// Remove our live sprite
if ( m_hLiveSprite )
{
m_hLiveSprite->Remove( );
m_hLiveSprite = NULL;
}
// Chain at end to mimic destructor unwind order
BaseClass::UpdateOnRemove();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGrenadeEMP::Explode( trace_t *pTrace, int bitsDamageType )
{
#if !defined( CLIENT_DLL )
// While in scope, this will allow messages to pass through without being filtered.
CDisablePredictionFiltering dpf;
// Create EMP pulse effect
int iEmpRings = 4;
float fEmpDelay = 0.05f;
float delay = 0.0f;
float frac;
for ( int r = 0 ; r < iEmpRings; r++, delay += fEmpDelay )
{
frac = (float)( r )/(float)(iEmpRings - 1);
CBroadcastRecipientFilter filter;
// Since this doesn't fire on the client right now, ignore the culling of the local player
filter.SetIgnorePredictionCull( true );
te->BeamRingPoint( filter, delay,
GetAbsOrigin() + Vector(0,0,32) , // origin
64.0f, // start radius
weapon_emp_grenade_radius.GetFloat() * 2, // end radius
g_iEMPPulseEffectIndex,
0, // halo index
0, // start frame
2, // framerate
0.3f, // life
25.0, // width
50, // spread
2, // amplitude
50 + ( 1-frac ) * 200,
63,
63 + 127 * frac,
255 - frac * 127,
20 );
}
ApplyRadiusEMPEffect( GetThrower(), GetAbsOrigin() + Vector(0,0,16) );
Remove( );
#endif
}
//-----------------------------------------------------------------------------
// Purpose: EMP enemies around the grenade
//-----------------------------------------------------------------------------
void CGrenadeEMP::ApplyRadiusEMPEffect( CBaseEntity *pOwner, const Vector& vecCenter )
{
// Oh oh, owner is gone...
if ( !pOwner )
return;
#if !defined( CLIENT_DLL )
CBaseEntity *pEntity = NULL;
for ( CEntitySphereQuery sphere( vecCenter, weapon_emp_grenade_radius.GetFloat() ); ( pEntity = sphere.GetCurrentEntity() ) != NULL; sphere.NextEntity() )
{
// Ignore team members, and unaligned targets
if ( pOwner->InSameTeam( pEntity ) || pEntity->GetTeamNumber() == 0 )
continue;
if ( pEntity->IsSolidFlagSet( FSOLID_NOT_SOLID ) )
continue;
// Make sure it's not blocked by a shield or wall
trace_t tr;
if ( TFGameRules()->IsTraceBlockedByWorldOrShield( vecCenter, pEntity->WorldSpaceCenter(), this, DMG_PROBE, &tr ) )
continue;
if ( pEntity->CanBePoweredUp() )
{
// Is it an object?
if ( pEntity->Classify() == CLASS_MILITARY )
{
pEntity->AttemptToPowerup( POWERUP_EMP, weapon_emp_grenade_object_duration.GetFloat() );
}
else
{
pEntity->AttemptToPowerup( POWERUP_EMP, weapon_emp_grenade_duration.GetFloat() );
}
}
}
#endif
}
//-----------------------------------------------------------------------------
// Purpose: Allow shield parry's
//-----------------------------------------------------------------------------
void CGrenadeEMP::BounceTouch( CBaseEntity *pOther )
{
Assert( pOther );
if ( !pOther->IsSolid() )
return;
BaseClass::BounceTouch( pOther );
}
//-----------------------------------------------------------------------------
// Purpose: Play a distinctive grenade bounce sound to warn nearby players
//-----------------------------------------------------------------------------
void CGrenadeEMP::BounceSound( void )
{
CPASAttenuationFilter filter( this, "GrenadeEMP.Bounce" );
filter.UsePredictionRules();
EmitSound( filter, entindex(), "GrenadeEMP.Bounce" );
}
//-----------------------------------------------------------------------------
// Purpose: Return the amplitude for the screenshake
//-----------------------------------------------------------------------------
float CGrenadeEMP::GetShakeAmplitude( void )
{
return 0;
}
//-----------------------------------------------------------------------------
// Purpose: Create a missile
//-----------------------------------------------------------------------------
CGrenadeEMP *CGrenadeEMP::Create( const Vector &vecOrigin, const Vector &vecForward, CBasePlayer *pOwner )
{
CGrenadeEMP *pGrenade = (CGrenadeEMP*)CREATE_PREDICTED_ENTITY( "grenade_emp" );
if ( pGrenade )
{
UTIL_SetOrigin( pGrenade, vecOrigin );
pGrenade->SetOwnerEntity( pOwner );
pGrenade->Spawn();
pGrenade->SetPlayerSimulated( pOwner );
pGrenade->ChangeTeam( pOwner->GetTeamNumber() );
pGrenade->SetThrower( pOwner );
pGrenade->SetAbsVelocity( vecForward );
QAngle angles;
VectorAngles( vecForward, angles );
pGrenade->SetLocalAngles( angles );
pGrenade->SetLocalAngularVelocity( SHARED_RANDOMANGLE( -500, 500 ) );
}
return pGrenade;
}
#if defined( CLIENT_DLL )
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGrenadeEMP::OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
// Only think when sapping
SetNextClientThink( CLIENT_THINK_ALWAYS );
}
//-----------------------------------------------------------------------------
// Purpose: Trail smoke
//-----------------------------------------------------------------------------
void CGrenadeEMP::ClientThink( void )
{
return;
CSmartPtr<CSimpleEmitter> pEmitter = CSimpleEmitter::Create( "EMPGrenade::Effect" );
PMaterialHandle hSphereMaterial = pEmitter->GetPMaterial( "sprites/chargeball" );
// Add particles at the target.
float flCur = gpGlobals->frametime;
while ( m_ParticleEvent.NextEvent( flCur ) )
{
Vector vecOrigin = GetAbsOrigin() + RandomVector( -2,2 );
pEmitter->SetSortOrigin( vecOrigin );
SimpleParticle *pParticle = (SimpleParticle *) pEmitter->AddParticle( sizeof(SimpleParticle), hSphereMaterial, vecOrigin );
if ( pParticle == NULL )
return;
pParticle->m_flLifetime = 0.0f;
pParticle->m_flDieTime = random->RandomFloat( 0.1f, 0.3f );
pParticle->m_uchStartSize = random->RandomFloat(2,4);
pParticle->m_uchEndSize = pParticle->m_uchStartSize + 2;
pParticle->m_vecVelocity = vec3_origin;
pParticle->m_uchStartAlpha = 128;
pParticle->m_uchEndAlpha = 0;
pParticle->m_flRoll = random->RandomFloat( 180, 360 );
pParticle->m_flRollDelta = random->RandomFloat( -1, 1 );
pParticle->m_uchColor[0] = 128;
pParticle->m_uchColor[1] = 128;
pParticle->m_uchColor[2] = 128;
}
}
int CGrenadeEMP::DrawModel( int flags )
{
bool bret = BaseClass::DrawModel( flags );
return bret;
}
#endif
+82
View File
@@ -0,0 +1,82 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef GRENADE_EMP_H
#define GRENADE_EMP_H
#ifdef _WIN32
#pragma once
#endif
class CSprite;
#include "grenade_base_empable.h"
#if defined( CLIENT_DLL )
#define CGrenadeEMP C_GrenadeEMP
#endif
//-----------------------------------------------------------------------------
// Purpose: EMP grenade
//-----------------------------------------------------------------------------
class CGrenadeEMP : public CBaseEMPableGrenade
{
DECLARE_CLASS( CGrenadeEMP, CBaseEMPableGrenade );
public:
CGrenadeEMP();
DECLARE_PREDICTABLE();
DECLARE_NETWORKCLASS();
virtual void Spawn( void );
virtual void Precache( void );
virtual void UpdateOnRemove( void );
virtual void Explode( trace_t *pTrace, int bitsDamageType );
virtual void BounceTouch( CBaseEntity *pOther );
virtual void BounceSound( void );
virtual float GetShakeAmplitude( void );
virtual int GetDamageType() const { return DMG_BLAST; }
void ApplyRadiusEMPEffect( CBaseEntity *pOwner, const Vector& vecCenter );
static CGrenadeEMP *CGrenadeEMP::Create( const Vector &vecOrigin, const Vector &vecAngles, CBasePlayer *pOwner );
// A derived class should return true here so that weapon sounds, etc, can
// apply the proper filter
virtual bool IsPredicted( void ) const
{
return true;
}
#if defined( CLIENT_DLL )
virtual bool ShouldPredict( void )
{
if ( GetThrower() &&
GetThrower() == C_BasePlayer::GetLocalPlayer() )
return true;
return BaseClass::ShouldPredict();
}
virtual void OnDataChanged( DataUpdateType_t updateType );
virtual void ClientThink( void );
TimedEvent m_ParticleEvent;
virtual int DrawModel( int flags );
#endif
private:
CNetworkHandle( CSprite, m_hLiveSprite );
private:
CGrenadeEMP( const CGrenadeEMP & );
};
#endif // GRENADE_EMP_H
+406
View File
@@ -0,0 +1,406 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "tf_player.h"
#include "tf_basecombatweapon.h"
#include "basegrenade_shared.h"
#include "weapon_limpetmine.h"
#include "engine/IEngineSound.h"
#include "grenade_limpetmine.h"
#include "tf_shareddefs.h"
#include "IEffects.h"
#include "player.h"
#include "basetfvehicle.h"
#define LIMPET_LIVE_TIME 0.5 // Time it takes before a limpet can be detonated after placement
#define LIMPET_LIFETIME 120 // After this time, limpets fizzle naturally
#define LIMPET_FIZZLE_DURATION 2.0f
#define LIMPET_MINS Vector(-5, -5, 0)
#define LIMPET_MAXS Vector( 5, 5, 10)
// Damage CVars
ConVar weapon_limpetmine_grenade_damage( "weapon_limpetmine_grenade_damage","0", FCVAR_NONE, "Limpet Mine's grenade maximum damage" );
ConVar weapon_limpetmine_grenade_radius( "weapon_limpetmine_grenade_radius","0", FCVAR_NONE, "Limpet Mine's grenade splash radius" );
// Global Savedata for friction modifier
BEGIN_DATADESC( CLimpetMine )
// Function Pointers
DEFINE_THINKFUNC( LiveThink ),
DEFINE_ENTITYFUNC( StickyTouch ),
DEFINE_THINKFUNC( LimpetThink ),
END_DATADESC()
IMPLEMENT_SERVERCLASS_ST(CLimpetMine, DT_LimpetMine)
SendPropInt(SENDINFO(m_bLive), 1, SPROP_UNSIGNED ),
END_SEND_TABLE()
LINK_ENTITY_TO_CLASS( grenade_limpetmine, CLimpetMine );
//-----------------------------------------------------------------------------
// Static initializers:
//-----------------------------------------------------------------------------
CLimpetMine* CLimpetMine::allLimpets = NULL;
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CLimpetMine::CLimpetMine( void )
{
UseClientSideAnimation();
// ---------------------------------
// Add to linked list of limpets
// ---------------------------------
nextLimpet = CLimpetMine::allLimpets;
CLimpetMine::allLimpets = this;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CLimpetMine::~CLimpetMine( void )
{
// --------------------------------------
// Remove from linked list of limpets
// --------------------------------------
CLimpetMine *pLimpet = CLimpetMine::allLimpets;
if (pLimpet == this)
{
CLimpetMine::allLimpets = pLimpet->nextLimpet;
}
else
{
while (pLimpet)
{
if (pLimpet->nextLimpet == this)
{
pLimpet->nextLimpet = pLimpet->nextLimpet->nextLimpet;
break;
}
pLimpet = pLimpet->nextLimpet;
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CLimpetMine::Precache( void )
{
PrecacheModel( "models/projectiles/grenade_limpet.mdl" );
PrecacheScriptSound( "LimpetMine.Beep" );
PrecacheScriptSound( "LimpetMine.Fizzle" );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CLimpetMine::Spawn( void )
{
SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE );
SetSolid( SOLID_BBOX );
SetGravity( 1.0 );
SetFriction( 1.25 );
SetModel( "models/projectiles/grenade_limpet.mdl");
UTIL_SetSize( this, LIMPET_MINS, LIMPET_MAXS );
m_bLive = false;
m_bFizzleInit = false;
m_bEMPed = false;
SetThink( LiveThink );
SetNextThink( gpGlobals->curtime + LIMPET_LIVE_TIME );
SetTouch( StickyTouch );
// Causes these to collide with everything but NPCs and players
SetCollisionGroup( TFCOLLISION_GROUP_GRENADE );
AddFlag( FL_OBJECT );
// Prevent sentry guns detecting these.
AddFlag( FL_NOTARGET );
// Set my damages to the cvar values
SetDamage( weapon_limpetmine_grenade_damage.GetFloat() );
SetDamageRadius( weapon_limpetmine_grenade_radius.GetFloat() );
}
//-----------------------------------------------------------------------------
// Purpose: Return true if this limpet mine can be detonated yet
//-----------------------------------------------------------------------------
bool CLimpetMine::IsLive( void )
{
return m_bLive;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CLimpetMine::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
Assert( pCaller );
// USE_SET Means we're being asked to fizzle out and dielf
if ( useType == USE_SET )
{
if ( !m_bFizzleInit )
{
// Set the defuse - fizzle think
m_flFizzleDuration = gpGlobals->curtime + 0.3;
SetThink( LimpetThink );
SetNextThink( gpGlobals->curtime + 0.1f );
m_bFizzleInit = true;
}
}
else if ( IsLive() )
{
// Get the TF2 player that owns this limpet:
CBaseTFPlayer *pPlayer = NULL;
if ( m_hLauncher )
{
pPlayer = ToBaseTFPlayer( m_hLauncher->GetOwner() );
}
// Get the TF2 player that is calling this object, if any:
CBaseTFPlayer *pCallerPlayer = NULL;
if ( pCaller )
{
pCallerPlayer = ToBaseTFPlayer( pCaller );
}
// If the owning player is directly using the limpet, then pick it up:
if( pPlayer && pCallerPlayer && pPlayer->IsSameClass( pCallerPlayer ) )
{
if ( m_hLauncher )
{
pPlayer->GiveAmmo( 1, m_hLauncher->m_iPrimaryAmmoType );
m_hLauncher->DecrementLimpets();
}
UTIL_Remove( this );
}
else if ( pActivator && !pActivator->InSameTeam( this ) )
{
// only the owning player can detonate his own limpets, so return if this isn't the owner.
return;
}
// We're being detonated
// If are EMPed then we cannot be detonated.
else if ( !IsEMPed() )
{
// Beep and detonate soon afterwards
EmitSound( "LimpetMine.Beep" );
SetThink( Detonate );
SetNextThink( gpGlobals->curtime + 0.5f );
// Pretend I'm not live anymore so I don't get exploded again
m_bLive = false;
if ( m_hLauncher )
{
m_hLauncher->DecrementLimpets();
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CLimpetMine::TakeEMPDamage( float duration )
{
if ( !m_bFizzleInit )
{
// Set the defuse - fizzle think
float flDuration = MIN( duration, LIMPET_FIZZLE_DURATION );
m_flFizzleDuration = gpGlobals->curtime + ( flDuration - 1.0f );
SetThink( LimpetThink );
SetNextThink( gpGlobals->curtime + 0.1f );
m_bFizzleInit = true;
m_bEMPed = true;
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Create a limpet mine
//-----------------------------------------------------------------------------
CLimpetMine* CLimpetMine::Create( const Vector &vecOrigin, const Vector &vecForward, CBasePlayer *pOwner )
{
CLimpetMine *pGrenade = (CLimpetMine*)CreateEntityByName("grenade_limpetmine");
pGrenade->Teleport( &vecOrigin, NULL, NULL );
pGrenade->Spawn();
pGrenade->SetOwnerEntity( pOwner );
pGrenade->SetThrower( pOwner );
pGrenade->SetAbsVelocity( vecForward );
pGrenade->ChangeTeam( pOwner->GetTeamNumber() );
return pGrenade;
}
//-----------------------------------------------------------------------------
// Purpose: Keep a pointer to the launcher (parent)
//-----------------------------------------------------------------------------
void CLimpetMine::SetLauncher( CWeaponLimpetmine *pLauncher )
{
m_hLauncher = pLauncher;
}
//-----------------------------------------------------------------------------
// Purpose: Go Live
//-----------------------------------------------------------------------------
void CLimpetMine::LiveThink( void )
{
m_bLive = true;
// Remove myself after a while
m_flFizzleDuration = gpGlobals->curtime + LIMPET_LIFETIME + 0.3;
SetNextThink( gpGlobals->curtime + 0.1f );
SetThink( LimpetThink );
}
//-----------------------------------------------------------------------------
// Purpose: Make the grenade stick to whatever it touches
//-----------------------------------------------------------------------------
void CLimpetMine::StickyTouch( CBaseEntity *pOther )
{
Assert( pOther );
if ( !pOther->IsSolid() )
return;
if ( !pOther->IsBSPModel() && !pOther->GetBaseAnimating() )
return;
BounceSound();
m_bStuckToTarget = false;
// Bounce off of shields
if ( pOther->GetCollisionGroup() == TFCOLLISION_GROUP_SHIELD )
{
// Move away from the shield...
// Fling it out a little extra along the plane normal
Vector vecNewVelocity;
Vector vecCenter;
AngleVectors( pOther->GetAbsAngles(), &vecCenter );
VectorMultiply( vecCenter, 400.0f, vecNewVelocity );
SetAbsVelocity( vecNewVelocity );
return;
}
// Only stick to non-moving entities
if ( !pOther->GetBaseAnimating() )
return;
// Don't stick to team members
if ( InSameTeam( pOther ) )
return;
// ROBIN: Removed stick to enemies for now
{
SetAbsVelocity( vec3_origin );
SetMoveType( MOVETYPE_NONE );
return;
}
m_bStuckToTarget = true;
// Orient to stick to the wall I just hit
trace_t tr;
Vector vecPrev = GetLocalOrigin() - (GetAbsVelocity() * 0.1);
UTIL_TraceLine( vecPrev, vecPrev + (GetAbsVelocity() * 2), MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );
if ( tr.fraction != 1 )
{
// Orient the *up* axis to be along the plane normal
Vector perp( 1, 0, 0 );
Vector forward, right;
CrossProduct( perp, tr.plane.normal, forward );
if (forward.LengthSqr() < 0.1f)
{
perp.Init( 0, 1, 0 );
CrossProduct( perp, tr.plane.normal, forward );
}
VectorNormalize( forward );
CrossProduct( tr.plane.normal, forward, right );
VMatrix orientation( forward, right, tr.plane.normal );
QAngle angles;
MatrixToAngles( orientation, angles );
SetAbsAngles( angles );
}
SetAbsVelocity( vec3_origin );
SetMoveType( MOVETYPE_NONE );
// At this point, it shouldn't affect player movement
SetCollisionGroup( COLLISION_GROUP_DEBRIS );
BounceSound();
SetParent( pOther );
}
//-----------------------------------------------------------------------------
// Purpose: Once the limpet's active, it starts running this
//-----------------------------------------------------------------------------
void CLimpetMine::LimpetThink( void )
{
SetNextThink( gpGlobals->curtime + 0.1f );
// If I'm not ready to fizzle yet, make sure my parent's still there.
if ( m_bStuckToTarget )
{
// Lost our parent?
if ( !GetMoveParent() )
{
m_bStuckToTarget = false;
// Fall to the ground
SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_CUSTOM );
SetTouch( StickyTouch );
}
}
float flDeltaTime = m_flFizzleDuration - gpGlobals->curtime;
// Not ready to fizzle yet?
if ( flDeltaTime > 0.3 )
return;
// Start fizzling
if ( flDeltaTime > 0.0f )
{
// Emit a fizzle sound
EmitSound( "LimpetMine.Fizzle" );
g_pEffects->Sparks( GetAbsOrigin() );
// Smoke.
UTIL_Smoke( GetAbsOrigin(), random->RandomInt( 1, 3), 10 );
}
else
{
// Done fizzling - no more sound.
StopSound( "LimpetMine.Fizzle" );
UTIL_Remove( this );
// Remove this limpet mine from the launcher deployment count.
if ( m_hLauncher )
{
m_hLauncher->DecrementLimpets();
}
return;
}
}
+70
View File
@@ -0,0 +1,70 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef GRENADE_LIMPETMINE_H
#define GRENADE_LIMPETMINE_H
#ifdef _WIN32
#pragma once
#endif
class CWeaponLimpetmine;
//=====================================================================================================
// LIMPET MINE
//=====================================================================================================
class CLimpetMine : public CBaseGrenade
{
DECLARE_CLASS( CLimpetMine, CBaseGrenade );
public:
DECLARE_SERVERCLASS();
DECLARE_DATADESC();
CLimpetMine( void );
virtual ~CLimpetMine( void );
// Creation and Initialization
virtual void Spawn( void );
virtual void Precache( void );
static CLimpetMine* CLimpetMine::Create( const Vector &vecOrigin, const Vector &vecAngles, CBasePlayer *pOwner );
virtual int GetDamageType() const { return DMG_BLAST; }
virtual bool CanBePoweredUp( void ) { return false; }
// Detonation
virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
bool IsLive( void );
virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() | FCAP_IMPULSE_USE; }
// EMP
virtual bool CanTakeEMPDamage() { return true; }
virtual bool TakeEMPDamage( float duration );
bool IsEMPed( void ) { return m_bEMPed; }
// Think and Touch
void LiveThink( void );
void StickyTouch( CBaseEntity *pOther );
void LimpetThink( void );
// Parent
void SetLauncher( CWeaponLimpetmine *pLauncher );
public:
static CLimpetMine* allLimpets; // A linked list of all limpets
CLimpetMine* nextLimpet; // The next limpet in list of all limpets
CNetworkVar( bool, m_bLive ); // are we active?
bool m_bStuckToTarget; // If true, the limpet stuck to something when it went active
bool m_bEMPed; // have we been EMPed?
bool m_bFizzleInit; // initialize the fizzle (EMP) process
float m_flFizzleDuration; // fizzle duration
CHandle<CWeaponLimpetmine> m_hLauncher; // parent (weapon launched from)
};
#endif // GRENADE_LIMPETMINE_H
+211
View File
@@ -0,0 +1,211 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "player.h"
#include "tf_obj.h"
#include "basegrenade_shared.h"
#include "grenade_objectsapper.h"
#include "engine/IEngineSound.h"
// Damage CVars
static ConVar weapon_objectsapper_damage( "weapon_objectsapper_damage","50", FCVAR_NONE, "Damage done, per second, by the object sapper." );
// Global Savedata for friction modifier
BEGIN_DATADESC( CGrenadeObjectSapper )
// Function Pointers
DEFINE_THINKFUNC( SapperThink ),
END_DATADESC()
IMPLEMENT_SERVERCLASS_ST(CGrenadeObjectSapper, DT_GrenadeObjectSapper)
SendPropInt(SENDINFO(m_bSapping), 1, SPROP_UNSIGNED ),
END_SEND_TABLE();
LINK_ENTITY_TO_CLASS( grenade_objectsapper, CGrenadeObjectSapper );
PRECACHE_WEAPON_REGISTER(grenade_objectsapper);
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGrenadeObjectSapper::Spawn( void )
{
SetMoveType( MOVETYPE_NONE );
SetSolid( SOLID_BBOX );
AddSolidFlags( FSOLID_NOT_SOLID );
SetGravity( 0.0 );
SetFriction( 1.0 );
SetModel( "models/sapper.mdl");
UTIL_SetSize(this, Vector( -8, -8, -8), Vector(8, 8, 8));
SetCollisionGroup( TFCOLLISION_GROUP_WEAPON );
m_takedamage = DAMAGE_NO;
m_iHealth = 50.0;
m_bSapping = false;
// Set my damages to the cvar values
SetDamage( weapon_objectsapper_damage.GetFloat() * 0.1 );
SetDamageRadius( 0 );
SetTouch( NULL );
SetThink( SapperThink );
SetNextThink( gpGlobals->curtime + 0.1f );
m_bArmed = true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGrenadeObjectSapper::Precache( void )
{
PrecacheModel( "models/sapper.mdl" );
PrecacheScriptSound( "GrenadeObjectSapper.Arming" );
PrecacheScriptSound( "GrenadeObjectSapper.RemoveSapper" );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGrenadeObjectSapper::PlayArmingSound( void )
{
EmitSound( "GrenadeObjectSapper.Arming" );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : armed -
//-----------------------------------------------------------------------------
void CGrenadeObjectSapper::SetArmed( bool armed )
{
bool ch = armed != m_bArmed;
m_bArmed = armed;
// Going armed
if ( ch && m_bArmed )
{
PlayArmingSound();
}
if ( m_bArmed )
{
RemoveEffects( EF_NODRAW );
}
else
{
AddEffects( EF_NODRAW );
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CGrenadeObjectSapper::GetArmed( void ) const
{
return m_bArmed;
}
//-----------------------------------------------------------------------------
// Purpose: Sap the health from the object I'm attached to
//-----------------------------------------------------------------------------
void CGrenadeObjectSapper::SapperThink( void )
{
SetNextThink( gpGlobals->curtime + 0.1f );
// Not armed yet?
if ( !GetArmed() )
return;
// Remove myself if I'm armed, but don't have an object to sap
if ( !m_hTargetObject )
{
UTIL_Remove( this );
return;
}
m_bSapping = true;
// Damage our target (add DMG_CRUSH to prevent physics damage)
m_hTargetObject->TakeDamage( CTakeDamageInfo( this, GetThrower(), GetDamage(), GetDamageType() | DMG_CRUSH ) );
}
//-----------------------------------------------------------------------------
// Purpose: Set our target object
//-----------------------------------------------------------------------------
void CGrenadeObjectSapper::SetTargetObject( CBaseObject *pObject )
{
// Remove myself from any object I'm on
if ( m_hTargetObject != pObject )
{
if ( m_hTargetObject.Get() )
{
m_hTargetObject->RemoveSapper( this );
SetParent( NULL );
}
m_hTargetObject = pObject;
// Tell any object I've just been attached to
if ( m_hTargetObject )
{
m_hTargetObject->AddSapper( this );
SetParent( m_hTargetObject );
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Allow players to remove sappers from objects
//-----------------------------------------------------------------------------
void CGrenadeObjectSapper::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
// Only enemies remove the sapper
if ( !InSameTeam( pActivator ) )
{
// Enemy is grabbing me
EmitSound( "GrenadeObjectSapper.RemoveSapper" );
SetTargetObject( NULL );
UTIL_Remove( this );
}
/*
ROBIN: Removed self-removal of sapper
else
{
// Ignore everyone except my owner
if ( pPlayer != m_hOwner )
return;
if ( pPlayer->GiveAmmo( 1, "Sappers") )
{
// Picked up, remove me
SetTargetObject( NULL );
UTIL_Remove( this );
}
}
*/
}
//-----------------------------------------------------------------------------
// Purpose: Create an object sapper grenade
//-----------------------------------------------------------------------------
CGrenadeObjectSapper *CGrenadeObjectSapper::Create( const Vector &vecOrigin, const Vector &vecForward, CBasePlayer *pOwner, CBaseObject *pObject )
{
CGrenadeObjectSapper *pGrenade = (CGrenadeObjectSapper*)CreateEntityByName("grenade_objectsapper");
UTIL_SetOrigin( pGrenade, vecOrigin );
pGrenade->Spawn();
pGrenade->SetThrower( pOwner );
pGrenade->SetAbsVelocity( vec3_origin );
QAngle angles;
VectorAngles( vecForward, angles );
angles.x -= 90;
pGrenade->SetLocalAngles( angles );
pGrenade->ChangeTeam( pOwner->GetTeamNumber() );
return pGrenade;
}
+50
View File
@@ -0,0 +1,50 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef GRENADE_OBJECTSAPPER_H
#define GRENADE_OBJECTSAPPER_H
#ifdef _WIN32
#pragma once
#endif
class CBaseObject;
//-----------------------------------------------------------------------------
// Purpose: Object sapper grenade
//-----------------------------------------------------------------------------
class CGrenadeObjectSapper : public CBaseGrenade
{
DECLARE_CLASS( CGrenadeObjectSapper, CBaseGrenade );
public:
DECLARE_DATADESC();
DECLARE_SERVERCLASS();
virtual void Spawn( void );
virtual void Precache( void );
virtual int GetDamageType() const { return DMG_BLAST; }
virtual void SapperThink( void );
void SetTargetObject( CBaseObject *pObject );
void SetArmed( bool armed );
bool GetArmed( void ) const;
void PlayArmingSound( void );
// Pickup
virtual int ObjectCaps( void ) { return FCAP_IMPULSE_USE; };
virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
static CGrenadeObjectSapper *CGrenadeObjectSapper::Create( const Vector &vecOrigin, const Vector &vecAngles, CBasePlayer *pOwner, CBaseObject *pObject );
public:
CNetworkVar( bool, m_bSapping );
CHandle<CBaseObject> m_hTargetObject;
bool m_bArmed;
};
#endif // GRENADE_OBJECTSAPPER_H
+176
View File
@@ -0,0 +1,176 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "tf_player.h"
#include "engine/IEngineSound.h"
#include "grenade_rocket.h"
extern short g_sModelIndexFireball;
IMPLEMENT_SERVERCLASS_ST( CGrenadeRocket, DT_GrenadeRocket)
END_SEND_TABLE()
BEGIN_DATADESC( CGrenadeRocket )
DEFINE_FIELD( m_flDamage, FIELD_FLOAT ),
// Function Pointers
DEFINE_FUNCTION( MissileTouch ),
DEFINE_FUNCTION( FollowThink ),
END_DATADESC()
LINK_ENTITY_TO_CLASS( grenade_rocket, CGrenadeRocket );
PRECACHE_REGISTER(grenade_rocket);
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CGrenadeRocket::CGrenadeRocket()
{
m_pRealOwner = NULL;
m_hLockTarget = NULL;
UseClientSideAnimation();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGrenadeRocket::Precache( void )
{
PrecacheModel( "models/weapons/w_missile.mdl" );
PrecacheScriptSound( "GrenadeRocket.FlyLoop" );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGrenadeRocket::Spawn( void )
{
Precache();
SetMoveType( MOVETYPE_FLY );
SetSolid( SOLID_BBOX );
SetModel( "models/weapons/w_missile.mdl" );
UTIL_SetSize( this, vec3_origin, vec3_origin );
SetCollisionGroup( TFCOLLISION_GROUP_WEAPON );
SetTouch( MissileTouch );
SetDamage( 50 );
// Forward!
Vector forward;
AngleVectors( GetLocalAngles(), &forward, NULL, NULL );
SetAbsVelocity( forward * ROCKET_VELOCITY );
EmitSound( "GrenadeRocket.FlyLoop" );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGrenadeRocket::MissileTouch( CBaseEntity *pOther )
{
Assert( pOther );
if ( !pOther->IsSolid() )
return;
Vector vecAbsOrigin = GetAbsOrigin();
CPASFilter filter( vecAbsOrigin );
te->Explosion( filter, 0.0, &vecAbsOrigin, g_sModelIndexFireball, 2.0, 15, TE_EXPLFLAG_NONE, 100, m_flDamage );
StopSound( "GrenadeRocket.FlyLoop" );
// Don't apply explosive damage if it hit a shield of any kind...
bool bHittingShield = false;
if (pOther->GetCollisionGroup() == TFCOLLISION_GROUP_SHIELD)
{
bHittingShield = true;
}
else if ( pOther->IsPlayer() )
{
CBaseTFPlayer *pPlayer = static_cast<CBaseTFPlayer*>(pOther);
trace_t tr;
float flDamage = m_flDamage;
bHittingShield = pPlayer->IsHittingShield( GetAbsVelocity(), &flDamage );
}
if (!bHittingShield)
{
RadiusDamage( CTakeDamageInfo( this, m_pRealOwner, m_flDamage, DMG_BLAST ), vecAbsOrigin, 100, CLASS_NONE, NULL );
}
UTIL_Remove( this );
}
//-----------------------------------------------------------------------------
// Purpose: Make this rocket lock onto it's target and track it
//-----------------------------------------------------------------------------
void CGrenadeRocket::LockOnto( CBaseEntity *pTarget )
{
m_hLockTarget = pTarget;
SetThink( FollowThink );
SetNextThink( gpGlobals->curtime + 0.1f );
}
//-----------------------------------------------------------------------------
// Purpose: Try and turn towards the target point
//-----------------------------------------------------------------------------
void CGrenadeRocket::FollowThink( void )
{
if ( m_hLockTarget == NULL )
return;
// Weave slightly drunkenly to target
Vector vecTarget = m_hLockTarget->GetAbsOrigin() - GetLocalOrigin();
VectorNormalize( vecTarget );
QAngle angles;
VectorAngles( vecTarget, angles );
SetLocalAngles( angles );
Vector vecVelocity = GetAbsVelocity();
float flSpeed = vecVelocity.Length();
vecVelocity = vecVelocity * 0.2 + vecTarget * flSpeed * 1.2;
// Clip to maxspeed
if ( vecVelocity.Length() > ROCKET_VELOCITY )
{
VectorNormalize( vecVelocity );
vecVelocity *= ROCKET_VELOCITY;
}
SetAbsVelocity( vecVelocity );
SetNextThink( gpGlobals->curtime + 0.1f );
}
//-----------------------------------------------------------------------------
// Purpose: Create a missile
//-----------------------------------------------------------------------------
CGrenadeRocket *CGrenadeRocket::Create( const Vector &vecOrigin, const Vector &vecForward, edict_t *pentOwner = NULL, CBaseEntity *pRealOwner = NULL )
{
CGrenadeRocket *pRocket = (CGrenadeRocket *)CreateEntityByName("grenade_rocket" );
UTIL_SetOrigin( pRocket, vecOrigin );
QAngle angles;
VectorAngles( vecForward, angles );
pRocket->SetLocalAngles( angles );
pRocket->Spawn();
pRocket->SetOwnerEntity( Instance( pentOwner ) );
pRocket->m_pRealOwner = pRealOwner;
if (pentOwner)
{
CBaseEntity *pOwnerEnt = GetContainingEntity( pentOwner );
pRocket->ChangeTeam( pOwnerEnt->GetTeamNumber() );
}
return pRocket;
}
+60
View File
@@ -0,0 +1,60 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef GRENADE_ROCKET_H
#define GRENADE_ROCKET_H
#ifdef _WIN32
#pragma once
#endif
#define ROCKET_VELOCITY 1000
//====================================================================================
// Purpose: ROCKET LAUNCHER SENTRYGUN'S ROCKETS
//====================================================================================
class CGrenadeRocket : public CBaseAnimating
{
DECLARE_CLASS( CGrenadeRocket, CBaseAnimating );
public:
DECLARE_DATADESC();
DECLARE_SERVERCLASS();
CGrenadeRocket();
void Spawn( void );
void Precache( void );
void MissileTouch( CBaseEntity *pOther );
void LockOnto( CBaseEntity *pTarget );
void FollowThink( void );
// Damage accessors.
virtual float GetDamage(void)
{
return m_flDamage;
}
virtual void SetDamage(float flDamage)
{
m_flDamage = flDamage;
}
virtual int GetDamageType() const
{
return DMG_BLAST;
}
static CGrenadeRocket *CGrenadeRocket::Create( const Vector &vecOrigin, const Vector &vecAngles, edict_t *pentOwner, CBaseEntity *pRealOwner );
public:
EHANDLE m_hLockTarget;
EHANDLE m_hOwner;
EHANDLE m_pRealOwner;
float m_flDamage;
};
#endif // GRENADE_ROCKET_H
+129
View File
@@ -0,0 +1,129 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Sticky bombs thrown by the recon
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "player.h"
#include "basegrenade_shared.h"
#include "tf_shareddefs.h"
#include "Sprite.h"
// Damage CVars
ConVar grenade_stickybomb_damage( "grenade_stickybomb_damage","0", 0, "Recon's stickybomb maximum damage" );
ConVar grenade_stickybomb_radius( "grenade_stickybomb_radius","0", 0, "Recon's stickybomb splash radius" );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CGrenadeStickyBomb : public CBaseGrenade
{
DECLARE_CLASS( CGrenadeStickyBomb, CBaseGrenade );
public:
CGrenadeStickyBomb();
DECLARE_DATADESC();
void Spawn( void );
void Precache( void );
void SetTimer( float timer );
void StickyTouch( CBaseEntity *pOther );
virtual void Explode( trace_t *pTrace, int bitsDamageType );
virtual int GetDamageType() const { return DMG_BLAST; }
private:
CSprite *m_pLiveSprite;
};
// Global Savedata for friction modifier
BEGIN_DATADESC( CGrenadeStickyBomb )
// Function Pointers
DEFINE_ENTITYFUNC( StickyTouch ),
END_DATADESC()
LINK_ENTITY_TO_CLASS( grenade_stickybomb, CGrenadeStickyBomb );
PRECACHE_WEAPON_REGISTER(grenade_stickybomb);
CGrenadeStickyBomb::CGrenadeStickyBomb()
{
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGrenadeStickyBomb::Precache( void )
{
PrecacheModel( "models/weapons/w_grenade.mdl" );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGrenadeStickyBomb::Spawn( void )
{
Precache();
SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE );
SetSolid( SOLID_BBOX );
SetGravity( 0.6 );
SetFriction( 1.0 );
SetModel( "models/weapons/w_grenade.mdl");
UTIL_SetSize(this, Vector( -4, -4, -4), Vector(4, 4, 4));
SetTouch( StickyTouch );
SetCollisionGroup( TFCOLLISION_GROUP_WEAPON );
// Create a red light
m_pLiveSprite = CSprite::SpriteCreate( "sprites/redglow1.vmt", GetLocalOrigin(), false );
m_pLiveSprite->SetTransparency( kRenderGlow, 255, 200, 200, 255, kRenderFxNoDissipation );
m_pLiveSprite->SetBrightness( 255 );
m_pLiveSprite->SetScale( 0.3 );
m_pLiveSprite->SetAttachment( this, 0 );
// Set my damages to the cvar values
SetDamage( grenade_stickybomb_damage.GetFloat() );
SetDamageRadius( grenade_stickybomb_radius.GetFloat() );
SetTimer( 2.0 );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGrenadeStickyBomb::SetTimer( float timer )
{
SetThink( Detonate );
SetNextThink( gpGlobals->curtime + timer );
}
//-----------------------------------------------------------------------------
// Purpose: Make the grenade stick to whatever it touches
//-----------------------------------------------------------------------------
void CGrenadeStickyBomb::StickyTouch( CBaseEntity *pOther )
{
if ( pOther->IsBSPModel() == false )
return;
BounceSound();
SetAbsVelocity( vec3_origin );
SetMoveType( MOVETYPE_NONE );
}
//-----------------------------------------------------------------------------
// Purpose: Remove my glow when I'm removed
//-----------------------------------------------------------------------------
void CGrenadeStickyBomb::Explode( trace_t *pTrace, int bitsDamageType )
{
if ( m_pLiveSprite )
{
UTIL_Remove( m_pLiveSprite );
m_pLiveSprite = NULL;
}
BaseClass::Explode( pTrace, bitsDamageType );
}
+60
View File
@@ -0,0 +1,60 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef IHASBUILDPOINTS_H
#define IHASBUILDPOINTS_H
#ifdef _WIN32
#pragma once
#endif
class CBaseObject;
// Derive from this interface if your entity can have objects placed on build points on it
class IHasBuildPoints
{
public:
// Tell me how many build points you have
virtual int GetNumBuildPoints( void ) const = 0;
// Give me the origin & angles of the specified build point
virtual bool GetBuildPoint( int iPoint, Vector &vecOrigin, QAngle &vecAngles ) = 0;
// If the build point wants to parent built objects to an attachment point on the entity,
// it'll return a value >= 1 here specifying which attachment to sit on.
virtual int GetBuildPointAttachmentIndex( int iPoint ) const = 0;
// Can I build the specified object on the specified build point?
virtual bool CanBuildObjectOnBuildPoint( int iPoint, int iObjectType ) = 0;
// I've finished building the specified object on the specified build point
virtual void SetObjectOnBuildPoint( int iPoint, CBaseObject *pObject ) = 0;
// Get the number of objects build on this entity
virtual int GetNumObjectsOnMe( void ) = 0;
// Get the first object that's built on me
virtual CBaseEntity *GetFirstObjectOnMe( void ) = 0;
// Get the first object of type, return NULL if no such type available
virtual CBaseObject *GetObjectOfTypeOnMe( int iObjectType ) = 0;
// Remove all objects built on me
virtual void RemoveAllObjects( void ) = 0;
// Return the maximum distance that this entity's build points can be snapped to
virtual float GetMaxSnapDistance( int iPoint ) = 0;
// Return true if it's possible that build points on this entity may move in local space (i.e. due to animation)
virtual bool ShouldCheckForMovement( void ) = 0;
// I've finished building the specified object on the specified build point
virtual int FindObjectOnBuildPoint( CBaseObject *pObject ) = 0;
// Returns an exit point for a vehicle built on a build point...
virtual void GetExitPoint( CBaseEntity *pPlayer, int iPoint, Vector *pAbsOrigin, QAngle *pAbsAngles ) = 0;
};
#endif // IHASBUILDPOINTS_H
+843
View File
@@ -0,0 +1,843 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "plasmaprojectile.h"
//#include "smoke_trail.h"
#include "basecombatweapon_shared.h"
#include "tf_shareddefs.h"
#if !defined( CLIENT_DLL )
#include "tf_shield.h"
#else
#include "c_tracer.h"
#include "hud.h"
#include "view.h"
#include "c_te_effect_dispatch.h"
#endif
#include "IEffects.h"
//#include "tf_player.h"
#include "basetfplayer_shared.h"
#include "engine/IEngineSound.h"
#include "worldsize.h"
#include "tf_gamerules.h"
#include "ammodef.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern ConVar tf_knockdowntime;
#define PLASMA_LIFETIME 2.0
// Time intervals at which we should simulate plasma projectiles
#define PLASMA_SIM_DELTA 0.01
#define PLASMA_VELOCITY_SQR (PLASMA_VELOCITY*PLASMA_VELOCITY)
#if defined( CLIENT_DLL )
ConVar shot_width( "shot_width","8", 0, "Shot" );
ConVar shot_length( "shot_length","140", 0, "Shot" );
ConVar shot_head_size( "shot_head_size","6", 0, "Shot" );
#endif
#if !defined( CLIENT_DLL )
//-----------------------------------------------------------------------------
// Purpose: PLASMA PROJECTILE
//-----------------------------------------------------------------------------
BEGIN_DATADESC( CBasePlasmaProjectile )
DEFINE_FIELD( m_flDamage, FIELD_FLOAT ),
// Function Pointers
DEFINE_ENTITYFUNC( MissileTouch ),
END_DATADESC()
#endif
BEGIN_NETWORK_TABLE_NOBASE( CPlasmaProjectileShared, DT_PlasmaProjectileShared )
#if !defined( CLIENT_DLL )
// These are parameters that are used to generate the entire motion
SendPropVector(SENDINFO(m_vecSpawnPosition), 0, SPROP_COORD),
SendPropVector(SENDINFO(m_vTracerDir), 0, SPROP_NOSCALE), //SPROP_NORMAL),
SendPropTime(SENDINFO(m_flSpawnTime)),
SendPropTime(SENDINFO(m_flDeathTime)),
SendPropFloat(SENDINFO(m_flSpawnSpeed), 0, SPROP_NOSCALE),
#else
RecvPropVector(RECVINFO(m_vecSpawnPosition)),
RecvPropVector(RECVINFO(m_vTracerDir)),
RecvPropTime(RECVINFO(m_flSpawnTime)),
RecvPropTime(RECVINFO(m_flDeathTime)),
RecvPropFloat(RECVINFO(m_flSpawnSpeed)),
#endif
END_NETWORK_TABLE()
BEGIN_PREDICTION_DATA_NO_BASE( CPlasmaProjectileShared )
DEFINE_PRED_FIELD_TOL( m_vecSpawnPosition, FIELD_VECTOR, FTYPEDESC_INSENDTABLE, 0.125f ),
DEFINE_PRED_FIELD_TOL( m_vTracerDir, FIELD_VECTOR, FTYPEDESC_INSENDTABLE, 0.01f ),
DEFINE_PRED_FIELD( m_flSpawnTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
DEFINE_PRED_FIELD( m_flDeathTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
DEFINE_PRED_FIELD( m_flSpawnSpeed, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
END_PREDICTION_DATA()
BEGIN_PREDICTION_DATA_NO_BASE( PositionHistory_t )
DEFINE_FIELD( m_Position, FIELD_VECTOR ),
DEFINE_FIELD( m_Time, FIELD_FLOAT ),
END_PREDICTION_DATA()
IMPLEMENT_NETWORKCLASS_ALIASED( BasePlasmaProjectile, DT_BasePlasmaProjectile)
BEGIN_NETWORK_TABLE( CBasePlasmaProjectile, DT_BasePlasmaProjectile )
#if !defined( CLIENT_DLL )
SendPropDataTable(SENDINFO_DT(m_Shared), &REFERENCE_SEND_TABLE(DT_PlasmaProjectileShared)),
SendPropExclude( "DT_BaseEntity", "m_vecVelocity" ),
SendPropExclude( "DT_BaseEntity", "m_vecAbsOrigin" ),
//SendPropVector(SENDINFO(m_vecGunOriginOffset), 0, SPROP_COORD),
#else
RecvPropDataTable(RECVINFO_DT(m_Shared), 0, &REFERENCE_RECV_TABLE(DT_PlasmaProjectileShared)),
//RecvPropVector(RECVINFO(m_vecGunOriginOffset)),
#endif
END_NETWORK_TABLE()
LINK_ENTITY_TO_CLASS( base_plasmaprojectile, CBasePlasmaProjectile );
PRECACHE_REGISTER(base_plasmaprojectile);
BEGIN_PREDICTION_DATA( CBasePlasmaProjectile )
DEFINE_PRED_TYPEDESCRIPTION( m_Shared, CPlasmaProjectileShared ),
DEFINE_PRED_FIELD( m_vecAbsOrigin, FIELD_VECTOR, FTYPEDESC_PRIVATE | FTYPEDESC_OVERRIDE ),
DEFINE_PRED_FIELD( m_vecVelocity, FIELD_VECTOR, FTYPEDESC_PRIVATE | FTYPEDESC_OVERRIDE ),
DEFINE_FIELD( m_flMaxRange, FIELD_FLOAT ),
// Predicted, but not in networking stream
DEFINE_PRED_TYPEDESCRIPTION( m_pPreviousPositions[0], PositionHistory_t ),
DEFINE_PRED_TYPEDESCRIPTION( m_pPreviousPositions[1], PositionHistory_t ),
DEFINE_PRED_TYPEDESCRIPTION( m_pPreviousPositions[2], PositionHistory_t ),
DEFINE_PRED_TYPEDESCRIPTION( m_pPreviousPositions[3], PositionHistory_t ),
DEFINE_PRED_TYPEDESCRIPTION( m_pPreviousPositions[4], PositionHistory_t ),
END_PREDICTION_DATA()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CBasePlasmaProjectile::CBasePlasmaProjectile()
{
#if defined( CLIENT_DLL )
m_pHeadParticle = NULL;
m_pTrailParticle = NULL;
m_pParticleMgr = NULL;
#endif
SetPredictionEligible( true );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CBasePlasmaProjectile::~CBasePlasmaProjectile()
{
#if defined( CLIENT_DLL )
if( m_pParticleMgr )
{
m_pParticleMgr->RemoveEffect( &m_ParticleEffect );
}
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBasePlasmaProjectile::Precache( void )
{
SetCollisionGroup( TFCOLLISION_GROUP_WEAPON );
PrecacheScriptSound( "BasePlasmaProjectile.ShieldBlock" );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBasePlasmaProjectile::Spawn( void )
{
Precache();
SetSolid( SOLID_BBOX );
SetSize( vec3_origin, vec3_origin );
SetCollisionGroup( TFCOLLISION_GROUP_WEAPON );
SetTouch( MissileTouch );
m_DamageType = DMG_ENERGYBEAM;
SetMoveType( MOVETYPE_CUSTOM );
m_flDamage = 0;
// SetMaxRange( 0 );
SetExplosive( 0 );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBasePlasmaProjectile::Activate( void )
{
BaseClass::Activate();
#if defined( CLIENT_DLL )
if ( IsClientCreated() && !m_pParticleMgr )
{
Start(ParticleMgr(), NULL);
SetNextClientThink( CLIENT_THINK_ALWAYS );
}
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBasePlasmaProjectile::SetDamage( float flDamage )
{
m_flDamage = flDamage;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float CBasePlasmaProjectile::GetDamage( void )
{
return m_flDamage;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBasePlasmaProjectile::SetMaxRange( float flRange )
{
m_flMaxRange = flRange;
// If we have a max range, calculate death time based upon velocity
if ( m_flMaxRange )
{
float flSpeed = GetAbsVelocity().Length();
Assert( flSpeed );
m_Shared.SetDeathTime( m_Shared.GetSpawnTime() + (flRange / flSpeed) );
}
else
{
m_Shared.SetDeathTime( m_Shared.GetSpawnTime() + PLASMA_LIFETIME );
}
}
//-----------------------------------------------------------------------------
// Purpose: Set the radius of the explosion created when this shot impacts
//-----------------------------------------------------------------------------
void CBasePlasmaProjectile::SetExplosive( float flRadius )
{
m_flExplosiveRadius = flRadius;
}
//-----------------------------------------------------------------------------
// Perform custom physics on this dude (when we're in ballistic mode)
//-----------------------------------------------------------------------------
void CBasePlasmaProjectile::PerformCustomPhysics( Vector *pNewPosition, Vector *pNewVelocity, QAngle *pNewAngles, QAngle *pNewAngVelocity )
{
#ifdef CLIENT_DLL
RecalculatePositions( pNewPosition, pNewVelocity, pNewAngles, pNewAngVelocity );
#else
// Simulate next position
m_Shared.ComputePosition( gpGlobals->curtime, pNewPosition, pNewVelocity, pNewAngles, pNewAngVelocity );
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pOther -
// tr -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CBasePlasmaProjectile::ProjectileHitShield( CBaseEntity *pOther, trace_t& tr )
{
if ( !pOther )
return false;
if ( !pOther->IsPlayer() )
return false;
#if !defined( CLIENT_DLL )
CBaseTFPlayer* pPlayer = static_cast<CBaseTFPlayer*>(pOther);
float flDamage = GetDamage();
if ( !pPlayer->IsHittingShield( GetAbsVelocity(), &flDamage ) )
return false;
#else
return false;
#endif
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pOther -
// tr -
//-----------------------------------------------------------------------------
void CBasePlasmaProjectile::HandleShieldImpact( CBaseEntity *pOther, trace_t& tr )
{
// Block
EmitSound( "BasePlasmaProjectile.ShieldBlock" );
// Remove the particle, and make a particle shower
g_pEffects->EnergySplash( tr.endpos, tr.plane.normal, ( m_flExplosiveRadius != 0 ) );
Remove( );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBasePlasmaProjectile::MissileTouch( CBaseEntity *pOther )
{
Assert( pOther );
if ( !pOther->IsSolid() )
return;
// Create a plasma effect
trace_t tr;
Vector velDir = GetAbsVelocity();
VectorNormalize( velDir );
Vector vecSpot = GetLocalOrigin() - velDir * 32;
// First, just clip to the box
Ray_t ray;
ray.Init( vecSpot, vecSpot + velDir * 64 );
enginetrace->ClipRayToEntity( ray, MASK_SHOT, pOther, &tr );
// Create the appropriate impact
bool bHurtTarget = ( !InSameTeam( pOther ) && pOther->m_takedamage != DAMAGE_NO );
WeaponImpact( &tr, velDir, bHurtTarget, pOther, GetDamageType() );
#if !defined( CLIENT_DLL )
CBaseEntity *pOwner = m_hOwner;
// Do damage (unless I'm explosive, in which case I'll do damage later)
if ( m_flDamage && !m_flExplosiveRadius )
{
ClearMultiDamage();
// Assume it's a projectile, so use its velocity instead
Vector vecDamageOrigin = GetAbsVelocity();
VectorNormalize( vecDamageOrigin );
vecDamageOrigin = GetAbsOrigin() - (vecDamageOrigin * 32);
CTakeDamageInfo info( this, pOwner, m_flDamage, m_DamageType );
CalculateBulletDamageForce( &info, GetAmmoDef()->Index("MediumRound"), GetAbsVelocity(), vecDamageOrigin );
pOther->DispatchTraceAttack( info, velDir, &tr );
ApplyMultiDamage();
}
#endif
Detonate();
}
//-----------------------------------------------------------------------------
// Purpose: Plasma projectiles return their owner as their scorer
//-----------------------------------------------------------------------------
CBasePlayer *CBasePlasmaProjectile::GetScorer( void )
{
return ToBasePlayer( m_hOwner );
}
//-----------------------------------------------------------------------------
// Purpose: Explode and die
//-----------------------------------------------------------------------------
void CBasePlasmaProjectile::Detonate( void )
{
#if !defined( CLIENT_DLL )
// Should I explode?
if ( m_flExplosiveRadius )
{
RadiusDamage( CTakeDamageInfo( this, GetOwnerEntity(), m_flDamage, m_DamageType | DMG_BLAST ), GetAbsOrigin(), m_flExplosiveRadius, CLASS_NONE, NULL );
}
#endif
Remove( );
}
#if defined( CLIENT_DLL )
//-----------------------------------------------------------------------------
// Add the position to the history
//-----------------------------------------------------------------------------
void CBasePlasmaProjectile::AddPositionToHistory( const Vector& org, float flSimTime )
{
// Store the particle position history
// Push the others down the stack
for ( int i = MAX_HISTORY-1; i >= 1; i-- )
{
m_pPreviousPositions[i].m_Position = m_pPreviousPositions[i-1].m_Position;
m_pPreviousPositions[i].m_Time = m_pPreviousPositions[i-1].m_Time;
}
m_pPreviousPositions[0].m_Position = org;
m_pPreviousPositions[0].m_Time = flSimTime;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : org -
//-----------------------------------------------------------------------------
void CBasePlasmaProjectile::ResetPositionHistories( const Vector& org )
{
for ( int i = 0; i < MAX_HISTORY; i++ )
{
m_pPreviousPositions[ i ].m_Position = org; //; - (m_Shared.TracerDir() * 48 * i);;
m_pPreviousPositions[ i ].m_Time = gpGlobals->curtime;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBasePlasmaProjectile::OnDataChanged(DataUpdateType_t updateType)
{
BaseClass::OnDataChanged(updateType);
if ( updateType != DATA_UPDATE_CREATED )
return;
if ( !m_pParticleMgr )
{
Start(ParticleMgr(), NULL);
SetNextClientThink( CLIENT_THINK_ALWAYS );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBasePlasmaProjectile::RecalculatePositions( Vector *pNewPosition, Vector *pNewVelocity, QAngle *pNewAngles, QAngle *pNewAngVelocity )
{
// Recalculate all points?
float flSimTime;
if ( !m_pPreviousPositions[0].m_Time )
{
flSimTime = m_Shared.GetSpawnTime();
}
else
{
flSimTime = gpGlobals->curtime;
}
// Simulate the points
for ( int i = 0; i < MAX_HISTORY; i++ )
{
if ( flSimTime < m_Shared.GetSpawnTime() )
{
flSimTime = m_Shared.GetSpawnTime();
}
Vector vecVelocity, vNewOrigin;
QAngle vecAngles, vecAngularVelocity;
// Only fill out the data with the most recent sim
if ( i == 0 )
{
m_Shared.ComputePosition( flSimTime, &vNewOrigin, &vecVelocity, pNewAngles, pNewAngVelocity );
*pNewPosition = vNewOrigin;
*pNewVelocity =vecVelocity;
}
else
{
m_Shared.ComputePosition( flSimTime, &vNewOrigin, &vecVelocity, &vecAngles, &vecAngularVelocity );
}
AddPositionToHistory( vNewOrigin, flSimTime );
// As we slow down, simulate slower
float flSpeed = vecVelocity.LengthSqr();
if ( flSpeed )
{
flSimTime -= PLASMA_SIM_DELTA * (PLASMA_VELOCITY_SQR / flSpeed);
}
else
{
flSimTime -= PLASMA_SIM_DELTA;
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBasePlasmaProjectile::ClientThink( void )
{
BaseClass::ClientThink();
// Don't mess with origin if it's being forward simulated on the client
if ( GetPredictable() || IsClientCreated() )
return;
Assert( !GetMoveParent() );
Vector pNewPosition, pNewVelocity;
QAngle pNewAngles, pNewAngVelocity;
RecalculatePositions( &pNewPosition, &pNewVelocity, &pNewAngles, &pNewAngVelocity );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : isbeingremoved -
// *predicted -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CBasePlasmaProjectile::OnPredictedEntityRemove( bool isbeingremoved, C_BaseEntity *predicted )
{
BaseClass::OnPredictedEntityRemove( isbeingremoved, predicted );
CBasePlasmaProjectile *bpp = dynamic_cast< CBasePlasmaProjectile * >( predicted );
if ( !bpp )
{
// Hrm, we didn't link up to correct type!!!
Assert( 0 );
// Delete right away since it's fucked up
return true;
}
memcpy( m_pPreviousPositions, bpp->m_pPreviousPositions, sizeof( m_pPreviousPositions ) );
m_vecGunOriginOffset = bpp->m_vecGunOriginOffset;
// Don't delete right away
return true; // isbeingremoved;
}
#define REMAP_BLEND_TIME 0.5f
//-----------------------------------------------------------------------------
// Purpose:
// Input : slot -
// curtime -
// outpos -
//-----------------------------------------------------------------------------
void CBasePlasmaProjectile::RemapPosition( Vector &vecStart, float curtime, Vector& outpos )
{
outpos = vecStart;
if ( curtime > m_Shared.GetSpawnTime() + REMAP_BLEND_TIME )
return;
float frac = ( curtime - m_Shared.GetSpawnTime() ) / REMAP_BLEND_TIME;
frac = 1.0f - clamp( frac, 0.0f, 1.0f );
Vector scaledOffset;
VectorScale( m_vecGunOriginOffset, frac, scaledOffset );
outpos += scaledOffset;
}
#define TIME_TILL_MAX_LENGTH 1.0
//-----------------------------------------------------------------------------
// Purpose: Update state + render
//-----------------------------------------------------------------------------
bool CBasePlasmaProjectile::SimulateAndRender(Particle *pInParticle, ParticleDraw *pDraw, float &sortKey)
{
if ( IsDormantPredictable() )
return true;
if ( GetMoveType() == MOVETYPE_NONE )
return true;
// Update the particle position
pInParticle->m_Pos = GetAbsOrigin();
// Add our blended offset
if ( gpGlobals->curtime < m_Shared.GetSpawnTime() + REMAP_BLEND_TIME )
{
float frac = ( gpGlobals->curtime - m_Shared.GetSpawnTime() ) / REMAP_BLEND_TIME;
frac = 1.0f - clamp( frac, 0.0f, 1.0f );
Vector scaledOffset;
VectorScale( m_vecGunOriginOffset, frac, scaledOffset );
pInParticle->m_Pos += scaledOffset;
}
float timeDelta = pDraw->GetTimeDelta();
// Render the head particle
if ( pInParticle == m_pHeadParticle )
{
SimpleParticle *pParticle = (SimpleParticle *) pInParticle;
pParticle->m_flLifetime += timeDelta;
// Render
Vector tPos, vecOrigin;
RemapPosition( m_pPreviousPositions[MAX_HISTORY-1].m_Position, m_pPreviousPositions[MAX_HISTORY-1].m_Time, vecOrigin );
TransformParticle( ParticleMgr()->GetModelView(), vecOrigin, tPos );
sortKey = (int) tPos.z;
//Render it
RenderParticle_ColorSizeAngle(
pDraw,
tPos,
UpdateColor( pParticle, timeDelta ),
UpdateAlpha( pParticle, timeDelta ) * GetAlphaDistanceFade( tPos, 16, 64 ),
UpdateScale( pParticle, timeDelta ),
UpdateRoll( pParticle, timeDelta ) );
/*
if ( m_flNextSparkEffect < gpGlobals->curtime )
{
// Drop sparks?
if ( GetTeamNumber() == TEAM_HUMANS )
{
g_pEffects->Sparks( pInParticle->m_Pos, 1, 3 );
}
else
{
g_pEffects->EnergySplash( pInParticle->m_Pos, vec3_origin );
}
m_flNextSparkEffect = gpGlobals->curtime + RandomFloat( 0.5, 2 );
}
*/
return true;
}
// Render the trail
TrailParticle *pParticle = (TrailParticle *) pInParticle;
pParticle->m_flLifetime += timeDelta;
Vector vecScreenStart, vecScreenDelta;
sortKey = pParticle->m_Pos.z;
// NOTE: We need to do everything in screen space
float flFragmentLength = (MAX_HISTORY > 1) ? 1.0 / (float)(MAX_HISTORY-1) : 1.0;
for ( int i = 0; i < (MAX_HISTORY-1); i++ )
{
Vector vecWorldStart, vecWorldEnd, vecScreenEnd;
float flStartV, flEndV;
// Did we just appear?
if ( m_pPreviousPositions[i].m_Time == 0 )
continue;
RemapPosition( m_pPreviousPositions[i+1].m_Position, m_pPreviousPositions[i+1].m_Time, vecWorldStart );
RemapPosition( m_pPreviousPositions[i].m_Position, m_pPreviousPositions[i].m_Time, vecWorldEnd );
// Texture wrapping
flStartV = (flFragmentLength * (i+1));
flEndV = (flFragmentLength * i);
TransformParticle( ParticleMgr()->GetModelView(), vecWorldStart, vecScreenStart );
TransformParticle( ParticleMgr()->GetModelView(), vecWorldEnd, vecScreenEnd );
Vector vecScreenDelta = (vecScreenEnd - vecScreenStart);
if ( vecScreenDelta == vec3_origin )
continue;
/*
Vector vecForward, vecRight;
AngleVectors( MainViewAngles(), &vecForward, &vecRight, NULL );
Vector vecWorldDelta = ( vecWorldEnd - vecWorldStart );
VectorNormalize( vecWorldDelta );
float flDot = fabs(DotProduct( vecWorldDelta, vecForward ));
if ( flDot > 0.99 )
{
// Remap alpha
pParticle->m_flColor[3] = 1.0 - MIN( 1.0, RemapVal( flDot, 0.99, 1.0, 0, 1 ) );
}
*/
// See if we should fade
float color[4];
Color32ToFloat4( color, pParticle->m_color );
Tracer_Draw( pDraw, vecScreenStart, vecScreenDelta, pParticle->m_flWidth, color, flStartV, flEndV );
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBasePlasmaProjectile::Start(CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs)
{
m_pParticleMgr = pParticleMgr;
m_pParticleMgr->AddEffect( &m_ParticleEffect, this );
PMaterialHandle HeadMaterial, TrailMaterial;
// Load the projectile material
if ( GetTeamNumber() == TEAM_HUMANS )
{
HeadMaterial = m_ParticleEffect.FindOrAddMaterial( "effects/human_tracers/human_sparksprite_A1" );
TrailMaterial = m_ParticleEffect.FindOrAddMaterial( "effects/human_tracers/human_sparktracer_A_" );
}
else
{
HeadMaterial = m_ParticleEffect.FindOrAddMaterial( "effects/alien_tracers/alien_pbsprite_A1" );
TrailMaterial = m_ParticleEffect.FindOrAddMaterial( "effects/alien_tracers/alien_pbtracer_A_" );
}
// Create the head & trail
m_pHeadParticle = (SimpleParticle *)m_ParticleEffect.AddParticle(sizeof(SimpleParticle), HeadMaterial );
m_pTrailParticle = (TrailParticle *)m_ParticleEffect.AddParticle(sizeof(TrailParticle), TrailMaterial );
if ( !m_pHeadParticle || !m_pTrailParticle )
return;
// 3rd person particles are larger
bool bFirst = (GetOwnerEntity() == C_BasePlayer::GetLocalPlayer());
m_pHeadParticle->m_Pos = GetRenderOrigin();
m_pHeadParticle->m_uchColor[0] = 255;
m_pHeadParticle->m_uchColor[1] = 255;
m_pHeadParticle->m_uchColor[2] = 255;
if ( bFirst )
{
m_pHeadParticle->m_uchStartSize = 6;
}
else
{
m_pHeadParticle->m_uchStartSize = shot_head_size.GetInt();
}
m_pHeadParticle->m_uchEndSize = m_pHeadParticle->m_uchStartSize;
m_pHeadParticle->m_uchStartAlpha = 255;
m_pHeadParticle->m_uchEndAlpha = 255;
m_pHeadParticle->m_flRoll = 0;
m_pHeadParticle->m_flRollDelta = 10;
m_pHeadParticle->m_iFlags = 0;
m_pTrailParticle->m_flLifetime = 0;
m_pTrailParticle->m_Pos = GetRenderOrigin();
if ( bFirst )
{
m_pTrailParticle->m_flWidth = 25;
m_pTrailParticle->m_flLength = 140;
}
else
{
m_pTrailParticle->m_flWidth = shot_width.GetFloat();
m_pTrailParticle->m_flLength = shot_length.GetFloat();
}
Color32Init( m_pTrailParticle->m_color, 255, 255, 255, 255 );
m_flNextSparkEffect = gpGlobals->curtime + RandomFloat( 0.05, 0.4 );
}
#endif
//-----------------------------------------------------------------------------
// Purpose: Setup this projectile's starting values
//-----------------------------------------------------------------------------
void CBasePlasmaProjectile::SetupProjectile( const Vector &vecOrigin, const Vector &vecForward, int damageType, CBaseEntity *pOwner )
{
UTIL_SetOrigin( this, vecOrigin );
QAngle angles;
VectorAngles( vecForward, angles );
SetLocalAngles( angles );
SetOwnerEntity( pOwner );
Spawn();
float flMySpeed = PLASMA_VELOCITY;// + RandomFloat( -500, 500 );
SetAbsVelocity( vecForward * flMySpeed );
m_DamageType = damageType;
m_Shared.Init( vecOrigin, vecForward, flMySpeed );
#ifdef CLIENT_DLL
ResetPositionHistories( GetAbsOrigin() );
#endif
m_Shared.SetSpawnTime( gpGlobals->curtime );
// Set my team
ChangeTeam( pOwner->GetTeamNumber() );
}
//-----------------------------------------------------------------------------
// Purpose: Create a missile
//-----------------------------------------------------------------------------
CBasePlasmaProjectile *CBasePlasmaProjectile::Create( const Vector &vecOrigin, const Vector &vecForward, int damageType, CBaseEntity *pOwner = NULL )
{
CBasePlasmaProjectile *pMissile = (CBasePlasmaProjectile*)CreateEntityByName("base_plasmaprojectile");
pMissile->SetupProjectile( vecOrigin, vecForward, damageType, pOwner );
return pMissile;
}
CBasePlasmaProjectile *CBasePlasmaProjectile::CreatePredicted( const Vector &vecOrigin, const Vector &vecForward, const Vector& gunOffset, int damageType, CBasePlayer *pOwner )
{
CBasePlasmaProjectile *pMissile = (CBasePlasmaProjectile*)CREATE_PREDICTED_ENTITY("base_plasmaprojectile");
if ( pMissile )
{
pMissile->SetOwnerEntity( pOwner );
pMissile->SetPlayerSimulated( pOwner );
pMissile->SetupProjectile( vecOrigin, vecForward, damageType, pOwner );
pMissile->m_vecGunOriginOffset = gunOffset;
}
return pMissile;
}
//===============================================================================================================
// Power Projectile
//===============================================================================================================
//-----------------------------------------------------------------------------
// Purpose: Create a power projectile
//-----------------------------------------------------------------------------
CPowerPlasmaProjectile *CPowerPlasmaProjectile::Create( const Vector &vecOrigin, const Vector &vecForward, int damageType, CBaseEntity *pOwner = NULL )
{
CPowerPlasmaProjectile *pMissile = (CPowerPlasmaProjectile*)CreateEntityByName("powerplasmaprojectile");
pMissile->SetupProjectile( vecOrigin, vecForward, damageType, pOwner );
pMissile->SetPower( 1.0 );
return pMissile;
}
CPowerPlasmaProjectile *CPowerPlasmaProjectile::CreatePredicted( const Vector &vecOrigin, const Vector &vecForward, const Vector& gunOffset, int damageType, CBasePlayer *pOwner )
{
CPowerPlasmaProjectile *pMissile = (CPowerPlasmaProjectile*)CREATE_PREDICTED_ENTITY("powerplasmaprojectile");
if ( pMissile )
{
pMissile->SetOwnerEntity( pOwner );
pMissile->SetPlayerSimulated( pOwner );
pMissile->SetupProjectile( vecOrigin, vecForward, damageType, pOwner );
pMissile->SetPower( 1.0 );
pMissile->m_vecGunOriginOffset = gunOffset;
}
return pMissile;
}
CPowerPlasmaProjectile::CPowerPlasmaProjectile( void )
{
m_flPower = 0;
SetPredictionEligible( true );
}
//-----------------------------------------------------------------------------
// Purpose: Factor power into size
//-----------------------------------------------------------------------------
float CPowerPlasmaProjectile::GetSize( void )
{
return ( 2 * (m_flPower * 2));
}
IMPLEMENT_NETWORKCLASS_ALIASED( PowerPlasmaProjectile, DT_PowerPlasmaProjectile);
BEGIN_NETWORK_TABLE( CPowerPlasmaProjectile, DT_PowerPlasmaProjectile)
#if !defined( CLIENT_DLL )
SendPropFloat( SENDINFO( m_flPower ), 7, SPROP_ROUNDDOWN, 1.0f, 10.0 ),
#else
RecvPropFloat(RECVINFO(m_flPower)),
#endif
END_NETWORK_TABLE()
LINK_ENTITY_TO_CLASS( powerplasmaprojectile, CPowerPlasmaProjectile );
PRECACHE_REGISTER(powerplasmaprojectile);
BEGIN_PREDICTION_DATA( CPowerPlasmaProjectile )
DEFINE_PRED_FIELD_TOL( m_flPower, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, 0.05f ),
END_PREDICTION_DATA()
+245
View File
@@ -0,0 +1,245 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef PLASMAPROJECTILE_H
#define PLASMAPROJECTILE_H
#ifdef _WIN32
#pragma once
#endif
#include "predictable_entity.h"
#include "baseparticleentity.h"
#include "plasmaprojectile_shared.h"
#if !defined( CLIENT_DLL )
#include "iscorer.h"
#else
#include "particle_prototype.h"
#include "particles_simple.h"
#include "particle_util.h"
#include "c_baseplayer.h"
#include "fx_sparks.h"
#endif
#if defined( CLIENT_DLL )
#define CBasePlasmaProjectile C_BasePlasmaProjectile
#endif
#define MAX_HISTORY 5
#define GUIDED_FADE_TIME 0.25f
#define GUIDED_WIDTH 3
struct PositionHistory_t
{
DECLARE_PREDICTABLE();
Vector m_Position;
float m_Time;
};
// ------------------------------------------------------------------------ //
// CBasePlasmaProjectile
// ------------------------------------------------------------------------ //
class CBasePlasmaProjectile : public CBaseParticleEntity
#if !defined( CLIENT_DLL )
, public IScorer
#endif
{
DECLARE_CLASS( CBasePlasmaProjectile, CBaseParticleEntity );
public:
CBasePlasmaProjectile();
~CBasePlasmaProjectile();
DECLARE_PREDICTABLE();
DECLARE_NETWORKCLASS();
#if !defined( CLIENT_DLL )
DECLARE_DATADESC();
#endif
virtual bool ProjectileHitShield( CBaseEntity *pOther, trace_t& tr );
virtual void HandleShieldImpact( CBaseEntity *pOther, trace_t& tr );
virtual void Spawn( void );
virtual void Precache( void );
virtual void Activate( void );
virtual void MissileTouch( CBaseEntity *pOther );
virtual float GetDamage( void );
virtual void SetDamage( float flDamage );
virtual void SetMaxRange( float flRange );
virtual void SetExplosive( float flRadius );
virtual void PerformCustomPhysics( Vector *pNewPosition, Vector *pNewVelocity, QAngle *pNewAngles, QAngle *pNewAngVelocity );
// Purpose: Returns the type of damage that this entity inflicts.
int GetDamageType() const
{
return m_DamageType;
}
virtual float GetSize( void ) { return 6.0; };
// FIXME!!!! Override the think of the baseparticle Think functions
virtual void Think( void ) { CBaseEntity::Think(); }
void SetupProjectile( const Vector &vecOrigin, const Vector &vecForward, int damageType, CBaseEntity *pOwner = NULL );
static CBasePlasmaProjectile *Create( const Vector &vecOrigin, const Vector &vecForward, int damageType, CBaseEntity *pOwner );
static CBasePlasmaProjectile *CreatePredicted( const Vector &vecOrigin, const Vector &vecForward, const Vector& gunOffset, int damageType, CBasePlayer *pOwner );
void RecalculatePositions( Vector *pNewPosition, Vector *pNewVelocity, QAngle *pNewAngles, QAngle *pNewAngVelocity );
// IScorer
public:
// Return the entity that should receive the score
virtual CBasePlayer *GetScorer( void );
// Return the entity that should get assistance credit
virtual CBasePlayer *GetAssistant( void ) { return NULL; };
protected:
void Detonate( void );
// A derived class should return true here so that weapon sounds, etc, can
// apply the proper filter
virtual bool IsPredicted( void ) const
{
return true;
}
#if defined( CLIENT_DLL )
virtual bool ShouldPredict( void )
{
if ( GetOwnerEntity() &&
GetOwnerEntity() == C_BasePlayer::GetLocalPlayer() )
return true;
return BaseClass::ShouldPredict();
}
virtual void OnDataChanged(DataUpdateType_t updateType);
virtual void Start(CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs);
virtual bool SimulateAndRender(Particle *pParticle, ParticleDraw *pDraw, float &sortKey);
// Add the position to the history
void AddPositionToHistory( const Vector& org, float flSimTime );
void ResetPositionHistories( const Vector& org );
// Adjustments for shots straight out of local player's eyes
void RemapPosition( Vector &vecStart, float curtime, Vector& outpos );
// Scale
virtual float UpdateScale( SimpleParticle *pParticle, float timeDelta )
{
return (float)pParticle->m_uchStartSize + RandomInt( -2,2 );
}
// Alpha
virtual float UpdateAlpha( SimpleParticle *pParticle, float timeDelta )
{
return (pParticle->m_uchStartAlpha + RandomInt( -50, 0 ) ) / 255.0f;
}
virtual float UpdateRoll( SimpleParticle *pParticle, float timeDelta )
{
pParticle->m_flRoll += pParticle->m_flRollDelta * timeDelta;
return pParticle->m_flRoll;
}
virtual Vector UpdateColor( SimpleParticle *pParticle, float timeDelta )
{
static Vector cColor;
cColor[0] = pParticle->m_uchColor[0] / 255.0f;
cColor[1] = pParticle->m_uchColor[1] / 255.0f;
cColor[2] = pParticle->m_uchColor[2] / 255.0f;
return cColor;
}
// Should this object cast shadows?
virtual ShadowType_t ShadowCastType() { return SHADOWS_NONE; }
virtual void ClientThink( void );
virtual bool OnPredictedEntityRemove( bool isbeingremoved, C_BaseEntity *predicted );
protected:
SimpleParticle *m_pHeadParticle;
TrailParticle *m_pTrailParticle;
CParticleMgr *m_pParticleMgr;
float m_flNextSparkEffect;
#endif
public:
EHANDLE m_hOwner;
protected:
CNetworkVarEmbedded( CPlasmaProjectileShared, m_Shared );
Vector m_vecGunOriginOffset;
CNetworkVar( float, m_flPower );
// Explosive radius
float m_flExplosiveRadius;
// Maximum range
float m_flMaxRange;
float m_flDamage;
int m_DamageType;
Vector m_vecTargetOffset;
PositionHistory_t m_pPreviousPositions[MAX_HISTORY];
private:
CBasePlasmaProjectile( const CBasePlasmaProjectile & );
};
#if defined( CLIENT_DLL )
#define CPowerPlasmaProjectile C_PowerPlasmaProjectile
#endif
// ------------------------------------------------------------------------ //
// Plasma projectile that has a concept of variable power
// ------------------------------------------------------------------------ //
class CPowerPlasmaProjectile : public CBasePlasmaProjectile
{
DECLARE_CLASS( CPowerPlasmaProjectile, CBasePlasmaProjectile );
public:
DECLARE_NETWORKCLASS();
DECLARE_PREDICTABLE();
CPowerPlasmaProjectile();
void SetPower( float flPower ) { m_flPower = flPower; };
static CPowerPlasmaProjectile* Create( const Vector &vecOrigin, const Vector &vecForward, int damageType, CBaseEntity *pOwner );
static CPowerPlasmaProjectile* CreatePredicted( const Vector &vecOrigin, const Vector &vecForward, const Vector& gunOffset, int damageType, CBasePlayer *pOwner );
virtual float GetSize( void );
// A derived class should return true here so that weapon sounds, etc, can
// apply the proper filter
virtual bool IsPredicted( void ) const
{
return true;
}
#if defined( CLIENT_DLL )
virtual bool ShouldPredict( void )
{
if ( GetOwnerEntity() &&
GetOwnerEntity() == C_BasePlayer::GetLocalPlayer() )
return true;
return BaseClass::ShouldPredict();
}
#endif
private:
CPowerPlasmaProjectile( const CPowerPlasmaProjectile & );
};
#endif // PLASMAPROJECTILE_H
@@ -0,0 +1,72 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "plasmaprojectile_shared.h"
#define PLASMA_LIFETIME 2.0
ConVar plasma_gravity( "plasma_gravity","1000", FCVAR_REPLICATED, "Plasma gravity" );
ConVar plasma_drag( "plasma_drag","2", FCVAR_REPLICATED, "Plasma drag" );
//-----------------------------------------------------------------------------
// Setup state needed to perform the physics computation
//-----------------------------------------------------------------------------
void CPlasmaProjectileShared::Init( const Vector &vecStart, const Vector &vecDir, float flSpawnSpeed )
{
m_vecSpawnPosition = vecStart;
m_vTracerDir = vecDir;
m_flSpawnSpeed = flSpawnSpeed;
}
void CPlasmaProjectileShared::SetSpawnTime( float flSpawnTime )
{
m_flSpawnTime = flSpawnTime;
}
void CPlasmaProjectileShared::SetDeathTime( float flDeathTime )
{
m_flDeathTime = flDeathTime;
}
//-----------------------------------------------------------------------------
// Perform custom physics on this dude (when we're in ballistic mode)
//-----------------------------------------------------------------------------
void CPlasmaProjectileShared::ComputePosition( float flTime, Vector *pNewPosition, Vector *pNewVelocity, QAngle *pNewAngles, QAngle *pNewAngVelocity )
{
float flLifeTime = flTime - m_flSpawnTime;
if (flLifeTime < 0)
return;
// Travel ballistically until we run out of juice..
if (flTime <= m_flDeathTime)
{
VectorMultiply( m_vTracerDir, m_flSpawnSpeed, *pNewVelocity );
VectorMA( m_vecSpawnPosition, flLifeTime, *pNewVelocity, *pNewPosition );
}
else
{
VectorMultiply( m_vTracerDir, m_flSpawnSpeed, *pNewVelocity );
VectorMA( m_vecSpawnPosition, m_flDeathTime - m_flSpawnTime, *pNewVelocity, *pNewPosition );
// Ran out of juice... fall!
float flFallTime = flTime - m_flDeathTime;
float flDragFactor = exp( -plasma_drag.GetFloat() * flFallTime );
*pNewVelocity *= flDragFactor;
float flDist = (m_flSpawnSpeed / plasma_drag.GetFloat()) * ( 1.0f - flDragFactor );
VectorMA( *pNewPosition, flDist, m_vTracerDir, *pNewPosition );
// Add in the effects of gravity!
pNewVelocity->z -= flFallTime * plasma_gravity.GetFloat();
pNewPosition->z -= 0.5f * plasma_gravity.GetFloat() * flFallTime * flFallTime;
}
}
+48
View File
@@ -0,0 +1,48 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef PLASMAPROJECTILE_SHARED_H
#define PLASMAPROJECTILE_SHARED_H
#ifndef _WIN32
#pragma once
#endif
#include "predictable_entity.h"
#include "server_class.h"
#include "client_class.h"
#include "mathlib/vector.h"
class CPlasmaProjectileShared
{
public:
DECLARE_PREDICTABLE();
DECLARE_NETWORKCLASS_NOBASE();
DECLARE_CLASS_NOBASE( CPlasmaProjectileShared );
DECLARE_EMBEDDED_NETWORKVAR();
public:
void Init( const Vector &vecStart, const Vector &vecDir, float flSpawnSpeed );
float GetSpawnTime() const { return m_flSpawnTime; }
void SetSpawnTime( float flSpawnTime );
void SetDeathTime( float flDeathTime );
float GetDeathTime() const { return m_flDeathTime; }
void ComputePosition( float flTime, Vector *pNewPosition, Vector *pNewVelocity, QAngle *pNewAngles, QAngle *pNewAngVelocity );
const Vector &TracerDir() { return m_vTracerDir.Get(); }
private:
CNetworkVector( m_vTracerDir );
CNetworkVector( m_vecSpawnPosition );
CNetworkVar( float, m_flSpawnTime );
CNetworkVar( float, m_flSpawnSpeed );
CNetworkVar( float, m_flDeathTime );
};
#endif // PLASMAPROJECTILE_SHARED_H
File diff suppressed because it is too large Load Diff
+320
View File
@@ -0,0 +1,320 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#if !defined( TECHTREE_H )
#define TECHTREE_H
#ifdef _WIN32
#pragma once
#endif
// Evil, Game DLL only code
#ifndef CLIENT_DLL
class CBaseTFPlayer;
class CTFTeam;
class CInfoCustomTechnology;
#endif
class IFileSystem;
//===========================================================================================
// Technology tree defines
#define MAX_TF_TECHLEVELS 6 // Number of TF2 tech levels
#define TECHLEVEL_PERCENTAGE_NEEDED 0.5 // Percentage of a tech level that must be owned before the next tech level becomes available
#define MAX_TECHNOLOGIES 128 // Max number of resource types
#define MAX_ASSOCIATED_WEAPONS 2 // Max number of weapons that a tech can be associated with
// Indexes into resource arrays
#define NORMAL_RESOURCES 0
#define PROCESSED_RESOURCES 1
#define RESOURCE_TYPES 2
// Tech
#define TECHNOLOGY_NAME_LENGTH 64 // Max length of a tech name
#define TECHNOLOGY_PRINTNAME_LENGTH 128 // Max length of a tech's print name
#define TECHNOLOGY_DESC_LENGTH 256 // Max length of a tech's description
#define MAX_CONTAINED_TECHNOLOGIES 16 // Max number of technologies that can be contained within another technology
#define MAX_DEPENDANT_TECHNOLOGIES 16 // Max number of technologies that a tech can depend on
#define TECHNOLOGY_SOUNDFILENAME_LENGTH 256
#define TECHNOLOGY_TEXTURENAME_LENGTH 128
#define TECHNOLOGY_BUTTONNAME_LENGTH 64
#define TECHNOLOGY_WEAPONNAME_LENGTH 128
// Color codes for Resources
struct rescolor
{
int r;
int g;
int b;
};
// Class result structure for technologies
struct classresult_t
{
bool bClassTouched; // This technology directly affects this class
char pszSoundFile[TECHNOLOGY_SOUNDFILENAME_LENGTH]; // Filename of the sound
int iSound; // Sound played to members of this class when this technology is achieved
char pszDescription[TECHNOLOGY_DESC_LENGTH]; // Description for this technology shown only to this class
// If true, then we should determine what weapons should be given to the player
// of this class when this technology is received by looking at the "associated_weapons"
// data
bool m_bAssociateWeaponsForClass;
};
extern char sResourceName[32];
extern rescolor sResourceColor;
#include "utlvector.h"
#include "tf_shareddefs.h"
//===========================================================================================
//-----------------------------------------------------------------------------
// Purpose: A Technology
//-----------------------------------------------------------------------------
class CBaseTechnology
{
public:
// Constructions
CBaseTechnology( void );
virtual ~CBaseTechnology( void );
// Data read from the data file
virtual void SetName( const char *pName );
virtual void SetPrintName( const char *pName );
virtual void SetDescription( const char *pDesc );
virtual void SetButtonName( const char *pName );
virtual void SetLevel( int iLevel );
virtual void SetCost( float fResourceCost );
virtual void SetClassResultSound( int iClass, const char *pSound );
virtual void SetClassResultSound( int iClass, int iSound );
virtual void SetClassResultDescription( int iClass, const char *pDesc );
virtual void SetClassResultAssociateWeapons( int iClass, bool associate );
virtual void AddContainedTechnology( const char *pszTech );
virtual void AddDependentTechnology( const char *pszTech );
// Returns true if the specified class is affected by this technology, or any contained techs
virtual bool AffectsClass( int iClass );
virtual bool IsClassUpgrade( void );
virtual bool IsVehicle( void );
virtual bool IsTechLevelUpgrade( void );
virtual bool IsResourceTech( void );
virtual void SetHidden( bool hide );
virtual bool IsHidden( void );
// Used by client to avoid giving you the same hint twice for a technology
// during a game/session
virtual void ResetHintsGiven( void );
virtual bool GetHintsGiven( int type );
virtual void SetHintsGiven( int type, bool given );
// Returns the level to which this technology belongs
virtual int GetLevel( void );
// Returns the internal name of the technology ( no spaces )
virtual const char *GetName( void );
// Returns the printable name of the technology
virtual const char *GetPrintName( void );
// Returns the button name of the technology;
virtual const char *GetButtonName( void );
// Returns the non-class specific description of this technology
virtual const char *GetDescription( int iPlayerClass );
// Returns the sound to play for this technology
virtual const char *GetSoundFile( int iClass );
virtual int GetSound( int iClass );
// Set availability of the technology for the specified team
virtual void SetAvailable( bool state );
// Returns true if the team has the technology
virtual int GetAvailable( void );
// Zero out all preference/voting by players
virtual void ZeroPreferences( void );
// Add one to the preference count for this technology for the specified team
virtual void IncrementPreferences( void );
// Retrieve the number of player's who want to vote for this technology
virtual int GetPreferenceCount( void );
// Retrieves the cost of purchasing the technology (doesn't factor in the resource levels)
float GetResourceCost( void );
// Retrieves the current amount of resources spent on the technology
float GetResourceLevel( void );
// Sets a resource level to an amount
void SetResourceLevel( float flResourceLevel );
// Spends resources on buying this technology
bool IncreaseResourceLevel( float flResourcesToSpend );
// Figure out my overall owned percentage
void RecalculateOverallLevel( void );
float GetOverallLevel( void );
void ForceComplete( void );
// Goal technologies ( Techs related to a team's goal in a map )
bool IsAGoalTechnology( void );
void SetGoalTechnology( bool bGoal );
// Check if class wants to enumerate weapon associations
bool GetAssociateWeaponsForClass( int iClass );
// Weapon associatations
int GetNumWeaponAssociations( void );
char const *GetAssociatedWeapon( int index );
void AddAssociatedWeapon( const char *weaponname );
// Contained Technology access
int GetNumberContainedTechs( void );
const char *GetContainedTechName( int iTech );
void SetContainedTech( int iTech, CBaseTechnology *pTech );
// Dependent Technology access
int GetNumberDependentTechs( void );
const char *GetDependentTechName( int iTech );
void SetDependentTech( int iTech, CBaseTechnology *pTech );
bool DependsOn( CBaseTechnology *pTech );
bool HasInactiveDependencies( void );
// Dirty bit, used for fast knowledge of when to resend techs
bool IsDirty( void );
void SetDirty( bool bDirty );
// Evil, Game DLL only code
#ifndef CLIENT_DLL
// The technology has been acquired by the team.
virtual void AddTechnologyToTeam( CTFTeam *pTeam );
// The technology has just been acquired, for each player on the acquiring team
// ask the technology to add any necessary weapons/items/abilities/modifiers, etc.
virtual void AddTechnologyToPlayer( CBaseTFPlayer *player );
// A technology watcher entity wants to register as a watcher for this technology
virtual void RegisterWatcher( CInfoCustomTechnology *pWatcher );
CUtlVector< CInfoCustomTechnology* > m_aWatchers;
#endif
void UpdateWatchers( void );
// Hud Data
void SetActive( bool state );
bool GetActive( void );
void SetPreferred( bool state );
bool GetPreferred( void );
void SetVoters( int voters );
int GetVoters( void );
void SetTextureName( const char *texture );
const char *GetTextureName( void );
void SetTextureId( int id );
int GetTextureId( void );
private:
// Name of the technology. Used to identify it in code.
char m_pszName[ TECHNOLOGY_NAME_LENGTH ];
// Print name of the technology. Used to print the name of this technology to users.
char m_pszPrintName[ TECHNOLOGY_PRINTNAME_LENGTH ];
// Button name of technology in the tech tree
char m_szButtonName[ TECHNOLOGY_BUTTONNAME_LENGTH ];
// Description of the technology
char m_pszDescription[ TECHNOLOGY_DESC_LENGTH ];
// Level to which the technology belongs
int m_nTechLevel;
// Sound played to the entire team when this technology is received
char m_pszTeamSoundFile[ TECHNOLOGY_SOUNDFILENAME_LENGTH ];
int m_iTeamSound;
// Results for this technology when it's achieved, on a per-class basis
classresult_t m_ClassResults[ TFCLASS_CLASS_COUNT ];
// Resource costs
float m_fResourceCost;
// Resource levels (amount of resource spent on the technology so far)
float m_fResourceLevel;
float m_flOverallOwnedPercentage;
// Technologies contained within this one
char m_apszContainedTechs[ MAX_CONTAINED_TECHNOLOGIES ][ TECHNOLOGY_NAME_LENGTH ];
int m_iContainedTechs;
CBaseTechnology *m_pContainedTechs[ MAX_CONTAINED_TECHNOLOGIES ];
// Technologies this tech depends on
char m_apszDependentTechs[ MAX_DEPENDANT_TECHNOLOGIES ][ TECHNOLOGY_NAME_LENGTH ];
int m_iDependentTechs;
CBaseTechnology *m_pDependentTechs[ MAX_DEPENDANT_TECHNOLOGIES ];
// Weapon association
int m_nNumWeaponAssociations;
char m_rgszWeaponAssociation[ MAX_ASSOCIATED_WEAPONS ][ TECHNOLOGY_WEAPONNAME_LENGTH ];
// Does the team have access to the technology
bool m_bAvailable;
// Is this a "placeholder" tech that shouldn't show up in the real tree
bool m_bHidden;
CUtlVector< int > m_HintsGiven;
// Count of how many team members voted for this technology for spending resources
int m_nPreferenceCount;
bool m_bGoalTechnology; // True if this tech's related to a team's goal in the current map
bool m_bClassUpgrade; // True if the tech unlocks a new class
bool m_bVehicle; // True if the tech unlocks a vehicle
bool m_bTechLevelUpgrade; // True if the tech unlocks a new tech level
bool m_bResourceTech; // True if related to resource gathering
// Dirty bit, used for fast knowledge of when to resend techs
bool m_bDirty;
// Hud data
bool m_bActive;
bool m_bPreferred;
int m_nVoters;
int m_nTextureID;
char m_szTextureName[ TECHNOLOGY_TEXTURENAME_LENGTH ];
};
//-----------------------------------------------------------------------------
// Purpose: The Technology Tree.
//-----------------------------------------------------------------------------
class CTechnologyTree
{
public:
// Construction
CTechnologyTree( IFileSystem* pFileSystem, int nTeamNumber );
virtual ~CTechnologyTree( void );
// Startup/shutdown
void Shutdown( void );
// Accessors
void AddTechnologyFile( IFileSystem* pFileSystem, int nTeamNumber, char *sFileName );
void LinkContainedTechnologies( void );
void LinkDependentTechnologies( void );
int GetIndex( CBaseTechnology *pItem ); // Get the index of the specified item
CBaseTechnology *GetTechnology( int index );
CBaseTechnology *GetTechnology( const char *pName );
float GetPercentageOfTechLevelOwned( int iTechLevel );
// Size of list
int GetNumberTechnologies( void );
// Local client's preferred item
void SetPreferredTechnology( CBaseTechnology *pItem );
CBaseTechnology *GetPreferredTechnology( void );
// Preference handling
void ClearPreferenceCount( void );
void IncrementPreferences( void );
int GetPreferenceCount( void ); // Get the number of players who've voted on techs
CBaseTechnology *GetDesiredTechnology( int iDesireLevel );
// Growable list of technologies
CUtlVector< CBaseTechnology * > m_Technologies;
int m_nPreferenceCount;
};
#endif // TECHTREE_H
+183
View File
@@ -0,0 +1,183 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Shared code that parse the Technology Tree on the client & server.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "utlvector.h"
#include "tf_shareddefs.h"
#include "techtree.h"
#include <KeyValues.h>
#include "filesystem.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Purpose: Parse a class result chunk inside a technology keyvalue
//-----------------------------------------------------------------------------
void ParseClassResult( CBaseTechnology *pTechnology, KeyValues *pkvResult, int iClass )
{
if ( !pkvResult )
return;
// All is a special case, used by general technologies
if ( iClass == TFCLASS_CLASS_COUNT )
{
for (int i = TFCLASS_RECON; i < TFCLASS_CLASS_COUNT; i++)
{
pTechnology->SetClassResultSound( i, pkvResult->GetString( "sound", NULL ) );
pTechnology->SetClassResultDescription( i, pkvResult->GetString( "description", NULL ) );
pTechnology->SetClassResultAssociateWeapons( i, pkvResult->GetInt( "associateweapons", 0 ) ? true : false );
}
}
else
{
pTechnology->SetClassResultSound( iClass, pkvResult->GetString( "sound", NULL ) );
pTechnology->SetClassResultDescription( iClass, pkvResult->GetString( "description", NULL ) );
pTechnology->SetClassResultAssociateWeapons( iClass, pkvResult->GetInt( "associateweapons", 0 ) ? true : false );
}
}
//-----------------------------------------------------------------------------
// Purpose: Parse a technology from a keyvalues chunk in the data file
//-----------------------------------------------------------------------------
void ParseTechnology( CBaseTechnology *pTechnology, KeyValues *pkvTech )
{
// Get the general data
pTechnology->SetName( pkvTech->GetName() );
pTechnology->SetPrintName( pkvTech->GetString( "printname", "" ) );
// Use the print name if no button name specified
pTechnology->SetButtonName( pkvTech->GetString( "buttonname", pTechnology->GetPrintName() ) );
pTechnology->SetDescription( pkvTech->GetString( "description", "" ) );
pTechnology->SetTextureName( pkvTech->GetString( "texture", "" ) );
pTechnology->SetLevel( pkvTech->GetInt( "level", 0 ) );
pTechnology->SetGoalTechnology( pkvTech->GetInt( "goal", 0 ) > 0 );
pTechnology->SetHidden( pkvTech->GetInt( "hidden", 0 ) != 0 );
// Retrieve weapon associations
KeyValues *pkvWeaponAssociations = pkvTech->FindKey( "associated_weapons" );
if ( pkvWeaponAssociations )
{
KeyValues *pkvWA = pkvWeaponAssociations->GetFirstSubKey();
while ( pkvWA )
{
const char *weaponname = pkvWA->GetString();
if ( weaponname && weaponname[ 0 ] )
{
pTechnology->AddAssociatedWeapon( weaponname );
}
pkvWA = pkvWA->GetNextKey();
}
}
// Get the cost
pTechnology->SetCost( pkvTech->GetFloat( "resourcecost", 0.0 ) );
// Get the class results
KeyValues *pkvClassResults = pkvTech->FindKey( "class_results" );
if ( pkvClassResults )
{
// Try and get each class result
for ( int iClass=0; iClass < TFCLASS_CLASS_COUNT; iClass++ )
{
ParseClassResult( pTechnology, pkvClassResults->FindKey( GetTFClassInfo( iClass )->m_pClassName ), iClass );
}
ParseClassResult( pTechnology, pkvClassResults->FindKey( "all" ), TFCLASS_CLASS_COUNT );
}
// Get any technologies contained within this one
KeyValues *pkvTechnologies = pkvTech->FindKey( "technologies" );
if ( pkvTechnologies )
{
KeyValues *pkvTechnology = pkvTechnologies->GetFirstSubKey();
int iContainedTechs = 0;
while ( pkvTechnology )
{
if ( iContainedTechs >= MAX_CONTAINED_TECHNOLOGIES )
break;
pTechnology->AddContainedTechnology( pkvTechnology->GetString() );
iContainedTechs++;
pkvTechnology = pkvTechnology->GetNextKey();
}
}
// Get any dependencies for this tech
KeyValues *pkvDependencies = pkvTech->FindKey( "dependencies" );
if ( pkvDependencies )
{
KeyValues *pkvTechnology = pkvDependencies->GetFirstSubKey();
int iDependentTechs = 0;
while ( pkvTechnology )
{
if ( iDependentTechs >= MAX_DEPENDANT_TECHNOLOGIES )
break;
pTechnology->AddDependentTechnology( pkvTechnology->GetString() );
iDependentTechs++;
pkvTechnology = pkvTechnology->GetNextKey();
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Parse the technology tree file and dump the data into the utlvector list
//-----------------------------------------------------------------------------
bool ParseTechnologyFile( CUtlVector< CBaseTechnology * > &pTechnologyList, IFileSystem* filesystem, int nTeamNumber, char *sFileName )
{
// Open the technology tree datafile
KeyValues *pkvTechTreeFile = new KeyValues( "TechTreeDataFile" );
if ( pkvTechTreeFile->LoadFromFile( filesystem, sFileName, "GAME" ) == false )
return false;
// Parse the list of techs
KeyValues *pkvTech = pkvTechTreeFile->GetFirstSubKey();
while ( pkvTech )
{
// Reached the maximum number of techs allowed?
if ( pTechnologyList.Size() >= MAX_TECHNOLOGIES )
{
pkvTechTreeFile->deleteThis();
return false;
}
// Create the technology
CBaseTechnology *pTechnology = NULL;
int nTeamTech = pkvTech->GetInt( "team", 0 );
if ((nTeamTech == 0) || (nTeamTech == nTeamNumber))
{
pTechnology = new CBaseTechnology();
ParseTechnology( pTechnology, pkvTech );
// Find out if it's already in the list
for ( int i = 0; i < pTechnologyList.Size(); i++ )
{
if ( !strcmp(pTechnologyList[i]->GetName(), pTechnology->GetName() ) )
{
// Found it in the tree already, so delete and continue
delete pTechnology;
pTechnology = NULL;
break;
}
}
}
// If we haven't deleted it, add it to the list
if ( pTechnology )
{
pTechnologyList.AddToTail( pTechnology );
}
pkvTech = pkvTech->GetNextKey();
}
pkvTechTreeFile->deleteThis();
return true;
}
File diff suppressed because it is too large Load Diff
+126
View File
@@ -0,0 +1,126 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef TF_GAMEMOVEMENT_H
#define TF_GAMEMOVEMENT_H
#ifdef _WIN32
#pragma once
#endif
#include "gamemovement.h"
#include "tf_movedata.h"
#include "movevars_shared.h"
class CBaseTFPlayer;
class CBasePlayer;
//-----------------------------------------------------------------------------
// This class is the GameMovement class for team fortress and overrides
// some of the default behavior.
//-----------------------------------------------------------------------------
class CTFGameMovement : public CGameMovement
{
// Team Fortress 2 game movement base class.
DECLARE_CLASS( CTFGameMovement, CGameMovement );
public:
// CGameMovement public overrides.
virtual void PlayerMove( void );
virtual void ProcessClassMovement( CBaseTFPlayer *pPlayer, CTFMoveData *pTFMoveData ) {}
// Utility
inline CTFMoveData *TFMove( void ) { return static_cast<CTFMoveData*>( mv ); }
protected:
// Player movement functions.
virtual bool PrePlayerMove( void );
virtual void HandlePlayerMove( void );
virtual void PostPlayerMove( void );
// Player pre-movement functions.
virtual int CheckStuck( void );
virtual void UpdateTimers( void );
bool CheckDeath( void );
virtual void SetupViewAngles( void );
virtual void HandleDuck( void );
virtual void FinishUnDuck( void );
virtual void SetupSpeed( void );
void SpeedCrop( void );
void Accelerate( Vector& wishdir, float wishspeed, float accel);
void AccelerateWithoutMomentum( Vector& wishdir, float wishspeed, float accel);
virtual float GetAirSpeedCap( void );
float CalcGravityAdjustment( const Vector &wishdir );
void HandleLadder( void );
virtual void CategorizePosition( void );
virtual bool CheckJumpButton( void );
virtual void PlayStepSound( surfacedata_t *psurface, float fvol, bool force );
// Should the step sound play?
virtual bool ShouldPlayStepSound( surfacedata_t *psurface, float fvol );
// Specific movement functions.
virtual void FullWalkMove();
virtual void WalkMove( void );
virtual void _WalkMove( void );
void WalkMove2( void );
void AirMove( void );
virtual int TryPlayerMove( Vector *pFirstDest=NULL, trace_t *pFirstTrace=NULL );
int TryPlayerMove2( void );
void ResolveStanding( void );
void TryStanding( void );
bool ChargeMove( void );
bool StunMove( void );
void EndCharge( void );
virtual void HandleDuckingSpeedCrop( void );
// Figures out how the constraint should slow us down
float ComputeConstraintSpeedFactor( void );
// Movement helpers.
virtual bool CalcWishVelocityAndPosition( Vector &vWishPos, Vector &vWishDir, float &flWishSpeed );
inline void TracePlayerBBoxWithStep( const Vector &vStart, const Vector &vEnd, unsigned int fMask, int collisionGroup, trace_t &trace );
// Momentum
void SetMomentumList( float flValue = 1.0f );
void AddToMomentumList( float flValue );
float GetMomentum( void );
// Collision response functions.
bool CollisionResponseGeneric( const trace_t &trace, int &nBlocked );
void CollisionResponseStuck( void );
void CollisionResponseNone( const trace_t &trace );
bool RedirectGroundVelocity( const trace_t &trace );
bool RedirectAirVelocity( const trace_t &trace );
inline int BlockerType( const Vector &vImpactNormal );
protected:
// Per movement collision data cache(s)
Vector m_vecGroundNormal;
Vector m_vecOriginalVelocity;
int m_nLanding;
enum { MAX_IMPACT_PLANES = 5 };
int m_nImpactPlaneCount;
Vector m_aImpactPlaneNormals[MAX_IMPACT_PLANES];
enum { MOVEMENTSTACK_MAXSIZE = 10 };
struct MovementStackData_t
{
Vector m_vecPosition;
Vector m_vecVelocity;
Vector m_vecImpactNormal;
};
int m_nMovementStackSize;
MovementStackData_t m_aMovementStack[MOVEMENTSTACK_MAXSIZE];
};
#endif // TF_GAMEMOVEMENT_H
@@ -0,0 +1,76 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Auto Repair
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "tf_gamemovement_chooser.h"
#include "tf_movedata.h"
static CTFGameMovementChooser g_GameMovement;
IGameMovement *g_pGameMovement = ( IGameMovement* )&g_GameMovement;
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CTFGameMovementChooser::CTFGameMovementChooser()
{
// Allocate memory for a movement type for each class (0 = undecided)
m_Movements.SetSize( TFCLASS_CLASS_COUNT );
// NOTE: the order here matches the enum order in tf_shareddefs.h
m_Movements[TFCLASS_RECON] = &m_ReconMovement;
m_Movements[TFCLASS_COMMANDO] = &m_CommandoMovement;
m_Movements[TFCLASS_MEDIC] = &m_MedicMovement;
m_Movements[TFCLASS_DEFENDER] = &m_DefenderMovement;
m_Movements[TFCLASS_SNIPER] = &m_SniperMovement;
m_Movements[TFCLASS_SUPPORT] = &m_SupportMovement;
m_Movements[TFCLASS_ESCORT] = &m_EscortMovement;
m_Movements[TFCLASS_SAPPER] = &m_SapperMovement;
m_Movements[TFCLASS_INFILTRATOR] = &m_InfiltratorMovement;
m_Movements[TFCLASS_PYRO] = &m_PyroMovement;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFGameMovementChooser::ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMoveData )
{
// Convert CMoveData to CTFMoveData
CTFMoveData *pTFMoveData = static_cast<CTFMoveData*>( pMoveData );
// Cache the current class id
m_nClassID = pTFMoveData->m_nClassID;
// Player class movement. (If possible)
if ( m_nClassID != TFCLASS_UNDECIDED )
{
m_Movements[m_nClassID]->ProcessClassMovement( (CBaseTFPlayer *)pPlayer, pTFMoveData );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const Vector &CTFGameMovementChooser::GetPlayerMins( bool ducked ) const
{
// Player class mins.
return m_Movements[m_nClassID]->GetPlayerMins( ducked );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const Vector &CTFGameMovementChooser::GetPlayerMaxs( bool ducked ) const
{
return m_Movements[m_nClassID]->GetPlayerMins( ducked );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const Vector &CTFGameMovementChooser::GetPlayerViewOffset( bool ducked ) const
{
return m_Movements[m_nClassID]->GetPlayerViewOffset( ducked );
}
+69
View File
@@ -0,0 +1,69 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Auto Repair
//
// $NoKeywords: $
//=============================================================================//
#ifndef TF_GAMEMOVEMENT_CHOOSER_H
#define TF_GAMEMOVEMENT_CHOOSER_H
#ifdef _WIN32
#pragma once
#endif
#include "utlvector.h"
#include "IGameMovement.h"
#include "tf_gamemovement.h"
#include "tf_gamemovement_recon.h"
#include "tf_gamemovement_commando.h"
#include "tf_gamemovement_medic.h"
#include "tf_gamemovement_defender.h"
#include "tf_gamemovement_sniper.h"
#include "tf_gamemovement_support.h"
#include "tf_gamemovement_escort.h"
#include "tf_gamemovement_sapper.h"
#include "tf_gamemovement_infiltrator.h"
#include "tf_gamemovement_pyro.h"
//=============================================================================
//
// Team Fortess Game Movement Chooser
//
class CTFGameMovementChooser : public IGameMovement
{
public:
CTFGameMovementChooser();
// Process the current movement command
virtual void ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMoveData );
// Allows other parts of the engine to find out the normal and ducked player bbox sizes
virtual const Vector &GetPlayerMins( bool ducked ) const;
virtual const Vector &GetPlayerMaxs( bool ducked ) const;
virtual const Vector &GetPlayerViewOffset( bool ducked ) const;
protected:
// Cache the current class id.
int m_nClassID;
// Create the class specific movement singletons.
CTFGameMovementRecon m_ReconMovement;
CTFGameMovementCommando m_CommandoMovement;
CTFGameMovementMedic m_MedicMovement;
CTFGameMovementDefender m_DefenderMovement;
CTFGameMovementSniper m_SniperMovement;
CTFGameMovementSupport m_SupportMovement;
CTFGameMovementEscort m_EscortMovement;
CTFGameMovementSapper m_SapperMovement;
CTFGameMovementInfiltrator m_InfiltratorMovement;
CTFGameMovementPyro m_PyroMovement;
// Vector of class specific movements (for quick addressing).
CUtlVector<CTFGameMovement*> m_Movements;
};
extern IGameMovement *g_pGameMovement;
#endif // TF_GAMEMOVEMENT_CHOOSER_H
@@ -0,0 +1,424 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Auto Repair
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "in_buttons.h"
#include "tf_gamemovement_commando.h"
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CTFGameMovementCommando::CTFGameMovementCommando()
{
m_pCommandoData = NULL;
m_vStandMins = COMMANDOCLASS_HULL_STAND_MIN;
m_vStandMaxs = COMMANDOCLASS_HULL_STAND_MAX;
m_vStandViewOffset = COMMANDOCLASS_VIEWOFFSET_STAND;
m_vDuckMins = COMMANDOCLASS_HULL_DUCK_MIN;
m_vDuckMaxs = COMMANDOCLASS_HULL_DUCK_MAX;
m_vDuckViewOffset = COMMANDOCLASS_VIEWOFFSET_DUCK;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFGameMovementCommando::ProcessClassMovement( CBaseTFPlayer *pPlayer, CTFMoveData *pTFMoveData )
{
// Get the class specific data from the TFMoveData structure
Assert( PlayerClassCommandoData_t::PLAYERCLASS_ID == pTFMoveData->m_nClassID );
// Is this how I want to handle this???
// m_pCommandoData = &pTFMoveData->CommandoData();
// to test pass it through!!
BaseClass::ProcessMovement( (CBasePlayer *)pPlayer, static_cast<CMoveData*>( pTFMoveData ) );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const Vector &CTFGameMovementCommando::GetPlayerMins( bool bDucked ) const
{
return bDucked ? m_vDuckMins : m_vStandMins;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const Vector &CTFGameMovementCommando::GetPlayerMaxs( bool bDucked ) const
{
return bDucked ? m_vDuckMaxs : m_vStandMaxs;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const Vector &CTFGameMovementCommando::GetPlayerViewOffset( bool bDucked ) const
{
return bDucked ? m_vDuckViewOffset : m_vStandViewOffset;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CTFGameMovementCommando::CheckDoubleTapForward( void )
{
// Check for other movement keys!!!
if ( ( TFMove()->m_nButtons & IN_MOVELEFT ) || ( TFMove()->m_nButtons & IN_MOVERIGHT ) ||
( TFMove()->m_nButtons & IN_BACK ) || ( TFMove()->m_nButtons & IN_JUMP ) )
{
TFMove()->CommandoData().m_flDoubleTapForwardTime = COMMANDO_TIME_INVALID;
return false;
}
if ( ( TFMove()->m_nButtons & IN_FORWARD ) && !( TFMove()->m_nOldButtons & IN_FORWARD ) )
{
// Start timer.
if ( TFMove()->CommandoData().m_flDoubleTapForwardTime == COMMANDO_TIME_INVALID )
{
TFMove()->CommandoData().m_flDoubleTapForwardTime = COMMANDO_DOUBLETAP_TIME;
}
// Check for a double tap.
else
{
if ( TFMove()->CommandoData().m_flDoubleTapForwardTime > 0.0f )
return true;
}
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFGameMovementCommando::CheckBullRush( void )
{
// Don't check for bullrush if we are dead!
if ( IsDead() )
return;
// Don't go into bullrush if noclipping
if ( player->GetMoveType() == MOVETYPE_NOCLIP )
return;
// Cannot bullrush inside of a vehicle (manned <gun>).
#if !defined (CLIENT_DLL)
IServerVehicle *pVehicle = player->GetVehicle();
if ( pVehicle )
return;
#else
IClientVehicle *pVehicle = player->GetVehicle();
if ( pVehicle )
return;
#endif
if ( CheckDoubleTapForward() && !TFMove()->CommandoData().m_bBullRush &&
TFMove()->CommandoData().m_bCanBullRush && !( player->GetFlags() & FL_DUCKING ) )
{
// Set in a bull rush.
TFMove()->CommandoData().m_bBullRush = true;
// Set timers.
TFMove()->CommandoData().m_flBullRushTime = COMMANDO_BULLRUSH_TIME;
// Lock view/move angles
Vector vBullrushDir;
AngleVectors( TFMove()->m_vecViewAngles, &vBullrushDir, NULL, NULL );
TFMove()->CommandoData().m_vecBullRushDir = vBullrushDir;
TFMove()->CommandoData().m_vecBullRushViewDir = TFMove()->m_vecViewAngles;
TFMove()->CommandoData().m_vecBullRushViewGoalDir.Init();
TFMove()->CommandoData().m_vecBullRushViewGoalDir.SetY( TFMove()->m_vecViewAngles.y );
// Set movement type.
player->SetMoveType( (MoveType_t)COMMANDO_MOVETYPE_BULLRUSH );
player->SetMoveCollide( MOVECOLLIDE_DEFAULT );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CTFGameMovementCommando::PrePlayerMove( void )
{
// Assume we don't touch anything (Reset the touch list).
MoveHelper()->ResetTouchList();
// Check to see if we are stuck.
if ( CheckStuck() )
return false;
CheckBullRush();
// Update (reduce) movement timers.
UpdateTimers();
// Check to see if the player is dead and setup death data, otherwise setup
// the players view angles.
if ( !CheckDeath() )
{
SetupViewAngles();
}
// Handle ducking.
HandleDuck();
// Handle ladder.
HandleLadder();
// Categorize the player's position.
CategorizePosition();
// Calculate the player's movement speed (has to happen after categorize position)
SetupSpeed();
// Update our stepping sound (based on the player's location).
player->UpdateStepSound( m_pSurfaceData, mv->m_vecAbsOrigin, mv->m_vecVelocity );
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFGameMovementCommando::HandlePlayerMove( void )
{
// Handle the specific bull rush movement type.
if ( player->GetMoveType() == COMMANDO_MOVETYPE_BULLRUSH )
{
BullRushMove();
return;
}
// Let the default TF2 player movement code handle the move.
BaseClass::HandlePlayerMove();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFGameMovementCommando::HandleDuck( void )
{
if ( player->GetMoveType() == COMMANDO_MOVETYPE_BULLRUSH )
return;
BaseClass::HandleDuck();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFGameMovementCommando::UpdateTimers( void )
{
BaseClass::UpdateTimers();
CTFMoveData *pMoveData = TFMove();
if ( !pMoveData )
return;
float frame_msec = 1000.0f * gpGlobals->frametime;
// Decrement the bull rush time.
if ( pMoveData->CommandoData().m_flBullRushTime != COMMANDO_TIME_INVALID )
{
if ( pMoveData->CommandoData().m_flBullRushTime > 0.0f )
{
pMoveData->CommandoData().m_flBullRushTime -= frame_msec;
}
else
{
TFMove()->CommandoData().m_bBullRush = false;
TFMove()->CommandoData().m_flBullRushTime = COMMANDO_TIME_INVALID;
player->SetMoveType( MOVETYPE_WALK );
player->SetMoveCollide( MOVECOLLIDE_DEFAULT );
}
}
if ( pMoveData->CommandoData().m_flDoubleTapForwardTime != COMMANDO_TIME_INVALID )
{
if ( pMoveData->CommandoData().m_flDoubleTapForwardTime > 0.0f )
{
pMoveData->CommandoData().m_flDoubleTapForwardTime -= frame_msec;
}
else
{
pMoveData->CommandoData().m_flDoubleTapForwardTime = COMMANDO_TIME_INVALID;
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFGameMovementCommando::SetupViewAngles( void )
{
BaseClass::SetupViewAngles();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFGameMovementCommando::SetupSpeed( void )
{
BaseClass::SetupSpeed();
if ( player->GetMoveType() == COMMANDO_MOVETYPE_BULLRUSH )
{
mv->m_flMaxSpeed = sv_maxspeed.GetFloat();
// Slow down by the speed factor
if (m_pSurfaceData)
{
mv->m_flMaxSpeed *= m_pSurfaceData->game.maxSpeedFactor;
}
mv->m_flForwardMove = TFMove()->m_flClientMaxSpeed * 4.0f;
mv->m_flUpMove = 0.0f;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CTFGameMovementCommando::CalcWishVelocityAndPosition( Vector &vWishPos, Vector &vWishDir, float &flWishSpeed )
{
//
// Determine the movement angles.
//
Vector vForward, vRight, vUp;
if ( player->GetMoveType() == COMMANDO_MOVETYPE_BULLRUSH )
{
vForward = TFMove()->CommandoData().m_vecBullRushDir;
// Cross the bullrush direction with the z-axis to get the right vector.
CrossProduct( vForward, Vector( 0.0f, 0.0f, 1.0f ), vRight );
vUp.Init();
}
else
{
AngleVectors( mv->m_vecViewAngles, &vForward, &vRight, &vUp );
//
// Zero out the z component of the movement vectors and renormalize.
//
vForward.z = 0.0f;
VectorNormalize( vForward );
vRight.z = 0.0f;
VectorNormalize( vRight );
}
//
// Determine the xy parts of the velocity.
//
Vector vWishVel( 0.0f, 0.0f, 0.0f );
for ( int axis = 0; axis < 2; axis++ )
{
vWishVel[axis] = ( vForward[axis] * mv->m_flForwardMove ) +
( vRight[axis] * mv->m_flSideMove );
}
vWishVel.z = 0.0f;
//
// Componentize the velocity into direction and speed.
//
VectorCopy( vWishVel, vWishDir );
flWishSpeed = VectorNormalize( vWishDir );
if ( flWishSpeed > mv->m_flMaxSpeed )
{
VectorScale( vWishVel, ( mv->m_flMaxSpeed / flWishSpeed ), vWishVel );
flWishSpeed = mv->m_flMaxSpeed;
}
//
// Accelerate (in the plane).
//
mv->m_vecVelocity.z = 0.0f;
Accelerate( vWishDir, flWishSpeed, sv_accelerate.GetFloat() );
mv->m_vecVelocity.z = 0.0f;
// Add in any base velocity (from conveyers, etc.) to the current velocity.
VectorAdd( mv->m_vecVelocity, player->GetBaseVelocity(), mv->m_vecVelocity );
//
// Stop the player (zero out velocity) if the player's speed is below a
// given threshold.
//
float flSpeed = VectorLength( mv->m_vecVelocity );
if ( flSpeed < 1.0f /*SPEED_STOP_THRESHOLD*/ )
{
mv->m_vecVelocity.Init();
return false;
}
//
// Calculate the wish position.
//
vWishPos.x = mv->m_vecAbsOrigin.x + ( mv->m_vecVelocity.x * gpGlobals->frametime );
vWishPos.y = mv->m_vecAbsOrigin.y + ( mv->m_vecVelocity.y * gpGlobals->frametime );
vWishPos.z = mv->m_vecAbsOrigin.z;
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFGameMovementCommando::BullRushMove( void )
{
CTFMoveData *pMoveData = TFMove();
if ( !pMoveData )
return;
// Ignoring water for now!!!!
StartGravity();
// Fricion is handled before we add in any base velocity. That way, if we are on a conveyor,
// we don't slow when standing still, relative to the conveyor.
if (player->GetGroundEntity() != NULL)
{
mv->m_vecVelocity[2] = 0.0;
Friction();
}
// Make sure velocity is valid.
CheckVelocity();
if (player->GetGroundEntity() != NULL)
{
WalkMove2();
}
else
{
AirMove(); // Take into account movement when in air.
}
// Set final flags.
CategorizePosition();
// Now pull the base velocity back out. Base velocity is set if you are on a moving object, like
// a conveyor (or maybe another monster?)
VectorSubtract (mv->m_vecVelocity, player->GetBaseVelocity(), mv->m_vecVelocity );
// Make sure velocity is valid.
CheckVelocity();
// Add any remaining gravitational component.
FinishGravity();
// If we are on ground, no downward velocity.
if ( player->GetGroundEntity() != NULL )
{
mv->m_vecVelocity[2] = 0;
}
CheckFalling();
}
@@ -0,0 +1,64 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Auto Repair
//
// $NoKeywords: $
//=============================================================================//
#ifndef TF_GAMEMOVEMENT_COMMANDO_H
#define TF_GAMEMOVEMENT_COMMANDO_H
#ifdef _WIN32
#pragma once
#endif
#include "tf_gamemovement.h"
#include "tfclassdata_shared.h"
class CTFMoveData;
//=============================================================================
//
// Commando Game Movement Class
//
class CTFGameMovementCommando : public CTFGameMovement
{
public:
DECLARE_CLASS( CTFGameMovementCommando, CTFGameMovement );
CTFGameMovementCommando();
// Interface Implementation
void ProcessClassMovement( CBaseTFPlayer *pPlayer, CTFMoveData *pTFMoveData );
Vector const &GetPlayerMins( bool bDucked ) const;
Vector const &GetPlayerMaxs( bool bDucked ) const;
Vector const &GetPlayerViewOffset( bool bDucked ) const;
protected:
// TF2 movement overrides.
bool PrePlayerMove( void );
void HandlePlayerMove( void );
void HandleDuck( void );
void SetupViewAngles( void );
void UpdateTimers( void );
void SetupSpeed( void );
bool CalcWishVelocityAndPosition( Vector &vWishPos, Vector &vWishDir, float &flWishSpeed );
bool CheckDoubleTapForward( void );
void CheckBullRush( void );
void BullRushMove( void );
PlayerClassCommandoData_t *m_pCommandoData;
Vector m_vStandMins;
Vector m_vStandMaxs;
Vector m_vStandViewOffset;
Vector m_vDuckMins;
Vector m_vDuckMaxs;
Vector m_vDuckViewOffset;
};
#endif // TF_GAMEMOVEMENT_COMMANDO_H
@@ -0,0 +1,65 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Auto Repair
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "tf_gamemovement_defender.h"
#include "tf_movedata.h"
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CTFGameMovementDefender::CTFGameMovementDefender()
{
m_pDefenderData = NULL;
m_vStandMins = DEFENDERCLASS_HULL_STAND_MIN;
m_vStandMaxs = DEFENDERCLASS_HULL_STAND_MAX;
m_vStandViewOffset = DEFENDERCLASS_VIEWOFFSET_STAND;
m_vDuckMins = DEFENDERCLASS_HULL_DUCK_MIN;
m_vDuckMaxs = DEFENDERCLASS_HULL_DUCK_MAX;
m_vDuckViewOffset = DEFENDERCLASS_VIEWOFFSET_DUCK;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFGameMovementDefender::ProcessClassMovement( CBaseTFPlayer *pPlayer, CTFMoveData *pTFMoveData )
{
// Get the class specific data from the TFMoveData structure
Assert( PlayerClassDefenderData_t::PLAYERCLASS_ID == pTFMoveData->m_nClassID );
m_pDefenderData = &pTFMoveData->DefenderData();
// to test pass it through!!
BaseClass::ProcessMovement( (CBasePlayer *)pPlayer, static_cast<CMoveData*>( pTFMoveData ) );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const Vector &CTFGameMovementDefender::GetPlayerMins( bool bDucked ) const
{
return bDucked ? m_vDuckMins : m_vStandMins;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const Vector &CTFGameMovementDefender::GetPlayerMaxs( bool bDucked ) const
{
return bDucked ? m_vDuckMaxs : m_vStandMaxs;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const Vector &CTFGameMovementDefender::GetPlayerViewOffset( bool bDucked ) const
{
return bDucked ? m_vDuckViewOffset : m_vStandViewOffset;
}
@@ -0,0 +1,50 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Auto Repair
//
// $NoKeywords: $
//=============================================================================//
#ifndef TF_GAMEMOVEMENT_DEFENDER_H
#define TF_GAMEMOVEMENT_DEFENDER_H
#ifdef _WIN32
#pragma once
#endif
#include "tf_gamemovement.h"
#include "tfclassdata_shared.h"
class CTFMoveData;
//=============================================================================
//
// Defender Game Movement Class
//
class CTFGameMovementDefender : public CTFGameMovement
{
DECLARE_CLASS( CTFGameMovementDefender, CTFGameMovement );
public:
CTFGameMovementDefender();
// Interface Implementation
// virtual void ProcessMovement( CTFMoveData *pTFMoveData );
virtual void ProcessClassMovement( CBaseTFPlayer *pPlayer, CTFMoveData *pTFMoveData );
virtual const Vector &GetPlayerMins( bool bDucked ) const;
virtual const Vector &GetPlayerMaxs( bool bDucked ) const;
virtual const Vector &GetPlayerViewOffset( bool bDucked ) const;
protected:
PlayerClassDefenderData_t *m_pDefenderData;
Vector m_vStandMins;
Vector m_vStandMaxs;
Vector m_vStandViewOffset;
Vector m_vDuckMins;
Vector m_vDuckMaxs;
Vector m_vDuckViewOffset;
};
#endif // TF_GAMEMOVEMENT_DEFENDER_H
@@ -0,0 +1,65 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Auto Repair
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "tf_gamemovement_escort.h"
#include "tf_movedata.h"
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CTFGameMovementEscort::CTFGameMovementEscort()
{
m_pEscortData = NULL;
m_vStandMins = ESCORTCLASS_HULL_STAND_MIN;
m_vStandMaxs = ESCORTCLASS_HULL_STAND_MAX;
m_vStandViewOffset = ESCORTCLASS_VIEWOFFSET_STAND;
m_vDuckMins = ESCORTCLASS_HULL_DUCK_MIN;
m_vDuckMaxs = ESCORTCLASS_HULL_DUCK_MAX;
m_vDuckViewOffset = ESCORTCLASS_VIEWOFFSET_DUCK;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFGameMovementEscort::ProcessClassMovement( CBaseTFPlayer *pPlayer, CTFMoveData *pTFMoveData )
{
// Get the class specific data from the TFMoveData structure
Assert( PlayerClassEscortData_t::PLAYERCLASS_ID == pTFMoveData->m_nClassID );
m_pEscortData = &pTFMoveData->EscortData();
// to test pass it through!!
BaseClass::ProcessMovement( (CBasePlayer *)pPlayer, static_cast<CMoveData*>( pTFMoveData ) );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const Vector &CTFGameMovementEscort::GetPlayerMins( bool bDucked ) const
{
return bDucked ? m_vDuckMins : m_vStandMins;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const Vector &CTFGameMovementEscort::GetPlayerMaxs( bool bDucked ) const
{
return bDucked ? m_vDuckMaxs : m_vStandMaxs;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const Vector &CTFGameMovementEscort::GetPlayerViewOffset( bool bDucked ) const
{
return bDucked ? m_vDuckViewOffset : m_vStandViewOffset;
}
+50
View File
@@ -0,0 +1,50 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Auto Repair
//
// $NoKeywords: $
//=============================================================================//
#ifndef TF_GAMEMOVEMENT_ESCORT_H
#define TF_GAMEMOVEMENT_ESCORT_H
#ifdef _WIN32
#pragma once
#endif
#include "tf_gamemovement.h"
#include "tfclassdata_shared.h"
class CTFMoveData;
//=============================================================================
//
// Escort Game Movement Class
//
class CTFGameMovementEscort : public CTFGameMovement
{
DECLARE_CLASS( CTFGameMovementEscort, CTFGameMovement );
public:
CTFGameMovementEscort();
// Interface Implementation
// virtual void ProcessMovement( CTFMoveData *pTFMoveData );
virtual void ProcessClassMovement( CBaseTFPlayer *pPlayer, CTFMoveData *pTFMoveData );
virtual const Vector &GetPlayerMins( bool bDucked ) const;
virtual const Vector &GetPlayerMaxs( bool bDucked ) const;
virtual const Vector &GetPlayerViewOffset( bool bDucked ) const;
protected:
PlayerClassEscortData_t *m_pEscortData;
Vector m_vStandMins;
Vector m_vStandMaxs;
Vector m_vStandViewOffset;
Vector m_vDuckMins;
Vector m_vDuckMaxs;
Vector m_vDuckViewOffset;
};
#endif // TF_GAMEMOVEMENT_ESCORT_H
@@ -0,0 +1,62 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Auto Repair
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "tf_gamemovement_infiltrator.h"
#include "tf_movedata.h"
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CTFGameMovementInfiltrator::CTFGameMovementInfiltrator()
{
m_pInfiltratorData = NULL;
m_vStandMins = INFILTRATORCLASS_HULL_STAND_MIN;
m_vStandMaxs = INFILTRATORCLASS_HULL_STAND_MAX;
m_vStandViewOffset = INFILTRATORCLASS_VIEWOFFSET_STAND;
m_vDuckMins = INFILTRATORCLASS_HULL_DUCK_MIN;
m_vDuckMaxs = INFILTRATORCLASS_HULL_DUCK_MAX;
m_vDuckViewOffset = INFILTRATORCLASS_VIEWOFFSET_DUCK;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFGameMovementInfiltrator::ProcessClassMovement( CBaseTFPlayer *pPlayer, CTFMoveData *pTFMoveData )
{
// Get the class specific data from the TFMoveData structure
Assert( PlayerClassInfiltratorData_t::PLAYERCLASS_ID == pTFMoveData->m_nClassID );
m_pInfiltratorData = &pTFMoveData->InfiltratorData();
// to test pass it through!!
BaseClass::ProcessMovement( (CBasePlayer *)pPlayer, static_cast<CMoveData*>( pTFMoveData ) );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const Vector &CTFGameMovementInfiltrator::GetPlayerMins( bool bDucked ) const
{
return bDucked ? m_vDuckMins : m_vStandMins;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const Vector &CTFGameMovementInfiltrator::GetPlayerMaxs( bool bDucked ) const
{
return bDucked ? m_vDuckMaxs : m_vStandMaxs;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const Vector &CTFGameMovementInfiltrator::GetPlayerViewOffset( bool bDucked ) const
{
return bDucked ? m_vDuckViewOffset : m_vStandViewOffset;
}
@@ -0,0 +1,50 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Auto Repair
//
// $NoKeywords: $
//=============================================================================//
#ifndef TF_GAMEMOVEMENT_INFILTRATOR_H
#define TF_GAMEMOVEMENT_INFILTRATOR_H
#ifdef _WIN32
#pragma once
#endif
#include "tf_gamemovement.h"
#include "tfclassdata_shared.h"
class CTFMoveData;
//=============================================================================
//
// Infiltrator Game Movement Class
//
class CTFGameMovementInfiltrator : public CTFGameMovement
{
DECLARE_CLASS( CTFGameMovementInfiltrator, CTFGameMovement );
public:
CTFGameMovementInfiltrator();
// Interface Implementation
// virtual void ProcessMovement( CTFMoveData *pTFMoveData );
virtual void ProcessClassMovement( CBaseTFPlayer *pPlayer, CTFMoveData *pTFMoveData );
virtual const Vector &GetPlayerMins( bool bDucked ) const;
virtual const Vector &GetPlayerMaxs( bool bDucked ) const;
virtual const Vector &GetPlayerViewOffset( bool bDucked ) const;
protected:
PlayerClassInfiltratorData_t *m_pInfiltratorData;
Vector m_vStandMins;
Vector m_vStandMaxs;
Vector m_vStandViewOffset;
Vector m_vDuckMins;
Vector m_vDuckMaxs;
Vector m_vDuckViewOffset;
};
#endif // TF_GAMEMOVEMENT_INFILTRATOR_H
+62
View File
@@ -0,0 +1,62 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Auto Repair
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "tf_gamemovement_medic.h"
#include "tf_movedata.h"
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CTFGameMovementMedic::CTFGameMovementMedic()
{
m_pMedicData = NULL;
m_vStandMins = MEDICCLASS_HULL_STAND_MIN;
m_vStandMaxs = MEDICCLASS_HULL_STAND_MAX;
m_vStandViewOffset = MEDICCLASS_VIEWOFFSET_STAND;
m_vDuckMins = MEDICCLASS_HULL_DUCK_MIN;
m_vDuckMaxs = MEDICCLASS_HULL_DUCK_MAX;
m_vDuckViewOffset = MEDICCLASS_VIEWOFFSET_DUCK;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFGameMovementMedic::ProcessClassMovement( CBaseTFPlayer *pPlayer, CTFMoveData *pTFMoveData )
{
// Get the class specific data from the TFMoveData structure
Assert( PlayerClassMedicData_t::PLAYERCLASS_ID == pTFMoveData->m_nClassID );
m_pMedicData = &pTFMoveData->MedicData();
// to test pass it through!!
BaseClass::ProcessMovement( (CBasePlayer *)pPlayer, static_cast<CMoveData*>( pTFMoveData ) );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const Vector &CTFGameMovementMedic::GetPlayerMins( bool bDucked ) const
{
return bDucked ? m_vDuckMins : m_vStandMins;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const Vector &CTFGameMovementMedic::GetPlayerMaxs( bool bDucked ) const
{
return bDucked ? m_vDuckMaxs : m_vStandMaxs;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const Vector &CTFGameMovementMedic::GetPlayerViewOffset( bool bDucked ) const
{
return bDucked ? m_vDuckViewOffset : m_vStandViewOffset;
}
+50
View File
@@ -0,0 +1,50 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Auto Repair
//
// $NoKeywords: $
//=============================================================================//
#ifndef TF_GAMEMOVEMENT_MEDIC_H
#define TF_GAMEMOVEMENT_MEDIC_H
#ifdef _WIN32
#pragma once
#endif
#include "tf_gamemovement.h"
#include "tfclassdata_shared.h"
class CTFMoveData;
//=============================================================================
//
// Medic Game Movement Class
//
class CTFGameMovementMedic : public CTFGameMovement
{
DECLARE_CLASS( CTFGameMovementMedic, CTFGameMovement );
public:
CTFGameMovementMedic();
// Interface Implementation
// virtual void ProcessMovement( CTFMoveData *pTFMoveData );
virtual void ProcessClassMovement( CBaseTFPlayer *pPlayer, CTFMoveData *pTFMoveData );
virtual const Vector &GetPlayerMins( bool bDucked ) const;
virtual const Vector &GetPlayerMaxs( bool bDucked ) const;
virtual const Vector &GetPlayerViewOffset( bool bDucked ) const;
protected:
PlayerClassMedicData_t *m_pMedicData;
Vector m_vStandMins;
Vector m_vStandMaxs;
Vector m_vStandViewOffset;
Vector m_vDuckMins;
Vector m_vDuckMaxs;
Vector m_vDuckViewOffset;
};
#endif // TF_GAMEMOVEMENT_MEDIC_H
+63
View File
@@ -0,0 +1,63 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Auto Repair
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "tf_gamemovement_pyro.h"
#include "tf_movedata.h"
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CTFGameMovementPyro::CTFGameMovementPyro()
{
m_pPyroData = NULL;
m_vStandMins = PYROCLASS_HULL_STAND_MIN;
m_vStandMaxs = PYROCLASS_HULL_STAND_MAX;
m_vStandViewOffset = PYROCLASS_VIEWOFFSET_STAND;
m_vDuckMins = PYROCLASS_HULL_DUCK_MIN;
m_vDuckMaxs = PYROCLASS_HULL_DUCK_MAX;
m_vDuckViewOffset = PYROCLASS_VIEWOFFSET_DUCK;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFGameMovementPyro::ProcessClassMovement( CBaseTFPlayer *pPlayer, CTFMoveData *pTFMoveData )
{
// Get the class specific data from the TFMoveData structure
Assert( PlayerClassPyroData_t::PLAYERCLASS_ID == pTFMoveData->m_nClassID );
m_pPyroData = &pTFMoveData->PyroData();
// to test pass it through!!
BaseClass::ProcessMovement( (CBasePlayer *)pPlayer, static_cast<CMoveData*>( pTFMoveData ) );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const Vector &CTFGameMovementPyro::GetPlayerMins( bool bDucked ) const
{
return bDucked ? m_vDuckMins : m_vStandMins;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const Vector &CTFGameMovementPyro::GetPlayerMaxs( bool bDucked ) const
{
return bDucked ? m_vDuckMaxs : m_vStandMaxs;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const Vector &CTFGameMovementPyro::GetPlayerViewOffset( bool bDucked ) const
{
return bDucked ? m_vDuckViewOffset : m_vStandViewOffset;
}
+50
View File
@@ -0,0 +1,50 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Auto Repair
//
// $NoKeywords: $
//=============================================================================//
#ifndef TF_GAMEMOVEMENT_PYRO_H
#define TF_GAMEMOVEMENT_PYRO_H
#ifdef _WIN32
#pragma once
#endif
#include "tf_gamemovement.h"
#include "tfclassdata_shared.h"
class CTFMoveData;
//=============================================================================
//
// Pyro Game Movement Class
//
class CTFGameMovementPyro : public CTFGameMovement
{
DECLARE_CLASS( CTFGameMovementPyro, CTFGameMovement );
public:
CTFGameMovementPyro();
// Interface Implementation
// virtual void ProcessMovement( CTFMoveData *pTFMoveData );
virtual void ProcessClassMovement( CBaseTFPlayer *pPlayer, CTFMoveData *pTFMoveData );
virtual const Vector &GetPlayerMins( bool bDucked ) const;
virtual const Vector &GetPlayerMaxs( bool bDucked ) const;
virtual const Vector &GetPlayerViewOffset( bool bDucked ) const;
protected:
PlayerClassPyroData_t *m_pPyroData;
Vector m_vStandMins;
Vector m_vStandMaxs;
Vector m_vStandViewOffset;
Vector m_vDuckMins;
Vector m_vDuckMaxs;
Vector m_vDuckViewOffset;
};
#endif // TF_GAMEMOVEMENT_PYRO_H
+595
View File
@@ -0,0 +1,595 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Auto Repair
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "tf_gamemovement_recon.h"
#include "tf_movedata.h"
#include "in_buttons.h"
#define TIME_WALL_SUPPRESSION_JUMP 100
#define TIME_WALL_SUPPRESSION_IMPACT 400
#define TIME_WALL_STICK 50
#define TIME_STRAFE_STICK 50
#define TIME_LEAP_STICK 300
#define TIME_WALL_ACTIVATE_JUMP 300
#define TIME_WALL_INVALID -99999
#define MAX_VERTICAL_SPEED 400
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CTFGameMovementRecon::CTFGameMovementRecon()
{
m_pReconData = NULL;
m_vStandMins = RECONCLASS_HULL_STAND_MIN;
m_vStandMaxs = RECONCLASS_HULL_STAND_MAX;
m_vStandViewOffset = RECONCLASS_VIEWOFFSET_STAND;
m_vDuckMins = RECONCLASS_HULL_DUCK_MIN;
m_vDuckMaxs = RECONCLASS_HULL_DUCK_MAX;
m_vDuckViewOffset = RECONCLASS_VIEWOFFSET_DUCK;
m_bPerformingAirMove = false;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFGameMovementRecon::ProcessClassMovement( CBaseTFPlayer *pPlayer, CTFMoveData *pTFMove )
{
// Get the class specific data from the TFMoveData structure
Assert( PlayerClassReconData_t::PLAYERCLASS_ID == pTFMove->m_nClassID );
m_pReconData = &pTFMove->ReconData();
// to test pass it through!!
BaseClass::ProcessMovement( (CBasePlayer *)pPlayer, pTFMove );
// Set the jump count appropriately...
// If we've hit the ground, we can double jump again...
if ((player->GetGroundEntity() != NULL) && (pTFMove->ReconData().m_flStickTime == TIME_WALL_INVALID))
{
m_pReconData->m_nJumpCount = 0;
ResetWallImpact( (CTFMoveData*)mv );
}
}
void CTFGameMovementRecon::PostPlayerMove( void )
{
BaseClass::PostPlayerMove( );
if (m_pReconData->m_flStickTime != TIME_WALL_INVALID)
{
// We're stuck, so stick!
mv->m_vecVelocity.Init( 0.0f, 0.0f, 0.0f );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFGameMovementRecon::UpdateTimers( void )
{
BaseClass::UpdateTimers();
CTFMoveData *pTFMove = TFMove();
if ( !pTFMove )
return;
float frame_msec = 1000.0f * gpGlobals->frametime;
// Decrement the recon timers.
if ( pTFMove->ReconData().m_flSuppressionJumpTime != TIME_WALL_INVALID )
{
pTFMove->ReconData().m_flSuppressionJumpTime -= frame_msec;
if ( pTFMove->ReconData().m_flSuppressionJumpTime <= 0.0f )
{
pTFMove->ReconData().m_flSuppressionJumpTime = TIME_WALL_INVALID;
}
}
if ( pTFMove->ReconData().m_flSuppressionImpactTime != TIME_WALL_INVALID )
{
pTFMove->ReconData().m_flSuppressionImpactTime -= frame_msec;
if ( pTFMove->ReconData().m_flSuppressionImpactTime <= 0.0f )
{
pTFMove->ReconData().m_flSuppressionImpactTime = TIME_WALL_INVALID;
}
}
if ( pTFMove->ReconData().m_flActiveJumpTime != TIME_WALL_INVALID )
{
pTFMove->ReconData().m_flActiveJumpTime -= frame_msec;
if ( pTFMove->ReconData().m_flActiveJumpTime <= 0.0f )
{
pTFMove->ReconData().m_flActiveJumpTime = TIME_WALL_INVALID;
}
}
if ( pTFMove->ReconData().m_flStickTime != TIME_WALL_INVALID )
{
pTFMove->ReconData().m_flStickTime -= frame_msec;
if ( pTFMove->ReconData().m_flStickTime <= 0.0f )
{
pTFMove->ReconData().m_flStickTime = TIME_WALL_INVALID;
// Restore velocity at this time
pTFMove->m_vecVelocity = pTFMove->ReconData().m_vecUnstickVelocity;
}
}
}
//-----------------------------------------------------------------------------
// Implement this if you want to know when the player collides during OnPlayerMove
//-----------------------------------------------------------------------------
void CTFGameMovementRecon::OnTryPlayerMoveCollision( trace_t &tr )
{
if ( !m_bPerformingAirMove )
return;
// Only keep track of world collisions
if ( tr.DidHitWorld() )
{
CTFMoveData *pTFMove = TFMove();
if ( pTFMove )
{
if ( ( pTFMove->ReconData().m_flSuppressionJumpTime == TIME_WALL_INVALID ) &&
( pTFMove->ReconData().m_flSuppressionImpactTime == TIME_WALL_INVALID ) )
{
// No walljumps off of mostly horizontal surfaces...
if ( fabs( tr.plane.normal.z ) > 0.9f )
return;
// No walljumps off of the same plane as the last one...
if ( (pTFMove->ReconData().m_flImpactDist == tr.plane.dist) &&
(VectorsAreEqual(pTFMove->ReconData().m_vecImpactNormal, tr.plane.normal, 1e-2) ) )
{
return;
}
// If you hit a wall, no double jumps for you
pTFMove->ReconData().m_nJumpCount = 2;
// Play an impact sound
MoveHelper()->StartSound( pTFMove->m_vecAbsOrigin, "Recon.WallJump" );
pTFMove->ReconData().m_vecImpactNormal = tr.plane.normal;
pTFMove->ReconData().m_flImpactDist = tr.plane.dist;
pTFMove->ReconData().m_flActiveJumpTime = TIME_WALL_ACTIVATE_JUMP;
pTFMove->ReconData().m_flSuppressionImpactTime = TIME_WALL_SUPPRESSION_IMPACT;
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFGameMovementRecon::AirMove()
{
m_bPerformingAirMove = true;
// When in the air, recon travels ballistically
if ( TFMove()->ReconData().m_nJumpCount )
{
// Add in any base velocity to the current velocity.
VectorAdd( mv->m_vecVelocity, player->GetBaseVelocity(), mv->m_vecVelocity );
TryPlayerMove();
}
else
{
// But if we're falling (or coming up off ladders), treat it normally
BaseClass::AirMove();
}
m_bPerformingAirMove = false;
}
//-----------------------------------------------------------------------------
// Purpose: Check the jump button to make various jumps
//-----------------------------------------------------------------------------
bool CTFGameMovementRecon::CheckWaterJump()
{
// See if we are waterjumping. If so, decrement count and return.
if (player->m_flWaterJumpTime)
{
player->m_flWaterJumpTime -= gpGlobals->frametime;
if (player->m_flWaterJumpTime < 0)
player->m_flWaterJumpTime = 0;
return true;
}
// If we are in the water most of the way...
if ( player->GetWaterLevel() >= 2 )
{
// swimming, not jumping
SetGroundEntity( NULL );
if(player->GetWaterType() == CONTENTS_WATER) // We move up a certain amount
mv->m_vecVelocity[2] = 100;
else if (player->GetWaterType() == CONTENTS_SLIME)
mv->m_vecVelocity[2] = 80;
// play swiming sound
if ( player->m_flSwimSoundTime <= 0 )
{
// Don't play sound again for 1 second
player->m_flSwimSoundTime = 1000;
PlaySwimSound();
}
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// Resets the impact time
//-----------------------------------------------------------------------------
void CTFGameMovementRecon::ResetWallImpact( CTFMoveData *pTFMove )
{
if ( pTFMove->ReconData().m_flActiveJumpTime != TIME_WALL_INVALID )
{
pTFMove->ReconData().m_flActiveJumpTime = TIME_WALL_INVALID;
pTFMove->ReconData().m_flSuppressionImpactTime = TIME_WALL_INVALID;
pTFMove->ReconData().m_vecImpactNormal.Init( 9999, 9999, 9999 );
pTFMove->ReconData().m_flImpactDist = -9999.0f;
}
}
//-----------------------------------------------------------------------------
// Purpose: Check the jump button to make various jumps
//-----------------------------------------------------------------------------
bool CTFGameMovementRecon::CheckWallJump( CTFMoveData *pTFMove )
{
if ( player->GetGroundEntity() != NULL )
return false;
if ( pTFMove->ReconData().m_flActiveJumpTime == TIME_WALL_INVALID )
return false;
// Play a jump sound
PlayStepSound( m_pSurfaceData, 1.0, true );
Vector jumpDir;
if ( ( pTFMove->m_nButtons & ( IN_MOVELEFT | IN_MOVERIGHT ) ) )
{
AngleVectors( pTFMove->m_vecViewAngles, NULL, &jumpDir, NULL );
// Apply strafe jump...
jumpDir *= ( pTFMove->m_nButtons & IN_MOVELEFT ) ? -1.0f : 1.0f;
jumpDir.z = 0.0f;
if ( pTFMove->m_nButtons & ( IN_FORWARD | IN_BACK ) )
{
Vector forward;
AngleVectors( pTFMove->m_vecViewAngles, &forward, NULL, NULL );
forward *= 0.5f;
forward *= ( pTFMove->m_nButtons & IN_BACK ) ? -1.0f : 1.0f;
forward.z = 0.0;
jumpDir += forward;
}
VectorNormalize( jumpDir );
jumpDir *= 400;
}
else
{
AngleVectors( pTFMove->m_vecViewAngles, &jumpDir, NULL, NULL );
jumpDir *= ( pTFMove->m_nButtons & IN_BACK ) ? -1.0f : 1.0f;
jumpDir.z = 0.0;
VectorNormalize( jumpDir );
jumpDir *= 400;
}
pTFMove->ReconData().m_flStickTime = TIME_WALL_STICK;
pTFMove->ReconData().m_vecUnstickVelocity.Init( jumpDir.x, jumpDir.y,
pTFMove->m_vecVelocity[2] + 1.5 * sqrt(2 * 800 * 45.0) );
if (pTFMove->ReconData().m_vecUnstickVelocity.GetZ() > MAX_VERTICAL_SPEED)
pTFMove->ReconData().m_vecUnstickVelocity.SetZ( MAX_VERTICAL_SPEED );
pTFMove->m_vecVelocity.Init( 0, 0, 0 );
// Don't allow jump into wall
float normalComponent = DotProduct( pTFMove->ReconData().m_vecUnstickVelocity, pTFMove->ReconData().m_vecImpactNormal );
if ( normalComponent < 0 )
{
Vector vUnstickVel;
VectorMA( pTFMove->ReconData().m_vecUnstickVelocity, -normalComponent,
pTFMove->ReconData().m_vecImpactNormal, vUnstickVel );
pTFMove->ReconData().m_vecUnstickVelocity = vUnstickVel;
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Check the jump button to make various jumps
//-----------------------------------------------------------------------------
bool CTFGameMovementRecon::CheckBackJump( bool bWasInAir )
{
if ((mv->m_nButtons & IN_BACK) == 0)
return false;
Vector jumpDir, right;
AngleVectors( mv->m_vecViewAngles, &jumpDir, &right, NULL );
jumpDir.z = 0.0f;
jumpDir *= -1.0f;
if (mv->m_nButtons & (IN_MOVELEFT | IN_MOVERIGHT))
{
// Apply strafe jump...
right *= (mv->m_nButtons & IN_MOVELEFT) ? -1.0f : 1.0f;
right.z = 0.0f;
// Make us not jump quite at a 45% angle if both are selected
right *= 0.5f;
jumpDir += right;
}
VectorNormalize( jumpDir );
float flGroundFactor = 1.0f;
if ((m_pSurfaceData) /*&& (!bWasInAir)*/ )
{
flGroundFactor = m_pSurfaceData->game.jumpFactor;
}
jumpDir *= 150 * flGroundFactor;
// Dampen current motion
mv->m_vecVelocity[0] *= 0.5f;
mv->m_vecVelocity[1] *= 0.5f;
float flSideFactor = (bWasInAir) ? 2.0f : 1.0f;
float flUpFactor = (bWasInAir) ? 0.5f : 1.5f;
flSideFactor *= flGroundFactor;
flUpFactor *= flGroundFactor;
mv->m_vecVelocity[0] += flSideFactor * jumpDir.x;
mv->m_vecVelocity[1] += flSideFactor * jumpDir.y;
mv->m_vecVelocity[2] += flUpFactor * sqrt(2 * 800 * 45.0);
mv->m_vecVelocity[0] = clamp( mv->m_vecVelocity[0], -200, 200 );
mv->m_vecVelocity[1] = clamp( mv->m_vecVelocity[1], -200, 200 );
if (mv->m_vecVelocity[2] > MAX_VERTICAL_SPEED)
mv->m_vecVelocity[2] = MAX_VERTICAL_SPEED;
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Check the jump button to make various jumps
//-----------------------------------------------------------------------------
bool CTFGameMovementRecon::CheckStrafeJump( bool bWasInAir )
{
if ( (mv->m_nButtons & (IN_MOVELEFT | IN_MOVERIGHT)) == 0 )
return false;
if (mv->m_nButtons & IN_FORWARD)
return false;
Vector jumpDir;
AngleVectors( mv->m_vecViewAngles, NULL, &jumpDir, NULL );
// Apply strafe jump...
jumpDir *= (mv->m_nButtons & IN_MOVELEFT) ? -1.0f : 1.0f;
jumpDir.z = 0.0f;
VectorNormalize( jumpDir );
float flGroundFactor = 1.0f;
if ((m_pSurfaceData) /*&& (!bWasInAir)*/ )
{
flGroundFactor = m_pSurfaceData->game.jumpFactor;
}
jumpDir *= 300 * flGroundFactor;
// Dampen current motion
mv->m_vecVelocity[0] *= 0.5f;
mv->m_vecVelocity[1] *= 0.5f;
mv->m_vecVelocity[0] += jumpDir.x;
mv->m_vecVelocity[1] += jumpDir.y;
if (!bWasInAir)
mv->m_vecVelocity[2] += flGroundFactor * sqrt(2 * 800 * 45.0); // 2 * gravity * height
else
mv->m_vecVelocity[2] += 0.5f * sqrt(2 * 800 * 45.0); // 2 * gravity * height
mv->m_vecVelocity[0] = clamp( mv->m_vecVelocity[0], -400, 400 );
mv->m_vecVelocity[1] = clamp( mv->m_vecVelocity[1], -400, 400 );
if (mv->m_vecVelocity[2] > MAX_VERTICAL_SPEED)
mv->m_vecVelocity[2] = MAX_VERTICAL_SPEED;
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Check the jump button to make various jumps
//-----------------------------------------------------------------------------
bool CTFGameMovementRecon::CheckForwardJump( bool bWasInAir )
{
// If we are ducking...
if ( ( player->m_Local.m_bDucking ) || ( player->GetFlags() & FL_DUCKING ) )
{
// d = 0.5 * g * t^2 - distance traveled with linear accel
// t = sqrt(2.0 * 45 / g) - how long to fall 45 units
// v = g * t - velocity at the end (just invert it to jump up that high)
// v = g * sqrt(2.0 * 45 / g )
// v^2 = g * g * 2.0 * 45 / g
// v = sqrt( g * 2.0 * 45 )
mv->m_vecVelocity[2] = sqrt(2 * 800 * 45.0); // 2 * gravity * height
}
else
{
Vector forward, right;
AngleVectors( mv->m_vecViewAngles, &forward, &right, NULL );
forward.z = 0.0;
if ((mv->m_nButtons & IN_FORWARD) == 0)
{
forward.x = forward.y = 0.0f;
}
if (mv->m_nButtons & (IN_MOVELEFT | IN_MOVERIGHT))
{
// Apply strafe jump...
right *= (mv->m_nButtons & IN_MOVELEFT) ? -1.0f : 1.0f;
right.z = 0.0f;
// Make us not jump quite at a 45% angle if both are selected
right *= 0.5f;
forward += right;
}
VectorNormalize( forward );
// Slow down by the speed factor
float flGroundFactor = 1.0f;
if ((m_pSurfaceData) /* && (!bWasInAir) */ )
{
flGroundFactor = m_pSurfaceData->game.jumpFactor;
}
forward *= 400 * flGroundFactor;
// Dampen current motion
mv->m_vecVelocity[0] *= 0.5f;
mv->m_vecVelocity[1] *= 0.5f;
mv->m_vecVelocity[0] += forward.x;
mv->m_vecVelocity[1] += forward.y;
float flUpFactor = (bWasInAir) ? 0.7f : 1.0f;
flUpFactor *= flGroundFactor;
mv->m_vecVelocity[2] += flUpFactor * MAX_VERTICAL_SPEED;
// Limit their velocity in X and Y. We don't want to just clamp because that will change the
// direction we're moving in.
for ( int i=0; i < 2; i++ )
{
float flAbs = fabs( mv->m_vecVelocity[i] );
if ( flAbs > 400 )
{
mv->m_vecVelocity[0] *= (400.0f / flAbs);
mv->m_vecVelocity[1] *= (400.0f / flAbs);
}
}
if (mv->m_vecVelocity[2] > MAX_VERTICAL_SPEED)
mv->m_vecVelocity[2] = MAX_VERTICAL_SPEED;
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Check the jump button to make various jumps
//-----------------------------------------------------------------------------
bool CTFGameMovementRecon::CheckJumpButton()
{
// FIXME: Refactor this so we don't have this complicated duplicate
// code here + in gamemovement.cpp
if ( player->pl.deadflag )
{
mv->m_nOldButtons |= IN_JUMP ; // don't jump again until released
return false;
}
// Water jumps!
if ( CheckWaterJump() )
return false;
if ( mv->m_nOldButtons & IN_JUMP )
return false; // don't pogo stick
CTFMoveData *pTFMove = static_cast<CTFMoveData*>( mv );
// Check for wall jump...
if ( !CheckWallJump( pTFMove ) )
{
// If we already did one air jump, can't do another
if ( (player->GetGroundEntity() == NULL ) && ( pTFMove->ReconData().m_nJumpCount > 1) )
{
mv->m_nOldButtons |= IN_JUMP;
return false; // in air, so no effect
}
pTFMove->ReconData().m_nJumpCount += 1;
// Am I doing a double-jump?
bool bWasInAir = (player->GetGroundEntity() == NULL);
// In the air now.
SetGroundEntity( NULL );
PlayStepSound( m_pSurfaceData, 1.0, true );
if (!CheckBackJump(bWasInAir))
{
if (CheckStrafeJump(bWasInAir))
{
// Can't double jump out of a roll....
pTFMove->ReconData().m_nJumpCount += 1;
}
else
{
CheckForwardJump(bWasInAir);
}
}
}
pTFMove->ReconData().m_flSuppressionJumpTime = TIME_WALL_SUPPRESSION_JUMP;
FinishGravity();
mv->m_outWishVel = mv->m_vecVelocity;
mv->m_outStepHeight += 0.1f;
// Flag that we jumped.
mv->m_nOldButtons |= IN_JUMP; // don't jump again until released
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const Vector &CTFGameMovementRecon::GetPlayerMins( bool bDucked ) const
{
return bDucked ? m_vDuckMins : m_vStandMins;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const Vector &CTFGameMovementRecon::GetPlayerMaxs( bool bDucked ) const
{
return bDucked ? m_vDuckMaxs : m_vStandMaxs;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const Vector &CTFGameMovementRecon::GetPlayerViewOffset( bool bDucked ) const
{
return bDucked ? m_vDuckViewOffset : m_vStandViewOffset;
}
+73
View File
@@ -0,0 +1,73 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Auto Repair
//
// $NoKeywords: $
//=============================================================================//
#ifndef TF_GAMEMOVEMENT_RECON_H
#define TF_GAMEMOVEMENT_RECON_H
#ifdef _WIN32
#pragma once
#endif
#include "tf_gamemovement.h"
#include "tfclassdata_shared.h"
class CTFMoveData;
//=============================================================================
//
// Recon Game Movement Class
//
class CTFGameMovementRecon : public CTFGameMovement
{
DECLARE_CLASS( CTFGameMovementRecon, CTFGameMovement );
public:
CTFGameMovementRecon();
// Interface Implementation
// virtual void ProcessMovement( CTFMoveData *pTFMoveData );
virtual void ProcessClassMovement( CBaseTFPlayer *pPlayer, CTFMoveData *pTFMoveData );
virtual const Vector &GetPlayerMins( bool bDucked ) const;
virtual const Vector &GetPlayerMaxs( bool bDucked ) const;
virtual const Vector &GetPlayerViewOffset( bool bDucked ) const;
// Purpose:
virtual void AirMove();
protected:
virtual void PostPlayerMove( void );
void UpdateTimers( void );
// Purpose: Check the jump button to make various jumps
bool CheckJumpButton();
// Check various jump types
bool CheckWaterJump();
bool CheckWallJump(CTFMoveData *pTFMove);
bool CheckBackJump( bool bWasInAir );
bool CheckStrafeJump( bool bWasInAir );
bool CheckForwardJump( bool bWasInAir );
// Resets the impact time
void ResetWallImpact(CTFMoveData *pTFMove);
// Implement this if you want to know when the player collides during OnPlayerMove
virtual void OnTryPlayerMoveCollision( trace_t &tr );
PlayerClassReconData_t *m_pReconData;
Vector m_vStandMins;
Vector m_vStandMaxs;
Vector m_vStandViewOffset;
Vector m_vDuckMins;
Vector m_vDuckMaxs;
Vector m_vDuckViewOffset;
bool m_bPerformingAirMove;
};
#endif // TF_GAMEMOVEMENT_RECON_H
@@ -0,0 +1,62 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Auto Repair
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "tf_gamemovement_sapper.h"
#include "tf_movedata.h"
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CTFGameMovementSapper::CTFGameMovementSapper()
{
m_pSapperData = NULL;
m_vStandMins = SAPPERCLASS_HULL_STAND_MIN;
m_vStandMaxs = SAPPERCLASS_HULL_STAND_MAX;
m_vStandViewOffset = SAPPERCLASS_VIEWOFFSET_STAND;
m_vDuckMins = SAPPERCLASS_HULL_DUCK_MIN;
m_vDuckMaxs = SAPPERCLASS_HULL_DUCK_MAX;
m_vDuckViewOffset = SAPPERCLASS_VIEWOFFSET_DUCK;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFGameMovementSapper::ProcessClassMovement( CBaseTFPlayer *pPlayer, CTFMoveData *pTFMoveData )
{
// Get the class specific data from the TFMoveData structure
Assert( PlayerClassSapperData_t::PLAYERCLASS_ID == pTFMoveData->m_nClassID );
m_pSapperData = &pTFMoveData->SapperData();
// to test pass it through!!
BaseClass::ProcessMovement( (CBasePlayer *)pPlayer, static_cast<CMoveData*>( pTFMoveData ) );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const Vector &CTFGameMovementSapper::GetPlayerMins( bool bDucked ) const
{
return bDucked ? m_vDuckMins : m_vStandMins;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const Vector &CTFGameMovementSapper::GetPlayerMaxs( bool bDucked ) const
{
return bDucked ? m_vDuckMaxs : m_vStandMaxs;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const Vector &CTFGameMovementSapper::GetPlayerViewOffset( bool bDucked ) const
{
return bDucked ? m_vDuckViewOffset : m_vStandViewOffset;
}
+50
View File
@@ -0,0 +1,50 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Sapper's game movement
//
// $NoKeywords: $
//=============================================================================//
#ifndef TF_GAMEMOVEMENT_SAPPER_H
#define TF_GAMEMOVEMENT_SAPPER_H
#ifdef _WIN32
#pragma once
#endif
#include "tf_gamemovement.h"
#include "tfclassdata_shared.h"
class CTFMoveData;
//=============================================================================
//
// Sapper Game Movement Class
//
class CTFGameMovementSapper : public CTFGameMovement
{
DECLARE_CLASS( CTFGameMovementSapper, CTFGameMovement );
public:
CTFGameMovementSapper();
// Interface Implementation
// virtual void ProcessMovement( CTFMoveData *pTFMoveData );
virtual void ProcessClassMovement( CBaseTFPlayer *pPlayer, CTFMoveData *pTFMoveData );
virtual const Vector &GetPlayerMins( bool bDucked ) const;
virtual const Vector &GetPlayerMaxs( bool bDucked ) const;
virtual const Vector &GetPlayerViewOffset( bool bDucked ) const;
protected:
PlayerClassSapperData_t *m_pSapperData;
Vector m_vStandMins;
Vector m_vStandMaxs;
Vector m_vStandViewOffset;
Vector m_vDuckMins;
Vector m_vDuckMaxs;
Vector m_vDuckViewOffset;
};
#endif // TF_GAMEMOVEMENT_SAPPER_H
@@ -0,0 +1,62 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Auto Repair
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "tf_gamemovement_sniper.h"
#include "tf_movedata.h"
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CTFGameMovementSniper::CTFGameMovementSniper()
{
m_pSniperData = NULL;
m_vStandMins = SNIPERCLASS_HULL_STAND_MIN;
m_vStandMaxs = SNIPERCLASS_HULL_STAND_MAX;
m_vStandViewOffset = SNIPERCLASS_VIEWOFFSET_STAND;
m_vDuckMins = SNIPERCLASS_HULL_DUCK_MIN;
m_vDuckMaxs = SNIPERCLASS_HULL_DUCK_MAX;
m_vDuckViewOffset = SNIPERCLASS_VIEWOFFSET_DUCK;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFGameMovementSniper::ProcessClassMovement( CBaseTFPlayer *pPlayer, CTFMoveData *pTFMoveData )
{
// Get the class specific data from the TFMoveData structure
Assert( PlayerClassSniperData_t::PLAYERCLASS_ID == pTFMoveData->m_nClassID );
m_pSniperData = &pTFMoveData->SniperData();
// to test pass it through!!
BaseClass::ProcessMovement( (CBasePlayer *)pPlayer, static_cast<CMoveData*>( pTFMoveData ) );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const Vector &CTFGameMovementSniper::GetPlayerMins( bool bDucked ) const
{
return bDucked ? m_vDuckMins : m_vStandMins;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const Vector &CTFGameMovementSniper::GetPlayerMaxs( bool bDucked ) const
{
return bDucked ? m_vDuckMaxs : m_vStandMaxs;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const Vector &CTFGameMovementSniper::GetPlayerViewOffset( bool bDucked ) const
{
return bDucked ? m_vDuckViewOffset : m_vStandViewOffset;
}
+50
View File
@@ -0,0 +1,50 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Auto Repair
//
// $NoKeywords: $
//=============================================================================//
#ifndef TF_GAMEMOVEMENT_SNIPER_H
#define TF_GAMEMOVEMENT_SNIPER_H
#ifdef _WIN32
#pragma once
#endif
#include "tf_gamemovement.h"
#include "tfclassdata_shared.h"
class CTFMoveData;
//=============================================================================
//
// Sniper Game Movement Class
//
class CTFGameMovementSniper : public CTFGameMovement
{
DECLARE_CLASS( CTFGameMovementSniper, CTFGameMovement );
public:
CTFGameMovementSniper();
// Interface Implementation
// virtual void ProcessMovement( CTFMoveData *pTFMoveData );
virtual void ProcessClassMovement( CBaseTFPlayer *pPlayer, CTFMoveData *pTFMoveData );
virtual const Vector &GetPlayerMins( bool bDucked ) const;
virtual const Vector &GetPlayerMaxs( bool bDucked ) const;
virtual const Vector &GetPlayerViewOffset( bool bDucked ) const;
protected:
PlayerClassSniperData_t *m_pSniperData;
Vector m_vStandMins;
Vector m_vStandMaxs;
Vector m_vStandViewOffset;
Vector m_vDuckMins;
Vector m_vDuckMaxs;
Vector m_vDuckViewOffset;
};
#endif // TF_GAMEMOVEMENT_SNIPER_H
@@ -0,0 +1,62 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Auto Repair
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "tf_gamemovement_support.h"
#include "tf_movedata.h"
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CTFGameMovementSupport::CTFGameMovementSupport()
{
m_pSupportData = NULL;
m_vStandMins = SUPPORTCLASS_HULL_STAND_MIN;
m_vStandMaxs = SUPPORTCLASS_HULL_STAND_MAX;
m_vStandViewOffset = SUPPORTCLASS_VIEWOFFSET_STAND;
m_vDuckMins = SUPPORTCLASS_HULL_DUCK_MIN;
m_vDuckMaxs = SUPPORTCLASS_HULL_DUCK_MAX;
m_vDuckViewOffset = SUPPORTCLASS_VIEWOFFSET_DUCK;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFGameMovementSupport::ProcessClassMovement( CBaseTFPlayer *pPlayer, CTFMoveData *pTFMoveData )
{
// Get the class specific data from the TFMoveData structure
Assert( PlayerClassSupportData_t::PLAYERCLASS_ID == pTFMoveData->m_nClassID );
m_pSupportData = &pTFMoveData->SupportData();
// to test pass it through!!
BaseClass::ProcessMovement( (CBasePlayer *)pPlayer, static_cast<CMoveData*>( pTFMoveData ) );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const Vector &CTFGameMovementSupport::GetPlayerMins( bool bDucked ) const
{
return bDucked ? m_vDuckMins : m_vStandMins;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const Vector &CTFGameMovementSupport::GetPlayerMaxs( bool bDucked ) const
{
return bDucked ? m_vDuckMaxs : m_vStandMaxs;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const Vector &CTFGameMovementSupport::GetPlayerViewOffset( bool bDucked ) const
{
return bDucked ? m_vDuckViewOffset : m_vStandViewOffset;
}
+50
View File
@@ -0,0 +1,50 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Auto Repair
//
// $NoKeywords: $
//=============================================================================//
#ifndef TF_GAMEMOVEMENT_SUPPORT_H
#define TF_GAMEMOVEMENT_SUPPORT_H
#ifdef _WIN32
#pragma once
#endif
#include "tf_gamemovement.h"
#include "tfclassdata_shared.h"
class CTFMoveData;
//=============================================================================
//
// Support Game Movement Class
//
class CTFGameMovementSupport : public CTFGameMovement
{
DECLARE_CLASS( CTFGameMovementSupport, CTFGameMovement );
public:
CTFGameMovementSupport();
// Interface Implementation
// virtual void ProcessMovement( CTFMoveData *pTFMoveData );
virtual void ProcessClassMovement( CBaseTFPlayer *pPlayer, CTFMoveData *pTFMoveData );
virtual const Vector &GetPlayerMins( bool bDucked ) const;
virtual const Vector &GetPlayerMaxs( bool bDucked ) const;
virtual const Vector &GetPlayerViewOffset( bool bDucked ) const;
protected:
PlayerClassSupportData_t *m_pSupportData;
Vector m_vStandMins;
Vector m_vStandMaxs;
Vector m_vStandViewOffset;
Vector m_vDuckMins;
Vector m_vDuckMaxs;
Vector m_vDuckViewOffset;
};
#endif // TF_GAMEMOVEMENT_SUPPORT_H
File diff suppressed because it is too large Load Diff
+142
View File
@@ -0,0 +1,142 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: The TF Game rules object
//
// $Workfile: $
// $Date: $
// $NoKeywords: $
//=============================================================================//
#ifndef TF_GAMERULES_H
#define TF_GAMERULES_H
#ifdef _WIN32
#pragma once
#endif
#include "Teamplay_GameRules.h"
#include "takedamageinfo.h"
#ifdef CLIENT_DLL
#define CTeamFortress C_TeamFortress
#endif
class CTeamFortress : public CTeamplayRules
{
public:
DECLARE_CLASS( CTeamFortress, CTeamplayRules );
int DefaultFOV( void ) { return 90; }
// Shared implementation between client and server.
void WeaponTraceLine( const Vector& src, const Vector& end, unsigned int mask, CBaseEntity *pShooter, int damageType, trace_t* pTrace );
virtual bool ShouldCollide( int collisionGroup0, int collisionGroup1 );
virtual void FireBullets( const CTakeDamageInfo &info, int cShots, const Vector &vecSrc, const Vector &vecDirShooting,
const Vector &vecSpread, float flDistance, int iBulletType, int iTracerFreq, int firingEntID,
int attachmentID, const char *sCustomTracer = NULL );
#ifdef CLIENT_DLL
#else
CTeamFortress();
virtual ~CTeamFortress();
CBaseEntity *GetPlayerSpawnSpot( CBasePlayer *pPlayer );
virtual void Think( void );
virtual void LevelInitPostEntity( void );
virtual void CreateStandardEntities();
// Called when game rules are destroyed by CWorld
virtual void LevelShutdown( void );
virtual void ClientDisconnected( edict_t *pClient );
virtual bool ClientCommand( CBaseEntity *pEdict, const CCommand &args );
virtual void PlayerSpawn( CBasePlayer *pPlayer );
virtual bool PlayTextureSounds( void ) { return true; }
virtual bool PlayFootstepSounds( CBasePlayer *pl );
virtual float FlPlayerFallDamage( CBasePlayer *pPlayer );
virtual void RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrcIn, float flRadius, int iClassIgnore );
// Let the game rules specify if fall death should fade screen to black
virtual bool FlPlayerFallDeathDoesScreenFade( CBasePlayer *pl ) { return FALSE; }
bool IsTraceBlockedByWorldOrShield( const Vector& src, const Vector& end, CBaseEntity *pShooter, int damageType, trace_t* pTrace );
virtual float WeaponTraceEntity( CBaseEntity *pEntity, const Vector &vecStart, const Vector &vecEnd, unsigned int mask, trace_t *ptr );
virtual void UpdateClientData( CBasePlayer *pl );
// Death notices
virtual void DeathNotice( CBasePlayer *pVictim, const CTakeDamageInfo &info );
virtual const char *GetDamageCustomString( const CTakeDamageInfo &info );
CBasePlayer *GetDeathAssistant( CBaseEntity *pKiller, CBaseEntity *pInflictor );
virtual bool PlayerCanHearChat( CBasePlayer *pListener, CBasePlayer *pSpeaker );
virtual void InitDefaultAIRelationships( void );
virtual const char *GetGameDescription( void ) { return "TeamFortress 2"; } // this is the game name that gets seen in the server browser
virtual const char *AIClassText(int classType);
virtual bool FShouldSwitchWeapon( CBasePlayer *pPlayer, CBaseCombatWeapon *pWeapon );
virtual const char *SetDefaultPlayerTeam( CBasePlayer *pPlayer );
// Is the ray blocked by enemy shields?
bool IsBlockedByEnemyShields( const Vector& src, const Vector& end, int nFriendlyTeam );
public:
virtual void SetAllowWeaponSwitch( bool allow );
virtual bool GetAllowWeaponSwitch( void );
private:
// Don't allow switching weapons while gaining new technologies
bool m_bAllowWeaponSwitch;
#endif
};
//-----------------------------------------------------------------------------
// Gets us at the team fortress game rules
//-----------------------------------------------------------------------------
inline CTeamFortress* TFGameRules()
{
#ifdef _DEBUG
Assert( dynamic_cast< CTeamFortress* >( g_pGameRules ) );
#endif
return static_cast<CTeamFortress*>(g_pGameRules);
}
// Send the appropriate weapon impact.
void WeaponImpact( trace_t *tr, Vector vecDir, bool bHurt, CBaseEntity *pEntity, int iDamageType );
#ifdef CLIENT_DLL
#else
//-----------------------------------------------------------------------------
// Purpose: Useful utility functions
//-----------------------------------------------------------------------------
class CTFTeam;
CTFTeam *GetOpposingTeam( CTeam *pTeam );
bool EntityPlacementTest( CBaseEntity *pMainEnt, const Vector &vOrigin, Vector &outPos, bool bDropToGround );
#endif
#endif // TF_GAMERULES_H
+34
View File
@@ -0,0 +1,34 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef TF_HINTS_H
#define TF_HINTS_H
#ifdef _WIN32
#pragma once
#endif
enum
{
TF_HINT_UNDEFINED = 0,
TF_HINT_VOTEFORTECHNOLOGY,
TF_HINT_BUILDRESOURCEPUMP,
TF_HINT_BUILDRESOURCEBOX,
TF_HINT_BUILDZONEINCREASER,
TF_HINT_BUILDSENTRYGUN_PLASMA,
TF_HINT_BUILDSANDBAG,
TF_HINT_BUILDANTIMORTAR,
TF_HINT_REPAIROBJECT,
TF_HINT_WEAPONRECEIVED,
TF_HINT_NEWTECHNOLOGY,
// Must be at end
TF_HINT_LASTHINT,
};
#endif // TF_HINTS_H
+71
View File
@@ -0,0 +1,71 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef TF_MOVEDATA_H
#define TF_MOVEDATA_H
#ifdef _WIN32
#pragma once
#endif
#include "igamemovement.h"
#include "tfclassdata_shared.h"
class CPlayerClassData;
// This class contains TF-specific prediction data. CMoveData can be casted to this class in
// CTFPlayerMove and CTFGameMovement to do TF-specific movement.
class CTFMoveData : public CMoveData
{
public:
Vector m_vecPosDelta;
// Revisit this!!!
enum { MOMENTUM_MAXSIZE = 10 };
float m_aMomentum[MOMENTUM_MAXSIZE];
int m_iMomentumHead;
int m_nClassID;
inline PlayerClassCommandoData_t &CommandoData() { return m_CommandoData; }
inline PlayerClassDefenderData_t &DefenderData() { return m_DefenderData; }
inline PlayerClassEscortData_t &EscortData() { return m_EscortData; }
inline PlayerClassInfiltratorData_t &InfiltratorData() { return m_InfiltratorData; }
inline PlayerClassMedicData_t &MedicData() { return m_MedicData; }
inline PlayerClassReconData_t &ReconData() { return m_ReconData; }
inline PlayerClassSniperData_t &SniperData() { return m_SniperData; }
inline PlayerClassSupportData_t &SupportData() { return m_SupportData; }
inline PlayerClassSapperData_t &SapperData() { return m_SapperData; }
inline PlayerClassPyroData_t &PyroData() { return m_PyroData; }
inline void* VehicleData() { return m_VehicleData; }
inline int VehicleDataMaxSize()
{
return VEHICLE_DATA_SIZE;
}
private:
enum
{
VEHICLE_DATA_SIZE = 256
};
PlayerClassCommandoData_t m_CommandoData;
PlayerClassDefenderData_t m_DefenderData;
PlayerClassEscortData_t m_EscortData;
PlayerClassInfiltratorData_t m_InfiltratorData;
PlayerClassMedicData_t m_MedicData;
PlayerClassReconData_t m_ReconData;
PlayerClassSniperData_t m_SniperData;
PlayerClassSupportData_t m_SupportData;
PlayerClassSapperData_t m_SapperData;
PlayerClassPyroData_t m_PyroData;
unsigned char m_VehicleData[VEHICLE_DATA_SIZE];
};
#endif // TF_MOVEDATA_H
+680
View File
@@ -0,0 +1,680 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: A stationary gun that players can man
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "tf_obj_base_manned_gun.h"
#include "tf_obj_manned_plasmagun_shared.h"
#include "in_buttons.h"
#include "tf_movedata.h"
#include "tf_gamerules.h"
#if defined( CLIENT_DLL )
#include "hudelement.h"
#include "bone_setup.h"
#include "hud_ammo.h"
#include "hud_crosshair.h"
#else
#endif
IMPLEMENT_NETWORKCLASS_ALIASED( ObjectBaseMannedGun, DT_ObjectBaseMannedGun )
BEGIN_NETWORK_TABLE( CObjectBaseMannedGun, DT_ObjectBaseMannedGun )
#if !defined( CLIENT_DLL )
SendPropInt (SENDINFO(m_nMoveStyle), 2, SPROP_UNSIGNED ),
SendPropInt (SENDINFO(m_nAmmoType), 8 ),
SendPropInt (SENDINFO(m_nAmmoCount), 6, SPROP_UNSIGNED ),
SendPropAngle(SENDINFO(m_flGunYaw), 12 ),
SendPropAngle(SENDINFO(m_flGunPitch), 12 ),
SendPropAngle(SENDINFO(m_flBarrelPitch), 12 ),
SendPropEHandle( SENDINFO( m_hLaserDesignation ) ),
SendPropEHandle( SENDINFO( m_hBeam ) ),
#else
RecvPropInt( RECVINFO(m_nMoveStyle) ),
RecvPropInt( RECVINFO(m_nAmmoType) ),
RecvPropInt( RECVINFO(m_nAmmoCount) ),
RecvPropFloat( RECVINFO(m_flGunYaw) ),
RecvPropFloat( RECVINFO(m_flGunPitch) ),
RecvPropFloat( RECVINFO(m_flBarrelPitch) ),
RecvPropEHandle( RECVINFO( m_hLaserDesignation ) ),
RecvPropEHandle( RECVINFO( m_hBeam ) ),
#endif
END_NETWORK_TABLE()
LINK_ENTITY_TO_CLASS( tf_obj_base_manned_gun, CObjectBaseMannedGun );
BEGIN_PREDICTION_DATA( CObjectBaseMannedGun )
DEFINE_PRED_FIELD( m_nMoveStyle, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
DEFINE_PRED_FIELD( m_nAmmoType, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
DEFINE_PRED_FIELD( m_nAmmoCount, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
DEFINE_PRED_FIELD_TOL( m_flGunYaw, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, 0.5f),
DEFINE_PRED_FIELD_TOL( m_flGunPitch, FIELD_FLOAT, FTYPEDESC_INSENDTABLE | FTYPEDESC_NOERRORCHECK, 0.125f ),
DEFINE_PRED_FIELD_TOL( m_flBarrelPitch, FIELD_FLOAT, FTYPEDESC_INSENDTABLE | FTYPEDESC_NOERRORCHECK, 0.125f ),
DEFINE_PRED_FIELD( m_hLaserDesignation, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ),
DEFINE_PRED_FIELD( m_hBeam, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ),
DEFINE_FIELD( m_flBarrelHeight, FIELD_FLOAT ),
// DEFINE_FIELD( m_nBarrelAttachment, FIELD_INTEGER ),
// DEFINE_FIELD( m_nBarrelPivotAttachment, FIELD_INTEGER ),
// DEFINE_FIELD( m_nStandAttachment, FIELD_INTEGER ),
// DEFINE_FIELD( m_nEyesAttachment, FIELD_INTEGER ),
END_PREDICTION_DATA()
extern ConVar mannedgun_usethirdperson;
static ConVar obj_manned_gun_designator_range( "obj_manned_gun_designator_range","2048", FCVAR_REPLICATED, "Manned gun's laser designation range" );
ConVar obj_child_range_factor( "obj_child_range_factor","1.1", FCVAR_REPLICATED, "Factor applied to range of objects that are built on a buildpoint" );
// Restoring initial state handling
#define OBJ_BASE_MANNEDGUN_THINK_CONTEXT "BaseMannedGunThink"
#define MANNEDGUN_RESTORE_TIME 5.0
#define MANNEDGUN_RESTORE_TURN_RATE 150
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CObjectBaseMannedGun::CObjectBaseMannedGun()
{
m_nMoveStyle = MOVEMENT_STYLE_STANDARD;
}
//-----------------------------------------------------------------------------
// Sets the movement style
//-----------------------------------------------------------------------------
void CObjectBaseMannedGun::SetMovementStyle( MovementStyle_t style )
{
m_nMoveStyle = style;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CObjectBaseMannedGun::Precache()
{
BaseClass::Precache();
#if !defined( CLIENT_DLL )
PrecacheVGuiScreen( "screen_obj_manned_plasmagun" );
PrecacheMaterial( "sprites/laserbeam" );
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CObjectBaseMannedGun::Spawn()
{
m_takedamage = DAMAGE_YES;
SetMaxPassengerCount( 1 );
m_flGunYaw = 0;
m_flGunPitch = 0;
m_flBarrelPitch = 0;
BaseClass::Spawn();
// Manned guns don't need to be built like other vehicles
int curFlags = GetObjectFlags();
curFlags &= ~OF_MUST_BE_BUILT_IN_CONSTRUCTION_YARD;
curFlags &= ~OF_MUST_BE_BUILT_ON_ATTACHMENT;
curFlags &= ~OF_DOESNT_NEED_POWER;
curFlags |= OF_DONT_PREVENT_BUILD_NEAR_OBJ;
SetObjectFlags( curFlags );
m_flMaxRange = 0;
}
//-----------------------------------------------------------------------------
// Purpose: Calculate the max range of this gun
//-----------------------------------------------------------------------------
void CObjectBaseMannedGun::CalculateMaxRange( float flDefensiveRange, float flOffensiveRange )
{
if ( GetTeamNumber() == TEAM_HUMANS )
{
m_flMaxRange = flDefensiveRange;
if ( GetParentObject() )
{
m_flMaxRange *= obj_child_range_factor.GetFloat();
}
}
else
{
m_flMaxRange = flOffensiveRange;
}
}
//-----------------------------------------------------------------------------
// Sets up various attachment points once the model is selected
//-----------------------------------------------------------------------------
void CObjectBaseMannedGun::OnModelSelected()
{
m_nBarrelAttachment = LookupAttachment( "barrel" );
m_nBarrelPivotAttachment = LookupAttachment( "barrelpivot" );
m_nStandAttachment = LookupAttachment( "vehicle_feet_passenger0" );
m_nEyesAttachment = LookupAttachment( "vehicle_eyes_passenger0" );
// Find the barrel height in its quiescent state...
Vector vBarrel;
QAngle vBarrelAngles;
GetAttachmentLocal( m_nBarrelAttachment, vBarrel, vBarrelAngles );
m_flBarrelHeight = vBarrel.z;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CObjectBaseMannedGun::UpdateOnRemove( void )
{
if ( m_hLaserDesignation.Get() )
{
m_hLaserDesignation->Remove( );
m_hLaserDesignation = NULL;
}
// Chain at end to mimic destructor unwind order
BaseClass::UpdateOnRemove();
}
//-----------------------------------------------------------------------------
// Purpose: Gets info about the control panels
//-----------------------------------------------------------------------------
void CObjectBaseMannedGun::GetControlPanelInfo( int nPanelIndex, const char *&pPanelName )
{
pPanelName = "screen_obj_manned_plasmagun";
}
//-----------------------------------------------------------------------------
// Purpose: Hide the base of the gun if it's on an attachment
//-----------------------------------------------------------------------------
void CObjectBaseMannedGun::SetupAttachedVersion( void )
{
BaseClass::SetupAttachedVersion();
SetBodygroup( 1, true );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CObjectBaseMannedGun::SetupUnattachedVersion( void )
{
BaseClass::SetupUnattachedVersion();
SetBodygroup( 1, false );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CObjectBaseMannedGun::OnGoInactive( void )
{
BaseClass::OnGoInactive();
// If we've got a player in the gun, tell him he's got to get out
if ( GetDriverPlayer() )
{
ClientPrint( GetDriverPlayer(), HUD_PRINTCENTER, "Lost power to the manned gun!" );
GetDriverPlayer()->LeaveVehicle();
}
#if 0
if ( GetBuffStation() )
{
GetBuffStation()->DeBuffObject( this );
}
#endif
}
//-----------------------------------------------------------------------------
// Purpose: Can we get into the vehicle?
//-----------------------------------------------------------------------------
bool CObjectBaseMannedGun::CanGetInVehicle( CBaseTFPlayer *pPlayer )
{
if ( !IsPowered() )
{
ClientPrint( pPlayer, HUD_PRINTCENTER, "No power source for the manned gun!" );
return false;
}
return true;
}
//-----------------------------------------------------------------------------
// Returns the eye position
//-----------------------------------------------------------------------------
void CObjectBaseMannedGun::GetVehicleViewPosition( int nRole, Vector *pOrigin, QAngle *pAngles, float *pFOV /*= NULL*/ )
{
BaseClass::GetVehicleViewPosition( nRole, pOrigin, pAngles, pFov );
return;
Assert( nRole == VEHICLE_DRIVER );
QAngle vPlayerFeetAngles;
GetAttachment(m_nEyesAttachment, *pOrigin, vPlayerFeetAngles);
}
//-----------------------------------------------------------------------------
// Purpose: Return to our original facing after a while
//-----------------------------------------------------------------------------
void CObjectBaseMannedGun::BaseMannedGunThink( void )
{
// If someone's got in the gun, stop moving
if ( GetDriverPlayer() )
return;
// Otherwise, move back towards the initial state
if ( m_flGunPitch )
{
float flPitch = anglemod( m_flGunPitch );
if (( flPitch <= 180 ) && ( flPitch >= 0 ))
{
m_flGunPitch = MAX( 0, flPitch - (gpGlobals->frametime * MANNEDGUN_RESTORE_TURN_RATE) );
}
else
{
m_flGunPitch = flPitch + (gpGlobals->frametime * MANNEDGUN_RESTORE_TURN_RATE);
if ( m_flGunPitch >= 360 )
{
m_flGunPitch = 0;
}
}
}
else if ( m_flGunYaw )
{
if ( m_flGunYaw > 180 )
{
m_flGunYaw = m_flGunYaw + (gpGlobals->frametime * MANNEDGUN_RESTORE_TURN_RATE);
if ( m_flGunYaw >= 360 )
{
m_flGunYaw = 0;
}
}
else
{
m_flGunYaw = MAX( 0, m_flGunYaw - (gpGlobals->frametime * MANNEDGUN_RESTORE_TURN_RATE) );
}
}
else
{
// We're done
return;
}
// Keep thinking
SetContextThink( BaseMannedGunThink, gpGlobals->curtime + 0.1, OBJ_BASE_MANNEDGUN_THINK_CONTEXT );
}
#ifndef CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose: Get and set the current driver.
//-----------------------------------------------------------------------------
void CObjectBaseMannedGun::SetPassenger( int nRole, CBasePlayer *pEnt )
{
BaseClass::SetPassenger( nRole, pEnt );
// If we don't have a driver anymore, return to our original facing after a while
if ( !GetDriverPlayer() && (m_flGunPitch || m_flGunYaw) )
{
StopDesignating();
SetContextThink( BaseMannedGunThink, gpGlobals->curtime + MANNEDGUN_RESTORE_TIME, OBJ_BASE_MANNEDGUN_THINK_CONTEXT );
}
}
#endif
//-----------------------------------------------------------------------------
// Here's where we deal with weapons
//-----------------------------------------------------------------------------
void CObjectBaseMannedGun::OnItemPostFrame( CBaseTFPlayer *pDriver )
{
// I can't do anything if I'm not active
if ( !ShouldBeActive() )
return;
if ( !IsReadyToDrive() )
return;
// If we don't have a laser designator yet, create one
if ( !m_hLaserDesignation )
{
m_hLaserDesignation = CEnvLaserDesignation::CreatePredicted( pDriver );
}
// Designating?
if (pDriver->m_nButtons & IN_ATTACK2)
{
UpdateDesignator();
return;
}
StopDesignating();
// Fire our base weapon?
if ( pDriver->m_nButtons & IN_ATTACK )
{
Fire();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CObjectBaseMannedGun::StopDesignating( void )
{
// Remove our beam if we just stopped designating
if ( m_hBeam.Get() )
{
m_hBeam->Remove( );
}
if ( m_hLaserDesignation.Get() )
{
m_hLaserDesignation->SetActive( false );
}
}
//-----------------------------------------------------------------------------
// Purpose: Update the designator position
//-----------------------------------------------------------------------------
void CObjectBaseMannedGun::UpdateDesignator( void )
{
// Make the beam, if we don't have one yet
if ( !m_hBeam && GetDriverPlayer() )
{
m_hBeam = BEAM_CREATE_PREDICTABLE_PERSIST( "sprites/laserbeam.vmt", 5, GetDriverPlayer() );
if ( m_hBeam.Get() )
{
m_hBeam->PointEntInit( vec3_origin, this );
m_hBeam->SetEndAttachment( m_nBarrelAttachment );
m_hBeam->SetColor( 255, 32, 32 );
m_hBeam->SetBrightness( 255 );
m_hBeam->SetNoise( 0 );
m_hBeam->SetWidth( 0.5 );
m_hBeam->SetEndWidth( 0.5 );
}
}
// We have to flush the bone cache because it's possible that only the bone controllers
// have changed since the bonecache was generated, and bone controllers aren't checked.
InvalidateBoneCache();
QAngle vecAng;
Vector vecSrc, vecAim;
GetAttachment( m_nBarrelAttachment, vecSrc, vecAng );
AngleVectors( vecAng, &vecAim, 0, 0 );
// "Fire" the designator beam
Vector vecEnd = vecSrc + vecAim * obj_manned_gun_designator_range.GetFloat();
trace_t tr;
TFGameRules()->WeaponTraceLine(vecSrc, vecEnd, MASK_SHOT, this, DMG_PROBE, &tr);
if ( m_hLaserDesignation.Get() )
{
// Only update our designated target point if we hit something
if ( tr.fraction != 1.0 )
{
m_hLaserDesignation->SetActive( true );
m_hLaserDesignation->SetAbsOrigin( tr.endpos );
}
else
{
m_hLaserDesignation->SetActive( false );
}
}
// Update beam visual
if ( m_hBeam.Get() )
{
m_hBeam->SetStartPos( tr.endpos );
m_hBeam->RelinkBeam();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CObjectBaseMannedGun::SetupMove( CBasePlayer *pPlayer, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move )
{
BaseClass::SetupMove( pPlayer, ucmd, pHelper, move );
CTFMoveData *pMoveData = (CTFMoveData*)move;
Assert( sizeof(MannedPlasmagunData_t) <= pMoveData->VehicleDataMaxSize() );
MannedPlasmagunData_t *pVehicleData = (MannedPlasmagunData_t*)pMoveData->VehicleData();
pVehicleData->m_pVehicle = this;
pVehicleData->m_flGunYaw = m_flGunYaw;
pVehicleData->m_flGunPitch = m_flGunPitch;
pVehicleData->m_flBarrelPitch = m_flBarrelPitch;
pVehicleData->m_nMoveStyle = m_nMoveStyle;
pVehicleData->m_flBarrelHeight = m_flBarrelHeight;
pVehicleData->m_nBarrelPivotAttachment = m_nBarrelPivotAttachment;
pVehicleData->m_nBarrelAttachment = m_nBarrelAttachment;
pVehicleData->m_nStandAttachment = m_nStandAttachment;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CObjectBaseMannedGun::FinishMove( CBasePlayer *player, CUserCmd *ucmd, CMoveData *move )
{
BaseClass::FinishMove( player, ucmd, move );
CTFMoveData *pMoveData = (CTFMoveData*)move;
Assert( sizeof(MannedPlasmagunData_t) <= pMoveData->VehicleDataMaxSize() );
MannedPlasmagunData_t *pVehicleData = (MannedPlasmagunData_t*)pMoveData->VehicleData();
m_flGunYaw = pVehicleData->m_flGunYaw;
m_flGunPitch = pVehicleData->m_flGunPitch;
m_flBarrelPitch = pVehicleData->m_flBarrelPitch;
// Set the bone state..
SetBoneController( 0, m_flGunYaw );
SetBoneController( 1, m_flGunPitch );
if ( m_nMoveStyle == MOVEMENT_STYLE_BARREL_PIVOT )
{
SetBoneController( 2, m_flBarrelPitch );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CObjectBaseMannedGun::ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMove )
{
m_Movement.ProcessMovement( pPlayer, pMove );
m_flGunPitch = AngleNormalize( m_flGunPitch );
m_flBarrelPitch = AngleNormalize( m_flBarrelPitch );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float CObjectBaseMannedGun::GetGunYaw() const
{
return m_flGunYaw;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float CObjectBaseMannedGun::GetGunPitch() const
{
return m_flGunPitch;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CObjectBaseMannedGun::ShouldUseThirdPersonVehicleView( void )
{
if ( mannedgun_usethirdperson.GetInt() )
{
// We want to use third person if we're mounted on a vehicle.
return dynamic_cast< CBaseTFVehicle* >( GetMoveParent() ) != NULL;
}
else
{
return false;
}
}
#if defined( CLIENT_DLL )
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_ObjectBaseMannedGun::OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged(updateType);
if ( updateType == DATA_UPDATE_CREATED )
{
// FIXME: Will this work with build animations models?
m_nBarrelAttachment = LookupAttachment( "barrel" );
m_nBarrelPivotAttachment = LookupAttachment( "barrelpivot" );
m_nStandAttachment = LookupAttachment( "vehicle_feet_passenger0" );
// Find the barrel height in its quiescent state...
Vector vBarrel;
QAngle vBarrelAngles;
GetAttachmentLocal(m_nBarrelAttachment, vBarrel, vBarrelAngles);
m_flBarrelHeight = vBarrel.z;
// HACK HACK: This should be read from a .txt file at some point!!!!
CHudTexture newTexture;
Q_strncpy( newTexture.szTextureFile, "sprites/crosshairs", sizeof( newTexture.szTextureFile ) );
newTexture.rc.left = 0;
newTexture.rc.top = 48;
newTexture.rc.right = newTexture.rc.left + 24;
newTexture.rc.bottom = newTexture.rc.top + 24;
iconCrosshair = gHUD.AddUnsearchableHudIconToList( newTexture );
}
else
{
// Set the bone state..
SetBoneController( 0, m_flGunYaw );
SetBoneController( 1, m_flGunPitch );
if ( m_nMoveStyle == MOVEMENT_STYLE_BARREL_PIVOT )
{
SetBoneController( 2, m_flBarrelPitch );
}
}
}
//-----------------------------------------------------------------------------
// Clamps the view angles while manning the gun
//-----------------------------------------------------------------------------
void C_ObjectBaseMannedGun::UpdateViewAngles( C_BasePlayer *pLocalPlayer, CUserCmd *pCmd )
{
#if 0
// Confine the view to the appropriate yaw range...
float flAngleDiff = AngleDiff( pCmd->viewangles[YAW], flCenterYaw );
// Here, we must clamp to the cone...
if (flAngleDiff < m_Movement.GetMinYaw())
pCmd->viewangles[YAW] = anglemod(flCenterYaw + m_Movement.GetMinYaw());
else if (flAngleDiff > m_Movement.GetMaxYaw())
pCmd->viewangles[YAW] = anglemod(flCenterYaw + m_Movement.GetMaxYaw());
#endif
// Prevent too much downward looking
if ( pCmd->viewangles[PITCH] > m_Movement.GetMaxPitch())
{
pCmd->viewangles[PITCH] = m_Movement.GetMaxPitch();
}
}
//-----------------------------------------------------------------------------
// Orients the gun correctly
//-----------------------------------------------------------------------------
void C_ObjectBaseMannedGun::GetBoneControllers(float controllers[MAXSTUDIOBONECTRLS], float dadt)
{
// turret angle values:
// 0 = front, 90 = left, 180 = back, 270 = right
studiohdr_t *pModel = modelinfo->GetStudiomodel( GetModel() );
Studio_SetController(pModel, 0, m_flGunYaw, controllers[0]);
Studio_SetController(pModel, 1, m_flGunPitch, controllers[1]);
if ( m_nMoveStyle == MOVEMENT_STYLE_BARREL_PIVOT )
{
Studio_SetController(pModel, 2, m_flBarrelPitch, controllers[2]);
}
}
//-----------------------------------------------------------------------------
// Purpose: Get the angles that a player in the specified role should be using for visuals
//-----------------------------------------------------------------------------
QAngle C_ObjectBaseMannedGun::GetPassengerAngles( QAngle angCurrent, int nRole )
{
// Stomp the current angle's pitch with our rotation
QAngle vecNewAngles = angCurrent;
angCurrent[PITCH] = m_flGunPitch;
return angCurrent;
}
//-----------------------------------------------------------------------------
// Renders hud elements
//-----------------------------------------------------------------------------
void C_ObjectBaseMannedGun::DrawHudElements( void )
{
GetHudAmmo()->SetPrimaryAmmo( m_nAmmoType, m_nAmmoCount );
GetHudAmmo()->SetSecondaryAmmo( -1, -1 );
// Let the plasma gun operator see a crosshair
DrawCrosshair();
}
//-----------------------------------------------------------------------------
// Purpose: Draw the weapon's crosshair
//-----------------------------------------------------------------------------
void C_ObjectBaseMannedGun::DrawCrosshair()
{
C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
if ( !player )
return;
CHudCrosshair *crosshair = GET_HUDELEMENT( CHudCrosshair );
if ( !crosshair )
return;
if ( iconCrosshair )
{
crosshair->SetCrosshair( iconCrosshair, gHUD.m_clrNormal );
}
else
{
static wrect_t nullrc;
crosshair->SetCrosshair( 0, Color( 255, 255, 255, 255 ) );
}
}
#endif
+169
View File
@@ -0,0 +1,169 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: A stationary gun that players can man
//
// $NoKeywords: $
//=============================================================================//
#ifndef TF_OBJ_BASE_MANNED_GUN_H
#define TF_OBJ_BASE_MANNED_GUN_H
#ifdef _WIN32
#pragma once
#endif
#include "basetfvehicle.h"
#include "tf_obj_manned_plasmagun_shared.h"
#include "env_laserdesignation.h"
#include "beam_shared.h"
class CMoveData;
#if defined( CLIENT_DLL )
#define CObjectBaseMannedGun C_ObjectBaseMannedGun
#define CBaseTFVehicle C_BaseTFVehicle
#endif
// ------------------------------------------------------------------------ //
// A stationary gun that players can man that's built by the player
// ------------------------------------------------------------------------ //
class CObjectBaseMannedGun : public CBaseTFVehicle
{
public:
DECLARE_NETWORKCLASS();
DECLARE_PREDICTABLE();
DECLARE_CLASS( CObjectBaseMannedGun, CBaseTFVehicle );
CObjectBaseMannedGun();
virtual void Spawn();
virtual void Precache();
virtual void UpdateOnRemove( void );
virtual void GetControlPanelInfo( int nPanelIndex, const char *&pPanelName );
virtual bool CanTakeEMPDamage( void ) { return true; }
virtual void OnGoInactive( void );
// Vehicle overrides
#ifndef CLIENT_DLL
virtual void SetPassenger( int nRole, CBasePlayer *pEnt );
#endif
virtual bool IsPassengerVisible( int nRole = VEHICLE_DRIVER ) { return true; }
// Returns the eye position
virtual void GetVehicleViewPosition( int nRole, Vector *pOrigin, QAngle *pAngles, float *pFOV = NULL );
// Manned plasma passengers aren't damagable
//virtual bool IsPassengerDamagable( int nRole = VEHICLE_DRIVER ) { return false; }
virtual void ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMove );
virtual void SetupMove( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move );
virtual void FinishMove( CBasePlayer *player, CUserCmd *ucmd, CMoveData *move );
virtual bool ShouldAttachToParent( void ) { return true; }
virtual bool MustNotBeBuiltInConstructionYard( void ) const { return true; }
virtual bool ShouldUseThirdPersonVehicleView( void );
virtual void BaseMannedGunThink( void );
float GetGunYaw() const;
float GetGunPitch() const;
// Buff
bool CanBeHookedToBuffStation( void );
#if defined ( CLIENT_DLL )
// IClientVehicle overrides.
public:
virtual void DrawHudElements( void );
virtual void UpdateViewAngles( C_BasePlayer *pLocalPlayer, CUserCmd *pCmd );
virtual QAngle GetPassengerAngles( QAngle angCurrent, int nRole );
// C_BaseEntity overrides.
public:
virtual void OnDataChanged( DataUpdateType_t updateType );
virtual void GetBoneControllers(float controllers[MAXSTUDIOBONECTRLS], float dadt);
private:
void DrawCrosshair( void );
#endif
protected:
// Sets up various attachment points once the model is selected
// Derived classes should call this from within their SetTeamModel call
void OnModelSelected();
// Can we get into the vehicle?
virtual bool CanGetInVehicle( CBaseTFPlayer *pPlayer );
// Here's where we deal with weapons
virtual void OnItemPostFrame( CBaseTFPlayer *pPassenger );
// Fire the weapon
virtual void Fire( void ) {}
void StopDesignating( void );
void UpdateDesignator( void );
virtual void SetupAttachedVersion( void );
virtual void SetupUnattachedVersion( void );
// Sets the movement style
void SetMovementStyle( MovementStyle_t style );
// Calculate the max range of this gun
void CalculateMaxRange( float flDefensiveRange, float flOffensiveRange );
protected:
// Movement...
CObjectMannedPlasmagunMovement m_Movement;
float m_flMaxRange;
// attachment points
int m_nBarrelAttachment;
int m_nBarrelPivotAttachment;
int m_nStandAttachment;
int m_nEyesAttachment;
// Movement style
CNetworkVar( MovementStyle_t, m_nMoveStyle );
// Barrel height...
float m_flBarrelHeight;
CNetworkVar( int, m_nAmmoType );
CNetworkVar( int, m_nAmmoCount );
CNetworkVar( float, m_flGunYaw ); // 0 = front, 90 = left, 180 = back, 270 = right
CNetworkVar( float, m_flGunPitch ); // 0 = forward, -90 = pointing down, 90 = pointing up..
CNetworkVar( float, m_flBarrelPitch );
float m_flReturnToInitialTime;
// Laser designation
CNetworkHandle( CBeam, m_hBeam );
CNetworkHandle( CEnvLaserDesignation, m_hLaserDesignation );
#if defined( CLIENT_DLL )
CHudTexture *iconCrosshair;
private:
CObjectBaseMannedGun( const CObjectBaseMannedGun & ); // not defined, not accessible
#endif
};
//-----------------------------------------------------------------------------
// Inline methods
//-----------------------------------------------------------------------------
inline bool CObjectBaseMannedGun::CanBeHookedToBuffStation( void )
{
return true;
}
#endif // TF_OBJ_BASE_MANNED_GUN_H
@@ -0,0 +1,92 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Base class for object upgrading objects
//
//=============================================================================//
#include "cbase.h"
#include "baseobject_shared.h"
#include "tf_obj_basedrivergun_shared.h"
#include "basetfvehicle.h"
IMPLEMENT_NETWORKCLASS_ALIASED( BaseObjectDriverGun, DT_BaseObjectDriverGun )
BEGIN_NETWORK_TABLE( CBaseObjectDriverGun, DT_BaseObjectDriverGun )
#if !defined( CLIENT_DLL )
SendPropVector( SENDINFO(m_vecGunAngles), -1, SPROP_COORD ),
#else
RecvPropVector( RECVINFO(m_vecGunAngles) ),
#endif
END_NETWORK_TABLE()
BEGIN_PREDICTION_DATA( CBaseObjectDriverGun )
DEFINE_PRED_FIELD_TOL( m_vecGunAngles, FIELD_VECTOR, FTYPEDESC_INSENDTABLE, 1.0f ),
END_PREDICTION_DATA()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CBaseObjectDriverGun::CBaseObjectDriverGun()
{
m_vecGunAngles = QAngle(0,0,0);
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseObjectDriverGun::Spawn()
{
BaseClass::Spawn();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseObjectDriverGun::FinishedBuilding( void )
{
#if !defined( CLIENT_DLL )
BaseClass::FinishedBuilding();
CBaseTFVehicle *pVehicle = dynamic_cast<CBaseTFVehicle*>(GetParentObject());
Assert( pVehicle );
pVehicle->SetDriverGun( this );
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseObjectDriverGun::SetTargetAngles( const QAngle &vecAngles )
{
m_vecGunAngles = vecAngles;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const QAngle &CBaseObjectDriverGun::GetCurrentAngles( void )
{
return m_vecGunAngles.Get();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
Vector CBaseObjectDriverGun::GetFireOrigin( void )
{
return GetAbsOrigin();
}
#ifdef CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CBaseObjectDriverGun::ShouldPredict( void )
{
CBaseTFVehicle *pVehicle = dynamic_cast<CBaseTFVehicle*>(GetParentObject());
if ( pVehicle && pVehicle->GetDriverPlayer() == C_BasePlayer::GetLocalPlayer() )
return true;
return BaseClass::ShouldPredict();
}
#endif
@@ -0,0 +1,64 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Base class for object upgrading objects
//
//=============================================================================//
#ifndef TF_OBJ_BASEDRIVERGUN_H
#define TF_OBJ_BASEDRIVERGUN_H
#ifdef _WIN32
#pragma once
#endif
#if defined( CLIENT_DLL )
#define CBaseObjectDriverGun C_BaseObjectDriverGun
#endif
#include "tf_obj_baseupgrade_shared.h"
// ------------------------------------------------------------------------
// Base class for objects that, when built on a vehicle, become under control of the driver
// ------------------------------------------------------------------------
class CBaseObjectDriverGun : public CBaseObjectUpgrade
{
DECLARE_CLASS( CBaseObjectDriverGun, CBaseObjectUpgrade );
public:
DECLARE_NETWORKCLASS();
DECLARE_PREDICTABLE();
CBaseObjectDriverGun();
virtual void Spawn( void );
virtual void FinishedBuilding( void );
// Firing
virtual bool CanFireNow( void ) { return false; }
virtual void Fire( CBaseTFPlayer *pDriver ) { return; }
// Turning
virtual void SetTargetAngles( const QAngle &vecAngles );
virtual const QAngle &GetCurrentAngles( void );
virtual Vector GetFireOrigin( void );
// HUD
virtual void DrawHudElements( void ) { return; }
#ifdef CLIENT_DLL
// All predicted weapons need to implement and return true
virtual bool IsPredicted( void ) const
{
return true;
}
virtual bool ShouldPredict( void );
#endif
protected:
CNetworkQAngle( m_vecGunAngles );
private:
CBaseObjectDriverGun( const CBaseObjectDriverGun & ); // not defined, not accessible
};
#endif // TF_OBJ_BASEDRIVERGUN_H
@@ -0,0 +1,58 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Base class for object upgrading objects
//
//=============================================================================//
#include "cbase.h"
#include "baseobject_shared.h"
#include "tf_obj_baseupgrade_shared.h"
IMPLEMENT_NETWORKCLASS_ALIASED( BaseObjectUpgrade, DT_BaseObjectUpgrade )
BEGIN_NETWORK_TABLE( CBaseObjectUpgrade, DT_BaseObjectUpgrade )
END_NETWORK_TABLE()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CBaseObjectUpgrade::CBaseObjectUpgrade()
{
#if !defined( CLIENT_DLL )
UseClientSideAnimation();
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseObjectUpgrade::Spawn()
{
BaseClass::Spawn();
#if !defined( CLIENT_DLL )
m_fObjectFlags |= OF_DONT_PREVENT_BUILD_NEAR_OBJ | OF_ALLOW_REPEAT_PLACEMENT |
OF_DOESNT_NEED_POWER | OF_MUST_BE_BUILT_ON_ATTACHMENT;
// Prevent anyone shooting / emping / buffing me
SetSolid( SOLID_NONE );
#endif
}
//-----------------------------------------------------------------------------
// Purpose: Prevent Team Damage
//-----------------------------------------------------------------------------
int CBaseObjectUpgrade::OnTakeDamage( const CTakeDamageInfo &info )
{
#if !defined( CLIENT_DLL )
// Check teams
if ( info.GetDamageType() & DMG_BLAST )
{
return 0;
}
return BaseClass::OnTakeDamage( info );
#else
return 0;
#endif
}
@@ -0,0 +1,41 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Base class for object upgrading objects
//
//=============================================================================//
#ifndef TF_OBJ_BASEUPGRADE_H
#define TF_OBJ_BASEUPGRADE_H
#ifdef _WIN32
#pragma once
#endif
#include "baseobject_shared.h"
#include "takedamageinfo.h"
#if defined( CLIENT_DLL )
#define CBaseObjectUpgrade C_BaseObjectUpgrade
#endif
// ------------------------------------------------------------------------ //
// Base class for object upgrading objects
// ------------------------------------------------------------------------ //
class CBaseObjectUpgrade : public CBaseObject
{
DECLARE_CLASS( CBaseObjectUpgrade, CBaseObject );
public:
DECLARE_NETWORKCLASS();
CBaseObjectUpgrade();
virtual void Spawn( void );
virtual bool IsAnUpgrade( void ) { return true; }
virtual int OnTakeDamage( const CTakeDamageInfo &info );
private:
CBaseObjectUpgrade( const CBaseObjectUpgrade & ); // not defined, not accessible
};
#endif // TF_OBJ_BASEUPGRADE_H
@@ -0,0 +1,219 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Vehicle mounted machinegun that the driver controls
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "basetfplayer_shared.h"
#include "baseobject_shared.h"
#include "tf_obj_driver_machinegun_shared.h"
#include "engine/IEngineSound.h"
#include "ammodef.h"
#include "tf_gamerules.h"
#if defined( CLIENT_DLL )
#include "hud_ammo.h"
#else
#endif
// ------------------------------------------------------------------------ //
#define DRIVER_MACHINEGUN_MINS Vector(-10, -10, 0)
#define DRIVER_MACHINEGUN_MAXS Vector( 10, 10, 10)
#define DRIVER_MACHINEGUN_MODEL "models/objects/obj_manned_plasmagun.mdl"
IMPLEMENT_NETWORKCLASS_ALIASED( ObjectDriverMachinegun, DT_ObjectDriverMachinegun )
BEGIN_NETWORK_TABLE( CObjectDriverMachinegun, DT_ObjectDriverMachinegun )
#if !defined( CLIENT_DLL )
SendPropInt( SENDINFO(m_nAmmoCount), 7, SPROP_UNSIGNED ),
#else
RecvPropInt( RECVINFO(m_nAmmoCount) ),
#endif
END_NETWORK_TABLE()
LINK_ENTITY_TO_CLASS(obj_driver_machinegun, CObjectDriverMachinegun);
PRECACHE_REGISTER(obj_driver_machinegun);
BEGIN_PREDICTION_DATA( CObjectDriverMachinegun )
DEFINE_PRED_FIELD( m_nAmmoCount, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
END_PREDICTION_DATA()
ConVar obj_driver_machinegun_health( "obj_driver_machinegun_health","100", FCVAR_REPLICATED, "Driver's mounted machinegun health" );
ConVar obj_driver_machinegun_range( "obj_driver_machinegun_range","1048", FCVAR_REPLICATED, "Driver's mounted machinegun range" );
ConVar obj_driver_machinegun_damage( "obj_driver_machinegun_damage","10", FCVAR_REPLICATED, "Driver's mounted machinegun damage" );
ConVar obj_driver_machinegun_max_ammo( "obj_driver_machinegun_max_ammo","30", FCVAR_REPLICATED, "Driver's mounted machinegun ammo" );
ConVar obj_driver_machinegun_ammo_recharge_rate( "obj_driver_machinegun_ammo_recharge_rate","0.5", FCVAR_REPLICATED, "Driver's mounted machinegun ammo recharge rate" );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CObjectDriverMachinegun::CObjectDriverMachinegun()
{
SetPredictionEligible( true );
#if !defined( CLIENT_DLL )
m_iHealth = obj_driver_machinegun_health.GetInt();
#endif
m_flNextAttack = 0;
m_nMaxAmmoCount = m_nAmmoCount = obj_driver_machinegun_max_ammo.GetInt();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CObjectDriverMachinegun::Spawn()
{
Precache();
SetModel( DRIVER_MACHINEGUN_MODEL );
#if !defined( CLIENT_DLL )
SetBodygroup( 1, true );
UTIL_SetSize(this, DRIVER_MACHINEGUN_MINS, DRIVER_MACHINEGUN_MAXS);
m_takedamage = DAMAGE_YES;
SetType( OBJ_DRIVER_MACHINEGUN );
m_fObjectFlags |= OF_SUPPRESS_NOTIFY_UNDER_ATTACK | OF_DONT_AUTO_REPAIR;
SetThink( RechargeThink );
#endif
m_nBarrelAttachment = LookupAttachment( "barrel" );
m_nAmmoType = GetAmmoDef()->Index( "Bullets" );
BaseClass::Spawn();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CObjectDriverMachinegun::Precache()
{
PrecacheModel( DRIVER_MACHINEGUN_MODEL );
PrecacheScriptSound( "DriverMachinegun.Fire" );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CObjectDriverMachinegun::CanFireNow( void )
{
if ( !m_nAmmoCount )
return false;
return ( m_flNextAttack < gpGlobals->curtime );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CObjectDriverMachinegun::Fire( CBaseTFPlayer *pDriver )
{
// We have to flush the bone cache because it's possible that only the bone controllers
// have changed since the bonecache was generated, and bone controllers aren't checked.
InvalidateBoneCache();
QAngle vecAng;
Vector vecSrc, vecAim;
GetAttachment( m_nBarrelAttachment, vecSrc, vecAng );
AngleVectors( vecAng, &vecAim, 0, 0 );
static Vector spread = VECTOR_CONE_5DEGREES;
TFGameRules()->FireBullets( CTakeDamageInfo( this, pDriver, obj_driver_machinegun_damage.GetFloat(), DMG_BULLET ),
1, vecSrc, vecAim, spread, obj_driver_machinegun_range.GetFloat(), m_nAmmoType, 4, entindex(), m_nBarrelAttachment );
#if !defined (CLIENT_DLL)
SetActivity( ACT_VM_PRIMARYATTACK );
#else
int sequence = SelectWeightedSequence( ACT_VM_PRIMARYATTACK );
if ( sequence != ACTIVITY_NOT_AVAILABLE )
{
ResetSequence( sequence );
SetCycle( 0 );
m_bClientSideFrameReset = !m_bClientSideFrameReset;
}
#endif
DoMuzzleFlash();
CPASAttenuationFilter filter( this );
filter.UsePredictionRules();
EmitSound( filter, entindex(), "DriverMachinegun.Fire" );
m_nAmmoCount -= 1;
#if !defined (CLIENT_DLL)
SetNextThink( gpGlobals->curtime + obj_driver_machinegun_ammo_recharge_rate.GetFloat() );
#endif
// If I'm EMPed, slow the firing rate down
m_flNextAttack = gpGlobals->curtime + ( HasPowerup(POWERUP_EMP) ? 0.3f : 0.15f );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CObjectDriverMachinegun::SetTargetAngles( const QAngle &vecAngles )
{
BaseClass::SetTargetAngles( vecAngles );
#if !defined( CLIENT_DLL )
SetBoneController( 0, vecAngles[YAW] );
SetBoneController( 1, vecAngles[PITCH] );
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
Vector CObjectDriverMachinegun::GetFireOrigin( void )
{
Vector vecOrigin;
QAngle dummy;
GetAttachment( m_nBarrelAttachment, vecOrigin, dummy );
return vecOrigin;
}
//-----------------------------------------------------------------------------
// Purpose: Rcharge my ammo count
//-----------------------------------------------------------------------------
void CObjectDriverMachinegun::RechargeThink( void )
{
#if !defined( CLIENT_DLL )
SetNextThink( gpGlobals->curtime + obj_driver_machinegun_ammo_recharge_rate.GetFloat() );
// I can't do anything if I'm not active
if ( !ShouldBeActive() )
return;
if (m_nAmmoCount < m_nMaxAmmoCount)
{
m_nAmmoCount += 1;
}
#endif
}
// Client code only
#if defined( CLIENT_DLL )
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CObjectDriverMachinegun::GetBoneControllers( float controllers[MAXSTUDIOBONECTRLS] )
{
BaseClass::GetBoneControllers( controllers );
controllers[0] = anglemod( m_vecGunAngles[YAW] ) / 360.0;
controllers[1] = anglemod( m_vecGunAngles[PITCH] ) / 360.0;
}
//-----------------------------------------------------------------------------
// Renders hud elements
//-----------------------------------------------------------------------------
void CObjectDriverMachinegun::DrawHudElements( void )
{
GetHudAmmo()->SetPrimaryAmmo( m_nAmmoType, m_nAmmoCount );
GetHudAmmo()->SetSecondaryAmmo( -1, -1 );
}
#endif
@@ -0,0 +1,62 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Vehicle mounted machinegun that the driver controls
//
//=============================================================================//
#ifndef TF_OBJ_DRIVER_MACHINEGUN_H
#define TF_OBJ_DRIVER_MACHINEGUN_H
#ifdef _WIN32
#pragma once
#endif
#include "tf_obj_basedrivergun_shared.h"
#if defined( CLIENT_DLL )
#define CObjectDriverMachinegun C_ObjectDriverMachinegun
#endif
// ------------------------------------------------------------------------ //
// Mounted machinegun
// ------------------------------------------------------------------------ //
class CObjectDriverMachinegun : public CBaseObjectDriverGun
{
DECLARE_CLASS( CObjectDriverMachinegun, CBaseObjectDriverGun );
public:
DECLARE_NETWORKCLASS();
DECLARE_PREDICTABLE();
CObjectDriverMachinegun();
virtual void Spawn();
virtual void Precache();
// Firing
virtual bool CanFireNow( void );
virtual void Fire( CBaseTFPlayer *pDriver );
// Turning
virtual Vector GetFireOrigin( void );
virtual void SetTargetAngles( const QAngle &vecAngles );
#if defined( CLIENT_DLL )
void GetBoneControllers( float controllers[MAXSTUDIOBONECTRLS] );
virtual void DrawHudElements( void );
#endif
// Ammo
void RechargeThink( void );
private:
float m_flNextAttack;
int m_nBarrelAttachment;
int m_nAmmoType;
CNetworkVar( int, m_nAmmoCount );
int m_nMaxAmmoCount;
private:
CObjectDriverMachinegun( const CObjectDriverMachinegun & ); // not defined, not accessible
};
#endif // TF_OBJ_DRIVER_MACHINEGUN_H
+304
View File
@@ -0,0 +1,304 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: A stationary gun that players can man
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "tf_obj_manned_plasmagun.h"
#include "ammodef.h"
#include "plasmaprojectile.h"
#include "SoundEmitterSystem/isoundemittersystembase.h"
#include "tf_gamerules.h"
#define MANNED_PLASMAGUN_MINS Vector(-20, -20, 0)
#define MANNED_PLASMAGUN_MAXS Vector( 20, 20, 55)
#define MANNED_PLASMAGUN_ALIEN_MODEL "models/objects/obj_manned_plasmagun.mdl"
#define MANNED_PLASMAGUN_HUMAN_MODEL "models/objects/human_obj_manned_plasmagun.mdl"
#define MANNED_PLASMAGUN_RECHARGE_TIME 0.2
#define MANNED_PLASMAGUN_IDLE_RECHARGE_TIME 0.1
#define MANNED_PLASMAGUN_IDLE_TIME 2.0
#if !defined( CLIENT_DLL )
BEGIN_DATADESC( CObjectMannedPlasmagun )
DEFINE_THINKFUNC( RechargeThink ),
END_DATADESC()
#endif
IMPLEMENT_NETWORKCLASS_ALIASED( ObjectMannedPlasmagun, DT_ObjectMannedPlasmagun )
BEGIN_NETWORK_TABLE( CObjectMannedPlasmagun, DT_ObjectMannedPlasmagun )
#if !defined( CLIENT_DLL )
SendPropTime( SENDINFO( m_flNextIdleTime ) ),
SendPropInt( SENDINFO( m_bFiringLeft ), 1, SPROP_UNSIGNED ),
SendPropInt( SENDINFO( m_nNextThinkTick ) ),
#else
RecvPropTime( RECVINFO( m_flNextIdleTime ) ),
RecvPropInt( RECVINFO( m_bFiringLeft ) ),
RecvPropInt ( RECVINFO( m_nNextThinkTick ) ),
#endif
END_NETWORK_TABLE()
BEGIN_PREDICTION_DATA( CObjectMannedPlasmagun )
DEFINE_PRED_FIELD_TOL( m_flNextIdleTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, TD_MSECTOLERANCE ),
DEFINE_PRED_FIELD( m_bFiringLeft, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
DEFINE_PRED_FIELD( m_nNextThinkTick, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
// DEFINE_FIELD( m_nRightBarrelAttachment, FIELD_INTEGER ),
DEFINE_FIELD( m_nMaxAmmoCount, FIELD_INTEGER ),
END_PREDICTION_DATA()
LINK_ENTITY_TO_CLASS(obj_manned_plasmagun, CObjectMannedPlasmagun);
PRECACHE_REGISTER(obj_manned_plasmagun);
// CVars
ConVar obj_manned_plasmagun_health( "obj_manned_plasmagun_health","100", FCVAR_REPLICATED, "Manned Plasmagun health" );
ConVar obj_manned_plasmagun_range_def( "obj_manned_plasmagun_range_def","1000", FCVAR_REPLICATED, "Defensive Manned Plasmagun range" );
ConVar obj_manned_plasmagun_range_off( "obj_manned_plasmagun_range_off","1000", FCVAR_REPLICATED, "Offensive Manned Plasmagun range" );
ConVar obj_manned_plasmagun_damage( "obj_manned_plasmagun_damage","20", FCVAR_REPLICATED, "Manned Plasmagun damage" );
ConVar obj_manned_plasmagun_radius( "obj_manned_plasmagun_radius","128", FCVAR_REPLICATED, "Manned Plasmagun explosive radius" );
ConVar obj_manned_plasmagun_clip( "obj_manned_plasmagun_clip","35", FCVAR_REPLICATED, "Manned Plasmagun's clip size" );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CObjectMannedPlasmagun::CObjectMannedPlasmagun()
{
m_bFiringLeft = true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CObjectMannedPlasmagun::Precache()
{
BaseClass::Precache();
PrecacheModel( MANNED_PLASMAGUN_ALIEN_MODEL );
PrecacheModel( MANNED_PLASMAGUN_HUMAN_MODEL );
PrecacheScriptSound( "ObjectMannedPlasmagun.Fire" );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CObjectMannedPlasmagun::SetupTeamModel( void )
{
// FIXME: When adding in build animations here, make sure C_ObjectBaseMannedGun::OnDataChanged
// does the right thing on the client!!
if ( GetTeamNumber() == TEAM_HUMANS )
{
SetMovementStyle( MOVEMENT_STYLE_BARREL_PIVOT );
SetModel( MANNED_PLASMAGUN_HUMAN_MODEL );
}
else
{
SetMovementStyle( MOVEMENT_STYLE_STANDARD );
SetModel( MANNED_PLASMAGUN_ALIEN_MODEL );
}
// Call this to get all the attachment points happy
OnModelSelected();
// Get our extra barrel
m_nRightBarrelAttachment = LookupAttachment( "barrelR" );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CObjectMannedPlasmagun::Spawn()
{
Precache();
SetSolid( SOLID_BBOX );
SetSize( MANNED_PLASMAGUN_MINS, MANNED_PLASMAGUN_MAXS );
SetHealth( obj_manned_plasmagun_health.GetInt() );
SetNextThink( gpGlobals->curtime + MANNED_PLASMAGUN_IDLE_RECHARGE_TIME );
SetType( OBJ_MANNED_PLASMAGUN );
m_nAmmoCount = m_nMaxAmmoCount = obj_manned_plasmagun_clip.GetInt();
m_flNextAttack = gpGlobals->curtime;
m_nAmmoType = GetAmmoDef()->Index( "RechargeEnergy" );
SetThink( RechargeThink );
BaseClass::Spawn();
}
//-----------------------------------------------------------------------------
// Purpose: Finished the build
//-----------------------------------------------------------------------------
void CObjectMannedPlasmagun::FinishedBuilding( void )
{
BaseClass::FinishedBuilding();
CalculateMaxRange( obj_manned_plasmagun_range_def.GetFloat(), obj_manned_plasmagun_range_off.GetFloat() );
}
//-----------------------------------------------------------------------------
// Recharge think...
//-----------------------------------------------------------------------------
void CObjectMannedPlasmagun::RechargeThink( )
{
// Prevent manned guns from deteriorating
ResetDeteriorationTime();
float flNextRechargeTime = MANNED_PLASMAGUN_RECHARGE_TIME;
/*
ROBIN: Remove idle recharging for now
if (gpGlobals->curtime >= m_flNextIdleTime)
flNextRechargeTime = MANNED_PLASMAGUN_IDLE_RECHARGE_TIME;
else
flNextRechargeTime = MANNED_PLASMAGUN_RECHARGE_TIME;
*/
// If I'm EMPed, slow the recharge rate down
if ( HasPowerup(POWERUP_EMP) )
{
flNextRechargeTime *= 1.5;
}
SetNextThink( gpGlobals->curtime + flNextRechargeTime );
// I can't do anything if I'm not active
if ( !ShouldBeActive() )
return;
if (m_nAmmoCount < m_nMaxAmmoCount)
{
++m_nAmmoCount;
}
else
{
// No need to think when it's full
SetNextThink( gpGlobals->curtime + 5.0f );
}
}
//-----------------------------------------------------------------------------
// Purpose: Plasma sentrygun's fire
//-----------------------------------------------------------------------------
void CObjectMannedPlasmagun::Fire( )
{
if (m_flNextAttack > gpGlobals->curtime)
return;
// Because the plasma sentrygun always thinks it has ammo (see below)
// we might not have ammo here, in which case we should just abort.
if ( !m_nAmmoCount )
return;
// Make sure we think soon enough in case of firing...
float flNextRecharge = gpGlobals->curtime + (HasPowerup(POWERUP_EMP) ? MANNED_PLASMAGUN_RECHARGE_TIME * 1.5 : MANNED_PLASMAGUN_RECHARGE_TIME);
SetNextThink( gpGlobals->curtime + flNextRecharge );
// We have to flush the bone cache because it's possible that only the bone controllers
// have changed since the bonecache was generated, and bone controllers aren't checked.
InvalidateBoneCache();
QAngle vecAng;
Vector vecSrc, vecAim;
// Alternate barrels when firing
if ( m_bFiringLeft )
{
// Aliens permanently fire left barrel because they have no right
if ( GetTeamNumber() == TEAM_HUMANS )
{
m_bFiringLeft = false;
}
GetAttachment( m_nBarrelAttachment, vecSrc, vecAng );
SetActivity( ACT_VM_PRIMARYATTACK );
}
else
{
m_bFiringLeft = true;
GetAttachment( m_nRightBarrelAttachment, vecSrc, vecAng );
SetActivity( ACT_VM_SECONDARYATTACK );
}
// Get the distance to the target
AngleVectors( vecAng, &vecAim, 0, 0 );
int damageType = GetAmmoDef()->DamageType( m_nAmmoType );
CBasePlasmaProjectile *pPlasma = CBasePlasmaProjectile::CreatePredicted( vecSrc, vecAim, Vector( 0, 0, 0 ), damageType, GetDriverPlayer() );
if ( pPlasma )
{
pPlasma->SetDamage( obj_manned_plasmagun_damage.GetFloat() );
pPlasma->m_hOwner = GetDriverPlayer();
//pPlasma->SetOwnerEntity( this );
pPlasma->SetMaxRange( m_flMaxRange );
if ( obj_manned_plasmagun_radius.GetFloat() )
{
pPlasma->SetExplosive( obj_manned_plasmagun_radius.GetFloat() );
}
}
CSoundParameters params;
if ( GetParametersForSound( "ObjectMannedPlasmagun.Fire", params, NULL ) )
{
CPASAttenuationFilter filter( this, params.soundlevel );
if ( IsPredicted() )
{
filter.UsePredictionRules();
}
EmitSound( filter, entindex(), "ObjectMannedPlasmagun.Fire" );
}
// SetSentryAnim( TFTURRET_ANIM_FIRE );
DoMuzzleFlash();
--m_nAmmoCount;
m_flNextIdleTime = gpGlobals->curtime + MANNED_PLASMAGUN_IDLE_TIME;
// If I'm EMPed, slow the firing rate down
m_flNextAttack = gpGlobals->curtime + ( HasPowerup(POWERUP_EMP) ? 0.3f : 0.1f );
}
#if defined( CLIENT_DLL )
//-----------------------------------------------------------------------------
// Purpose:
// Input : updateType -
//-----------------------------------------------------------------------------
void CObjectMannedPlasmagun::PostDataUpdate( DataUpdateType_t updateType )
{
BaseClass::PostDataUpdate( updateType );
bool teamchanged = GetTeamNumber() != m_nPreviousTeam;
if ( teamchanged ||
updateType == DATA_UPDATE_CREATED )
{
C_BaseAnimating::AllowBoneAccess( true, false );
SetupTeamModel();
C_BaseAnimating::AllowBoneAccess( false, false );
}
}
void CObjectMannedPlasmagun::PreDataUpdate( DataUpdateType_t updateType )
{
BaseClass::PreDataUpdate( updateType );
m_nPreviousTeam = GetTeamNumber();
}
#endif
+88
View File
@@ -0,0 +1,88 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: A stationary gun that players can man
//
// $NoKeywords: $
//=============================================================================//
#ifndef TF_OBJ_MANNED_PLASMAGUN_H
#define TF_OBJ_MANNED_PLASMAGUN_H
#ifdef _WIN32
#pragma once
#endif
#include "tf_obj_base_manned_gun.h"
#if defined( CLIENT_DLL )
#define CObjectMannedPlasmagun C_ObjectMannedPlasmagun
#endif
// ------------------------------------------------------------------------ //
// A stationary gun that players can man that's built by the player
// ------------------------------------------------------------------------ //
class CObjectMannedPlasmagun : public CObjectBaseMannedGun
{
public:
#if !defined( CLIENT_DLL )
DECLARE_DATADESC();
#endif
DECLARE_NETWORKCLASS();
DECLARE_PREDICTABLE();
DECLARE_CLASS( CObjectMannedPlasmagun, CObjectBaseMannedGun );
static CObjectMannedPlasmagun* Create(const Vector &vOrigin, const QAngle &vAngles);
CObjectMannedPlasmagun();
virtual void Spawn();
virtual void Precache();
virtual void SetupTeamModel( void );
virtual void FinishedBuilding( void );
// All predicted weapons need to implement and return true
virtual bool IsPredicted( void ) const
{
return true;
}
#if defined( CLIENT_DLL )
virtual bool ShouldPredict( void )
{
if ( GetOwner() == C_BasePlayer::GetLocalPlayer() )
return true;
return BaseClass::ShouldPredict();
}
virtual void PreDataUpdate( DataUpdateType_t updateType );
virtual void PostDataUpdate( DataUpdateType_t updateType );
#endif
protected:
// Think function
void RechargeThink();
// Fire the weapon
virtual void Fire( void );
protected:
int m_nMaxAmmoCount;
CNetworkVar( float, m_flNextIdleTime );
// Handling for the multiple barrels
int m_nRightBarrelAttachment;
CNetworkVar( bool, m_bFiringLeft );
private:
CObjectMannedPlasmagun( const CObjectMannedPlasmagun& src );
int m_nPreviousTeam;
};
#endif // TF_OBJ_MANNED_PLASMAGUN_H
@@ -0,0 +1,117 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: A stationary gun that players can man
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "tf_obj_manned_plasmagun_shared.h"
#include "tf_movedata.h"
ConVar mannedgun_usethirdperson( "mannedgun_usethirdperson", "1", FCVAR_REPLICATED, "Use third person view while in manned guns built on vehicles." );
#define MANNED_PLASMAGUN_AIMING_CONE_ANGLE 45.0f // total angle of aiming
#define MANNED_PLASMAGUN_YAW_SPEED 1000.0f
#define MANNED_PLASMAGUN_MAX_PITCH 50.0f
#define MANNED_PLASMAGUN_BARREL_MAX_PITCH 30.0f
float CObjectMannedPlasmagunMovement::GetMaxYaw() const
{
return MANNED_PLASMAGUN_AIMING_CONE_ANGLE;
}
float CObjectMannedPlasmagunMovement::GetMinYaw() const
{
return -MANNED_PLASMAGUN_AIMING_CONE_ANGLE;
}
float CObjectMannedPlasmagunMovement::GetMaxPitch() const
{
return MANNED_PLASMAGUN_MAX_PITCH;
}
void CObjectMannedPlasmagunMovement::ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMove )
{
CTFMoveData *pMoveData = (CTFMoveData*)pMove;
Assert( sizeof(MannedPlasmagunData_t) <= pMoveData->VehicleDataMaxSize() );
MannedPlasmagunData_t *pVehicleData = (MannedPlasmagunData_t*)pMoveData->VehicleData();
bool bSimple = (pVehicleData->m_nMoveStyle == MOVEMENT_STYLE_SIMPLE);
CBaseTFVehicle *pVehicle = pVehicleData->m_pVehicle;
// Flush caches since bone controllers might be wrong since they are not in the cache yet
pVehicle->InvalidateBoneCache();
// Get the view direction *in world coordinates*
Vector vPlayerEye = pPlayer->EyePosition();
QAngle angEyeAngles = pPlayer->LocalEyeAngles();
Vector vPlayerForward;
AngleVectors( angEyeAngles, &vPlayerForward, NULL, NULL );
// Now figure out the pitch. This is done by casting a ray to see where the player's aiming reticle is pointing.
// Then we do some trig to find out what angle the turret should point so it can see the target.
// NOTE: this is done in the tank's local space so it works when the tank is banked.
VMatrix mGunToWorld = SetupMatrixTranslation(pVehicle->GetAbsOrigin()) * SetupMatrixAngles(pVehicle->GetAbsAngles());
VMatrix mWorldToGun = mGunToWorld.InverseTR();
// First trace only on the world..
Vector start = vPlayerEye;
Vector end = start + vPlayerForward * 5000.0f;
Vector vTarget;
if ( bSimple )
{
vTarget = end;
}
else
{
trace_t trace;
UTIL_TraceLine(start, end, MASK_SOLID_BRUSHONLY, pVehicle, COLLISION_GROUP_NONE, &trace);
vTarget = trace.endpos;
if(trace.fraction == 1)
{
// It didn't hit the world, so trace on ents.
UTIL_TraceLine(start, end, MASK_PLAYERSOLID|MASK_NPCSOLID, pVehicle, COLLISION_GROUP_NONE, &trace);
vTarget = trace.endpos;
if(trace.fraction == 1)
{
// Didn't hit any ents.. just assume it's way out in front of the player's view.
vTarget = end;
}
}
}
// Transform the world position into gun space.
vTarget = mWorldToGun * vTarget;
// Compute the position of the barrel pivot point as measured in the coordinate system of the gun
Vector vTurretBase;
QAngle vTurretBaseAngles;
pVehicle->GetAttachment(pVehicleData->m_nBarrelPivotAttachment, vTurretBase, vTurretBaseAngles);
vTurretBase = mWorldToGun * vTurretBase;
// Make everything be relative to the pivot...
vTarget -= vTurretBase;
// Now we've got the target vector in local space. Now just figure out what
// the gun angles need to be to hit the target.
QAngle vWantedAngles;
VectorAngles( vTarget, vWantedAngles );
pVehicleData->m_flGunPitch = vWantedAngles[PITCH];
pVehicleData->m_flGunYaw = vWantedAngles[YAW];
// Place the player at the feet of the vehicle
Vector vStandAngles;
pVehicle->GetAttachmentLocal(pVehicleData->m_nStandAttachment, pMove->m_vecAbsOrigin, pMove->m_vecAngles);
}
@@ -0,0 +1,50 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: A stationary gun that players can man
//
// $NoKeywords: $
//=============================================================================//
#ifndef TF_OBJ_MANNED_PLASMAGUN_SHARED_H
#define TF_OBJ_MANNED_PLASMAGUN_SHARED_H
#ifdef _WIN32
#pragma once
#endif
#include "basetfvehicle.h"
class CMoveData;
enum MovementStyle_t
{
MOVEMENT_STYLE_STANDARD = 0,
MOVEMENT_STYLE_BARREL_PIVOT = 1,
MOVEMENT_STYLE_SIMPLE = 2,
};
struct MannedPlasmagunData_t : public VehicleBaseMoveData_t
{
float m_flGunYaw;
float m_flGunPitch;
float m_flBarrelPitch;
float m_flBarrelHeight;
int m_nBarrelPivotAttachment;
int m_nBarrelAttachment;
int m_nStandAttachment;
MovementStyle_t m_nMoveStyle;
};
class CObjectMannedPlasmagunMovement
{
public:
void ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMove );
float GetMaxYaw() const;
float GetMinYaw() const;
float GetMaxPitch() const;
};
#endif // TF_OBJ_MANNED_PLASMAGUN_SHARED_H
+76
View File
@@ -0,0 +1,76 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef TF_PLAYERANIMSTATE_H
#define TF_PLAYERANIMSTATE_H
#ifdef _WIN32
#pragma once
#endif
#include "studio.h"
#if defined( CLIENT_DLL )
#define CBaseTFPlayer C_BaseTFPlayer
#endif
class CPlayerAnimState
{
public:
enum
{
TURN_NONE = 0,
TURN_LEFT,
TURN_RIGHT
};
CPlayerAnimState( CBaseTFPlayer *outer );
Activity BodyYawTranslateActivity( Activity activity );
void Update();
const QAngle& GetRenderAngles();
void GetPoseParameters( float poseParameter[MAXSTUDIOPOSEPARAM] );
CBaseTFPlayer *GetOuter();
private:
void GetOuterAbsVelocity( Vector& vel );
int ConvergeAngles( float goal,float maxrate, float dt, float& current );
void EstimateYaw( void );
void ComputePoseParam_BodyYaw( void );
void ComputePoseParam_BodyPitch( void );
void ComputePoseParam_BodyLookYaw( void );
void ComputePlaybackRate();
CBaseTFPlayer *m_pOuter;
float m_flGaitYaw;
float m_flStoredCycle;
// The following variables are used for tweaking the yaw of the upper body when standing still and
// making sure that it smoothly blends in and out once the player starts moving
// Direction feet were facing when we stopped moving
float m_flGoalFeetYaw;
float m_flCurrentFeetYaw;
float m_flCurrentTorsoYaw;
// To check if they are rotating in place
float m_flLastYaw;
// Time when we stopped moving
float m_flLastTurnTime;
// One of the above enums
int m_nTurningInPlace;
QAngle m_angRender;
};
#endif // TF_PLAYERANIMSTATE_H
+64
View File
@@ -0,0 +1,64 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "tf_reconvars.h"
// FIXME: put these in a config file.
CReconJetpackLevel g_ReconJetpackLevels[MAX_TF_TECHLEVELS] =
{
{
0.35f, // How fast the jetpack recharges.
1.0f, // How fast the jetpack depletes.
-0.1f, // When the jetpack is fully depleted, it snaps to this so the pilot sputters.
150, // Fastest you can go upwards.
15 // How fast it accelerates.
},
{
0.55f, // How fast the jetpack recharges.
0.75f, // How fast the jetpack depletes.
-0.1f, // When the jetpack is fully depleted, it snaps to this so the pilot sputters.
150, // Fastest you can go upwards.
15 // How fast it accelerates.
},
{
0.55f, // How fast the jetpack recharges.
0.55f, // How fast the jetpack depletes.
-0.1f, // When the jetpack is fully depleted, it snaps to this so the pilot sputters.
200, // Fastest you can go upwards.
15 // How fast it accelerates.
},
{
0.75f, // How fast the jetpack recharges.
0.35f, // How fast the jetpack depletes.
-0.1f, // When the jetpack is fully depleted, it snaps to this so the pilot sputters.
200, // Fastest you can go upwards.
15 // How fast it accelerates.
},
// Not used
{
0.7f, // How fast the jetpack recharges.
1.0f, // How fast the jetpack depletes.
-0.1f, // When the jetpack is fully depleted, it snaps to this so the pilot sputters.
130, // Fastest you can go upwards.
15 // How fast it accelerates.
},
{
0.7f, // How fast the jetpack recharges.
1.0f, // How fast the jetpack depletes.
-0.1f, // When the jetpack is fully depleted, it snaps to this so the pilot sputters.
130, // Fastest you can go upwards.
15 // How fast it accelerates.
},
};
+31
View File
@@ -0,0 +1,31 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef TF_RECONVARS_H
#define TF_RECONVARS_H
#pragma once
#include "techtree.h"
// Jetpack vars for each tech level.
class CReconJetpackLevel
{
public:
float m_RechargeRate; // How fast the jetpack recharges.
float m_DepleteRate; // How fast the jetpack depletes.
float m_NegSnap; // When the jetpack is fully depleted, it snaps to this so the pilot sputters.
float m_MaxVerticalVel; // Fastest you can go upwards.
float m_AccelRate; // How fast it accelerates.
};
extern CReconJetpackLevel g_ReconJetpackLevels[MAX_TF_TECHLEVELS];
#endif // TF_RECONVARS_H
+605
View File
@@ -0,0 +1,605 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Data shared between the client & game dlls
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "tf_shareddefs.h"
#include "tier0/dbg.h"
#include "basetypes.h"
#include <KeyValues.h>
#ifndef CLIENT_DLL
#include "tf_team.h"
#include "tf_class_commando.h"
#include "tf_class_defender.h"
#include "tf_class_escort.h"
#include "tf_class_infiltrator.h"
#include "tf_class_medic.h"
#include "tf_class_recon.h"
#include "tf_class_sniper.h"
#include "tf_class_support.h"
#include "tf_class_sapper.h"
#include "tf_class_pyro.h"
#else
#include "c_tfteam.h"
#include "c_tf_class_commando.h"
#include "c_tf_class_defender.h"
#include "c_tf_class_escort.h"
#include "c_tf_class_infiltrator.h"
#include "c_tf_class_medic.h"
#include "c_tf_class_recon.h"
#include "c_tf_class_sniper.h"
#include "c_tf_class_support.h"
#include "c_tf_class_sapper.h"
#include "c_tf_class_pyro.h"
#define CTFTeam C_TFTeam
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
ConVar inv_demo( "inv_demo","0", FCVAR_REPLICATED, "Invasion demo." );
ConVar lod_effect_distance( "lod_effect_distance","3240000", FCVAR_REPLICATED, "Distance at which effects LOD." );
ConVar tf_cheapobjects( "tf_cheapobjects","0", FCVAR_REPLICATED, "Set to 1 and all objects will cost 0" );
//--------------------------------------------------------------------------
// OBJECTS
//--------------------------------------------------------------------------
static int g_iClassInfo_Undecided[] =
{
OBJ_LAST
};
static int g_iClassInfo_Recon[] =
{
OBJ_WAGON,
OBJ_LAST
};
static int g_iClassInfo_Commando[] =
{
OBJ_POWERPACK,
OBJ_VEHICLE_BOOST,
OBJ_DRAGONSTEETH,
OBJ_MANNED_MISSILELAUNCHER,
OBJ_SANDBAG_BUNKER,
OBJ_DRAGONSTEETH,
OBJ_LAST
};
static int g_iClassInfo_Medic[] =
{
OBJ_POWERPACK,
OBJ_SELFHEAL,
OBJ_BUFF_STATION,
OBJ_MANNED_PLASMAGUN,
OBJ_SANDBAG_BUNKER,
OBJ_BUNKER,
OBJ_DRAGONSTEETH,
OBJ_SHIELDWALL,
OBJ_LAST
};
static int g_iClassInfo_Defender[] =
{
OBJ_POWERPACK,
OBJ_SENTRYGUN_PLASMA,
OBJ_MANNED_MISSILELAUNCHER,
OBJ_BARBED_WIRE,
OBJ_DRAGONSTEETH,
OBJ_TOWER,
OBJ_SANDBAG_BUNKER,
OBJ_BUNKER,
OBJ_DRIVER_MACHINEGUN,
//OBJ_MORTAR,
OBJ_LAST
};
static int g_iClassInfo_Sniper[] =
{
OBJ_WAGON,
OBJ_LAST
};
static int g_iClassInfo_Support[] =
{
OBJ_WAGON,
OBJ_LAST
};
static int g_iClassInfo_Escort[] =
{
OBJ_SHIELDWALL,
OBJ_MANNED_SHIELD,
OBJ_SANDBAG_BUNKER,
OBJ_BUNKER,
OBJ_LAST
};
static int g_iClassInfo_Sapper[] =
{
OBJ_POWERPACK,
OBJ_DRAGONSTEETH,
OBJ_TOWER,
OBJ_SANDBAG_BUNKER,
OBJ_MANNED_PLASMAGUN,
OBJ_LAST
};
static int g_iClassInfo_Infiltrator[] =
{
OBJ_WAGON,
OBJ_LAST
};
static int g_iClassInfo_Pyro[] =
{
OBJ_WAGON,
OBJ_LAST
};
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool IsObjectAnUpgrade( int iObjectType )
{
return ( iObjectType >= OBJ_SELFHEAL && iObjectType < OBJ_BATTERING_RAM );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool IsObjectAVehicle( int iObjectType )
{
return ( iObjectType >= OBJ_BATTERING_RAM && iObjectType < OBJ_TOWER );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool IsObjectADefensiveBuilding( int iObjectType )
{
return ( iObjectType >= OBJ_TOWER );
}
//--------------------------------------------------------------------------
// PLAYER CLASSES
//--------------------------------------------------------------------------
#if defined( CLIENT_DLL )
#define DEFINE_PLAYERCLASS_ALLOC_FNS( className, iClass ) \
C_PlayerClass* AllocClient##className##( C_BaseTFPlayer *pPlayer ) \
{ \
return new C_PlayerClass##className##( pPlayer ); \
} \
CPlayerClass* AllocServer##className##( CBaseTFPlayer *pPlayer ) \
{ \
Assert( false ); \
return NULL; \
}
#define GENERATE_PLAYERCLASS_INFO( className ) \
AllocClient##className##, AllocServer##className, NULL
// ------------------------------------------------------------------------------------- //
// DT_AllPlayerClasses recv table.
// ------------------------------------------------------------------------------------- //
BEGIN_RECV_TABLE_NOBASE( C_AllPlayerClasses, DT_AllPlayerClasses )
RecvPropDataTable( RECVINFO_DT(m_pClasses[TFCLASS_COMMANDO]), 0, &REFERENCE_RECV_TABLE( DT_PlayerClassCommandoData ), DataTableRecvProxy_PointerDataTable ),
RecvPropDataTable( RECVINFO_DT(m_pClasses[TFCLASS_DEFENDER]), 0, &REFERENCE_RECV_TABLE( DT_PlayerClassDefenderData ), DataTableRecvProxy_PointerDataTable ),
RecvPropDataTable( RECVINFO_DT(m_pClasses[TFCLASS_ESCORT]), 0, &REFERENCE_RECV_TABLE( DT_PlayerClassEscortData ), DataTableRecvProxy_PointerDataTable ),
RecvPropDataTable( RECVINFO_DT(m_pClasses[TFCLASS_INFILTRATOR]), 0, &REFERENCE_RECV_TABLE( DT_PlayerClassInfiltratorData ), DataTableRecvProxy_PointerDataTable ),
RecvPropDataTable( RECVINFO_DT(m_pClasses[TFCLASS_MEDIC]), 0, &REFERENCE_RECV_TABLE( DT_PlayerClassMedicData ), DataTableRecvProxy_PointerDataTable ),
RecvPropDataTable( RECVINFO_DT(m_pClasses[TFCLASS_RECON]), 0, &REFERENCE_RECV_TABLE( DT_PlayerClassReconData ), DataTableRecvProxy_PointerDataTable ),
RecvPropDataTable( RECVINFO_DT(m_pClasses[TFCLASS_SNIPER]), 0, &REFERENCE_RECV_TABLE( DT_PlayerClassSniperData ), DataTableRecvProxy_PointerDataTable ),
RecvPropDataTable( RECVINFO_DT(m_pClasses[TFCLASS_SUPPORT]), 0, &REFERENCE_RECV_TABLE( DT_PlayerClassSupportData ), DataTableRecvProxy_PointerDataTable ),
RecvPropDataTable( RECVINFO_DT(m_pClasses[TFCLASS_SAPPER]), 0, &REFERENCE_RECV_TABLE( DT_PlayerClassSapperData ), DataTableRecvProxy_PointerDataTable )
END_RECV_TABLE()
#else
#define DEFINE_PLAYERCLASS_ALLOC_FNS( className, iClass ) \
ConVar class_##className##_health( "class_" #className "_health", "0", FCVAR_NONE, #className "'s max health" ); \
C_PlayerClass* AllocClient##className##( C_BaseTFPlayer *pPlayer ) \
{ \
Assert( false ); \
return NULL; \
} \
CPlayerClass* AllocServer##className##( CBaseTFPlayer *pPlayer ) \
{ \
return new CPlayerClass##className##( pPlayer, iClass ); \
}
#define GENERATE_PLAYERCLASS_INFO( className ) \
AllocClient##className##, AllocServer##className, &class_##className##_health
// ------------------------------------------------------------------------------------- //
// DT_AllPlayerClasses recv table.
// ------------------------------------------------------------------------------------- //
BEGIN_SEND_TABLE_NOBASE( CAllPlayerClasses, DT_AllPlayerClasses )
SendPropDataTable( SENDINFO_DT(m_pClasses[TFCLASS_COMMANDO]), &REFERENCE_SEND_TABLE( DT_PlayerClassCommandoData ), SendProxy_DataTablePtrToDataTable ),
SendPropDataTable( SENDINFO_DT(m_pClasses[TFCLASS_DEFENDER]), &REFERENCE_SEND_TABLE( DT_PlayerClassDefenderData ), SendProxy_DataTablePtrToDataTable ),
SendPropDataTable( SENDINFO_DT(m_pClasses[TFCLASS_ESCORT]), &REFERENCE_SEND_TABLE( DT_PlayerClassEscortData ), SendProxy_DataTablePtrToDataTable ),
SendPropDataTable( SENDINFO_DT(m_pClasses[TFCLASS_INFILTRATOR]),&REFERENCE_SEND_TABLE( DT_PlayerClassInfiltratorData ), SendProxy_DataTablePtrToDataTable ),
SendPropDataTable( SENDINFO_DT(m_pClasses[TFCLASS_MEDIC]), &REFERENCE_SEND_TABLE( DT_PlayerClassMedicData ), SendProxy_DataTablePtrToDataTable ),
SendPropDataTable( SENDINFO_DT(m_pClasses[TFCLASS_RECON]), &REFERENCE_SEND_TABLE( DT_PlayerClassReconData ), SendProxy_DataTablePtrToDataTable ),
SendPropDataTable( SENDINFO_DT(m_pClasses[TFCLASS_SNIPER]), &REFERENCE_SEND_TABLE( DT_PlayerClassSniperData ), SendProxy_DataTablePtrToDataTable ),
SendPropDataTable( SENDINFO_DT(m_pClasses[TFCLASS_SUPPORT]), &REFERENCE_SEND_TABLE( DT_PlayerClassSupportData ), SendProxy_DataTablePtrToDataTable ),
SendPropDataTable( SENDINFO_DT(m_pClasses[TFCLASS_SAPPER]), &REFERENCE_SEND_TABLE( DT_PlayerClassSapperData ), SendProxy_DataTablePtrToDataTable )
END_SEND_TABLE()
#endif
// ------------------------------------------------------------------------------------- //
// CAllPlayerClasses implementation.
// ------------------------------------------------------------------------------------- //
CAllPlayerClasses::CAllPlayerClasses( PLAYER_TYPE *pPlayer )
{
for ( int i=0; i < TFCLASS_CLASS_COUNT; i++ )
{
m_pClasses[i] = NULL;
#if defined( CLIENT_DLL )
if ( GetTFClassInfo( i )->m_pClientAlloc )
m_pClasses[i] = GetTFClassInfo( i )->m_pClientAlloc( pPlayer );
#else
if ( GetTFClassInfo( i )->m_pServerAlloc )
m_pClasses[i] = GetTFClassInfo( i )->m_pServerAlloc( pPlayer );
#endif
}
}
CAllPlayerClasses::~CAllPlayerClasses()
{
for ( int i=0; i < TFCLASS_CLASS_COUNT; i++ )
{
delete m_pClasses[i];
}
}
PLAYER_CLASS_TYPE* CAllPlayerClasses::GetPlayerClass( int iClass )
{
Assert( iClass >= 0 && iClass < TFCLASS_CLASS_COUNT );
return m_pClasses[iClass];
}
DEFINE_PLAYERCLASS_ALLOC_FNS( Recon, TFCLASS_RECON );
DEFINE_PLAYERCLASS_ALLOC_FNS( Commando, TFCLASS_COMMANDO );
DEFINE_PLAYERCLASS_ALLOC_FNS( Medic, TFCLASS_MEDIC );
DEFINE_PLAYERCLASS_ALLOC_FNS( Defender, TFCLASS_DEFENDER );
DEFINE_PLAYERCLASS_ALLOC_FNS( Sniper, TFCLASS_SNIPER );
DEFINE_PLAYERCLASS_ALLOC_FNS( Support, TFCLASS_SUPPORT );
DEFINE_PLAYERCLASS_ALLOC_FNS( Escort, TFCLASS_ESCORT );
DEFINE_PLAYERCLASS_ALLOC_FNS( Sapper, TFCLASS_SAPPER );
DEFINE_PLAYERCLASS_ALLOC_FNS( Infiltrator, TFCLASS_INFILTRATOR );
DEFINE_PLAYERCLASS_ALLOC_FNS( Pyro, TFCLASS_PYRO );
CTFClassInfo g_TFClassInfos[ TFCLASS_CLASS_COUNT ] =
{
{ "Undecided", g_iClassInfo_Undecided, false, NULL, NULL, NULL },
{ "Recon", g_iClassInfo_Recon, false, GENERATE_PLAYERCLASS_INFO( Recon ) },
{ "Commando", g_iClassInfo_Commando, true, GENERATE_PLAYERCLASS_INFO( Commando ) },
{ "Medic", g_iClassInfo_Medic, true, GENERATE_PLAYERCLASS_INFO( Medic ) },
{ "Defender", g_iClassInfo_Defender, true, GENERATE_PLAYERCLASS_INFO( Defender ) },
{ "Sniper", g_iClassInfo_Sniper, false, GENERATE_PLAYERCLASS_INFO( Sniper ) },
{ "Support", g_iClassInfo_Support, false, GENERATE_PLAYERCLASS_INFO( Support ) },
{ "Escort", g_iClassInfo_Escort, true, GENERATE_PLAYERCLASS_INFO( Escort ) },
{ "Sapper", g_iClassInfo_Sapper, true, GENERATE_PLAYERCLASS_INFO( Sapper ) },
{ "Infiltrator",g_iClassInfo_Infiltrator, false, GENERATE_PLAYERCLASS_INFO( Infiltrator ) },
{ "Pyro", g_iClassInfo_Pyro, false, GENERATE_PLAYERCLASS_INFO( Pyro ) }
};
const CTFClassInfo* GetTFClassInfo( int i )
{
Assert( i >= 0 && i < TFCLASS_CLASS_COUNT );
return &g_TFClassInfos[i];
}
// ------------------------------------------------------------------------------------------------ //
// CObjectInfo tables.
// ------------------------------------------------------------------------------------------------ //
CObjectInfo::CObjectInfo( char *pObjectName )
{
m_pObjectName = pObjectName;
m_pClassName = NULL;
m_flBuildTime = -9999;
m_nMaxObjects = -9999;
m_Cost = -9999;
m_CostMultiplierPerInstance = -999;
m_UpgradeCost = -9999;
m_MaxUpgradeLevel = -9999;
m_pBuilderWeaponName = NULL;
m_pBuilderPlacementString = NULL;
m_SelectionSlot = -9999;
m_SelectionPosition = -9999;
m_bSolidToPlayerMovement = false;
m_flSapperAttachTime = -9999;
m_pIconActive = NULL;
}
CObjectInfo::~CObjectInfo()
{
delete [] m_pClassName;
delete [] m_pStatusName;
delete [] m_pBuilderWeaponName;
delete [] m_pBuilderPlacementString;
delete [] m_pIconActive;
}
CObjectInfo g_ObjectInfos[OBJ_LAST] =
{
CObjectInfo( "OBJ_POWERPACK" ),
CObjectInfo( "OBJ_RESUPPLY" ),
CObjectInfo( "OBJ_SENTRYGUN_PLASMA" ),
CObjectInfo( "OBJ_SENTRYGUN_ROCKET_LAUNCHER" ),
CObjectInfo( "OBJ_SHIELDWALL" ),
CObjectInfo( "OBJ_RESOURCEPUMP" ),
CObjectInfo( "OBJ_RESPAWN_STATION" ),
CObjectInfo( "OBJ_RALLYFLAG" ),
CObjectInfo( "OBJ_MANNED_PLASMAGUN" ),
CObjectInfo( "OBJ_MANNED_MISSILELAUNCHER" ),
CObjectInfo( "OBJ_MANNED_SHIELD" ),
CObjectInfo( "OBJ_EMPGENERATOR" ),
CObjectInfo( "OBJ_BUFF_STATION" ),
CObjectInfo( "OBJ_BARBED_WIRE" ),
CObjectInfo( "OBJ_MCV_SELECTION_PANEL" ),
CObjectInfo( "OBJ_MAPDEFINED" ),
CObjectInfo( "OBJ_MORTAR" ),
CObjectInfo( "OBJ_SELFHEAL" ),
CObjectInfo( "OBJ_ARMOR_UPGRADE" ),
CObjectInfo( "OBJ_VEHICLE_BOOST" ),
CObjectInfo( "OBJ_EXPLOSIVES" ),
CObjectInfo( "OBJ_DRIVER_MACHINEGUN" ),
CObjectInfo( "OBJ_BATTERING_RAM" ),
CObjectInfo( "OBJ_SIEGE_TOWER" ),
CObjectInfo( "OBJ_WAGON" ),
CObjectInfo( "OBJ_FLATBED" ),
CObjectInfo( "OBJ_VEHICLE_MORTAR" ),
CObjectInfo( "OBJ_VEHICLE_TELEPORT_STATION" ),
CObjectInfo( "OBJ_VEHICLE_TANK" ),
CObjectInfo( "OBJ_VEHICLE_MOTORCYCLE" ),
CObjectInfo( "OBJ_WALKER_STRIDER" ),
CObjectInfo( "OBJ_WALKER_MINI_STRIDER" ),
CObjectInfo( "OBJ_TOWER" ),
CObjectInfo( "OBJ_TUNNEL" ),
CObjectInfo( "OBJ_SANDBAG_BUNKER" ),
CObjectInfo( "OBJ_BUNKER" ),
CObjectInfo( "OBJ_DRAGONSTEETH" ),
};
char* ReadAndAllocStringValue( KeyValues *pSub, const char *pName, const char *pFilename )
{
const char *pValue = pSub->GetString( pName, NULL );
if ( !pValue )
{
DevWarning( "Can't get key value '%s' from file '%s'.\n", pName, pFilename );
return "";
}
int len = Q_strlen( pValue ) + 1;
char *pAlloced = new char[ len ];
Assert( pAlloced );
Q_strncpy( pAlloced, pValue, len );
return pAlloced;
}
bool AreObjectInfosLoaded()
{
return g_ObjectInfos[0].m_pClassName != NULL;
}
void LoadObjectInfos( IBaseFileSystem *pFileSystem )
{
const char *pFilename = "scripts/objects.txt";
// Make sure this stuff hasn't already been loaded.
Assert( !AreObjectInfosLoaded() );
KeyValues *pValues = new KeyValues( "Object descriptions" );
if ( !pValues->LoadFromFile( pFileSystem, pFilename, "GAME" ) )
{
Error( "Can't open %s for object info.", pFilename );
pValues->deleteThis();
return;
}
// Now read each class's information in.
for ( int iObj=0; iObj < ARRAYSIZE( g_ObjectInfos ); iObj++ )
{
CObjectInfo *pInfo = &g_ObjectInfos[iObj];
KeyValues *pSub = pValues->FindKey( pInfo->m_pObjectName );
if ( !pSub )
{
Error( "Missing section '%s' from %s.", pInfo->m_pObjectName, pFilename );
pValues->deleteThis();
return;
}
// Read all the info in.
if ( (pInfo->m_flBuildTime = pSub->GetFloat( "BuildTime", -999 )) == -999 ||
(pInfo->m_nMaxObjects = pSub->GetInt( "MaxObjects", -999 )) == -999 ||
(pInfo->m_Cost = pSub->GetInt( "Cost", -999 )) == -999 ||
(pInfo->m_CostMultiplierPerInstance = pSub->GetFloat( "CostMultiplier", -999 )) == -999 ||
(pInfo->m_UpgradeCost = pSub->GetInt( "UpgradeCost", -999 )) == -999 ||
(pInfo->m_MaxUpgradeLevel = pSub->GetInt( "MaxUpgradeLevel", -999 )) == -999 ||
(pInfo->m_SelectionSlot = pSub->GetInt( "SelectionSlot", -999 )) == -999 ||
(pInfo->m_SelectionPosition = pSub->GetInt( "SelectionPosition", -999 )) == -999 ||
(pInfo->m_flSapperAttachTime = pSub->GetInt( "SapperAttachTime", -999 )) == -999 )
{
Error( "Missing data for object '%s' in %s.", pInfo->m_pObjectName, pFilename );
pValues->deleteThis();
return;
}
pInfo->m_pClassName = ReadAndAllocStringValue( pSub, "ClassName", pFilename );
pInfo->m_pStatusName = ReadAndAllocStringValue( pSub, "StatusName", pFilename );
pInfo->m_pBuilderWeaponName = ReadAndAllocStringValue( pSub, "BuilderWeaponName", pFilename );
pInfo->m_pBuilderPlacementString = ReadAndAllocStringValue( pSub, "BuilderPlacementString", pFilename );
pInfo->m_bSolidToPlayerMovement = pSub->GetInt( "SolidToPlayerMovement", 0 ) ? true : false;
pInfo->m_pIconActive = ReadAndAllocStringValue( pSub, "Icon", pFilename );
}
pValues->deleteThis();
}
const CObjectInfo* GetObjectInfo( int iObject )
{
Assert( iObject >= 0 && iObject < OBJ_LAST );
Assert( AreObjectInfosLoaded() );
return &g_ObjectInfos[iObject];
}
//-----------------------------------------------------------------------------
// Purpose: Return true if the specified class is allowed to build the specified object type
//-----------------------------------------------------------------------------
bool ClassCanBuild( int iClass, int iObjectType )
{
for ( int i = 0; i < OBJ_LAST; i++ )
{
// Hit the end?
if ( g_TFClassInfos[iClass].m_pClassObjects[i] == OBJ_LAST )
return false;
// Found it?
if ( g_TFClassInfos[iClass].m_pClassObjects[i] == iObjectType )
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose: Return the cost of another object of the specified type
// If bLast is set, return the cost of the last built object of the specified type
//-----------------------------------------------------------------------------
int CalculateObjectCost( int iObjectType, int iNumberOfObjects, int iTeam, bool bLast )
{
if ( tf_cheapobjects.GetInt() )
{
return 0;
}
// Find out how much the next object should cost
if ( bLast )
{
iNumberOfObjects = MAX(0,iNumberOfObjects-1);
}
int iCost = GetObjectInfo( iObjectType )->m_Cost;
// If a cost is negative, it means the first object of that type is free, and then
// it counts up as normal, using the negative value.
if ( iCost < 0 )
{
if ( iNumberOfObjects == 0 )
return 0;
iCost *= -1;
iNumberOfObjects--;
}
// MCVs have special rules: The team's first one is always free
if ( iObjectType == OBJ_VEHICLE_TELEPORT_STATION )
{
CTFTeam *pTeam = (CTFTeam *)GetGlobalTeam(iTeam);
if ( pTeam && pTeam->GetNumObjects(OBJ_VEHICLE_TELEPORT_STATION) == 0 )
{
iCost = 0;
}
}
// Human objects cost less across the board
if ( iTeam == TEAM_HUMANS )
{
iCost = ( ((float)iCost) * 0.8 );
}
// Calculate the cost based upon the number of objects
for ( int i = 0; i < iNumberOfObjects; i++ )
{
iCost *= GetObjectInfo( iObjectType )->m_CostMultiplierPerInstance;
}
return iCost;
}
//-----------------------------------------------------------------------------
// Purpose: Calculate the cost to upgrade an object of a specific type
//-----------------------------------------------------------------------------
int CalculateObjectUpgrade( int iObjectType, int iObjectLevel )
{
// Max level?
if ( iObjectLevel >= GetObjectInfo( iObjectType )->m_MaxUpgradeLevel )
return 0;
int iCost = GetObjectInfo( iObjectType )->m_UpgradeCost;
for ( int i = 0; i < (iObjectLevel - 1); i++ )
{
iCost *= OBJECT_UPGRADE_COST_MULTIPLIER_PER_LEVEL;
}
return iCost;
}
//--------------------------------------------------------------------------
// MORTAR
//--------------------------------------------------------------------------
// Names for each mortar ammo type
char *MortarAmmoNames[ MA_LASTAMMOTYPE ] =
{
"Normal Rounds",
//"Smoke Rounds",
"Cluster Rounds",
"Starburst Rounds",
};
// Techs needs for each mortar ammo type
char *MortarAmmoTechs[ MA_LASTAMMOTYPE ] =
{
"",
//"mortar_ammo_smoke",
"mortar_ammo_cluster",
"mortar_ammo_starburst",
};
// Max amounts of each mortar ammo type in a single mortar
int MortarAmmoMax[ MA_LASTAMMOTYPE ] =
{
-1, // -1 is infinite ammo
//20,
20,
10,
};
+663
View File
@@ -0,0 +1,663 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef TF_SHAREDDEFS_H
#define TF_SHAREDDEFS_H
#ifdef _WIN32
#pragma once
#endif
#define MAX_TF_TEAMS 4
extern ConVar inv_demo;
extern ConVar lod_effect_distance;
#include "const.h"
//--------------------------------------------------------------------------
// Teams
#define TEAM_HUMANS 1
#define TEAM_ALIENS 2
//--------------------------------------------------------------------------
// TF player flags.
#define TF_PLAYER_HIDDEN (1<<0)
#define TF_PLAYER_DAMAGE_BOOST (1<<1)
#define TF_PLAYER_NUMFLAGS 2
//--------------------------------------------------------------------------
// Custom Kill types
#define DMG_KILL_BULLRUSH 1
//--------------
// TF2 SPECIFIC DAMAGE FLAGS
//--------------
#define DMG_EMP (DMG_LASTGENERICFLAG<<1) // Hit by EMP
#define DMG_PROBE (DMG_LASTGENERICFLAG<<2) // Doing a shield-aware probe (heal guns, emp guns)
//--------------------------------------------------------------------------
// Zone states
#define ZONE_FRIENDLY 1
#define ZONE_ENEMY 2
#define ZONE_CONTESTED 3
//--------------------------------------------------------------------------
// Loot state
#define LOOT_NOT 0
#define LOOT_CAPABLE 1
#define LOOT_LOOTING 2
//--------------------------------------------------------------------------
// Powerups
//--------------------------------------------------------------------------
enum
{
POWERUP_BOOST, // Medic, buff station
POWERUP_EMP, // Technician
POWERUP_RUSH, // Rally flag
POWERUP_POWER, // Object power
MAX_POWERUPS
};
#define MAX_CABLE_CONNECTIONS 4
//--------------------------------------------------------------------------
// Acts
//--------------------------------------------------------------------------
#define MIN_ACT_OVERLAY_TIME 10.0
// C/C_InfoAct spawnflags
#define SF_ACT_INTERMISSION 1
#define SF_ACT_WAITINGFORGAMESTART 2
#define SF_ACT_BITS 2
//--------------------------------------------------------------------------
// Order types
//--------------------------------------------------------------------------
enum
{
ORDER_NONE = 0,
ORDER_ATTACK, // Enemy held resource zone, attack it and capture it
ORDER_DEFEND, // Defend a resource zone we own
ORDER_CAPTURE, // Resource zone not held by either team, capture it
ORDER_KILL, // Kill a specific enemy player
ORDER_HEAL, // Heal a specific friendly player
ORDER_BUILD, // Order to build something.
// m_iStructure is one of the OBJ_ defines.
// If it's a sentry gun order, it's always OBJ_SENTRYGUN_PLASMA.
ORDER_REPAIR, // Repair a built item.
ORDER_MORTAR_ATTACK, // Build a mortar to shell an enemy object.
ORDER_ASSIST // Assist a player who is under attack.
};
//--------------------------------------------------------------------------
// Collision groups
//--------------------------------------------------------------------------
enum
{
TFCOLLISION_GROUP_SHIELD = LAST_SHARED_COLLISION_GROUP,
TFCOLLISION_GROUP_WEAPON,
TFCOLLISION_GROUP_GRENADE,
TFCOLLISION_GROUP_RESOURCE_CHUNK,
// Combat objects (override for above)
TFCOLLISION_GROUP_COMBATOBJECT,
// Objects in general
TFCOLLISION_GROUP_OBJECT,
TFCOLLISION_GROUP_OBJECT_SOLIDTOPLAYERMOVEMENT,
};
//--------------------------------------------------------------------------
// MAP DEFINED OBJECTS
//--------------------------------------------------------------------------
#define MAX_OBJ_CUSTOMNAME_SIZE 128
//--------------------------------------------------------------------------
// OBJECTS
//--------------------------------------------------------------------------
enum
{
OBJ_POWERPACK=0,
OBJ_RESUPPLY,
OBJ_SENTRYGUN_PLASMA, // Orders always refer to this type of sentry gun.
OBJ_SENTRYGUN_ROCKET_LAUNCHER,
OBJ_SHIELDWALL,
OBJ_RESOURCEPUMP,
OBJ_RESPAWN_STATION,
OBJ_RALLYFLAG,
OBJ_MANNED_PLASMAGUN,
OBJ_MANNED_MISSILELAUNCHER,
OBJ_MANNED_SHIELD,
OBJ_EMPGENERATOR,
OBJ_BUFF_STATION,
OBJ_BARBED_WIRE,
OBJ_MCV_SELECTION_PANEL,
OBJ_MAPDEFINED,
OBJ_MORTAR,
// ADD STANDARD OBJECTS HERE
// Upgrades
OBJ_SELFHEAL,
OBJ_ARMOR_UPGRADE,
OBJ_VEHICLE_BOOST,
OBJ_EXPLOSIVES,
OBJ_DRIVER_MACHINEGUN,
// ADD UPGRADES HERE
// Vehicles
OBJ_BATTERING_RAM,
OBJ_SIEGE_TOWER,
OBJ_WAGON,
OBJ_FLATBED,
OBJ_VEHICLE_MORTAR,
OBJ_VEHICLE_TELEPORT_STATION,
OBJ_VEHICLE_TANK,
OBJ_VEHICLE_MOTORCYCLE,
OBJ_WALKER_STRIDER,
OBJ_WALKER_MINI_STRIDER,
// ADD VEHICLES HERE
// Defensive buildings
OBJ_TOWER,
OBJ_TUNNEL,
OBJ_SANDBAG_BUNKER,
OBJ_BUNKER,
OBJ_DRAGONSTEETH,
// ADD DEFENSIVE-ONLY BUILDINGS HERE
// If you add a new object, you need to add it to the g_ObjectInfos array
// in tf_shareddefs.cpp, and add it's data to the scripts/object.txt
OBJ_LAST,
};
#define OBJECT_COST_MULTIPLIER_PER_OBJECT 3
#define OBJECT_UPGRADE_COST_MULTIPLIER_PER_LEVEL 3
bool IsObjectAnUpgrade( int iObjectType );
bool IsObjectAVehicle( int iObjectType );
bool IsObjectADefensiveBuilding( int iObjectType );
class CHudTexture;
class CObjectInfo
{
public:
CObjectInfo( char *pObjectName );
~CObjectInfo();
// This is initialized by the code and matched with a section in objects.txt
char *m_pObjectName;
// This stuff all comes from objects.txt
char *m_pClassName; // Code classname (in LINK_ENTITY_TO_CLASS).
char *m_pStatusName; // Shows up when crosshairs are on the object.
float m_flBuildTime;
int m_nMaxObjects; // Maximum number of objects per player
int m_Cost; // Base object resource cost
float m_CostMultiplierPerInstance; // Cost multiplier
int m_UpgradeCost; // Base object resource cost for upgrading
int m_MaxUpgradeLevel; // Max object upgrade level
char *m_pBuilderWeaponName; // Names shown for each object onscreen when using the builder weapon
char *m_pBuilderPlacementString; // String shown to player during placement of this object
int m_SelectionSlot; // Weapon selection slots for objects
int m_SelectionPosition; // Weapon selection positions for objects
bool m_bSolidToPlayerMovement;
float m_flSapperAttachTime; // Time it takes to place a sapper on this object
// HUD weapon selection menu icon ( from hud_textures.txt )
char *m_pIconActive;
};
// Loads the objects.txt script.
class IBaseFileSystem;
void LoadObjectInfos( IBaseFileSystem *pFileSystem );
// Get a CObjectInfo from a TFOBJ_ define.
const CObjectInfo* GetObjectInfo( int iObject );
// Object utility funcs
bool ClassCanBuild( int iClass, int iObjectType );
int CalculateObjectCost( int iObjectType, int iNumberOfObjects, int iTeam, bool bLast = false );
int CalculateObjectUpgrade( int iObjectType, int iObjectLevel );
//--------------------------------------------------------------------------
// OBJECT FLAGS
//--------------------------------------------------------------------------
enum
{
OF_SUPPRESS_APPEAR_ON_MINIMAP = 0x0001,
OF_SUPPRESS_NOTIFY_UNDER_ATTACK = 0x0002,
OF_SUPPRESS_VISIBLE_TO_TACTICAL = 0x0004,
OF_ALLOW_REPEAT_PLACEMENT = 0x0008,
OF_SUPPRESS_TECH_ANALYZER = 0x0010,
OF_DONT_AUTO_REPAIR = 0x0020,
OF_ALIGN_TO_GROUND = 0x0040, // Align my angles to match the ground underneath me
OF_DONT_PREVENT_BUILD_NEAR_OBJ = 0x0080, // Don't prevent building if there's another object nearby
OF_CAN_BE_PICKED_UP = 0x0100,
OF_DOESNT_NEED_POWER = 0x0200, // Doesn't need power, even on the human team
OF_DOESNT_HAVE_A_MODEL = 0x0400, // It's built from map placed geometry
OF_MUST_BE_BUILT_IN_CONSTRUCTION_YARD = 0x0800,
OF_MUST_BE_BUILT_IN_RESOURCE_ZONE = 0x1000,
OF_MUST_BE_BUILT_ON_ATTACHMENT = 0x2000,
OF_CANNOT_BE_DISMANTLED = 0x4000,
OF_BIT_COUNT = 15
};
//--------------------------------------------------------------------------
// Builder "weapon" states
//--------------------------------------------------------------------------
enum
{
BS_IDLE = 0,
BS_SELECTING,
BS_PLACING,
BS_PLACING_INVALID,
BS_BUILDING,
BS_REPAIR,
};
//--------------------------------------------------------------------------
// Builder object id...
//--------------------------------------------------------------------------
enum
{
BUILDER_OBJECT_BITS = 8,
BUILDER_INVALID_OBJECT = ((1 << BUILDER_OBJECT_BITS) - 1)
};
// Analyzer state
enum
{
AS_INACTIVE = 0,
AS_SUBVERTING,
AS_ANALYZING
};
// Max number of objects a team can have
#define MAX_OBJECTS_PER_TEAM 512
#define MAX_OBJECTS_PER_PLAYER 64
//--------------------------------------------------------------------------
// BUILDING
//--------------------------------------------------------------------------
// Build checks will return one of these for a player
enum
{
CB_CAN_BUILD, // Player is allowed to build this object
CB_NOT_RESEARCHED, // Player's team hasn't researched this object
CB_LIMIT_REACHED, // Player has reached the limit of the number of these objects allowed
CB_NEED_RESOURCES, // Player doesn't have enough resources to build this object
CB_NEED_ADRENALIN, // Commando doesn't have enough adrenalin to build a rally flag
};
//--------------------------------------------------------------------------
// MORTAR
//--------------------------------------------------------------------------
// Mortar Firing States
enum
{
MORTAR_IDLE,
MORTAR_CHARGING_POWER,
MORTAR_CHARGING_ACCURACY,
};
// Mortar salvos
#define MORTAR_SALVO_SIZE 5
#define MORTAR_RELOAD_TIME 5.0
// Mortar firing details
#define MORTAR_RANGE_MIN 1024
#define MORTAR_RANGE_MAX_INITIAL 3000
#define MORTAR_RANGE_MAX_UPGRADED 5000
// Inaccuracy Data
// These values are all max inaccuracies. The accuracy used is between 0 & Max, based upon how close the player gets to hitting
// the fire button at the right time on the mortar firing slider bar.
// Perpendicular-to-the-shot inaccuracy
#define MORTAR_INACCURACY_MAX_INITIAL 0.85 // Percentage of distance that a mortar can be wide of the mark
#define MORTAR_INACCURACY_MAX_UPGRADED 0.35 // Percentage of distance that a mortar can be wide of the mark
// Distance inaccuracy
#define MORTAR_DIST_INACCURACY 0.3 // Percentage of distance that the mortar can deviate
// Mortar firing details
#define MORTAR_CHARGE_POWER_RATE 1.5 // Time taken to hit full charge for power
#define MORTAR_CHARGE_ACCURACY_RATE 1.25 // Time taken to hit perfect accuracy, given a half-power shot
// Mortar ammo types
enum MortarAmmoType
{
MA_SHELL = 0, // Normal mortar round
//MA_SMOKE, // Smoke mortar round
MA_CLUSTER, // Mirv mortar round
MA_STARBURST, // Starburst / phosphorous mortar round
MA_LASTAMMOTYPE,
};
extern char *MortarAmmoNames[ MA_LASTAMMOTYPE ];
extern char *MortarAmmoTechs[ MA_LASTAMMOTYPE ];
extern int MortarAmmoMax[ MA_LASTAMMOTYPE ];
//--------------------------------------------------------------------------
// ROCKET PACK
//--------------------------------------------------------------------------
#define RP_LOCK_TIME 3.0 // Time taken to lock onto a target
//--------------------------------------------------------------------------
// PARTICLE BEAM
//--------------------------------------------------------------------------
#define PB_RECHARGE_TIME 30.0 // Time taken to recharge the particle beam
//--------------------------------------------------------------------------
// PLASMA PROJECTILE TYPES
//--------------------------------------------------------------------------
enum
{
PLASMATYPE_GATLING,
PLASMATYPE_EMP,
PLASMATYPE_GUIDED,
PLASMATYPE_GUIDED_NOTARGET,
PLASMATYPE_GUIDED_PARRIED,
PLASMATYPE_PLASMABALL,
PLASMATYPE_PLASMABALL_EXPLOSIVE,
};
#define PLASMA_VELOCITY ( 2500 )
//--------------------------------------------------------------------------
// SCANNERS
//--------------------------------------------------------------------------
// Ranges
#define SCANNER_RANGE 3000
#define LOCAL_PLAYER_SCANNER_RANGE 1500
//--------------------------------------------------------------------------
// EMP
//--------------------------------------------------------------------------
#define EMP_HITSCAN_DURATION 5.0f
//--------------------------------------------------------------------------
// KNOCKDOWN
//--------------------------------------------------------------------------
// Knockdown blend in and out times
#define KNOCKDOWN_BLEND_IN ( 0.3f )
#define KNOCKDOWN_BLEND_OUT ( 0.5f )
//--------------------------------------------------------------------------
// THERMAL VISION
//--------------------------------------------------------------------------
// Thermal vision radius
// Players outside of this radius will not be sent to the local player
// Player's inside start to fade at the startfade distance and are alpha'd out completely
// at the full radius
#define THERMAL_VISION_RADIUS ( 1024.0f )
#define THERMAL_VISION_STARTFADE ( THERMAL_VISION_RADIUS / 2.0f )
//--------------------------------------------------------------------------
// CAMO
//--------------------------------------------------------------------------
// Infiltrator Camouflage constants
// # of seconds to go into/back into camo mode
#define CAMO_ENABLETIME ( 3.0f )
// # of seconds to remove
#define CAMO_REMOVETIME ( 1.0f )
// # of seconds to temporarily suppress
#define CAMO_SUPPRESSTIME ( 1.0f )
// Outside this, exclude from PVS
#define CAMO_OUTER_RADIUS ( 2048.0f )
// From here to outer, just alpha to 0
#define CAMO_INNER_RADIUS ( CAMO_OUTER_RADIUS / 2.0f )
// 75 % opacity at the inner_radius
#define CAMO_INNER_ALPHA ( 192 )
// From here to inner fade alpha again and start using invis effect
#define CAMO_INVIS_RADIUS ( CAMO_INNER_RADIUS / 2.0f )
// Infiltrator's phaseout duration
#define INFILTRATOR_PHASEOUT_DURATION 30.0f
// Time required to recharge
#define INFILTRATOR_PHASEOUT_RECHARGETIME 30.0f
// After sitting still, remove from tactical and minimiap starting at this time
#define SNIPER_STATIONARY_FADESTART 2.5f
// After sitting still, remove from tactical and minimiap starting and finishing here
#define SNIPER_STATIONARY_FADEFINISH 7.5f
// Infiltrator Camouflage constants
// # of seconds to go into/back into camo mode
#define CAMO_ENABLETIME ( 3.0f )
// # of seconds to remove
#define CAMO_REMOVETIME ( 1.0f )
// # of seconds to temporarily suppress
#define CAMO_SUPPRESSTIME ( 1.0f )
// Outside this, exclude from PVS
#define CAMO_OUTER_RADIUS ( 2048.0f )
// From here to outer, just alpha to 0
#define CAMO_INNER_RADIUS ( CAMO_OUTER_RADIUS / 2.0f )
// 75 % opacity at the inner_radius
#define CAMO_INNER_ALPHA ( 192 )
// From here to inner fade alpha again and start using invis effect
#define CAMO_INVIS_RADIUS ( CAMO_INNER_RADIUS / 2.0f )
// Infiltrator's phaseout duration
#define INFILTRATOR_PHASEOUT_DURATION 30.0f
// Time required to recharge
#define INFILTRATOR_PHASEOUT_RECHARGETIME 30.0f
// After sitting still, remove from tactical and minimiap starting at this time
#define SNIPER_STATIONARY_FADESTART 2.5f
// After sitting still, remove from tactical and minimiap starting and finishing here
#define SNIPER_STATIONARY_FADEFINISH 7.5f
//--------------------------------------------------------------------------
// ANIM STATEMACHINE DEFINES
//--------------------------------------------------------------------------
// Sniper deploy node
enum
{
SNIPER_DEPLOY_START = 1,
SNIPER_DEPLOY_IDLE,
SNIPER_DEPLOY_LEAVE,
};
//--------------------------------------------------------------------------
// COMBAT SHIELD
//--------------------------------------------------------------------------
#define SHIELD_HITGROUP 1
// Length after raising the shield during which releasing the shield will cause a parry
#define PARRY_DETECTION_TIME 0.5
// Length after a parry detection in which a parry can occur
#define PARRY_OPPORTUNITY_LENGTH 0.3
// Length after a parry has finished before I can do anything again
#define PARRY_VULNERABLE_TIME 0.5
//--------------------------------------------------------------------------
// SENTRYGUNS
//--------------------------------------------------------------------------
// Time it takes to turtle / unturtle
#define SENTRY_TURTLE_TIME 2.0
//--------------------------------------------------------------------------
// PORTABLE POWER GENERATOR - BUFF STATION
//--------------------------------------------------------------------------
#define BUFF_STATION_MAX_PLAYERS 4
#define BUFF_STATION_MAX_PLAYER_BITS 3
#define BUFF_STATION_MAX_OBJECTS 3
#define BUFF_STATION_MAX_OBJECT_BITS 2
//--------------------------------------------------------------------------
// ADRENALIN
//--------------------------------------------------------------------------
// Animation speed while in adrenalin
#define ADRENALIN_ANIM_SPEED 1.5
//--------------------------------------------------------------------------
// PLASMA RIFLE
//--------------------------------------------------------------------------
#define MAX_RIFLE_POWER 3.0
#define RIFLE_CHARGE_TIME 2.0
//--------------------------------------------------------------------------
// HUMAN POWER PACKS
//--------------------------------------------------------------------------
#define MAX_OBJECTS_PER_PACK 3
//--------------------------------------------------------------------------
// Rally flag defines
//--------------------------------------------------------------------------
#define RALLYFLAG_MINS Vector(-20, -20, 0)
#define RALLYFLAG_MAXS Vector( 20, 20, 90)
#define RALLYFLAG_RADIUS 512
#define RALLYFLAG_LIFETIME 30
#define RALLYFLAG_RATE 2 // Rate at which it looks for friendlies to rally
#define RALLYFLAG_ADRENALIN_TIME 5 // Time an adrenalin rush lasts
#define RALLYFLAG_MODEL "models/props/common/holo_banner/holo_banner.mdl"
//--------------------------------------------------------------------------
// Resupply-related stuff
//--------------------------------------------------------------------------
enum ResupplyBuyType_t
{
RESUPPLY_BUY_AMMO = 0,
RESUPPLY_BUY_HEALTH,
RESUPPLY_BUY_GRENADES,
RESUPPLY_BUY_ALL,
RESUPPLY_BUY_TYPE_COUNT
};
#define RESUPPLY_HEALTH_COST 20
#define RESUPPLY_AMMO_COST 5
#define RESUPPLY_GRENADES_COST 25
#define RESUPPLY_ALL_COST 50
#define RESUPPLY_ROCKET_COST 100
// Build animation events
#define TF_OBJ_ENABLEBODYGROUP 6000
#define TF_OBJ_DISABLEBODYGROUP 6001
#define TF_OBJ_ENABLEALLBODYGROUPS 6002
#define TF_OBJ_DISABLEALLBODYGROUPS 6003
#define TF_OBJ_PLAYBUILDSOUND 6004
//--------------------------------------------------------------------------
// Class id
//--------------------------------------------------------------------------
#include "tfclassdata_shared.h"
//--------------------------------------------------------------------------
//
// Class info tables. Any time a class is added or removed, this is where
// generic data about each class is stored.
//
// The other things you need to add or remove for a class are:
//
// - A class derived from CPlayerClass.
// - Class-specific accessors and data members functions in CTFMoveData.
// - tf_gamemovement_chooser.h and CTFGameMovementChooser::CTFGameMovementChooser().
// - DEFINE_PRED_TYPEDESCRIPTION_PTR entries in c_basetfplayer.cpp
// - Add class_X_health in skill1.cfg.
//
//--------------------------------------------------------------------------
class CPlayerClass;
class CBaseTFPlayer;
typedef CPlayerClass* (*PlayerClassAllocFn_Server)( CBaseTFPlayer *pPlayer );
class C_PlayerClass;
class C_BaseTFPlayer;
typedef C_PlayerClass* (*PlayerClassAllocFn_Client)( C_BaseTFPlayer *pPlayer );
class ConVar;
class CTFClassInfo
{
public:
char *m_pClassName;
// Objects that each class can build
// OBJ_X, OBJ_Y ... terminated with OBJ_LAST.
int *m_pClassObjects;
// This is just to make stats gathering easy... which classes are in the game right now?
bool m_pCurrentlyActive;
PlayerClassAllocFn_Client m_pClientAlloc; // Only valid in client.dll
PlayerClassAllocFn_Server m_pServerAlloc; // Only valid in the game dll
ConVar *m_pMaxHealthCVar; // Only valid in game dll
};
const CTFClassInfo* GetTFClassInfo( int i );
#if defined( CLIENT_DLL )
#define CAllPlayerClasses C_AllPlayerClasses
#define PLAYER_CLASS_TYPE C_PlayerClass
#define PLAYER_TYPE C_BaseTFPlayer
EXTERN_RECV_TABLE( DT_AllPlayerClasses );
#else
#define PLAYER_CLASS_TYPE CPlayerClass
#define PLAYER_TYPE CBaseTFPlayer
EXTERN_SEND_TABLE( DT_AllPlayerClasses );
#endif
class PLAYER_TYPE;
class PLAYER_CLASS_TYPE;
//
// The player object contains this on both the client and the server.
// It holds a copy of each player class that can be used.
//
class CAllPlayerClasses // (#define as C_AllPlayerClasses on the client)
{
public:
CAllPlayerClasses( PLAYER_TYPE *pPlayer );
~CAllPlayerClasses();
PLAYER_CLASS_TYPE* GetPlayerClass( int iClass );
public:
PLAYER_CLASS_TYPE* m_pClasses[ TFCLASS_CLASS_COUNT ];
};
//--------------------------------------------------------------------------
// Impact data
//--------------------------------------------------------------------------
// This sucks
#define NUM_WOOD_GIBS_SMALL 5
extern const char *ImpactHurtGibs_Wood_Small[ NUM_WOOD_GIBS_SMALL ];
#define PLAYER_MSG_PERSONAL_SHIELD 2
#endif // TF_SHAREDDEFS_H
+850
View File
@@ -0,0 +1,850 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: The Escort's Shield weapon
//
// $Revision: $
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "in_buttons.h"
#include "tf_shieldshared.h"
#include "tf_shareddefs.h"
#include "baseentity_shared.h"
#if defined( CLIENT_DLL )
#include "c_shield.h"
#else
#include "tf_shield.h"
#include "gamerules.h"
#endif
#if defined( CLIENT_DLL )
#define CShieldMobile C_ShieldMobile
#define CShield C_Shield
#endif
//-----------------------------------------------------------------------------
// ConVars
//-----------------------------------------------------------------------------
ConVar shield_mobile_power( "shield_mobile_power","30", FCVAR_REPLICATED, "Max power level of a escort's mobile projected shield." );
ConVar shield_mobile_recharge_delay( "shield_mobile_recharge_delay","0.1", FCVAR_REPLICATED, "Time after taking damage before mobile projected shields begin to recharge." );
ConVar shield_mobile_recharge_amount( "shield_mobile_recharge_amount","2", FCVAR_REPLICATED, "Power recharged each recharge tick for mobile projected shields." );
ConVar shield_mobile_recharge_time( "shield_mobile_recharge_time","0.5", FCVAR_REPLICATED, "Time between each recharge tick for mobile projected shields." );
#define EMP_WAVE_AMPLITUDE 8.0f
//-----------------------------------------------------------------------------
// Mobile version of the shield
//-----------------------------------------------------------------------------
class CShieldMobile;
class CShieldMobileActiveVertList : public IActiveVertList
{
public:
void Init( CShieldMobile *pShield );
// IActiveVertList overrides.
public:
virtual int GetActiveVertState( int iVert );
virtual void SetActiveVertState( int iVert, int bOn );
private:
CShieldMobile *m_pShield;
};
//-----------------------------------------------------------------------------
// Mobile version of the shield
//-----------------------------------------------------------------------------
class CShieldMobile : public CShield, public IEntityEnumerator
{
DECLARE_CLASS( CShieldMobile, CShield );
public:
DECLARE_NETWORKCLASS();
DECLARE_PREDICTABLE();
friend class CShieldMobileActiveVertList;
CShieldMobile();
#ifndef CLIENT_DLL
DECLARE_DATADESC();
#endif
public:
void Spawn( void );
void Precache( void );
void ShieldThink( void );
virtual void ClientThink();
virtual void SetAngularSpringConstant( float flConstant );
virtual void SetFrontDistance( float flDistance );
virtual void ComputeWorldSpaceSurroundingBox( Vector *pWorldMins, Vector *pWorldMaxs );
virtual void SetAttachmentIndex( int nAttachmentIndex );
virtual void SetEMPed( bool isEmped );
virtual void SetAlwaysOrient( bool bOrient );
virtual bool IsAlwaysOrienting( );
virtual int Width();
virtual int Height();
virtual bool IsPanelActive( int x, int y );
virtual const Vector& GetPoint( int x, int y );
virtual void SetCenterAngles( const QAngle& angles );
virtual void SetThetaPhi( float flTheta, float flPhi );
virtual void GetRenderBounds( Vector& mins, Vector& maxs );
// All predicted weapons need to implement and return true
virtual bool IsPredicted( void ) const
{
return true;
}
public:
#ifdef CLIENT_DLL
virtual void OnDataChanged( DataUpdateType_t updateType );
virtual void GetBounds( Vector& mins, Vector& maxs );
virtual void AddEntity( );
virtual void GetShieldData( const Vector** ppVerts, float* pOpacity, float* pBlend );
virtual bool ShouldPredict( void )
{
if ( GetOwnerEntity() == C_BasePlayer::GetLocalPlayer() )
return true;
return BaseClass::ShouldPredict();
}
#endif
public:
// Inherited from IEntityEnumerator
virtual bool EnumEntity( IHandleEntity *pHandleEntity );
private:
// Teleport!
void OnTeleported( );
void SimulateShield( void );
private:
struct SweepContext_t
{
SweepContext_t( const CBaseEntity *passentity, int collisionGroup ) :
m_Filter( passentity, collisionGroup ) {}
CTraceFilterSimple m_Filter;
Vector m_vecStartDelta;
Vector m_vecEndDelta;
};
enum
{
NUM_SUBDIVISIONS = 21,
};
enum
{
SHIELD_ORIENT_TO_OWNER = 0x2
};
private:
CShieldMobile( const CShieldMobile & );
void ComputeBoundingBox( void );
void DetermineObstructions( );
private:
#ifdef CLIENT_DLL
// Is a particular panel an edge?
bool IsVertexValid( float s, float t ) const;
void PreRender( );
#endif
private:
CShieldMobileActiveVertList m_VertList;
QAngle m_tmpAngLockedAngles;
// Bitfield indicating which vertices are active
CShieldEffect m_ShieldEffect;
CNetworkArray( unsigned char, m_pVertsActive, SHIELD_NUM_CONTROL_POINTS >> 3 );
CNetworkVar( unsigned char, m_ShieldState );
CNetworkVar( float, m_flFrontDistance );
CNetworkVar( QAngle, m_angLockedAngles );
SweepContext_t *m_pEnumCtx;
// This is the width + height of the shield, not the current theta, phi
CNetworkVar( float, m_flShieldTheta );
CNetworkVar( float, m_flShieldPhi );
CNetworkVar( float, m_flSpringConstant );
CNetworkVar( int, m_nAttachmentIndex );
};
//=============================================================================
// Shield effect
//=============================================================================
#ifndef CLIENT_DLL
BEGIN_DATADESC( CShieldMobile )
DEFINE_THINKFUNC( ShieldThink ),
END_DATADESC()
#endif
LINK_ENTITY_TO_CLASS( shield_mobile, CShieldMobile );
IMPLEMENT_NETWORKCLASS_ALIASED( ShieldMobile, DT_ShieldMobile );
// -------------------------------------------------------------------------------- //
// This data only gets sent to clients that ARE this player entity.
// -------------------------------------------------------------------------------- //
BEGIN_NETWORK_TABLE(CShieldMobile, DT_ShieldMobile)
#if !defined( CLIENT_DLL )
SendPropInt (SENDINFO(m_ShieldState), 2, SPROP_UNSIGNED ),
SendPropArray(
SendPropInt( SENDINFO_ARRAY(m_pVertsActive), 8, SPROP_UNSIGNED),
m_pVertsActive),
SendPropFloat( SENDINFO(m_flFrontDistance), 0, SPROP_NOSCALE ),
SendPropFloat( SENDINFO(m_flShieldTheta), 0, SPROP_NOSCALE ),
SendPropFloat( SENDINFO(m_flShieldPhi), 0, SPROP_NOSCALE ),
SendPropFloat( SENDINFO(m_flSpringConstant), 0, SPROP_NOSCALE ),
SendPropQAngles( SENDINFO(m_angLockedAngles), 9 ),
SendPropInt (SENDINFO(m_nAttachmentIndex), 10, SPROP_UNSIGNED ),
// Don't bother sending these, they are totally controlled by the think function
SendPropExclude( "DT_BaseEntity", "m_vecOrigin" ),
SendPropExclude( "DT_BaseEntity", "m_angAbsRotation[0]" ),
SendPropExclude( "DT_BaseEntity", "m_angAbsRotation[1]" ),
SendPropExclude( "DT_BaseEntity", "m_angAbsRotation[2]" ),
#else
RecvPropInt( RECVINFO(m_ShieldState) ),
RecvPropArray(
RecvPropInt( RECVINFO(m_pVertsActive[0])),
m_pVertsActive
),
RecvPropFloat( RECVINFO(m_flFrontDistance) ),
RecvPropFloat( RECVINFO(m_flShieldTheta) ),
RecvPropFloat( RECVINFO(m_flShieldPhi) ),
RecvPropFloat( RECVINFO(m_flSpringConstant) ),
RecvPropQAngles( RECVINFO( m_angLockedAngles ) ),
RecvPropInt (RECVINFO(m_nAttachmentIndex) ),
#endif
END_NETWORK_TABLE()
BEGIN_PREDICTION_DATA( CShieldMobile )
DEFINE_PRED_FIELD( m_ShieldState, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
DEFINE_PRED_FIELD( m_flFrontDistance, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
DEFINE_PRED_FIELD( m_angLockedAngles, FIELD_VECTOR, FTYPEDESC_INSENDTABLE ),
DEFINE_PRED_TYPEDESCRIPTION( m_ShieldEffect, CShieldEffect ),
DEFINE_FIELD( m_nNextThinkTick, FIELD_INTEGER ),
DEFINE_FIELD( m_tmpAngLockedAngles, FIELD_VECTOR ),
// FIXME: How can I make this work now that I have an embedded collision property?
// DEFINE_PRED_FIELD( m_vecMins, FIELD_VECTOR, FTYPEDESC_INSENDTABLE | FTYPEDESC_OVERRIDE | FTYPEDESC_NOERRORCHECK ),
// DEFINE_PRED_FIELD( m_vecMaxs, FIELD_VECTOR, FTYPEDESC_INSENDTABLE | FTYPEDESC_OVERRIDE | FTYPEDESC_NOERRORCHECK ),
#ifdef CLIENT_DLL
DEFINE_PRED_FIELD( m_vecNetworkOrigin, FIELD_VECTOR, FTYPEDESC_OVERRIDE | FTYPEDESC_NOERRORCHECK ),
DEFINE_PRED_FIELD( m_angNetworkAngles, FIELD_VECTOR, FTYPEDESC_OVERRIDE | FTYPEDESC_NOERRORCHECK ),
#endif
END_PREDICTION_DATA()
//-----------------------------------------------------------------------------
// CShieldMobileActiveVertList functions
//-----------------------------------------------------------------------------
void CShieldMobileActiveVertList::Init( CShieldMobile *pShield )
{
m_pShield = pShield;
}
int CShieldMobileActiveVertList::GetActiveVertState( int iVert )
{
return m_pShield->m_pVertsActive[iVert>>3] & (1 << (iVert & 7));
}
void CShieldMobileActiveVertList::SetActiveVertState( int iVert, int bOn )
{
unsigned char val;
if ( bOn )
val = m_pShield->m_pVertsActive[iVert>>3] | (1 << (iVert & 7));
else
val = m_pShield->m_pVertsActive[iVert>>3] & ~(1 << (iVert & 7));
m_pShield->m_pVertsActive.Set( iVert>>3, val );
}
//-----------------------------------------------------------------------------
// constructor
//-----------------------------------------------------------------------------
CShieldMobile::CShieldMobile()
{
SetPredictionEligible( true );
m_VertList.Init( this );
m_flFrontDistance = 0;
SetAngularSpringConstant( 2.0f );
SetThetaPhi( SHIELD_INITIAL_THETA, SHIELD_INITIAL_PHI );
m_nAttachmentIndex = 0;
#ifdef CLIENT_DLL
InitShield( SHIELD_NUM_HORIZONTAL_POINTS, SHIELD_NUM_VERTICAL_POINTS, NUM_SUBDIVISIONS );
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CShieldMobile::Precache( void )
{
m_ShieldEffect.SetActiveVertexList( &m_VertList );
m_ShieldEffect.SetCollisionGroup( TFCOLLISION_GROUP_SHIELD );
BaseClass::Precache();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CShieldMobile::Spawn( void )
{
Precache();
BaseClass::Spawn();
AddSolidFlags( FSOLID_FORCE_WORLD_ALIGNED );
// Assert( GetOwnerEntity() );
m_angLockedAngles.Set( vec3_angle );
m_tmpAngLockedAngles = vec3_angle;
m_ShieldEffect.Spawn(GetAbsOrigin(), GetAbsAngles());
m_ShieldState = 0;
SetAlwaysOrient( true );
// All movement occurs during think
SetMoveType( MOVETYPE_NONE );
SetThink( ShieldThink );
SetNextThink( gpGlobals->curtime + 0.01f );
#ifdef CLIENT_DLL
// This goofiness is required so that non-predicted entities work
SetNextClientThink( CLIENT_THINK_ALWAYS );
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CShieldMobile::SetAlwaysOrient( bool bOrient )
{
if (bOrient)
{
m_ShieldState.Set( m_ShieldState.Get() | SHIELD_ORIENT_TO_OWNER );
}
else
{
m_angLockedAngles.Set( m_tmpAngLockedAngles );
m_ShieldState.Set( m_ShieldState.Get() & (~SHIELD_ORIENT_TO_OWNER) );
}
}
int CShieldMobile::Width()
{
return SHIELD_NUM_HORIZONTAL_POINTS;
}
int CShieldMobile::Height()
{
return SHIELD_NUM_VERTICAL_POINTS;
}
const Vector& CShieldMobile::GetPoint( int x, int y )
{
return m_ShieldEffect.GetPoint( x, y );
}
void CShieldMobile::SetAttachmentIndex( int nAttachmentIndex )
{
m_nAttachmentIndex = nAttachmentIndex;
}
//-----------------------------------------------------------------------------
// Returns the render bounds
//-----------------------------------------------------------------------------
void CShieldMobile::GetRenderBounds( Vector& mins, Vector& maxs )
{
mins = m_ShieldEffect.GetRenderMins();
maxs = m_ShieldEffect.GetRenderMaxs();
}
//-----------------------------------------------------------------------------
// Return true if the panel is active
//-----------------------------------------------------------------------------
bool CShieldMobile::IsPanelActive( int x, int y )
{
return m_ShieldEffect.IsPanelActive(x, y);
}
//-----------------------------------------------------------------------------
// Called when the shield is EMPed
//-----------------------------------------------------------------------------
void CShieldMobile::SetEMPed( bool isEmped )
{
CShield::SetEMPed(isEmped);
if (IsEMPed())
m_ShieldState |= SHIELD_MOBILE_EMP;
else
m_ShieldState &= ~SHIELD_MOBILE_EMP;
}
//-----------------------------------------------------------------------------
// Set the shield angles
//-----------------------------------------------------------------------------
void CShieldMobile::SetCenterAngles( const QAngle& angles )
{
// The tmp ang locked angles is simply there to prevent unnecessary network traffic
m_tmpAngLockedAngles = angles;
if ( ( m_ShieldState.Get() & SHIELD_ORIENT_TO_OWNER ) == 0 )
{
m_angLockedAngles.Set( angles );
}
}
bool CShieldMobile::IsAlwaysOrienting( )
{
return ( m_ShieldState.Get() & SHIELD_ORIENT_TO_OWNER ) != 0;
}
void CShieldMobile::SetAngularSpringConstant( float flConstant )
{
m_flSpringConstant = flConstant;
m_ShieldEffect.SetAngularSpringConstant( flConstant );
}
void CShieldMobile::SetFrontDistance( float flDistance )
{
m_flFrontDistance = flDistance;
}
void CShieldMobile::SetThetaPhi( float flTheta, float flPhi )
{
// This sets the bounds of the shield; how tall + wide is it?
m_flShieldTheta = flTheta;
m_flShieldPhi = flPhi;
m_ShieldEffect.SetThetaPhi(flTheta, flPhi);
}
//-----------------------------------------------------------------------------
// Computes the shield bounding box
//-----------------------------------------------------------------------------
void CShieldMobile::ComputeBoundingBox( void )
{
Vector mins, maxs;
m_ShieldEffect.ComputeBounds(mins, maxs);
SetCollisionBounds( mins, maxs );
}
//-----------------------------------------------------------------------------
// Compute world axis-aligned bounding box
//-----------------------------------------------------------------------------
void CShieldMobile::ComputeWorldSpaceSurroundingBox( Vector *pWorldMins, Vector *pWorldMaxs )
{
// We don't use USE_SPECIFIED_BOUNDS because that would generate a ton of network traffic
VectorAdd( CollisionProp()->GetCollisionOrigin(), CollisionProp()->OBBMins(), *pWorldMins );
VectorAdd( CollisionProp()->GetCollisionOrigin(), CollisionProp()->OBBMaxs(), *pWorldMaxs );
}
//-----------------------------------------------------------------------------
// Determines shield obstructions
//-----------------------------------------------------------------------------
void CShieldMobile::DetermineObstructions( )
{
m_ShieldEffect.ComputeVertexActivity();
}
//-----------------------------------------------------------------------------
// Called by the enumerator call in ShieldThink
//-----------------------------------------------------------------------------
bool CShieldMobile::EnumEntity( IHandleEntity *pHandleEntity )
{
#ifdef CLIENT_DLL
CBaseEntity *pOther = cl_entitylist->GetBaseEntityFromHandle( pHandleEntity->GetRefEHandle() );
#else
CBaseEntity *pOther = gEntList.GetBaseEntity( pHandleEntity->GetRefEHandle() );
#endif
if (!pOther)
return true;
// Blow off non-solid things
if ( !::IsSolid(pOther->GetSolid(), pOther->GetSolidFlags()) )
return true;
// No model, blow it off
if ( !pOther->GetModelIndex() )
return true;
// Blow off point-sized things....
if ( pOther->IsPointSized() )
return true;
// Don't bother if we shouldn't be colliding with this guy...
if (!m_pEnumCtx->m_Filter.ShouldHitEntity( pOther, MASK_SOLID ))
return true;
// The shield is in its final position, so we're gonna have to determine the
// point of collision by working in the space of the final position....
// We do this by moving the obstruction by the relative movement amount...
Vector vecObsMins, vecObsMaxs, vecObsCenter;
pOther->CollisionProp()->WorldSpaceAABB( &vecObsMins, &vecObsMaxs );
vecObsCenter = (vecObsMins + vecObsMaxs) * 0.5f;
vecObsMins -= vecObsCenter;
vecObsMaxs -= vecObsCenter;
Vector vecStart, vecEnd;
VectorAdd( vecObsCenter, m_pEnumCtx->m_vecStartDelta, vecStart );
VectorAdd( vecStart, m_pEnumCtx->m_vecEndDelta, vecEnd );
Ray_t ray;
ray.Init( vecStart, vecEnd, vecObsMins, vecObsMaxs );
trace_t tr;
if (TestCollision( ray, pOther->PhysicsSolidMaskForEntity(), tr ))
{
// Ok, we got a collision. Let's indicate it happened...
// At the moment, we'll report the collision point as being on the
// surface of the shield in its final position, which is kind of bogus...
pOther->PhysicsImpact( this, tr );
}
return true;
}
//-----------------------------------------------------------------------------
// Update the shield position:
//-----------------------------------------------------------------------------
void CShieldMobile::SimulateShield( void )
{
CBaseEntity *owner = GetOwnerEntity();
Vector origin;
if ( owner )
{
if ( m_ShieldState & SHIELD_ORIENT_TO_OWNER )
{
if ( owner->IsPlayer() )
{
m_ShieldEffect.SetDesiredAngles( owner->EyeAngles() );
}
else
{
m_ShieldEffect.SetDesiredAngles( owner->GetAbsAngles() );
}
}
else
{
m_ShieldEffect.SetDesiredAngles( m_angLockedAngles );
}
if ( m_nAttachmentIndex == 0 )
{
origin = owner->EyePosition();
}
else
{
QAngle angles;
CBaseAnimating *pAnim = dynamic_cast<CBaseAnimating*>( owner );
if (pAnim)
{
pAnim->GetAttachment( m_nAttachmentIndex, origin, angles );
}
else
{
origin = owner->EyePosition();
}
}
if ( m_flFrontDistance )
{
Vector vForward;
AngleVectors( m_ShieldEffect.GetDesiredAngles(), &vForward );
origin += vForward * m_flFrontDistance;
}
}
else
{
Assert( 0 );
origin = vec3_origin;
}
// We pretty much always need to recompute this
CollisionProp()->MarkSurroundingBoundsDirty();
Vector vecOldOrigin = m_ShieldEffect.GetCurrentPosition();
Vector vecDelta;
VectorSubtract( origin, vecOldOrigin, vecDelta );
float flMaxDist = 100 + m_flFrontDistance;
if (vecDelta.LengthSqr() > flMaxDist * flMaxDist )
{
OnTeleported();
return;
}
m_ShieldEffect.SetDesiredOrigin( origin );
m_ShieldEffect.Simulate(gpGlobals->frametime);
DetermineObstructions();
SetAbsOrigin( m_ShieldEffect.GetCurrentPosition() );
SetAbsAngles( m_ShieldEffect.GetCurrentAngles() );
#ifdef CLIENT_DLL
// Necessary because we exclude the network origin
SetNetworkOrigin( m_ShieldEffect.GetCurrentPosition() );
SetNetworkAngles( m_ShieldEffect.GetCurrentAngles() );
#endif
// Compute a composite bounding box surrounding the initial + new positions..
Vector vecCompositeMins = WorldAlignMins() + vecOldOrigin;
Vector vecCompositeMaxs = WorldAlignMaxs() + vecOldOrigin;
ComputeBoundingBox();
// Sweep the shield through the world + touch things it hits...
SweepContext_t ctx( this, GetCollisionGroup() );
VectorSubtract( GetAbsOrigin(), vecOldOrigin, ctx.m_vecStartDelta );
if (ctx.m_vecStartDelta != vec3_origin)
{
// FIXME: Brutal hack; needed because IntersectRayWithTriangle misses stuff
// especially with short rays; I'm not sure what to do about this.
// This basically simulates a shield thickness of 15 units
ctx.m_vecEndDelta = ctx.m_vecStartDelta;
VectorNormalize( ctx.m_vecEndDelta );
ctx.m_vecEndDelta *= -15.0f;
Vector vecNewMins = WorldAlignMins() + GetAbsOrigin();
Vector vecNewMaxs = WorldAlignMaxs() + GetAbsOrigin();
VectorMin( vecCompositeMins, vecNewMins, vecCompositeMins );
VectorMax( vecCompositeMaxs, vecNewMaxs, vecCompositeMaxs );
m_pEnumCtx = &ctx;
enginetrace->EnumerateEntities( vecCompositeMins, vecCompositeMaxs, this );
}
}
//-----------------------------------------------------------------------------
// Update the shield position:
//-----------------------------------------------------------------------------
void CShieldMobile::ShieldThink( void )
{
SimulateShield();
#ifdef CLIENT_DLL
m_ShieldEffect.ComputeControlPoints();
m_ShieldEffect.ComputePanelActivity();
#endif
SetNextThink( gpGlobals->curtime + 0.01f );
}
void CShieldMobile::ClientThink()
{
#ifdef CLIENT_DLL
if ( GetPredictable() )
return;
SimulateShield();
m_ShieldEffect.ComputeControlPoints();
m_ShieldEffect.ComputePanelActivity();
#endif
}
//-----------------------------------------------------------------------------
// Teleport!
//-----------------------------------------------------------------------------
void CShieldMobile::OnTeleported( )
{
CBaseEntity *owner = GetOwnerEntity();
if (!owner)
return;
m_ShieldEffect.SetCurrentAngles( owner->GetAbsAngles() );
Vector origin;
origin = owner->EyePosition();
if ( m_flFrontDistance )
{
Vector vForward;
AngleVectors( m_ShieldEffect.GetCurrentAngles(), &vForward );
origin += vForward * m_flFrontDistance;
}
m_ShieldEffect.SetCurrentPosition( origin );
}
#ifdef CLIENT_DLL
//-----------------------------------------------------------------------------
// Get this after the data changes
//-----------------------------------------------------------------------------
void CShieldMobile::OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
m_ShieldEffect.SetThetaPhi( m_flShieldTheta, m_flShieldPhi );
m_ShieldEffect.SetAngularSpringConstant( m_flSpringConstant );
}
//-----------------------------------------------------------------------------
// A little pre-render processing
//-----------------------------------------------------------------------------
void C_ShieldMobile::PreRender( )
{
if (m_ShieldState & SHIELD_MOBILE_EMP)
{
// Decay fade if we've been EMPed or if we're inactive
if (m_FadeValue > 0.0f)
{
m_FadeValue -= gpGlobals->frametime / SHIELD_EMP_FADE_TIME;
if (m_FadeValue < 0.0f)
{
m_FadeValue = 0.0f;
// Reset the shield to un-wobbled state
m_ShieldEffect.ComputeControlPoints();
}
else
{
Vector dir;
AngleVectors( m_ShieldEffect.GetCurrentAngles(), & dir, 0, 0 );
// Futz with the control points if we've been EMPed
for (int i = 0; i < SHIELD_NUM_CONTROL_POINTS; ++i)
{
// Get the direction for the point
float factor = -EMP_WAVE_AMPLITUDE * sin( i * M_PI * 0.5f + gpGlobals->curtime * M_PI / SHIELD_EMP_WOBBLE_TIME );
m_ShieldEffect.GetPoint(i) += dir * factor;
}
}
}
}
else
{
// Fade back in, no longer EMPed
if (m_FadeValue < 1.0f)
{
m_FadeValue += gpGlobals->frametime / SHIELD_EMP_FADE_TIME;
if (m_FadeValue >= 1.0f)
{
m_FadeValue = 1.0f;
}
}
}
}
void CShieldMobile::AddEntity( )
{
BaseClass::AddEntity( );
PreRender();
}
//-----------------------------------------------------------------------------
// Bounds computation
//-----------------------------------------------------------------------------
void CShieldMobile::GetBounds( Vector& mins, Vector& maxs )
{
m_ShieldEffect.ComputeBounds( mins, maxs );
}
//-----------------------------------------------------------------------------
// Gets at the control point data; who knows how it was made?
//-----------------------------------------------------------------------------
void CShieldMobile::GetShieldData( const Vector** ppVerts, float* pOpacity, float* pBlend )
{
for ( int i = 0; i < SHIELD_NUM_CONTROL_POINTS; ++i )
{
ppVerts[i] = &m_ShieldEffect.GetControlPoint(i);
if ( m_pVertsActive[i >> 3] & (1 << (i & 0x7)) )
{
pOpacity[i] = m_ShieldEffect.ComputeOpacity( *ppVerts[i], GetAbsOrigin() );
pBlend[i] = 1.0f;
}
else
{
pOpacity[i] = 192.0f;
pBlend[i] = 0.0f;
}
}
}
#endif // CLIENT_DLL
#ifndef CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose: Create a mobile version of the shield
//-----------------------------------------------------------------------------
CShield *CreateMobileShield( CBaseEntity *owner, float flFrontDistance )
{
CShieldMobile *pShield = (CShieldMobile*)CreateEntityByName("shield_mobile");
pShield->SetOwnerEntity( owner );
pShield->SetLocalAngles( owner->GetAbsAngles() );
pShield->SetFrontDistance( flFrontDistance );
// Start it in the right place
Vector vForward;
AngleVectors( owner->GetAbsAngles(), &vForward );
Vector vecOrigin = owner->EyePosition() + (vForward * flFrontDistance);
UTIL_SetOrigin( pShield, vecOrigin );
pShield->ChangeTeam( owner->GetTeamNumber() );
pShield->SetupRecharge( shield_mobile_power.GetFloat(), shield_mobile_recharge_delay.GetFloat(), shield_mobile_recharge_amount.GetFloat(), shield_mobile_recharge_time.GetFloat() );
pShield->Spawn();
return pShield;
}
#endif
+579
View File
@@ -0,0 +1,579 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: The Escort's Shield weapon effect
//
// $Workfile: $
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "tf_shieldshared.h"
#include "edict.h"
#include "mathlib/vmatrix.h"
#include "engine/IEngineTrace.h"
#ifdef CLIENT_DLL
#include "cdll_client_int.h"
#else
#include "gameinterface.h"
#endif
BEGIN_PREDICTION_DATA_NO_BASE( CShieldEffect )
DEFINE_FIELD( m_TestPoint, FIELD_INTEGER ),
DEFINE_FIELD( m_Position, FIELD_VECTOR ),
DEFINE_FIELD( m_Velocity, FIELD_VECTOR ),
DEFINE_FIELD( m_CurrentAngles, FIELD_VECTOR ),
DEFINE_FIELD( m_Theta, FIELD_FLOAT ),
DEFINE_FIELD( m_Phi, FIELD_FLOAT ),
DEFINE_FIELD( m_ThetaVelocity, FIELD_FLOAT ),
DEFINE_FIELD( m_PhiVelocity, FIELD_FLOAT ),
DEFINE_FIELD( m_vecDesiredOrigin, FIELD_VECTOR ),
DEFINE_FIELD( m_angDesiredAngles, FIELD_VECTOR ),
DEFINE_FIELD( m_ShieldTheta, FIELD_FLOAT ),
DEFINE_FIELD( m_ShieldPhi, FIELD_FLOAT ),
END_PREDICTION_DATA()
//-----------------------------------------------------------------------------
// constructor, destructor
//-----------------------------------------------------------------------------
CShieldEffect::CShieldEffect( )
{
}
//-----------------------------------------------------------------------------
// compute rest positions of the springs
//-----------------------------------------------------------------------------
void CShieldEffect::ComputeRestPositions()
{
int i;
m_vecRenderMins.Init( FLT_MAX, FLT_MAX, FLT_MAX );
m_vecRenderMaxs.Init( -FLT_MAX, -FLT_MAX, -FLT_MAX );
// Set the initial directions and distances (in shield space)...
for ( i = 0; i < SHIELD_NUM_VERTICAL_POINTS; ++i)
{
// Choose phi centered at pi/2
float phi = (M_PI - m_ShieldPhi) * 0.5f + m_ShieldPhi *
(float)i / (float)(SHIELD_NUM_VERTICAL_POINTS - 1);
for (int j = 0; j < SHIELD_NUM_HORIZONTAL_POINTS; ++j)
{
// Choose theta centered at pi/2 also (y, or forward axis)
float theta = (M_PI - m_ShieldTheta) * 0.5f + m_ShieldTheta *
(float)j / (float)(SHIELD_NUM_HORIZONTAL_POINTS - 1);
int idx = i * SHIELD_NUM_HORIZONTAL_POINTS + j;
m_pFixedDirection[idx].x = cos(theta) * sin(phi);
m_pFixedDirection[idx].y = sin(theta) * sin(phi);
m_pFixedDirection[idx].z = cos(phi);
m_pFixedDirection[idx] *= m_RestLength;
VectorMin( m_vecRenderMins, m_pFixedDirection[idx], m_vecRenderMins );
VectorMax( m_vecRenderMaxs, m_pFixedDirection[idx], m_vecRenderMaxs );
}
}
// Compute box for fake volume testing
Vector dist = m_pFixedDirection[0] - m_pFixedDirection[1];
float l = dist.Length(); // * m_RestLength;
SetShieldPanelSize( Vector( -l * 0.25f, -l * 0.25f, -l * 0.25f),
Vector( l * 0.25f, l * 0.25f, l * 0.25f) );
}
//-----------------------------------------------------------------------------
// Sets orientation + position
//-----------------------------------------------------------------------------
void CShieldEffect::SetDesiredOrigin( const Vector& origin )
{
VectorCopy( origin, m_vecDesiredOrigin );
}
void CShieldEffect::SetDesiredAngles( const QAngle& angles )
{
VectorCopy( angles, m_angDesiredAngles );
}
const QAngle& CShieldEffect::GetDesiredAngles() const
{
return m_angDesiredAngles;
}
//-----------------------------------------------------------------------------
// Gets a point...
//-----------------------------------------------------------------------------
const Vector& CShieldEffect::GetPoint( int x, int y ) const
{
return m_pControlPoint[ x + y * SHIELD_NUM_HORIZONTAL_POINTS ];
}
const Vector& CShieldEffect::GetPoint( int i ) const
{
return m_pControlPoint[ i ];
}
Vector& CShieldEffect::GetPoint( int i )
{
return m_pControlPoint[ i ];
}
//-----------------------------------------------------------------------------
// Sets the collision group
//-----------------------------------------------------------------------------
void CShieldEffect::SetCollisionGroup( int group )
{
m_CollisionGroup = group;
}
//-----------------------------------------------------------------------------
// Hooks in active bits...
//-----------------------------------------------------------------------------
void CShieldEffect::SetActiveVertexList( IActiveVertList *pActiveVerts )
{
m_pActiveVerts = pActiveVerts;
// No points are visible initially
for ( int i=0; i < SHIELD_VERTEX_BYTES*8; i++ )
m_pActiveVerts->SetActiveVertState( i, 0 );
}
//-----------------------------------------------------------------------------
// Is a particular vertex active?
//-----------------------------------------------------------------------------
bool CShieldEffect::IsVertexActive( int x, int y ) const
{
if ((x < 0) || (y < 0) || (x >= SHIELD_NUM_HORIZONTAL_POINTS) ||
(y >= SHIELD_NUM_VERTICAL_POINTS))
{
return false;
}
int idx = x + (SHIELD_NUM_HORIZONTAL_POINTS) * y;
return m_pActiveVerts->GetActiveVertState( idx ) != 0;
}
//-----------------------------------------------------------------------------
// Is a particular panel active?
//-----------------------------------------------------------------------------
bool CShieldEffect::IsPanelActive( int x, int y ) const
{
if ((x < 0) || (y < 0) || (x >= SHIELD_HORIZONTAL_PANEL_COUNT) ||
(y >= SHIELD_VERTICAL_PANEL_COUNT))
{
return false;
}
int idx = x + (SHIELD_HORIZONTAL_PANEL_COUNT) * y;
return m_pActivePanels[idx];
}
//-----------------------------------------------------------------------------
// Recompute whether the panels are active or not
//-----------------------------------------------------------------------------
void CShieldEffect::ComputePanelActivity()
{
// Check neighbors to see how many squares we've got
for ( int i = 0; i < SHIELD_NUM_HORIZONTAL_POINTS - 1; ++i)
{
for ( int j = 0; j < SHIELD_NUM_VERTICAL_POINTS - 1; ++j)
{
int idx = i + j * (SHIELD_NUM_HORIZONTAL_POINTS - 1);
// Test the neighbors
m_pActivePanels[idx] =
IsVertexActive( i, j ) ||
IsVertexActive( i+1, j ) ||
IsVertexActive( i, j+1 ) ||
IsVertexActive( i+1, j+1 );
}
}
}
//-----------------------------------------------------------------------------
// Compute vertex activity
//-----------------------------------------------------------------------------
enum
{
SHIELD_TESTS_PER_FRAME = 4
};
void CShieldEffect::ComputeVertexActivity()
{
int i;
for ( i = 0; i < SHIELD_TESTS_PER_FRAME; ++i )
{
// Visit points in random order...
int pt = m_PointList[m_TestPoint];
// Collision test...
// Check a line that goes farther out than our current point...
// This will let us check for resting contact
trace_t tr;
CTraceFilterWorldOnly traceFilter;
UTIL_TraceHull( m_Position, m_pControlPoint[pt],
m_PanelBoxMin, m_PanelBoxMax, MASK_SOLID_BRUSHONLY, &traceFilter, &tr );
bool isActive = (!tr.allsolid) && ( (tr.fraction - 1.0f) >= 0.0f );
m_pActiveVerts->SetActiveVertState( pt, isActive );
if (++m_TestPoint >= SHIELD_NUM_CONTROL_POINTS)
m_TestPoint = 0;
}
ComputePanelActivity();
}
//-----------------------------------------------------------------------------
// bounding box for collision
//-----------------------------------------------------------------------------
void CShieldEffect::SetShieldPanelSize( Vector& mins, Vector& maxs )
{
m_PanelBoxMin = mins;
m_PanelBoxMax = maxs;
}
//-----------------------------------------------------------------------------
// bounding box for collision
//-----------------------------------------------------------------------------
void CShieldEffect::ComputeBounds( Vector& mins, Vector& maxs )
{
VectorCopy( m_pControlPoint[0], mins );
VectorCopy( m_pControlPoint[0], maxs );
for (int i = 1; i < SHIELD_NUM_CONTROL_POINTS; ++i)
{
VectorMin( mins, m_pControlPoint[i], mins );
VectorMax( maxs, m_pControlPoint[i], maxs );
}
// Bounds are in local coords
mins -= m_Position;
maxs -= m_Position;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CShieldEffect::Precache( void )
{
m_RestLength = 200.0;
m_SpringConstant = 30.0f;
m_DampConstant = 4.0f;
m_ViscousDrag = 4.0f;
m_Mass = 1.0f;
m_AngularSpringConstant = 2.0f;
m_AngularViscousDrag = 4.0f;
SetThetaPhi( SHIELD_INITIAL_THETA, SHIELD_INITIAL_PHI );
}
//-----------------------------------------------------------------------------
// Compute orientation matrix:
//-----------------------------------------------------------------------------
void CShieldEffect::ComputeOrientationMatrix()
{
// Generate the orientation matrix from theta and phi...
// X = forward direction, Y - left direction
Vector forward, left, up;
forward.x = cos(m_Theta) * sin(m_Phi);
forward.y = sin(m_Theta) * sin(m_Phi);
forward.z = cos(m_Phi);
left.x = -forward.y;
left.y = forward.x;
left.z = 0;
if ( VectorNormalize(left) == 0.0f )
left.Init( 0.0f, 1.0f, 0.0f );
CrossProduct( forward, left, up );
m_Orientation.SetBasisVectors( forward, left, up );
// Turn the current matrix into angles...
MatrixToAngles( m_Orientation, m_CurrentAngles );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CShieldEffect::Spawn( const Vector& currentPosition, const QAngle& currentAngles )
{
Precache();
VectorCopy( currentPosition, m_Position );
m_Velocity.Init();
Vector forward;
AngleVectors( currentAngles, &forward, 0, 0 );
m_Phi = acos( forward.z );
m_Theta = atan2( forward.y, forward.x );
m_PhiVelocity = 0.0f;
m_ThetaVelocity = 0.0f;
ComputeOrientationMatrix();
VectorCopy( currentAngles, m_CurrentAngles );
VectorCopy( currentAngles, m_angDesiredAngles );
// No points are visible initially
memset( m_pActivePanels, 0, SHIELD_PANELS_COUNT );
m_TestPoint = 0;
// Choose random order to visit shield verts
int i;
for ( i = 0; i < SHIELD_NUM_CONTROL_POINTS; ++i )
{
m_PointList[i] = i;
}
for ( i = 0; i < SHIELD_NUM_CONTROL_POINTS; ++i )
{
int j = rand() % SHIELD_NUM_CONTROL_POINTS;
swap( m_PointList[i], m_PointList[j] );
}
}
//-----------------------------------------------------------------------------
// Computes the opacity....
//-----------------------------------------------------------------------------
float CShieldEffect::ComputeOpacity( const Vector& pt, const Vector& center ) const
{
float dist = pt.DistTo( center ) / m_RestLength;
if (dist > 1.0)
dist = 1.0f;
return 32 + (1.0 - dist) * 192;
}
//-----------------------------------------------------------------------------
// Computes control points
//-----------------------------------------------------------------------------
void CShieldEffect::ComputeControlPoints()
{
Vector forward, right, up;
AngleVectors(m_CurrentAngles, &forward, &right, &up);
for ( int i = 0; i < SHIELD_NUM_CONTROL_POINTS; ++i )
{
// Compute the world space position...
VectorCopy( m_Position, m_pControlPoint[i] );
m_pControlPoint[i] += right * m_pFixedDirection[i].x;
m_pControlPoint[i] += up * m_pFixedDirection[i].z;
m_pControlPoint[i] += forward * m_pFixedDirection[i].y;
}
}
//-----------------------------------------------------------------------------
// Gets the frustum size
//-----------------------------------------------------------------------------
void CShieldEffect::GetPanelSize( Vector& mins, Vector& maxs ) const
{
VectorCopy( m_PanelBoxMin, mins );
VectorCopy( m_PanelBoxMax, maxs );
}
void CShieldEffect::SetAngularSpringConstant( float flConstant )
{
m_AngularSpringConstant = flConstant;
}
//-----------------------------------------------------------------------------
// Set the shield theta & phi
//-----------------------------------------------------------------------------
void CShieldEffect::SetThetaPhi( float flTheta, float flPhi )
{
m_ShieldTheta = M_PI * flTheta / 180.0f;
m_ShieldPhi = M_PI * flPhi / 180.0f;
// Computes the rest positions
ComputeRestPositions();
}
//-----------------------------------------------------------------------------
// The current position (computed by Simulate on the server)
//-----------------------------------------------------------------------------
const Vector& CShieldEffect::GetCurrentPosition()
{
return m_Position;
}
void CShieldEffect::SetCurrentPosition( const Vector& pos )
{
m_Position = pos;
}
void CShieldEffect::SetCurrentAngles( const QAngle& angles )
{
VectorCopy( angles, m_CurrentAngles );
}
//-----------------------------------------------------------------------------
// Simulate the center of mass
//-----------------------------------------------------------------------------
void CShieldEffect::SimulateTranslation( float dt )
{
// Hook's law for a damped spring:
// got two particles, a and b with positions xa and xb and velocities va and vb
// and l = xa - xb
// fa = -( ks * (|l| - r) + kd * (va - vb) dot (l) / |l|) * l/|l|
Vector dx, force;
// Case where we're connected to a control point
dx = m_Position - m_vecDesiredOrigin;
// rest condition
float length = dx.Length();
float speedSq = m_Velocity.LengthSqr();
if ((length < 1e-3) && (speedSq < 1e-6))
return;
// Compute force
if (length > 1e-3)
dx /= length;
else
dx.Init( 0, 0, 0 );
float springfactor = m_SpringConstant * length;
float dampfactor = m_DampConstant * DotProduct( m_Velocity, dx );
force = dx * -( springfactor + dampfactor );
assert( force.IsValid( ) );
Vector drag = m_Velocity * m_ViscousDrag;
force -= drag;
// Update position and velocity
m_Position += m_Velocity * dt;
m_Velocity += force * dt / m_Mass;
assert( m_Velocity.IsValid( ) );
// clamp for stability
if (speedSq > 1e6)
{
m_Velocity *= 1e3 / sqrt(speedSq);
}
}
void CShieldEffect::SimulateRotation( float dt, const Vector& forward )
{
// Here's a torsional spring for the angular component...
// A little tricky: We need to actually think about 2 torsional springs,
// one in thetha (x-y plane), and one in phi (z-plane)
float phi2 = acos( forward.z );
float dPhi = m_Phi - phi2;
float theta2 = atan2( forward.y, forward.x );
float dTheta = (m_Theta - theta2);
if (dTheta > M_PI)
dTheta -= 2 * M_PI;
else if (dTheta < -M_PI)
dTheta += 2 * M_PI;
// rest condition...
if ((fabs(dTheta) < 1e-3) && (fabs(m_ThetaVelocity) < 1e-6) &&
(fabs(dPhi) < 1e-3) && (fabs(m_PhiVelocity) < 1e-6))
{
return;
}
float springfactor = m_AngularSpringConstant * dTheta;
float torqueTheta = -springfactor; // + dampfactor);
torqueTheta -= m_ThetaVelocity * m_AngularViscousDrag;
springfactor = m_AngularSpringConstant * dPhi;
float torqueTPhi = -springfactor; // + dampfactor);
torqueTPhi -= m_PhiVelocity * m_AngularViscousDrag;
// Update position and velocity
m_Theta += m_ThetaVelocity * dt;
m_ThetaVelocity += torqueTheta * dt;
m_Phi += m_PhiVelocity * dt;
m_PhiVelocity += torqueTPhi * dt;
// clamp for stability
if (fabs(m_ThetaVelocity) > 1e2)
{
m_ThetaVelocity *= 1e2 / m_ThetaVelocity;
}
if (fabs(m_PhiVelocity) > 1e2)
{
m_PhiVelocity *= 1e2 / m_PhiVelocity;
}
ComputeOrientationMatrix();
}
//-----------------------------------------------------------------------------
// Update the shield position:
//-----------------------------------------------------------------------------
void CShieldEffect::Simulate( float dt )
{
// We're gonna basically assume a spring connected to the center control point
Vector forward;
AngleVectors(m_angDesiredAngles, &forward, 0, 0);
// We've got two springs: a spring connected to the origin
// and a torsional spring connected to the view direction.
// Stiff spring, subdivide time....
dt /= SHIELD_TIME_SUBVISIBIONS;
for (int i = 0; i < SHIELD_TIME_SUBVISIBIONS; ++i)
{
SimulateTranslation( dt );
SimulateRotation( dt, forward );
}
ComputeControlPoints();
}
//-----------------------------------------------------------------------------
// Determines shield obstructions
//-----------------------------------------------------------------------------
static inline bool IsPointValid( bool* pActivePoints, int i, int j )
{
// Here's the control point we're checking
int idx = j * SHIELD_NUM_HORIZONTAL_POINTS + i;
return pActivePoints[idx];
}
+262
View File
@@ -0,0 +1,262 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef TF_SHIELD_SHARED_H
#define TF_SHIELD_SHARED_H
#ifdef _WIN32
#pragma once
#endif
#include "mathlib/mathlib.h"
#include "mathlib/vector.h"
#include "mathlib/vmatrix.h"
#include "utlvector.h"
#include "SheetSimulator.h"
#include "predictable_entity.h"
//-----------------------------------------------------------------------------
// Purpose: Shield (mobile version)
//-----------------------------------------------------------------------------
enum
{
SHIELD_NUM_HORIZONTAL_POINTS = 8,
SHIELD_NUM_VERTICAL_POINTS = 8,
SHIELD_NUM_CONTROL_POINTS = SHIELD_NUM_HORIZONTAL_POINTS * SHIELD_NUM_VERTICAL_POINTS,
SHIELD_INITIAL_THETA = 135,
SHIELD_INITIAL_PHI = 90,
SHIELD_HORIZONTAL_PANEL_COUNT = (SHIELD_NUM_HORIZONTAL_POINTS - 1),
SHIELD_VERTICAL_PANEL_COUNT = (SHIELD_NUM_VERTICAL_POINTS - 1),
SHIELD_PANELS_COUNT = (SHIELD_HORIZONTAL_PANEL_COUNT * SHIELD_VERTICAL_PANEL_COUNT),
SHIELD_VERTEX_BYTES = (SHIELD_NUM_CONTROL_POINTS + 7) >> 3,
SHIELD_TIME_SUBVISIBIONS = 2
};
//--------------------------------------------------------------------------
// Mobile shield state flags
//--------------------------------------------------------------------------
enum
{
SHIELD_MOBILE_EMP = 0x1
};
//--------------------------------------------------------------------------
// Shield grenade state
//--------------------------------------------------------------------------
enum
{
SHIELD_FLAT_EMP = 0x1,
SHIELD_FLAT_INACTIVE = 0x2
};
enum
{
SHIELD_FLAT_SHUTDOWN_TIME = 1
};
enum
{
SHIELD_GRENADE_WIDTH = 150,
SHIELD_GRENADE_HEIGHT = 150,
};
#define SHIELD_DAMAGE_CHANGE_TIME 1.5f
//-----------------------------------------------------------------------------
// Amount of time it takes to fade the shield in or out due to EMP
//-----------------------------------------------------------------------------
#define SHIELD_EMP_FADE_TIME 0.7f
//-----------------------------------------------------------------------------
// Amount of time it takes a point to wobble when EMPed
//-----------------------------------------------------------------------------
#define SHIELD_EMP_WOBBLE_TIME 0.1f
//-----------------------------------------------------------------------------
// Methods we must install into the effect
//-----------------------------------------------------------------------------
class IActiveVertList
{
public:
virtual int GetActiveVertState( int iVert ) = 0;
virtual void SetActiveVertState( int iVert, int bOn ) = 0;
};
class CShieldEffect
{
DECLARE_CLASS_NOBASE( CShieldEffect );
DECLARE_PREDICTABLE();
public:
CShieldEffect();
void Precache();
void Spawn(const Vector& currentPosition, const QAngle& currentAngles);
// Sets the collision group
void SetCollisionGroup( int group );
// Computes the opacity....
float ComputeOpacity( const Vector& pt, const Vector& center ) const;
// Computes the bounds
void ComputeBounds( Vector& mins, Vector& maxs );
// Simulation
void Simulate( float dt );
// Sets desired orientation + position
void SetDesiredOrigin( const Vector& origin );
void SetDesiredAngles( const QAngle& angles );
const QAngle& GetDesiredAngles() const;
// Hooks in active bits...
void SetActiveVertexList( IActiveVertList *pActiveVerts );
// Gets a point...
const Vector& GetPoint( int x, int y ) const;
const Vector& GetPoint( int i ) const;
Vector& GetPoint( int i );
// Computes control points
void ComputeControlPoints();
// The current angles (computed by Simulate on the server)
const QAngle& GetCurrentAngles() const;
void SetCurrentAngles( const QAngle& angles);
// The current position (computed by Simulate on the server)
const Vector& GetCurrentPosition();
void SetCurrentPosition( const Vector& pos );
// Compute vertex activity
void ComputeVertexActivity();
// Recompute whether the panels are active or not
void ComputePanelActivity();
// Is a particular vertex active?
bool IsVertexActive( int x, int y ) const;
// Is a particular panel active?
bool IsPanelActive( int x, int y ) const;
// Gets a control point (for collision)
const Vector& GetControlPoint( int i ) const { return m_pControlPoint[i]; }
// Returns the panel size (for collision testing)
void GetPanelSize( Vector& mins, Vector& maxs ) const;
// Change the angular spring constant. This affects how fast the shield rotates to face the angles
// given in SetAngles. Higher numbers are more responsive, but if you go too high (around 40), it will
// jump past the specified angles and wiggle a little bit.
void SetAngularSpringConstant( float flConstant );
// Set the shield theta & phi
void SetThetaPhi( float flTheta, float flPhi );
// Returns the render bounds
const Vector& GetRenderMins() const;
const Vector& GetRenderMaxs() const;
private:
// Simulation set up
void ComputeRestPositions();
void SetShieldPanelSize( Vector& mins, Vector& maxs );
void SimulateTranslation( float dt );
void SimulateRotation( float dt, const Vector& forward );
void ComputeOrientationMatrix();
float m_RestLength;
float m_PlaneDist;
float m_ShieldTheta;
float m_ShieldPhi;
// Spring constants
float m_SpringConstant;
float m_DampConstant;
float m_ViscousDrag;
float m_Mass;
float m_AngularSpringConstant;
float m_AngularViscousDrag;
// collision group
int m_CollisionGroup;
// Directions of the control points in shield space
Vector m_pFixedDirection[SHIELD_NUM_CONTROL_POINTS];
// Position of the control points in world space
Vector m_pControlPoint[SHIELD_NUM_CONTROL_POINTS];
// Bitfield indicating which vertices are active
IActiveVertList *m_pActiveVerts;
// Bitfield indicating which panels are active
bool m_pActivePanels[SHIELD_PANELS_COUNT];
// Which point on the shield to test next
int m_TestPoint;
int m_PointList[SHIELD_NUM_CONTROL_POINTS];
// desired position + orientation
Vector m_vecDesiredOrigin;
QAngle m_angDesiredAngles;
// collision box
Vector m_PanelBoxMin;
Vector m_PanelBoxMax;
// Render bounds (shield space)
Vector m_vecRenderMins;
Vector m_vecRenderMaxs;
// Actual center position (relative to m_Origin)
// + velocity (world space)
Vector m_Position;
Vector m_Velocity;
// our current orientation....
QAngle m_CurrentAngles;
VMatrix m_Orientation;
float m_Theta;
float m_Phi;
float m_ThetaVelocity;
float m_PhiVelocity;
};
//-----------------------------------------------------------------------------
// Inline methods
//-----------------------------------------------------------------------------
inline const QAngle& CShieldEffect::GetCurrentAngles() const
{
return m_CurrentAngles;
}
//-----------------------------------------------------------------------------
// Returns the render bounds
//-----------------------------------------------------------------------------
inline const Vector& CShieldEffect::GetRenderMins() const
{
return m_vecRenderMins;
}
inline const Vector& CShieldEffect::GetRenderMaxs() const
{
return m_vecRenderMaxs;
}
#endif // TF_SHIELD_SHARED_H
+122
View File
@@ -0,0 +1,122 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Shared stuff for the Tactical map
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
// Unfortunate hack.
// Needed to cycle through the player & radar scanner entities in both the client and game dlls
#ifdef CLIENT_DLL
// Client DLL functions
#include "c_team.h"
#include "c_tfteam.h"
#include "c_basetfplayer.h"
#include "C_BaseObject.h"
static inline bool IsPlayerCamoed( int iEntIndex )
{
C_BaseTFPlayer* pPlayer = (C_BaseTFPlayer*)ClientEntityList().GetClientEntity(iEntIndex);
if (!pPlayer)
return false;
return pPlayer->IsCamouflaged();
}
static inline bool IsPlayerVisible( int iEntIndex )
{
C_BaseTFPlayer* pPlayer = (C_BaseTFPlayer*)ClientEntityList().GetClientEntity(iEntIndex);
if (!pPlayer)
return false;
return pPlayer->GetClass() != TFCLASS_UNDECIDED;
}
static inline bool IsEntityAnObject( int iEntIndex )
{
IClientNetworkable *pEnt = ClientEntityList().GetClientEntity(iEntIndex);
return dynamic_cast<C_BaseObject*>(pEnt) != 0;
}
#else
// Game DLL functions
#include "team.h"
#include "tf_team.h"
#include "tf_player.h"
static inline bool IsPlayerCamoed( int iEntIndex )
{
CBaseTFPlayer* pPlayer = (CBaseTFPlayer *)CBaseEntity::Instance( engine->PEntityOfEntIndex( iEntIndex ) );
if (!pPlayer)
return false;
return pPlayer->IsCamouflaged();
}
static inline bool IsPlayerVisible( int iEntIndex )
{
CBaseTFPlayer* pPlayer = (CBaseTFPlayer *)CBaseEntity::Instance( engine->PEntityOfEntIndex( iEntIndex ) );
if (!pPlayer)
return false;
return pPlayer->PlayerClass() != TFCLASS_UNDECIDED;
}
static inline bool IsEntityAnObject( int iEntIndex )
{
CBaseEntity* pEnt = CBaseEntity::Instance( engine->PEntityOfEntIndex( iEntIndex ) );
CBaseObject *pObject = dynamic_cast<CBaseObject*>(pEnt);
if (!pObject)
return false;
// Don't bother with boring ones... they're boring!
return ((pObject->GetObjectFlags( ) & OF_SUPPRESS_VISIBLE_TO_TACTICAL) == 0);
}
#endif
// Visibility defines
#define PLAYER_VISIBILITY_DISTANCE 2000 // Distance around a player that's exposed on the tactical map
//-----------------------------------------------------------------------------
// Purpose: Return true if the entity is visible on this player's tactical map
//-----------------------------------------------------------------------------
bool IsEntityVisibleToTactical( int iLocalTeamNumber, int iLocalTeamPlayers,
int iLocalTeamObjects, int entIndex, const char *pEntName, int iEntTeamNumber, const Vector &entOrigin )
{
// Resource zones are always visible
if ( !strcmp( pEntName, "trigger_resourcezone") )
return true;
// Tunnels are always visible
if ( !strcmp( pEntName, "obj_tunnel") || !strcmp( pEntName, "obj_tunnel_prop") )
return true;
// Fixed shields are never visible
if ( !strcmp( pEntName, "shield") )
return false;
// NOTE: If you're looking for various object types, fix the ugly hack
// in mapdata.cpp!!
if ( iLocalTeamNumber == iEntTeamNumber )
{
// Objects are always visible to their team
if (IsEntityAnObject( entIndex ))
return true;
// Players are always visible to their team
if (!Q_strncmp( pEntName, "player", 7) )
return true;
// Resource collectors are always visible to their team
if ( !strcmp( pEntName, "npc_rescollector_aerial") )
return true;
}
return false;
}
+43
View File
@@ -0,0 +1,43 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "usermessages.h"
#include "shake.h"
#include "voice_gamemgr.h"
void RegisterUserMessages( void )
{
usermessages->Register( "Geiger", 1 );
usermessages->Register( "Train", 1 );
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 );
usermessages->Register( "ItemPickup", -1 );
usermessages->Register( "ShowMenu", -1 );
usermessages->Register( "Shake", 13 );
usermessages->Register( "Fade", 10 );
usermessages->Register( "VGUIMenu", -1 ); // Show VGUI menu
usermessages->Register( "VoiceMask", VOICE_MAX_PLAYERS_DW*4 * 2 + 1 );
usermessages->Register( "RequestState", 0 );
usermessages->Register( "CloseCaption", -1 ); // Show a caption (by string id number)(duration in 10th of a second)
usermessages->Register( "HintText", -1 );
usermessages->Register( "AmmoDenied", 2 );
// TF User messages
usermessages->Register( "Damage", 13 );
usermessages->Register( "Accuracy", 2 );
usermessages->Register( "ZoneState", 1 );
usermessages->Register( "Technology", -1 );
usermessages->Register( "ActBegin", -1 );
usermessages->Register( "ActEnd", -1 );
usermessages->Register( "MinimapPulse", -1 );
usermessages->Register( "PickupRes", 1 );
}
+47
View File
@@ -0,0 +1,47 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef TF_VEHICLESHARED_H
#define TF_VEHICLESHARED_H
#ifdef _WIN32
#pragma once
#endif
enum VehicleModeDeploy_e
{
VEHICLE_MODE_NORMAL = 0,
VEHICLE_MODE_DEPLOYING,
VEHICLE_MODE_UNDEPLOYING,
VEHICLE_MODE_DEPLOYED
};
#define NUM_VEHICLE_DEPLOYMODE_BITS 2
// Attachment indices.
#define TANK_ATTACHMENT_TURRET_FIREPOS 1
#define TANK_ATTACHMENT_TURRET_BASE 2
#define TANK_ATTACHMENT_PLAYER_WAIST 3
// Tread indices.
enum TreadIndex
{
TREAD_LEFT=0,
TREAD_RIGHT=1
};
// Tread states (send across the wire).
enum TreadState
{
TREAD_NOTMOVING=0,
TREAD_FORWARD=1,
TREAD_BACKWARD=2
};
#endif // TF_VEHICLESHARED_H
+58
View File
@@ -0,0 +1,58 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "tfclassdata_shared.h"
BEGIN_PREDICTION_DATA_NO_BASE( PlayerClassCommandoData_t )
DEFINE_PRED_FIELD( m_bCanBullRush, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
DEFINE_PRED_FIELD( m_bBullRush, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
DEFINE_PRED_FIELD( m_vecBullRushDir, FIELD_VECTOR, FTYPEDESC_INSENDTABLE ),
DEFINE_PRED_FIELD( m_vecBullRushViewDir, FIELD_VECTOR, FTYPEDESC_INSENDTABLE ),
DEFINE_PRED_FIELD( m_vecBullRushViewGoalDir, FIELD_VECTOR, FTYPEDESC_INSENDTABLE ),
DEFINE_PRED_FIELD( m_flBullRushTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
DEFINE_PRED_FIELD( m_flDoubleTapForwardTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
END_PREDICTION_DATA()
BEGIN_PREDICTION_DATA_NO_BASE( PlayerClassReconData_t )
DEFINE_FIELD( m_nJumpCount, FIELD_INTEGER ),
DEFINE_FIELD( m_flSuppressionJumpTime, FIELD_FLOAT ),
DEFINE_FIELD( m_flSuppressionImpactTime, FIELD_FLOAT ),
DEFINE_FIELD( m_flActiveJumpTime, FIELD_FLOAT ),
DEFINE_FIELD( m_flStickTime, FIELD_FLOAT ),
DEFINE_FIELD( m_vecImpactNormal, FIELD_VECTOR ),
DEFINE_FIELD( m_flImpactDist, FIELD_FLOAT ),
DEFINE_FIELD( m_vecUnstickVelocity, FIELD_VECTOR ),
DEFINE_FIELD( m_bTrailParticles, FIELD_BOOLEAN ),
END_PREDICTION_DATA()
BEGIN_PREDICTION_DATA_NO_BASE( PlayerClassDefenderData_t )
END_PREDICTION_DATA()
BEGIN_PREDICTION_DATA_NO_BASE( PlayerClassEscortData_t )
END_PREDICTION_DATA()
BEGIN_PREDICTION_DATA_NO_BASE( PlayerClassInfiltratorData_t )
END_PREDICTION_DATA()
BEGIN_PREDICTION_DATA_NO_BASE( PlayerClassMedicData_t )
END_PREDICTION_DATA()
BEGIN_PREDICTION_DATA_NO_BASE( PlayerClassSniperData_t )
END_PREDICTION_DATA()
BEGIN_PREDICTION_DATA_NO_BASE( PlayerClassSupportData_t )
END_PREDICTION_DATA()
BEGIN_PREDICTION_DATA_NO_BASE( PlayerClassSapperData_t )
END_PREDICTION_DATA()
BEGIN_PREDICTION_DATA_NO_BASE( PlayerClassPyroData_t )
END_PREDICTION_DATA()
+368
View File
@@ -0,0 +1,368 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef TFCLASSDATA_SHARED_H
#define TFCLASSDATA_SHARED_H
#ifdef _WIN32
#pragma once
#endif
#include "mathlib/vector.h"
enum TFClass
{
TFCLASS_UNDECIDED = 0,
TFCLASS_RECON,
TFCLASS_COMMANDO,
TFCLASS_MEDIC,
TFCLASS_DEFENDER,
TFCLASS_SNIPER,
TFCLASS_SUPPORT,
TFCLASS_ESCORT,
TFCLASS_SAPPER,
TFCLASS_INFILTRATOR,
TFCLASS_PYRO,
// TFCLASS_INDIRECT,
TFCLASS_CLASS_COUNT,
};
//=============================================================================
//
// Class Shared Data
//
#define PLAYERCLASS_HULL_STAND_MIN Vector( -24.0f, -24.0f, 0.0f )
#define PLAYERCLASS_HULL_STAND_MAX Vector( 24.0f, 24.0f, 72.0f )
#define PLAYERCLASS_VIEWOFFSET_STAND Vector( 0.0f, 0.0f, 64.0f )
#define PLAYERCLASS_HULL_DUCK_MIN Vector( -24.0f, -24.0f, 0.0f )
#define PLAYERCLASS_HULL_DUCK_MAX Vector( 24.0f, 24.0f, 36.0f )
#define PLAYERCLASS_VIEWOFFSET_DUCK Vector( 0.0f, 0.0f, 30.0f )
#define PLAYERCLASS_STEPSIZE 18.0f
//=============================================================================
//
// Commando Class Specific Data
//
//#define COMMANDO_TEST
#ifndef COMMANDO_TEST
#define COMMANDOCLASS_HULL_STAND_MIN PLAYERCLASS_HULL_STAND_MIN
#define COMMANDOCLASS_HULL_STAND_MAX PLAYERCLASS_HULL_STAND_MAX
#define COMMANDOCLASS_VIEWOFFSET_STAND PLAYERCLASS_VIEWOFFSET_STAND
#define COMMANDOCLASS_HULL_DUCK_MIN PLAYERCLASS_HULL_DUCK_MIN
#define COMMANDOCLASS_HULL_DUCK_MAX PLAYERCLASS_HULL_DUCK_MAX
#define COMMANDOCLASS_VIEWOFFSET_DUCK PLAYERCLASS_VIEWOFFSET_DUCK
#define COMMANDOCLASS_STEPSIZE PLAYERCLASS_STEPSIZE
#else
#define COMMANDOCLASS_HULL_STAND_MIN Vector( -18.0f, -18.0f, 0.0f )
#define COMMANDOCLASS_HULL_STAND_MAX Vector( 18.0f, 18.0f, 54.0f )
#define COMMANDOCLASS_VIEWOFFSET_STAND Vector( 0.0f, 0.0f, 51.0f )
#define COMMANDOCLASS_HULL_DUCK_MIN Vector( -18.0f, -18.0f, 0.0f )
#define COMMANDOCLASS_HULL_DUCK_MAX Vector( 18.0f, 18.0f, 40.0f )
#define COMMANDOCLASS_VIEWOFFSET_DUCK Vector( 0.0f, 0.0f, 35.0f )
#define COMMANDOCLASS_STEPSIZE 18.0f
#endif
#define COMMANDO_MOVETYPE_BULLRUSH ( MOVETYPE_LAST + 1 )
#define COMMANDO_TIME_INVALID -9999.0f
#define COMMANDO_DOUBLETAP_TIME 300.0f
#define COMMANDO_BULLRUSH_TIME 2000.0f
#define COMMANDO_BULLRUSH_VIEWDELTA_TIME 1000.0f
#define COMMANDO_BULLRUSH_VIEWDELTA_TEST ( COMMANDO_BULLRUSH_TIME - COMMANDO_BULLRUSH_VIEWDELTA_TIME )
struct PlayerClassCommandoData_t
{
DECLARE_PREDICTABLE();
DECLARE_CLASS_NOBASE( PlayerClassCommandoData_t );
DECLARE_EMBEDDED_NETWORKVAR();
enum { PLAYERCLASS_ID = TFCLASS_COMMANDO };
CNetworkVar( bool, m_bCanBullRush );
CNetworkVar( bool, m_bBullRush );
CNetworkVector( m_vecBullRushDir );
CNetworkQAngle( m_vecBullRushViewDir );
CNetworkQAngle( m_vecBullRushViewGoalDir );
CNetworkVar( float, m_flBullRushTime );
CNetworkVar( float, m_flDoubleTapForwardTime );
};
//=============================================================================
//
// Defender Class Specific Data
//
#if 0
#define DEFENDERCLASS_HULL_STAND_MIN PLAYERCLASS_HULL_STAND_MIN
#define DEFENDERCLASS_HULL_STAND_MAX PLAYERCLASS_HULL_STAND_MAX
#define DEFENDERCLASS_VIEWOFFSET_STAND PLAYERCLASS_VIEWOFFSET_STAND
#define DEFENDERCLASS_HULL_DUCK_MIN PLAYERCLASS_HULL_DUCK_MIN
#define DEFENDERCLASS_HULL_DUCK_MAX PLAYERCLASS_HULL_DUCK_MAX
#define DEFENDERCLASS_VIEWOFFSET_DUCK PLAYERCLASS_VIEWOFFSET_DUCK
#define DEFENDERCLASS_STEPSIZE PLAYERCLASS_STEPSIZE
#else
#define DEFENDERCLASS_HULL_STAND_MIN Vector( -18.0f, -18.0f, 0.0f )
#define DEFENDERCLASS_HULL_STAND_MAX Vector( 18.0f, 18.0f, 55.0f )
#define DEFENDERCLASS_VIEWOFFSET_STAND Vector( 0.0f, 0.0f, 53.0f )
#define DEFENDERCLASS_HULL_DUCK_MIN Vector( -18.0f, -18.0f, 0.0f )
#define DEFENDERCLASS_HULL_DUCK_MAX Vector( 18.0f, 18.0f, 30.0f )
#define DEFENDERCLASS_VIEWOFFSET_DUCK Vector( 0.0f, 0.0f, 25.0f )
#define DEFENDERCLASS_STEPSIZE 15.0f
#endif
struct PlayerClassDefenderData_t
{
DECLARE_PREDICTABLE();
enum { PLAYERCLASS_ID = TFCLASS_DEFENDER };
};
//=============================================================================
//
// Escort Class Specific Data
//
#if 0
#define ESCORTCLASS_HULL_STAND_MIN PLAYERCLASS_HULL_STAND_MIN
#define ESCORTCLASS_HULL_STAND_MAX PLAYERCLASS_HULL_STAND_MAX
#define ESCORTCLASS_VIEWOFFSET_STAND PLAYERCLASS_VIEWOFFSET_STAND
#define ESCORTCLASS_HULL_DUCK_MIN PLAYERCLASS_HULL_DUCK_MIN
#define ESCORTCLASS_HULL_DUCK_MAX PLAYERCLASS_HULL_DUCK_MAX
#define ESCORTCLASS_VIEWOFFSET_DUCK PLAYERCLASS_VIEWOFFSET_DUCK
#define ESCORTCLASS_STEPSIZE PLAYERCLASS_STEPSIZE
#else
#define ESCORTCLASS_HULL_STAND_MIN Vector( -24.0f, -24.0f, 0.0f )
#define ESCORTCLASS_HULL_STAND_MAX Vector( 24.0f, 24.0f, 74.0f )
#define ESCORTCLASS_VIEWOFFSET_STAND Vector( 0.0f, 0.0f, 67.0f )
#define ESCORTCLASS_HULL_DUCK_MIN Vector( -24.0f, -24.0f, 0.0f )
#define ESCORTCLASS_HULL_DUCK_MAX Vector( 24.0f, 24.0f, 72.0f )
#define ESCORTCLASS_VIEWOFFSET_DUCK Vector( 0.0f, 0.0f, 48.0f )
#define ESCORTCLASS_STEPSIZE 18.0f
#endif
struct PlayerClassEscortData_t
{
DECLARE_PREDICTABLE();
enum { PLAYERCLASS_ID = TFCLASS_ESCORT };
};
//=============================================================================
//
// Infiltrator Class Specific Data
//
#define INFILTRATORCLASS_HULL_STAND_MIN PLAYERCLASS_HULL_STAND_MIN
#define INFILTRATORCLASS_HULL_STAND_MAX PLAYERCLASS_HULL_STAND_MAX
#define INFILTRATORCLASS_VIEWOFFSET_STAND PLAYERCLASS_VIEWOFFSET_STAND
#define INFILTRATORCLASS_HULL_DUCK_MIN PLAYERCLASS_HULL_DUCK_MIN
#define INFILTRATORCLASS_HULL_DUCK_MAX PLAYERCLASS_HULL_DUCK_MAX
#define INFILTRATORCLASS_VIEWOFFSET_DUCK PLAYERCLASS_VIEWOFFSET_DUCK
#define INFILTRATORCLASS_STEPSIZE PLAYERCLASS_STEPSIZE
struct PlayerClassInfiltratorData_t
{
DECLARE_PREDICTABLE();
enum { PLAYERCLASS_ID = TFCLASS_INFILTRATOR };
};
//=============================================================================
//
// Pyro Class Specific Data
//
#define PYROCLASS_HULL_STAND_MIN PLAYERCLASS_HULL_STAND_MIN
#define PYROCLASS_HULL_STAND_MAX PLAYERCLASS_HULL_STAND_MAX
#define PYROCLASS_VIEWOFFSET_STAND PLAYERCLASS_VIEWOFFSET_STAND
#define PYROCLASS_HULL_DUCK_MIN PLAYERCLASS_HULL_DUCK_MIN
#define PYROCLASS_HULL_DUCK_MAX PLAYERCLASS_HULL_DUCK_MAX
#define PYROCLASS_VIEWOFFSET_DUCK PLAYERCLASS_VIEWOFFSET_DUCK
#define PYROCLASS_STEPSIZE PLAYERCLASS_STEPSIZE
struct PlayerClassPyroData_t
{
DECLARE_PREDICTABLE();
enum { PLAYERCLASS_ID = TFCLASS_PYRO };
};
//=============================================================================
//
// Medic Class Specific Data
//
#define MEDICCLASS_HULL_STAND_MIN PLAYERCLASS_HULL_STAND_MIN
#define MEDICCLASS_HULL_STAND_MAX PLAYERCLASS_HULL_STAND_MAX
#define MEDICCLASS_VIEWOFFSET_STAND PLAYERCLASS_VIEWOFFSET_STAND
#define MEDICCLASS_HULL_DUCK_MIN PLAYERCLASS_HULL_DUCK_MIN
#define MEDICCLASS_HULL_DUCK_MAX PLAYERCLASS_HULL_DUCK_MAX
#define MEDICCLASS_VIEWOFFSET_DUCK PLAYERCLASS_VIEWOFFSET_DUCK
#define MEDICCLASS_STEPSIZE PLAYERCLASS_STEPSIZE
struct PlayerClassMedicData_t
{
DECLARE_PREDICTABLE();
enum { PLAYERCLASS_ID = TFCLASS_MEDIC };
};
//=============================================================================
//
// Recon Class Specific Data
//
#define RECONCLASS_HULL_STAND_MIN PLAYERCLASS_HULL_STAND_MIN
#define RECONCLASS_HULL_STAND_MAX PLAYERCLASS_HULL_STAND_MAX
#define RECONCLASS_VIEWOFFSET_STAND PLAYERCLASS_VIEWOFFSET_STAND
#define RECONCLASS_HULL_DUCK_MIN PLAYERCLASS_HULL_DUCK_MIN
#define RECONCLASS_HULL_DUCK_MAX PLAYERCLASS_HULL_DUCK_MAX
#define RECONCLASS_VIEWOFFSET_DUCK PLAYERCLASS_VIEWOFFSET_DUCK
#define RECONCLASS_STEPSIZE PLAYERCLASS_STEPSIZE
struct PlayerClassReconData_t
{
DECLARE_PREDICTABLE();
DECLARE_CLASS_NOBASE( PlayerClassReconData_t );
DECLARE_EMBEDDED_NETWORKVAR();
enum { PLAYERCLASS_ID = TFCLASS_RECON };
// For in-air jumps
CNetworkVar( int, m_nJumpCount );
// For wall jumps
CNetworkVar( float, m_flSuppressionJumpTime );
CNetworkVar( float, m_flSuppressionImpactTime );
CNetworkVar( float, m_flActiveJumpTime );
CNetworkVar( float, m_flStickTime );
CNetworkVector( m_vecImpactNormal );
CNetworkVar( float, m_flImpactDist );
CNetworkVector( m_vecUnstickVelocity );
// Trail
CNetworkVar( bool, m_bTrailParticles );
};
//=============================================================================
//
// Sniper Class Specific Data
//
#define SNIPERCLASS_HULL_STAND_MIN PLAYERCLASS_HULL_STAND_MIN
#define SNIPERCLASS_HULL_STAND_MAX PLAYERCLASS_HULL_STAND_MAX
#define SNIPERCLASS_VIEWOFFSET_STAND PLAYERCLASS_VIEWOFFSET_STAND
#define SNIPERCLASS_HULL_DUCK_MIN PLAYERCLASS_HULL_DUCK_MIN
#define SNIPERCLASS_HULL_DUCK_MAX PLAYERCLASS_HULL_DUCK_MAX
#define SNIPERCLASS_VIEWOFFSET_DUCK PLAYERCLASS_VIEWOFFSET_DUCK
#define SNIPERCLASS_STEPSIZE PLAYERCLASS_STEPSIZE
struct PlayerClassSniperData_t
{
DECLARE_PREDICTABLE();
enum { PLAYERCLASS_ID = TFCLASS_SNIPER };
};
//=============================================================================
//
// Support Class Specific Data
//
#if 0
#define SUPPORTCLASS_HULL_STAND_MIN PLAYERCLASS_HULL_STAND_MIN
#define SUPPORTCLASS_HULL_STAND_MAX PLAYERCLASS_HULL_STAND_MAX
#define SUPPORTCLASS_VIEWOFFSET_STAND PLAYERCLASS_VIEWOFFSET_STAND
#define SUPPORTCLASS_HULL_DUCK_MIN PLAYERCLASS_HULL_DUCK_MIN
#define SUPPORTCLASS_HULL_DUCK_MAX PLAYERCLASS_HULL_DUCK_MAX
#define SUPPORTCLASS_VIEWOFFSET_DUCK PLAYERCLASS_VIEWOFFSET_DUCK
#define SUPPORTCLASS_STEPSIZE PLAYERCLASS_STEPSIZE
#else
#define SUPPORTCLASS_HULL_STAND_MIN Vector( -30.0f, -30.0f, 0.0f )
#define SUPPORTCLASS_HULL_STAND_MAX Vector( 30.0f, 30.0f, 106.0f )
#define SUPPORTCLASS_VIEWOFFSET_STAND Vector( 0.0f, 0.0f, 120.0f )
#define SUPPORTCLASS_HULL_DUCK_MIN Vector( -30.0f, -30.0f, 0.0f )
#define SUPPORTCLASS_HULL_DUCK_MAX Vector( 30.0f, 30.0f, 72.0f )
#define SUPPORTCLASS_VIEWOFFSET_DUCK Vector( 0.0f, 0.0f, 64.0f )
#define SUPPORTCLASS_STEPSIZE 27.0f
#endif
struct PlayerClassSupportData_t
{
DECLARE_PREDICTABLE();
enum { PLAYERCLASS_ID = TFCLASS_SUPPORT };
};
//=============================================================================
//
// Sapper Class Specific Data
//
#define SAPPERCLASS_HULL_STAND_MIN PLAYERCLASS_HULL_STAND_MIN
#define SAPPERCLASS_HULL_STAND_MAX PLAYERCLASS_HULL_STAND_MAX
#define SAPPERCLASS_VIEWOFFSET_STAND PLAYERCLASS_VIEWOFFSET_STAND
#define SAPPERCLASS_HULL_DUCK_MIN PLAYERCLASS_HULL_DUCK_MIN
#define SAPPERCLASS_HULL_DUCK_MAX PLAYERCLASS_HULL_DUCK_MAX
#define SAPPERCLASS_VIEWOFFSET_DUCK PLAYERCLASS_VIEWOFFSET_DUCK
#define SAPPERCLASS_STEPSIZE PLAYERCLASS_STEPSIZE
struct PlayerClassSapperData_t
{
DECLARE_PREDICTABLE();
enum { PLAYERCLASS_ID = TFCLASS_SAPPER };
};
#include "tf_shareddefs.h"
#endif // TFCLASSDATA_SHARED_H
+18
View File
@@ -0,0 +1,18 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef VEHICLE_MORTAR_SHARED_H
#define VEHICLE_MORTAR_SHARED_H
#ifdef _WIN32
#pragma once
#endif
// How long it takes to deploy the mortar.
#define VEHICLE_MORTAR_DEPLOY_WAIT_TIME 3
#endif // VEHICLE_MORTAR_SHARED_H
+322
View File
@@ -0,0 +1,322 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "basetfplayer_shared.h"
#include "in_buttons.h"
#include "tf_gamerules.h"
#include "weapon_combatshield.h"
#if defined( CLIENT_DLL )
#include "particles_simple.h"
#include "fx.h"
#include "fx_quad.h"
#include "clienteffectprecachesystem.h"
#define CWeaponArcWelder C_WeaponArcWelder
#else
#endif
#include "weapon_repairgun.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// Buff ranges
ConVar weapon_arcwelder_target_range( "weapon_arcwelder_target_range", "90", FCVAR_REPLICATED, "The farthest away you can be for the arcwelder to initially lock onto a target." );
ConVar weapon_arcwelder_stick_range( "weapon_arcwelder_stick_range", "100", FCVAR_REPLICATED, "How far away the arcwelder can stay locked onto someone." );
ConVar weapon_arcwelder_rate( "weapon_arcwelder_rate", "15", FCVAR_REPLICATED );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CWeaponArcWelder : public CWeaponRepairGun
{
DECLARE_CLASS( CWeaponArcWelder, CWeaponRepairGun );
public:
DECLARE_NETWORKCLASS();
DECLARE_PREDICTABLE();
CWeaponArcWelder( void );
virtual void Precache();
virtual float GetTargetRange( void );
virtual float GetStickRange( void );
virtual float GetHealRate( void );
virtual bool AppliesModifier( void ) { return false; }
virtual bool TargetsPlayers( void ) { return false; }
virtual CBaseEntity *GetTargetToHeal( CBaseEntity *pCurHealing );
// All predicted weapons need to implement and return true
virtual bool IsPredicted( void ) const
{
return true;
}
#if defined( CLIENT_DLL )
virtual void ClientThink( void );
virtual bool OnFireEvent( C_BaseViewModel *pViewModel, const Vector& origin, const QAngle& angles, int event, const char *options );
virtual void ViewModelDrawn( C_BaseViewModel *pViewModel );
virtual bool ShouldPredict( void )
{
if ( GetOwner() == C_BasePlayer::GetLocalPlayer() )
return true;
return BaseClass::ShouldPredict();
}
#endif
private:
bool m_bWelding;
#if defined( CLIENT_DLL )
float m_flNextEffectTime;
#endif
private:
CWeaponArcWelder( const CWeaponArcWelder & );
};
LINK_ENTITY_TO_CLASS( weapon_arcwelder, CWeaponArcWelder );
PRECACHE_WEAPON_REGISTER( weapon_arcwelder );
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponArcWelder, DT_WeaponArcWelder )
BEGIN_NETWORK_TABLE( CWeaponArcWelder, DT_WeaponArcWelder )
END_NETWORK_TABLE()
BEGIN_PREDICTION_DATA( CWeaponArcWelder )
END_PREDICTION_DATA()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CWeaponArcWelder::CWeaponArcWelder()
{
SetPredictionEligible( true );
m_bWelding = false;
#ifdef CLIENT_DLL
m_flNextEffectTime = 0;
#endif
}
void CWeaponArcWelder::Precache()
{
BaseClass::Precache();
PrecacheScriptSound( "WeaponRepairGun.Healing" );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float CWeaponArcWelder::GetTargetRange( void )
{
return weapon_arcwelder_target_range.GetFloat();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float CWeaponArcWelder::GetStickRange( void )
{
return weapon_arcwelder_target_range.GetFloat();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float CWeaponArcWelder::GetHealRate( void )
{
return weapon_arcwelder_rate.GetFloat();
}
//-----------------------------------------------------------------------------
// Purpose: Returns a pointer to a healable target
//-----------------------------------------------------------------------------
CBaseEntity *CWeaponArcWelder::GetTargetToHeal( CBaseEntity *pCurHealing )
{
CBaseEntity *pTarget = BaseClass::GetTargetToHeal(pCurHealing);
if ( !pTarget )
return pTarget;
// Make sure the target is within our field of view
CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() );
if ( !pOwner )
return NULL;
Vector vecAiming;
pOwner->EyeVectors( &vecAiming );
// Find a player in range of this player, and make sure they're healable.
Vector vecSrc = pOwner->Weapon_ShootPosition( );
Vector vecEnd = vecSrc + vecAiming * GetTargetRange();
trace_t tr;
// Use WeaponTraceLine so shields are tested...
TFGameRules()->WeaponTraceLine( vecSrc, vecEnd, (MASK_SHOT & ~CONTENTS_HITBOX), pOwner, DMG_PROBE, &tr );
if ( tr.fraction != 1.0 && tr.m_pEnt == pTarget )
return pTarget;
return NULL;
}
#ifdef CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponArcWelder::ClientThink( void )
{
CBasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
if ( !pPlayer )
return;
if ( m_hHealingTarget == NULL )
return;
// Don't show it while the player is dead. Ideally, we'd respond to m_bHealing in OnDataChanged,
// but it stops sending the weapon when it's holstered, and it gets holstered when the player dies.
C_BasePlayer *pFiringPlayer = dynamic_cast< C_BasePlayer* >( GetOwner() );
if ( !pFiringPlayer || pFiringPlayer->IsPlayerDead() )
{
ClientThinkList()->SetNextClientThink( GetClientHandle(), CLIENT_THINK_NEVER );
m_bPlayingSound = false;
StopRepairSound();
return;
}
// Start playing the heal sound, if we're not already
if ( !m_bPlayingSound )
{
m_bPlayingSound = true;
CLocalPlayerFilter filter;
EmitSound( filter, entindex(), "WeaponRepairGun.Healing" );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CWeaponArcWelder::OnFireEvent( C_BaseViewModel *pViewModel, const Vector& origin, const QAngle& angles, int event, const char *options )
{
CBaseTFPlayer *pPlayer = static_cast<CBaseTFPlayer*>( GetOwner() );
if ( !pPlayer )
return true;
switch ( event )
{
case 7001:
m_bWelding = true;
return true;
case 7002:
m_bWelding = false;
return true;
default:
break;
};
return BaseClass::OnFireEvent( pViewModel, origin, angles, event, options );
}
CLIENTEFFECT_REGISTER_BEGIN( PrecacheArcWelderEffect )
CLIENTEFFECT_MATERIAL( "particle/smoke_arcwelder" )
CLIENTEFFECT_MATERIAL( "effects/spark2" )
CLIENTEFFECT_MATERIAL( "effects/blueflare" )
CLIENTEFFECT_MATERIAL( "effects/blueflare2" )
CLIENTEFFECT_REGISTER_END()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponArcWelder::ViewModelDrawn( C_BaseViewModel *pViewModel )
{
if ( !m_bWelding || !m_hHealingTarget.Get() )
return;
if ( m_flNextEffectTime > gpGlobals->curtime )
return;
m_flNextEffectTime = gpGlobals->curtime + 0.1;
// Get our weldpoint
Vector attachOrigin;
QAngle attachAngles;
pViewModel->GetAttachment( pViewModel->LookupAttachment("muzzle"), attachOrigin, attachAngles );
Vector vecEnd = m_hHealingTarget->WorldSpaceCenter();
trace_t tr;
// Use WeaponTraceLine so shields are tested...
TFGameRules()->WeaponTraceLine( attachOrigin, vecEnd, (MASK_SHOT & ~CONTENTS_HITBOX), GetOwner(), DMG_PROBE, &tr );
// Smoke
unsigned char color[3];
int iColOff = random->RandomInt(-16,16);
color[0] = 120 + iColOff;
color[1] = 230 + iColOff;
color[2] = 235 + iColOff;
/*
// Pull out from the target a bit
Vector vecOrigin = vecEnd;
Vector vecFromTarget = (vecEnd - attachOrigin);
VectorNormalize( vecFromTarget );
vecOrigin -= (vecFromTarget * 24);
*/
Vector vecOrigin = attachOrigin;
// Velocity
Vector vecVelocity = tr.plane.normal;
vecVelocity.z += random->RandomFloat( 8, 12 );
// Add it
CSmartPtr<CSimpleEmitter> pSimple = FX_Smoke( vecOrigin, vecVelocity,
random->RandomFloat( 4, 8 ), // Scale
1,
random->RandomFloat( 0.5, 3.0 ), // Dietime
color,
random->RandomInt( 64, 200 ), // Alpha
"particle/smoke_arcwelder",
random->RandomInt(0,255), // Roll
0 ); // Rolldelta
// Sparks
FX_Sparks( vecOrigin, 1, 4, tr.plane.normal, 2.5, 8, 64, "effects/spark2" );
// Bright Glow
SimpleParticle *sParticle;
sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( "effects/blueflare" ), vecOrigin );
if ( sParticle == NULL )
return;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flDieTime = 0.5f;
sParticle->m_vecVelocity.Init();
sParticle->m_uchColor[0] = 255;
sParticle->m_uchColor[1] = 255;
sParticle->m_uchColor[2] = 255;
sParticle->m_uchStartSize = random->RandomInt(5,7);
sParticle->m_uchEndSize = sParticle->m_uchStartSize;
sParticle->m_flRoll = random->RandomInt(0,360);
sParticle->m_flRollDelta = 0;
// Dull Glow
sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( "effects/blueflare2" ), vecOrigin );
if ( sParticle == NULL )
return;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flDieTime = 0.2f;
sParticle->m_vecVelocity.Init();
sParticle->m_uchColor[0] = 255;
sParticle->m_uchColor[1] = 255;
sParticle->m_uchColor[2] = 255;
sParticle->m_uchStartSize = random->RandomInt(15,20);
sParticle->m_uchEndSize = sParticle->m_uchStartSize;
sParticle->m_flRoll = random->RandomInt(0,360);
sParticle->m_flRollDelta = 0;
}
#endif
+126
View File
@@ -0,0 +1,126 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "basetfplayer_shared.h"
#include "weapon_basecombatobject.h"
//====================================================================================================
// BASE COMBAT OBJECT WEAPON
//====================================================================================================
LINK_ENTITY_TO_CLASS( weapon_basecombatobject, CWeaponBaseCombatObject );
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponBaseCombatObject, DT_WeaponBaseCombatObject )
BEGIN_NETWORK_TABLE( CWeaponBaseCombatObject, DT_WeaponBaseCombatObject )
END_NETWORK_TABLE()
BEGIN_PREDICTION_DATA( CWeaponBaseCombatObject )
/*
DEFINE_PRED_ARRAY( m_szObjectName, FIELD_CHARACTER, sizeof( m_szObjectName ) ),
DEFINE_PRED_FIELD( m_vecBuildMins, FIELD_VECTOR, 0 ),
DEFINE_PRED_FIELD( m_vecBuildMaxs, FIELD_VECTOR, 0 ),
*/
END_PREDICTION_DATA()
CWeaponBaseCombatObject::CWeaponBaseCombatObject()
{
}
//-----------------------------------------------------------------------------
// Purpose: Place the combat object
//-----------------------------------------------------------------------------
void CWeaponBaseCombatObject::PrimaryAttack( void )
{
CBaseTFPlayer *pPlayer = dynamic_cast<CBaseTFPlayer*>((CBaseEntity*)GetOwner());
if ( !pPlayer )
return;
if ( pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0 )
return;
m_flNextPrimaryAttack = gpGlobals->curtime + GetFireRate();
Vector vecPlaceOrigin;
QAngle angPlaceAngles;
if ( GetPlacePosition( pPlayer, &vecPlaceOrigin, &angPlaceAngles ) == false )
{
WeaponSound( WPN_DOUBLE );
return;
}
// Place the combat object
PlaceCombatObject( pPlayer, vecPlaceOrigin, angPlaceAngles );
WeaponSound( SINGLE );
pPlayer->RemoveAmmo( 1, m_iPrimaryAmmoType );
// If I'm now out of ammo, switch away
if ( !HasPrimaryAmmo() )
{
pPlayer->SelectLastItem();
}
}
//-----------------------------------------------------------------------------
// Purpose: Return true if we found a valid placement point
//-----------------------------------------------------------------------------
bool CWeaponBaseCombatObject::GetPlacePosition( CBaseTFPlayer *pBuilder, Vector *vecPlaceOrigin, QAngle *angPlaceAngles )
{
Vector vecForward;
QAngle vecAngles = vec3_angle;
vecAngles.y = pBuilder->EyeAngles().y;
AngleVectors( vecAngles, &vecForward, NULL, NULL);
*vecPlaceOrigin = pBuilder->WorldSpaceCenter() + (vecForward * ((m_vecBuildMaxs.x - m_vecBuildMins.x) + 32));
if ( UTIL_PointContents( *vecPlaceOrigin ) != CONTENTS_EMPTY )
return false;
// Room to fit?
trace_t tr;
UTIL_TraceHull( *vecPlaceOrigin, *vecPlaceOrigin + Vector(0,0,-64), m_vecBuildMins, m_vecBuildMaxs, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr );
if ( tr.allsolid || tr.startsolid )
return false;
if ( tr.fraction == 1.0 )
return false;
*vecPlaceOrigin = tr.endpos;
//VectorAngles( tr.plane.normal, *angPlaceAngles );
*angPlaceAngles = QAngle(0,0,0);
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Put the combat object for this weapon on the specified point
//-----------------------------------------------------------------------------
void CWeaponBaseCombatObject::PlaceCombatObject( CBaseTFPlayer *pBuilder, Vector vecOrigin, QAngle angles )
{
#if !defined( CLIENT_DLL )
Assert( m_szObjectName != NULL );
CBaseEntity *pEntity = CreateEntityByName( m_szObjectName );
pEntity->SetLocalAngles( angles );
pEntity->Spawn();
pEntity->Teleport( &vecOrigin, &angles, &vec3_origin );
// If it's an object, set it's builder & team
CBaseObject *pObject = dynamic_cast< CBaseObject * >( pEntity );
if ( pObject )
{
pObject->SetBuilder( pBuilder );
pObject->ChangeTeam( pBuilder->GetTeamNumber() );
}
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float CWeaponBaseCombatObject::GetFireRate( void )
{
return 0.5;
}
+68
View File
@@ -0,0 +1,68 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef WEAPON_BASECOMBATOBJECT_H
#define WEAPON_BASECOMBATOBJECT_H
#ifdef _WIN32
#pragma once
#endif
#include "basetfcombatweapon_shared.h"
class CBaseTFPlayer;
#if defined( CLIENT_DLL )
#define CWeaponBaseCombatObject C_WeaponBaseCombatObject
#endif
//-----------------------------------------------------------------------------
// Purpose: Base class for combat object weapons
//-----------------------------------------------------------------------------
class CWeaponBaseCombatObject : public CBaseTFCombatWeapon
{
DECLARE_CLASS( CWeaponBaseCombatObject, CBaseTFCombatWeapon );
public:
DECLARE_NETWORKCLASS();
DECLARE_PREDICTABLE();
CWeaponBaseCombatObject();
virtual void PrimaryAttack( void );
virtual bool GetPlacePosition( CBaseTFPlayer *pBuilder, Vector *vecPlaceOrigin, QAngle *angPlaceAngles );
virtual void PlaceCombatObject( CBaseTFPlayer *pBuilder, Vector vecOrigin, QAngle angles );
virtual float GetFireRate( void );
protected:
char *m_szObjectName;
Vector m_vecBuildMins;
Vector m_vecBuildMaxs;
/*
// All predicted weapons need to implement and return true
virtual bool IsPredicted( void ) const
{
return true;
}
#if defined( CLIENT_DLL )
virtual bool ShouldPredict( void )
{
if ( GetOwner() == C_BasePlayer::GetLocalPlayer() )
return true;
return BaseClass::ShouldPredict();
}
#endif
*/
private:
CWeaponBaseCombatObject( const CWeaponBaseCombatObject & );
};
#endif // WEAPON_BASECOMBATOBJECT_H
+530
View File
@@ -0,0 +1,530 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: The "weapon" used to build objects
//
//
// $Workfile: $
// $Date: $
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "tf_player.h"
#include "tf_basecombatweapon.h"
#include "EntityList.h"
#include "in_buttons.h"
#include "weapon_builder.h"
#include "tf_obj.h"
#include "sendproxy.h"
#include "weapon_objectselection.h"
#include "info_act.h"
#include "vguiscreen.h"
extern ConVar tf2_object_hard_limits;
extern ConVar tf_fastbuild;
EXTERN_SEND_TABLE(DT_BaseCombatWeapon)
IMPLEMENT_SERVERCLASS_ST(CWeaponBuilder, DT_WeaponBuilder)
SendPropInt( SENDINFO( m_iBuildState ), 4, SPROP_UNSIGNED ),
SendPropInt( SENDINFO( m_iCurrentObject ), BUILDER_OBJECT_BITS, SPROP_UNSIGNED ),
SendPropInt( SENDINFO( m_iCurrentObjectState ), 4, SPROP_UNSIGNED ),
SendPropEHandle( SENDINFO( m_hObjectBeingBuilt ) ),
SendPropTime( SENDINFO( m_flStartTime ) ),
SendPropTime( SENDINFO( m_flTotalTime ) ),
SendPropArray
(
SendPropInt( SENDINFO_ARRAY(m_bObjectValidity), 1, SPROP_UNSIGNED), m_bObjectValidity
),
SendPropArray
(
SendPropInt( SENDINFO_ARRAY(m_bObjectBuildability), 1, SPROP_UNSIGNED), m_bObjectBuildability
),
END_SEND_TABLE()
LINK_ENTITY_TO_CLASS( weapon_builder, CWeaponBuilder );
PRECACHE_WEAPON_REGISTER(weapon_builder);
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CWeaponBuilder::CWeaponBuilder()
{
for ( int i=0; i < m_bObjectValidity.Count(); i++ )
m_bObjectValidity.Set( i, 0 );
m_iCurrentObject = BUILDER_INVALID_OBJECT;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponBuilder::Precache( void )
{
BaseClass::Precache();
PrecacheModel( "models/weapons/v_slam.mdl" );
PrecacheVGuiScreen( "screen_human_pda" );
}
//-----------------------------------------------------------------------------
// Purpose: Gets info about the control panels
//-----------------------------------------------------------------------------
void CWeaponBuilder::GetControlPanelInfo( int nPanelIndex, const char *&pPanelName )
{
pPanelName = "screen_human_pda";
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CWeaponBuilder::ShouldShowControlPanels( void )
{
if ( GetActivity() == ACT_VM_IDLE )
return true;
return false;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponBuilder::UpdateOnRemove( void )
{
// Tell the player he's lost his build weapon
CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() );
if ( pOwner && pOwner->GetWeaponBuilder() == this )
{
pOwner->SetWeaponBuilder( NULL );
}
// Chain at end to mimic destructor unwind order
BaseClass::UpdateOnRemove();
}
//-----------------------------------------------------------------------------
// Purpose: Builder weapon has just been given to a player
//-----------------------------------------------------------------------------
void CWeaponBuilder::Equip( CBaseCombatCharacter *pOwner )
{
BaseClass::Equip( pOwner );
((CBaseTFPlayer*)pOwner)->SetWeaponBuilder( this );
}
//-----------------------------------------------------------------------------
// Purpose: Add a new object type to this build weapon. This will allow
// the player carrying this builder to build the object.
//-----------------------------------------------------------------------------
void CWeaponBuilder::AddBuildableObject( int iObjectType )
{
m_bObjectValidity.Set( iObjectType, true );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CWeaponBuilder::CanDeploy( void )
{
if ( m_iCurrentObject != BUILDER_INVALID_OBJECT )
{
SetCurrentState( BS_PLACING );
StartPlacement();
m_flNextPrimaryAttack = gpGlobals->curtime + 0.35f;
}
else
{
m_hObjectBeingBuilt = NULL;
SetCurrentState( BS_IDLE );
SetCurrentObject( m_iCurrentObject );
}
return BaseClass::CanDeploy();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CWeaponBuilder::Deploy( )
{
#if !defined( CLIENT_DLL )
if ( m_hObjectBeingBuilt.Get() && m_hObjectBeingBuilt->IsAnUpgrade() )
return DefaultDeploy( (char*)GetViewModel(), (char*)GetWorldModel(), ACT_SLAM_STICKWALL_ND_DRAW, (char*)GetAnimPrefix() );
return DefaultDeploy( (char*)GetViewModel(), (char*)GetWorldModel(), ACT_VM_DRAW, (char*)GetAnimPrefix() );
#else
return true;
#endif
}
//-----------------------------------------------------------------------------
// Purpose: Prevent switching when working on something
//-----------------------------------------------------------------------------
bool CWeaponBuilder::CanHolster( void )
{
if ( IsBuilding() )
return false;
return BaseClass::CanHolster();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CBaseCombatWeapon *CWeaponBuilder::GetLastWeapon( void )
{
return BaseClass::GetLastWeapon();
}
//-----------------------------------------------------------------------------
// Purpose: Stop placement when holstering
//-----------------------------------------------------------------------------
bool CWeaponBuilder::Holster( CBaseCombatWeapon *pSwitchingTo )
{
if ( m_iBuildState == BS_PLACING || m_iBuildState == BS_PLACING_INVALID )
{
SetCurrentState( BS_IDLE );
}
StopPlacement();
return BaseClass::Holster(pSwitchingTo);
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponBuilder::ItemPostFrame( void )
{
CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() );
if ( !pOwner )
return;
// Ignore input while the player's building anything
if ( pOwner->IsBuilding() )
return;
// Switch away if I'm not in placement mode
if ( m_iBuildState != BS_PLACING && m_iBuildState != BS_PLACING_INVALID )
{
pOwner->SwitchToNextBestWeapon( NULL );
return;
}
if (( pOwner->m_nButtons & IN_ATTACK ) && (m_flNextPrimaryAttack <= gpGlobals->curtime) )
{
PrimaryAttack();
}
// Allow shield post frame
AllowShieldPostFrame( true );
WeaponIdle();
}
//-----------------------------------------------------------------------------
// Purpose: Start placing or building the currently selected object
//-----------------------------------------------------------------------------
void CWeaponBuilder::PrimaryAttack( void )
{
CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() );
if ( !pOwner )
return;
// What state should we move to?
switch( m_iBuildState )
{
case BS_IDLE:
{
// Idle state starts selection
SetCurrentState( BS_SELECTING );
}
break;
case BS_SELECTING:
{
// Do nothing, client handles selection
return;
}
break;
case BS_PLACING:
{
if ( m_hObjectBeingBuilt )
{
// Give the object a chance to veto the "start building" command. Objects like barbed wire
// may want to change their properties instead of actually building yet.
if ( m_hObjectBeingBuilt->PreStartBuilding() )
{
int iFlags = m_hObjectBeingBuilt->GetObjectFlags();
// Can't build if the game hasn't started
if ( !tf_fastbuild.GetInt() && CurrentActIsAWaitingAct() )
{
ClientPrint( pOwner, HUD_PRINTCENTER, "Can't build until the game's started.\n" );
return;
}
StartBuilding();
// Should we switch away?
if ( iFlags & OF_ALLOW_REPEAT_PLACEMENT )
{
// Start placing another
SetCurrentState( BS_PLACING );
StartPlacement();
}
else
{
pOwner->SwitchToNextBestWeapon( NULL );
}
}
}
}
break;
case BS_PLACING_INVALID:
{
WeaponSound( SINGLE_NPC );
// If there is any associated error text when placing the object, display it
if( m_hObjectBeingBuilt != NULL )
{
if (m_hObjectBeingBuilt->MustBeBuiltInResourceZone())
{
ClientPrint( pOwner, HUD_PRINTCENTER, "Only placeable in an empty resource zone.\n" );
}
else if (m_hObjectBeingBuilt->MustBeBuiltInConstructionYard())
{
ClientPrint( pOwner, HUD_PRINTCENTER, "Only placeable in a construction yard.\n" );
}
}
}
break;
}
m_flNextPrimaryAttack = gpGlobals->curtime + 0.2f;
}
//-----------------------------------------------------------------------------
// Purpose: Set the builder to the specified state
//-----------------------------------------------------------------------------
void CWeaponBuilder::SetCurrentState( int iState )
{
// Check the current build state... we may need to shut some stuff down...
switch(m_iBuildState)
{
case BS_PLACING:
case BS_PLACING_INVALID:
{
if ((iState != BS_PLACING) && (iState != BS_PLACING_INVALID) && (iState != BS_BUILDING))
{
StopPlacement();
WeaponSound( SPECIAL1 );
}
}
break;
}
m_iBuildState = iState;
}
//-----------------------------------------------------------------------------
// Purpose: Set the builder to the specified object
//-----------------------------------------------------------------------------
void CWeaponBuilder::SetCurrentObject( int iObject )
{
// Fixup for invalid objects
if (iObject < 0)
iObject = BUILDER_INVALID_OBJECT;
CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() );
if ( !pOwner )
return;
int i;
// If -1 was passed in, set to our first available object
if ( iObject == BUILDER_INVALID_OBJECT )
{
for ( i = 0; i < OBJ_LAST; i++ )
{
if ( m_bObjectValidity[i] )
{
iObject = i;
break;
}
}
}
// Recalculate the buildability of each object (for propagation to the client)
for ( i=0; i < m_bObjectBuildability.Count(); i++ )
m_bObjectBuildability.Set( i, 0 );
for ( i = 0; i < OBJ_LAST; i++ )
{
if ( m_bObjectValidity[i] && pOwner->CanBuild(i) == CB_CAN_BUILD )
{
m_bObjectBuildability.Set( i, true );
}
}
m_iCurrentObject = iObject;
m_iCurrentObjectState = pOwner->CanBuild( m_iCurrentObject );
m_flStartTime = 0;
m_flTotalTime = 0;
}
//-----------------------------------------------------------------------------
// Purpose: Idle updates the position of the build placement model
//-----------------------------------------------------------------------------
void CWeaponBuilder::WeaponIdle( void )
{
CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() );
if ( !pOwner )
return;
// If we're in placement mode, update the placement model
switch( m_iBuildState )
{
case BS_PLACING:
case BS_PLACING_INVALID:
{
if ( UpdatePlacement() )
{
SetCurrentState( BS_PLACING );
}
else
{
SetCurrentState( BS_PLACING_INVALID );
}
}
break;
default:
break;
}
if ( HasWeaponIdleTimeElapsed() )
{
SendWeaponAnim( ACT_VM_IDLE );
}
}
//-----------------------------------------------------------------------------
// Purpose: The player holding this weapon has just gained new technology.
// Check to see if it affects the medikit
//-----------------------------------------------------------------------------
void CWeaponBuilder::GainedNewTechnology( CBaseTechnology *pTechnology )
{
CBaseTFPlayer *pPlayer = ToBaseTFPlayer( GetOwner() );
if ( pPlayer )
{
// Force a recalculation of the state for this object
SetCurrentObject( m_iCurrentObject );
}
}
//-----------------------------------------------------------------------------
// Purpose: Start placing the object
//-----------------------------------------------------------------------------
void CWeaponBuilder::StartPlacement( void )
{
StopPlacement();
// Create the slab
m_hObjectBeingBuilt = (CBaseObject*)CreateEntityByName( GetObjectInfo( m_iCurrentObject )->m_pClassName );
if ( m_hObjectBeingBuilt )
{
m_hObjectBeingBuilt->Spawn();
m_hObjectBeingBuilt->StartPlacement( ToBaseTFPlayer( GetOwner() ) );
UpdatePlacement();
// Stomp this here in the same frame we make the object, so prevent clientside warnings that it's under attack
m_hObjectBeingBuilt->m_iHealth = OBJECT_CONSTRUCTION_STARTINGHEALTH;
}
}
//-----------------------------------------------------------------------------
// Purpose: Set the viewmodel according to the type of object we're placing
//-----------------------------------------------------------------------------
const char *CWeaponBuilder::GetViewModel( int viewmodelindex /*=0*/ ) const
{
if ( m_hObjectBeingBuilt.Get() && m_hObjectBeingBuilt->IsAnUpgrade() )
return "models/weapons/v_slam.mdl";
return BaseClass::GetViewModel( viewmodelindex );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponBuilder::StopPlacement( void )
{
if ( m_hObjectBeingBuilt )
{
m_hObjectBeingBuilt->StopPlacement();
m_hObjectBeingBuilt = NULL;
}
}
//-----------------------------------------------------------------------------
// Purpose: Move the placement model to the current position. Return false if it's an invalid position
//-----------------------------------------------------------------------------
bool CWeaponBuilder::UpdatePlacement( void )
{
if ( !m_hObjectBeingBuilt )
return false;
return m_hObjectBeingBuilt->UpdatePlacement( ToBaseTFPlayer(GetOwner()) );
}
//-----------------------------------------------------------------------------
// Purpose: Player holding this weapon has started building something
//-----------------------------------------------------------------------------
void CWeaponBuilder::StartBuilding( void )
{
if ( m_hObjectBeingBuilt.Get() && UpdatePlacement() )
{
SetCurrentState( BS_BUILDING );
m_hObjectBeingBuilt->StartBuilding( GetOwner() );
}
}
//-----------------------------------------------------------------------------
// Purpose: Player holding this weapon has aborted the build of an object
//-----------------------------------------------------------------------------
void CWeaponBuilder::StoppedBuilding( int iObjectType )
{
CBaseTFPlayer *pPlayer = ToBaseTFPlayer( GetOwner() );
if ( pPlayer )
{
// Force a recalculation of the state for this object
SetCurrentObject( m_iCurrentObject );
SetCurrentState( BS_IDLE );
WeaponSound( SPECIAL2 );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CWeaponBuilder::IsBuilding( void )
{
return ( m_iBuildState == BS_BUILDING );
}
//-----------------------------------------------------------------------------
// Purpose: The player holding this weapon has just finished building an object
//-----------------------------------------------------------------------------
void CWeaponBuilder::FinishedObject( void )
{
CBaseTFPlayer *pPlayer = ToBaseTFPlayer( GetOwner() );
if ( pPlayer )
{
// We're no longer building anything...
m_hObjectBeingBuilt = NULL;
// Force a recalculation of the state for this object
SetCurrentObject( m_iCurrentObject );
SetCurrentState( BS_IDLE );
}
}
+90
View File
@@ -0,0 +1,90 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef WEAPON_BUILDER_H
#define WEAPON_BUILDER_H
#ifdef _WIN32
#pragma once
#endif
#include "weapon_combat_usedwithshieldbase.h"
class CBaseObject;
//=========================================================
// Builder Weapon
//=========================================================
class CWeaponBuilder : public CWeaponCombatUsedWithShieldBase
{
DECLARE_CLASS( CWeaponBuilder, CWeaponCombatUsedWithShieldBase );
public:
CWeaponBuilder();
virtual void UpdateOnRemove( void );
DECLARE_SERVERCLASS();
virtual void Precache( void );
virtual bool CanDeploy( void );
virtual bool CanHolster( void );
virtual CBaseCombatWeapon *GetLastWeapon( void );
virtual bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL );
virtual void ItemPostFrame( void );
virtual void PrimaryAttack( void );
virtual void WeaponIdle( void );
virtual bool Deploy( void );
virtual const char *GetViewModel( int viewmodelindex = 0 ) const;
void SetCurrentState( int iState );
void SetCurrentObject( int iObject );
virtual void GainedNewTechnology( CBaseTechnology *pTechnology );
virtual void Equip( CBaseCombatCharacter *pOwner );
// Add a new object type to the list of objects this builder weapon can build
void AddBuildableObject( int iObjectType );
// Placement
void StartPlacement( void );
void StopPlacement( void );
bool UpdatePlacement( void );
// Building
void StartBuilding( void );
void StoppedBuilding( int iObjectType );
bool IsBuilding( void );
void FinishedObject( void );
virtual void GetControlPanelInfo( int nPanelIndex, const char *&pPanelName );
virtual bool ShouldShowControlPanels( void );
private:
void PerformModifications( CBaseObject* pObject );
public:
CNetworkVar( int, m_iBuildState );
CNetworkVar( unsigned int, m_iCurrentObject );
int m_iCurrentObjectID;
CNetworkVar( int, m_iCurrentObjectState );
// Objects that this builder can build
CNetworkArray( bool, m_bObjectValidity, OBJ_LAST );
// Buildability of each object
CNetworkArray( bool, m_bObjectBuildability, OBJ_LAST );
// Build data for the current object, propagated when the player starts to build it
CNetworkVar( float, m_flStartTime );
CNetworkVar( float, m_flTotalTime );
float m_flLastRepairTime;
CNetworkHandle( CBaseObject, m_hObjectBeingBuilt );
};
#endif // WEAPON_BUILDER_H
@@ -0,0 +1,152 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Base class for hand-thrown grenades that work with the handheld shield
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "basetfplayer_shared.h"
#include "weapon_combat_basegrenade.h"
#include "weapon_combatshield.h"
#include "in_buttons.h"
LINK_ENTITY_TO_CLASS( weapon_combat_basegrenade, CWeaponCombatBaseGrenade );
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponCombatBaseGrenade, DT_WeaponCombatBaseGrenade )
BEGIN_NETWORK_TABLE( CWeaponCombatBaseGrenade, DT_WeaponCombatBaseGrenade )
#if !defined( CLIENT_DLL )
SendPropTime( SENDINFO( m_flStartedThrowAt ) ),
#else
RecvPropTime( RECVINFO( m_flStartedThrowAt ) ),
#endif
END_NETWORK_TABLE()
BEGIN_PREDICTION_DATA( CWeaponCombatBaseGrenade )
DEFINE_PRED_FIELD_TOL( m_flStartedThrowAt, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, TD_MSECTOLERANCE ),
END_PREDICTION_DATA()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CWeaponCombatBaseGrenade::CWeaponCombatBaseGrenade( void )
{
m_flStartedThrowAt = 0;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float CWeaponCombatBaseGrenade::GetFireRate( void )
{
return 2.0;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponCombatBaseGrenade::ItemPostFrame( void )
{
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
if (!pOwner)
return;
AllowShieldPostFrame( !m_flStartedThrowAt );
// Look for button downs
if ( (pOwner->m_nButtons & IN_ATTACK) && GetShieldState() == SS_DOWN && !m_flStartedThrowAt && (m_flNextPrimaryAttack <= gpGlobals->curtime) )
{
m_flStartedThrowAt = gpGlobals->curtime;
SendWeaponAnim( ACT_VM_DRAW );
}
// Look for button ups
if ( (pOwner->m_afButtonReleased & IN_ATTACK) && (m_flNextPrimaryAttack <= gpGlobals->curtime) && m_flStartedThrowAt )
{
m_flNextPrimaryAttack = gpGlobals->curtime;
PrimaryAttack();
m_flStartedThrowAt = 0;
}
// No buttons down?
if ( !((pOwner->m_nButtons & IN_ATTACK) || (pOwner->m_nButtons & IN_ATTACK2) || (pOwner->m_nButtons & IN_RELOAD)) )
{
WeaponIdle( );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponCombatBaseGrenade::PrimaryAttack( void )
{
CBasePlayer *pPlayer = dynamic_cast<CBasePlayer*>( GetOwner() );
if ( !pPlayer )
return;
if ( !ComputeEMPFireState() )
return;
// player "shoot" animation
PlayAttackAnimation( ACT_VM_THROW );
ThrowGrenade();
// Setup for refire
m_flNextPrimaryAttack = gpGlobals->curtime + 1.0;
CheckRemoveDisguise();
// If I'm now out of ammo, switch away
if ( !HasPrimaryAmmo() )
{
pPlayer->SelectLastItem();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponCombatBaseGrenade::ThrowGrenade( void )
{
CBasePlayer *pPlayer = dynamic_cast<CBasePlayer*>( GetOwner() );
if ( !pPlayer )
return;
BaseClass::WeaponSound(WPN_DOUBLE);
// Calculate launch velocity (3 seconds for max distance)
float flThrowTime = MIN( (gpGlobals->curtime - m_flStartedThrowAt), 3.0 );
float flSpeed = 650 + (175 * flThrowTime);
// If the player's crouched, roll the grenade
if ( pPlayer->GetFlags() & FL_DUCKING )
{
// Launch the grenade
Vector vecForward;
QAngle vecAngles = pPlayer->EyeAngles();
// Throw it up just a tad
vecAngles.x = -1;
AngleVectors( vecAngles, &vecForward, NULL, NULL);
Vector vecOrigin;
VectorLerp( pPlayer->EyePosition(), pPlayer->GetAbsOrigin(), 0.25f, vecOrigin );
vecOrigin += (vecForward * 16);
vecForward = vecForward * flSpeed;
CreateGrenade(vecOrigin, vecForward, pPlayer );
}
else
{
// Launch the grenade
Vector vecForward;
QAngle vecAngles = pPlayer->EyeAngles();
AngleVectors( vecAngles, &vecForward, NULL, NULL);
Vector vecOrigin = pPlayer->EyePosition();
vecOrigin += (vecForward * 16);
vecForward = vecForward * flSpeed;
CreateGrenade(vecOrigin, vecForward, pPlayer );
}
pPlayer->RemoveAmmo( 1, m_iPrimaryAmmoType );
}
@@ -0,0 +1,66 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef WEAPON_COMBAT_BASEGRENADE_H
#define WEAPON_COMBAT_BASEGRENADE_H
#ifdef _WIN32
#pragma once
#endif
#include "weapon_combat_usedwithshieldbase.h"
#include "basegrenade_shared.h"
#if defined( CLIENT_DLL )
#define CWeaponCombatBaseGrenade C_WeaponCombatBaseGrenade
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CWeaponCombatBaseGrenade : public CWeaponCombatUsedWithShieldBase
{
DECLARE_CLASS( CWeaponCombatBaseGrenade, CWeaponCombatUsedWithShieldBase );
public:
CWeaponCombatBaseGrenade();
DECLARE_NETWORKCLASS();
DECLARE_PREDICTABLE();
virtual void ItemPostFrame( void );
virtual void PrimaryAttack( void );
virtual float GetFireRate( void );
virtual void ThrowGrenade( void );
// Custom grenade types
virtual CBaseGrenade *CreateGrenade( const Vector &vecOrigin, const Vector &vecAngles, CBasePlayer *pOwner ) { return NULL; }
/*
// All predicted weapons need to implement and return true
virtual bool IsPredicted( void ) const
{
return true;
}
#if defined( CLIENT_DLL )
virtual bool ShouldPredict( void )
{
if ( GetOwner() == C_BasePlayer::GetLocalPlayer() )
return true;
return BaseClass::ShouldPredict();
}
#endif
*/
public:
CNetworkVar( float, m_flStartedThrowAt );
private:
CWeaponCombatBaseGrenade( const CWeaponCombatBaseGrenade & );
};
#endif // WEAPON_COMBAT_BASEGRENADE_H
@@ -0,0 +1,327 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Burst rifle & Shield combo
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "basetfplayer_shared.h"
#include "weapon_combatshield.h"
#include "weapon_combat_usedwithshieldbase.h"
#include "in_buttons.h"
#include "plasmaprojectile.h"
#include "IEffects.h"
#if defined( CLIENT_DLL )
#include "fx.h"
#define CWeaponCombatBurstRifle C_WeaponCombatBurstRifle
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// Damage CVars
ConVar weapon_combat_burstrifle_damage( "weapon_combat_burstrifle_damage","10", FCVAR_REPLICATED, "Burst Rifle damage" );
ConVar weapon_combat_burstrifle_range( "weapon_combat_burstrifle_range","500", FCVAR_REPLICATED, "Burst Rifle maximum range" );
ConVar weapon_combat_burstrifle_ducking_mod( "weapon_combat_burstrifle_ducking_mod", "0.75", FCVAR_REPLICATED, "Burst Rifle ducking speed modifier" );
#define MAX_RIFLE_POWER 3.0
#define RIFLE_CHARGE_TIME 2.0
#define BURSTRIFLE_BOOSTED_FIRERATE 0.015f
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CWeaponCombatBurstRifle : public CWeaponCombatUsedWithShieldBase
{
DECLARE_CLASS( CWeaponCombatBurstRifle, CWeaponCombatUsedWithShieldBase );
public:
DECLARE_NETWORKCLASS();
DECLARE_PREDICTABLE();
CWeaponCombatBurstRifle( void );
virtual void ItemPostFrame( void );
virtual void PrimaryAttack( void );
virtual float GetFireRate( void );
virtual float GetDefaultAnimSpeed( void );
virtual const Vector& GetBulletSpread( void );
// All predicted weapons need to implement and return true
virtual bool IsPredicted( void ) const
{
return true;
}
private:
CWeaponCombatBurstRifle( const CWeaponCombatBurstRifle & );
public:
#if defined( CLIENT_DLL )
virtual bool ShouldPredict( void )
{
if ( GetOwner() &&
GetOwner() == C_BasePlayer::GetLocalPlayer() )
return true;
return BaseClass::ShouldPredict();
}
void GetViewmodelBoneControllers( C_BaseViewModel *pViewModel, float controllers[MAXSTUDIOBONECTRLS]);
void ViewModelDrawn( C_BaseViewModel *pViewModel );
private:
void BoostedMuzzleFlash( C_BaseViewModel *pViewModel, const Vector &vecOrigin, const QAngle &angle, float flScale );
struct model_t *m_pSpriteBurstRifleFlash[5];
#endif
};
CWeaponCombatBurstRifle::CWeaponCombatBurstRifle( void )
{
SetPredictionEligible( true );
}
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponCombatBurstRifle, DT_WeaponCombatBurstRifle )
BEGIN_NETWORK_TABLE( CWeaponCombatBurstRifle, DT_WeaponCombatBurstRifle )
END_NETWORK_TABLE()
BEGIN_PREDICTION_DATA( CWeaponCombatBurstRifle )
END_PREDICTION_DATA()
LINK_ENTITY_TO_CLASS( weapon_combat_burstrifle, CWeaponCombatBurstRifle );
PRECACHE_WEAPON_REGISTER(weapon_combat_burstrifle);
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponCombatBurstRifle::ItemPostFrame( void )
{
CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() );
if (!pOwner)
return;
if ( UsesClipsForAmmo1() )
{
CheckReload();
}
// Handle firing
if ( GetShieldState() == SS_DOWN && !m_bInReload )
{
if ( (pOwner->m_nButtons & IN_ATTACK ) && (m_flNextPrimaryAttack <= gpGlobals->curtime) )
{
if ( m_iClip1 > 0 )
{
// Fire the plasma shot
PrimaryAttack();
}
else
{
Reload();
}
}
// Reload button (or fire button when we're out of ammo)
if ( m_flNextPrimaryAttack <= gpGlobals->curtime )
{
if ( pOwner->m_nButtons & IN_RELOAD )
{
Reload();
}
else if ( !((pOwner->m_nButtons & IN_ATTACK) || (pOwner->m_nButtons & IN_ATTACK2) || (pOwner->m_nButtons & IN_RELOAD)) )
{
if ( !m_iClip1 && HasPrimaryAmmo() )
{
Reload();
}
}
}
}
// Prevent shield post frame if we're not ready to attack, or we're charging
AllowShieldPostFrame( m_flNextPrimaryAttack <= gpGlobals->curtime || m_bInReload );
}
//-----------------------------------------------------------------------------
// Purpose: Get the accuracy derived from weapon and player, and return it
//-----------------------------------------------------------------------------
const Vector& CWeaponCombatBurstRifle::GetBulletSpread( void )
{
static Vector cone = VECTOR_CONE_5DEGREES;
return cone;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponCombatBurstRifle::PrimaryAttack( void )
{
CBaseTFPlayer *pPlayer = (CBaseTFPlayer*)GetOwner();
if (!pPlayer)
return;
WeaponSound(SINGLE);
// Fire the bullets
Vector vecSrc = pPlayer->Weapon_ShootPosition( );
Vector vecSpread = GetBulletSpread();
Vector vecAiming, vecRight, vecUp;
pPlayer->EyeVectors( &vecAiming, &vecRight, &vecUp );
// Add some inaccuracy
int seed = 0;
float x, y, z;
do
{
float x1, x2, y1, y2;
// Note the additional seed because otherwise we get the same set of random #'s and will get stuck
// in an infinite loop here potentially
// FIXME: Can we use a gaussian random # function instead? ywb
x1 = SHARED_RANDOMFLOAT_SEED( -0.5, 0.5, ++seed );
x2 = SHARED_RANDOMFLOAT_SEED( -0.5, 0.5, ++seed );
y1 = SHARED_RANDOMFLOAT_SEED( -0.5, 0.5, ++seed );
y2 = SHARED_RANDOMFLOAT_SEED( -0.5, 0.5, ++seed );
x = x1 + x2;
y = y1 + y2;
z = x*x+y*y;
} while (z > 1);
Vector vecDir = vecAiming + x * vecSpread.x * vecRight + y * vecSpread.y * vecUp;
PlayAttackAnimation( GetPrimaryAttackActivity() );
// Shift it down a bit so the firer can see it
Vector right, forward;
AngleVectors( pPlayer->EyeAngles() + pPlayer->m_Local.m_vecPunchAngle, &forward, &right, NULL );
Vector vecStartSpot = vecSrc;
// Get the firing position
#ifdef CLIENT_DLL
// On our client, grab the viewmodel's firing position
Vector vecWorldOffset = vecStartSpot + Vector(0,0,-8) + right * 12 + forward * 16;
#else
// For everyone else, grab the weapon model's position
/*
Vector vecWorldOffset;
QAngle angIgnore;
GetAttachment( LookupAttachment( "muzzle" ), vecWorldOffset, angIgnore );
*/
Vector vecWorldOffset = vecStartSpot + Vector(0,0,-8) + right * 12 + forward * 16;
#endif
Vector gunOffset = vecWorldOffset - vecStartSpot;
CPowerPlasmaProjectile *pPlasma = CPowerPlasmaProjectile::CreatePredicted( vecStartSpot, vecDir, gunOffset, DMG_ENERGYBEAM, pPlayer );
if ( pPlasma )
{
pPlasma->SetDamage( weapon_combat_burstrifle_damage.GetFloat() );
pPlasma->m_hOwner = pPlayer;
pPlasma->SetPower( 2.0 );
pPlasma->SetMaxRange( weapon_combat_burstrifle_range.GetFloat() );
pPlasma->Activate();
}
m_flNextPrimaryAttack = gpGlobals->curtime + GetFireRate();
m_iClip1 = m_iClip1 - 1;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float CWeaponCombatBurstRifle::GetFireRate( void )
{
if ( !inv_demo.GetFloat() )
{
float flFireRate = ( SequenceDuration() * 0.6f ) + SHARED_RANDOMFLOAT( 0.0, 0.035f );
CBaseTFPlayer *pPlayer = static_cast<CBaseTFPlayer*>( GetOwner() );
if ( pPlayer )
{
// Ducking players should fire more rapidly.
if ( pPlayer->GetFlags() & FL_DUCKING )
{
flFireRate *= weapon_combat_burstrifle_ducking_mod.GetFloat();
}
}
return flFireRate;
}
// Get the player and check to see if we are powered up.
CBaseTFPlayer *pPlayer = ( CBaseTFPlayer* )GetOwner();
if ( pPlayer && pPlayer->HasPowerup( POWERUP_BOOST ) )
{
return BURSTRIFLE_BOOSTED_FIRERATE;
}
return SHARED_RANDOMFLOAT( 0.075f, 0.15f );
}
//-----------------------------------------------------------------------------
// Purpose: Match the anim speed to the weapon speed while crouching
//-----------------------------------------------------------------------------
float CWeaponCombatBurstRifle::GetDefaultAnimSpeed( void )
{
if ( GetOwner() && GetOwner()->IsPlayer() )
{
if ( GetOwner()->GetFlags() & FL_DUCKING )
return (1.0 + (1.0 - weapon_combat_burstrifle_ducking_mod.GetFloat()) );
}
return 1.0;
}
#if defined ( CLIENT_DLL )
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponCombatBurstRifle::GetViewmodelBoneControllers( C_BaseViewModel *pViewModel,
float controllers[MAXSTUDIOBONECTRLS])
{
float flAmmoCount;
C_BaseTFPlayer *pPlayer = ( C_BaseTFPlayer* )GetOwner();
if ( pPlayer && pPlayer->IsDamageBoosted() )
{
flAmmoCount = random->RandomFloat( 0.0f, 1.0f );
}
else
{
// Dial shows ammo count!
flAmmoCount = ( float )m_iClip1 / ( float )GetMaxClip1();
}
// Add some shake
flAmmoCount += RandomFloat( -0.02, 0.02 );
controllers[0] = flAmmoCount;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponCombatBurstRifle::ViewModelDrawn( C_BaseViewModel *pViewModel )
{
C_BaseTFPlayer *pPlayer = ( C_BaseTFPlayer* )GetOwner();
if ( pPlayer && pPlayer->IsDamageBoosted() )
{
Vector vecBarrelPos;
QAngle angMuzzle;
int iAttachment = pViewModel->LookupAttachment( "muzzle" );
pViewModel->GetAttachment( iAttachment, vecBarrelPos, angMuzzle );
unsigned char color[3];
color[0] = 50;
color[1] = 128;
color[2] = 50;
FX_Smoke( vecBarrelPos, angMuzzle, 0.5, 1, &color[0], 192 );
}
}
#endif
@@ -0,0 +1,322 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Chargeable Plasma & Shield combo
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "tf_player.h"
#include "weapon_combat_usedwithshieldbase.h"
#include "weapon_combatshield.h"
#include "tf_guidedplasma.h"
#include "in_buttons.h"
#include "tf_gamerules.h"
#define BURST_FIRE_RATE 0.15
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CWeaponCombat_ChargeablePlasma : public CWeaponCombatUsedWithShieldBase
{
DECLARE_CLASS( CWeaponCombat_ChargeablePlasma, CWeaponCombatUsedWithShieldBase );
public:
DECLARE_SERVERCLASS();
virtual void ItemPostFrame( void );
virtual void PrimaryAttack( void );
virtual float GetFireRate( void );
virtual void Spawn();
virtual bool Deploy( void );
virtual bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL );
virtual void Precache( void );
virtual void GainedNewTechnology( CBaseTechnology *pTechnology );
virtual CBaseEntity *GetLockTarget( void );
private:
CNetworkVar( bool, m_bCharging );
float m_flChargeStartTime;
float m_flPower;
float m_flNextBurstShotTime;
int m_iBurstShotsRemaining;
bool m_bHasBurstShot;
bool m_bHasCharge;
// Guidance
EHANDLE m_hLockTarget;
Vector m_vecTargetOffset;
float m_flLockedAt;
};
IMPLEMENT_SERVERCLASS_ST(CWeaponCombat_ChargeablePlasma, DT_WeaponCombat_ChargeablePlasma )
SendPropInt( SENDINFO( m_bCharging ), 1, SPROP_UNSIGNED ),
END_SEND_TABLE()
LINK_ENTITY_TO_CLASS( weapon_combat_chargeableplasma, CWeaponCombat_ChargeablePlasma );
PRECACHE_WEAPON_REGISTER(weapon_combat_chargeableplasma);
//-----------------------------------------------------------------------------
// Spawn weapon
//-----------------------------------------------------------------------------
void CWeaponCombat_ChargeablePlasma::Spawn()
{
BaseClass::Spawn();
m_bHasBurstShot = false;
m_bHasCharge = false;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponCombat_ChargeablePlasma::Precache( void )
{
BaseClass::Precache();
}
//-----------------------------------------------------------------------------
// New technologies:
//-----------------------------------------------------------------------------
void CWeaponCombat_ChargeablePlasma::GainedNewTechnology( CBaseTechnology *pTechnology )
{
BaseClass::GainedNewTechnology( pTechnology );
CBaseTFPlayer *pPlayer = ToBaseTFPlayer( (CBaseEntity*)GetOwner() );
if ( pPlayer )
{
// Charge-up mode?
if ( pPlayer->HasNamedTechnology( "com_comboshield_charge" ) )
{
m_bHasCharge = true;
}
else
{
m_bHasCharge = false;
}
// Burst shot mode?
if ( pPlayer->HasNamedTechnology( "com_comboshield_tripleshot" ) )
{
m_bHasBurstShot = true;
}
else
{
m_bHasBurstShot = false;
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponCombat_ChargeablePlasma::ItemPostFrame( void )
{
CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() );
if (!pOwner)
return;
if ( UsesClipsForAmmo1() )
{
CheckReload();
}
// If burst shots are firing, ignore input
if ( m_iBurstShotsRemaining > 0 )
{
if ( gpGlobals->curtime < m_flNextBurstShotTime )
return;
if ( m_iClip1 > 0 )
{
PrimaryAttack();
}
m_iBurstShotsRemaining--;
m_flNextBurstShotTime = gpGlobals->curtime + BURST_FIRE_RATE;
m_flNextPrimaryAttack = gpGlobals->curtime + GetFireRate();
return;
}
// Handle charge firing
if ( m_iClip1 > 0 && GetShieldState() == SS_DOWN && !m_bInReload )
{
if ( (pOwner->m_nButtons & IN_ATTACK ) )
{
if (m_bHasCharge)
{
if ( !m_bCharging && (m_flNextPrimaryAttack <= gpGlobals->curtime) )
{
m_bCharging = true;
m_flChargeStartTime = gpGlobals->curtime;
// Get a lock target right now
m_hLockTarget = GetLockTarget();
}
}
else
{
// Fire the plasma shot
if (m_flNextPrimaryAttack <= gpGlobals->curtime)
PrimaryAttack();
}
}
else if ( m_bCharging )
{
m_bCharging = false;
// Fire the plasma shot
PrimaryAttack();
// We might be firing a burst shot
if (m_bHasBurstShot)
{
if ( m_flPower >= (MAX_CHARGED_TIME * 0.5) )
{
if ( m_flPower >= MAX_CHARGED_TIME )
{
m_iBurstShotsRemaining = 2;
}
else
{
m_iBurstShotsRemaining = 1;
}
m_flNextBurstShotTime = gpGlobals->curtime + BURST_FIRE_RATE;
}
}
}
}
// Reload button
if ( m_iBurstShotsRemaining == 0 && !m_bCharging )
{
if ( pOwner->m_nButtons & IN_RELOAD && UsesClipsForAmmo1() && !m_bInReload )
{
Reload();
}
}
// Prevent shield post frame if we're not ready to attack, or we're charging
AllowShieldPostFrame( !m_bCharging && ((m_flNextPrimaryAttack <= gpGlobals->curtime) || m_bInReload) );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponCombat_ChargeablePlasma::PrimaryAttack( void )
{
CBaseTFPlayer *pPlayer = (CBaseTFPlayer*)GetOwner();
if (!pPlayer)
return;
WeaponSound(SINGLE);
// Fire the bullets
Vector vecSrc = pPlayer->Weapon_ShootPosition( );
Vector vecAiming;
pPlayer->EyeVectors( &vecAiming );
// If we already have a lock target from button down, see if we shouldn't try and get a new one
// Only do this is the button was released immediately
if ( !m_hLockTarget || ( m_flLockedAt < gpGlobals->curtime ) )
{
m_hLockTarget = GetLockTarget();
}
PlayAttackAnimation( GetPrimaryAttackActivity() );
// Shift it down a bit so the firer can see it
Vector right;
AngleVectors( pPlayer->EyeAngles() + pPlayer->m_Local.m_vecPunchAngle, NULL, &right, NULL );
Vector vecStartSpot = vecSrc + Vector(0,0,-8) + right * 12;
CGuidedPlasma *pShot = CGuidedPlasma::Create(vecStartSpot, vecAiming, m_hLockTarget, m_vecTargetOffset, pPlayer);
// Set it's charged power level
if (m_bHasCharge)
m_flPower = MIN( MAX_CHARGED_TIME, gpGlobals->curtime - m_flChargeStartTime );
else
m_flPower = 0.0f;
float flDamageMult = RemapVal( m_flPower, 0, MAX_CHARGED_TIME, 1.0, MAX_CHARGED_POWER );
pShot->SetPowerLevel( flDamageMult );
m_flNextPrimaryAttack = gpGlobals->curtime + GetFireRate();
m_iClip1 = m_iClip1 - 1;
m_hLockTarget = NULL;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float CWeaponCombat_ChargeablePlasma::GetFireRate( void )
{
return SequenceDuration();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CWeaponCombat_ChargeablePlasma::Deploy( void )
{
if ( BaseClass::Deploy() )
{
GainedNewTechnology(NULL);
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose: Our player just died
//-----------------------------------------------------------------------------
bool CWeaponCombat_ChargeablePlasma::Holster( CBaseCombatWeapon *pSwitchingTo )
{
bool bReturn = BaseClass::Holster(pSwitchingTo);
// Stop the charging sound
if ( m_bCharging )
{
m_bCharging = false;
}
return bReturn;
}
//-----------------------------------------------------------------------------
// Purpose: Try and find an entity to lock onto
//-----------------------------------------------------------------------------
CBaseEntity *CWeaponCombat_ChargeablePlasma::GetLockTarget( void )
{
CBaseTFPlayer *pPlayer = (CBaseTFPlayer*)GetOwner();
if ( !pPlayer )
return NULL;
Vector vecSrc = pPlayer->Weapon_ShootPosition( );
Vector vecAiming;
pPlayer->EyeVectors( &vecAiming );
Vector vecEnd = vecSrc + vecAiming * MAX_TRACE_LENGTH;
trace_t tr;
TFGameRules()->WeaponTraceLine( vecSrc, vecEnd, MASK_SHOT, pPlayer, GetDamageType(), &tr );
if ( (tr.fraction < 1.0f) && tr.m_pEnt )
{
CBaseEntity *pTargetEntity = tr.m_pEnt;
// Don't guide on same team or on anything other than players, objects, and NPCs
if ( pTargetEntity->InSameTeam(pPlayer) || (!pTargetEntity->IsPlayer()
&& (pTargetEntity->MyNPCPointer() == NULL)) )
return NULL;
// Compute the target offset relative to the target
Vector vecWorldOffset;
VectorSubtract( tr.endpos, pTargetEntity->GetAbsOrigin(), vecWorldOffset );
VectorIRotate( vecWorldOffset, pTargetEntity->EntityToWorldTransform(), m_vecTargetOffset );
m_flLockedAt = gpGlobals->curtime + 0.2;
return pTargetEntity;
}
return NULL;
}
+97
View File
@@ -0,0 +1,97 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: The Commando's anti-personnel grenades
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "basetfplayer_shared.h"
#include "weapon_combat_usedwithshieldbase.h"
#include "weapon_combat_basegrenade.h"
#include "weapon_combatshield.h"
#include "in_buttons.h"
#if !defined( CLIENT_DLL )
#include "grenade_antipersonnel.h"
#else
#define CWeaponCombatGrenade C_WeaponCombatGrenade
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
class CBaseGrenade;
//-----------------------------------------------------------------------------
// Purpose: Combo shield & grenade weapon
//-----------------------------------------------------------------------------
class CWeaponCombatGrenade : public CWeaponCombatBaseGrenade
{
DECLARE_CLASS( CWeaponCombatGrenade, CWeaponCombatBaseGrenade );
public:
DECLARE_NETWORKCLASS();
DECLARE_PREDICTABLE();
CWeaponCombatGrenade();
virtual void Precache( void );
virtual CBaseGrenade *CreateGrenade( const Vector &vecOrigin, const Vector &vecAngles, CBasePlayer *pOwner );
// All predicted weapons need to implement and return true
virtual bool IsPredicted( void ) const
{
return true;
}
#if defined( CLIENT_DLL )
virtual bool ShouldPredict( void )
{
if ( GetOwner() == C_BasePlayer::GetLocalPlayer() )
return true;
return BaseClass::ShouldPredict();
}
#endif
private:
CWeaponCombatGrenade( const CWeaponCombatGrenade & );
};
CWeaponCombatGrenade::CWeaponCombatGrenade( void )
{
SetPredictionEligible( true );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponCombatGrenade::Precache( void )
{
BaseClass::Precache();
#if !defined( CLIENT_DLL )
UTIL_PrecacheOther( "grenade_antipersonnel" );
#endif
}
CBaseGrenade *CWeaponCombatGrenade::CreateGrenade( const Vector &vecOrigin, const Vector &vecAngles, CBasePlayer *pOwner )
{
#if !defined( CLIENT_DLL )
return CGrenadeAntiPersonnel::Create(vecOrigin, vecAngles, pOwner );
#else
return NULL;
#endif
}
LINK_ENTITY_TO_CLASS( weapon_combat_grenade, CWeaponCombatGrenade );
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponCombatGrenade, DT_WeaponCombatGrenade )
BEGIN_NETWORK_TABLE( CWeaponCombatGrenade, DT_WeaponCombatGrenade )
END_NETWORK_TABLE()
BEGIN_PREDICTION_DATA( CWeaponCombatGrenade )
END_PREDICTION_DATA()
PRECACHE_WEAPON_REGISTER(weapon_combat_grenade);
@@ -0,0 +1,92 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: The Commando's anti-personnel grenades
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "Sprite.h"
#include "basetfplayer_shared.h"
#include "weapon_combat_usedwithshieldbase.h"
#include "weapon_combat_basegrenade.h"
#include "weapon_combatshield.h"
#include "in_buttons.h"
#include "grenade_emp.h"
#if defined( CLIENT_DLL )
#define CWeaponCombatGrenadeEMP C_WeaponCombatGrenadeEMP
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Purpose: Combo shield & grenade weapon
//-----------------------------------------------------------------------------
class CWeaponCombatGrenadeEMP : public CWeaponCombatBaseGrenade
{
DECLARE_CLASS( CWeaponCombatGrenadeEMP, CWeaponCombatBaseGrenade );
public:
DECLARE_NETWORKCLASS();
DECLARE_PREDICTABLE();
CWeaponCombatGrenadeEMP();
virtual void Precache( void );
virtual CBaseGrenade *CreateGrenade( const Vector &vecOrigin, const Vector &vecAngles, CBasePlayer *pOwner );
// All predicted weapons need to implement and return true
virtual bool IsPredicted( void ) const
{
return true;
}
#if defined( CLIENT_DLL )
virtual bool ShouldPredict( void )
{
if ( GetOwner() == C_BasePlayer::GetLocalPlayer() )
return true;
return BaseClass::ShouldPredict();
}
#endif
private:
CWeaponCombatGrenadeEMP( const CWeaponCombatGrenadeEMP & );
};
LINK_ENTITY_TO_CLASS( weapon_combat_grenade_emp, CWeaponCombatGrenadeEMP );
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponCombatGrenadeEMP, DT_WeaponCombatGrenadeEMP )
BEGIN_NETWORK_TABLE( CWeaponCombatGrenadeEMP, DT_WeaponCombatGrenadeEMP )
END_NETWORK_TABLE()
BEGIN_PREDICTION_DATA( CWeaponCombatGrenadeEMP )
END_PREDICTION_DATA()
PRECACHE_WEAPON_REGISTER(weapon_combat_grenade_emp);
CWeaponCombatGrenadeEMP::CWeaponCombatGrenadeEMP( void )
{
SetPredictionEligible( true );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponCombatGrenadeEMP::Precache( void )
{
BaseClass::Precache();
#if !defined( CLIENT_DLL )
UTIL_PrecacheOther( "grenade_emp" );
#endif
}
CBaseGrenade *CWeaponCombatGrenadeEMP::CreateGrenade( const Vector &vecOrigin, const Vector &vecAngles, CBasePlayer *pOwner )
{
return CGrenadeEMP::Create(vecOrigin, vecAngles, pOwner );
}
@@ -0,0 +1,375 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Laser Rifle & Shield combo
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "weapon_combatshield.h"
#include "weapon_combat_usedwithshieldbase.h"
#include "in_buttons.h"
#include "takedamageinfo.h"
#include "beam_shared.h"
#include "tf_gamerules.h"
// Damage CVars
ConVar weapon_combat_laserrifle_damage( "weapon_combat_laserrifle_damage","20", FCVAR_REPLICATED, "Laser rifle damage" );
ConVar weapon_combat_laserrifle_range( "weapon_combat_laserrifle_range","1000", FCVAR_REPLICATED, "Laser rifle maximum range" );
ConVar weapon_combat_laserrifle_ducking_mod( "weapon_combat_laserrifle_ducking_mod", "0.75", FCVAR_REPLICATED, "Laser rifle ducking ROF modifier" );
#if defined( CLIENT_DLL )
#include "fx.h"
#include "hud.h"
#include "c_te_effect_dispatch.h"
#include <vgui/ISurface.h>
#define CWeaponCombatLaserRifle C_WeaponCombatLaserRifle
#else
#include "te_effect_dispatch.h"
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CWeaponCombatLaserRifle : public CWeaponCombatUsedWithShieldBase
{
DECLARE_CLASS( CWeaponCombatLaserRifle, CWeaponCombatUsedWithShieldBase );
public:
DECLARE_NETWORKCLASS();
DECLARE_PREDICTABLE();
CWeaponCombatLaserRifle( void );
virtual const Vector& GetBulletSpread( void );
virtual void ItemBusyFrame( void );
virtual void ItemPostFrame( void );
virtual void PrimaryAttack( void );
virtual float GetFireRate( void );
virtual float GetDefaultAnimSpeed( void );
virtual void BulletWasFired( const Vector &vecStart, const Vector &vecEnd );
void RecalculateAccuracy( void );
// All predicted weapons need to implement and return true
virtual bool IsPredicted( void ) const
{
return true;
}
private:
CWeaponCombatLaserRifle( const CWeaponCombatLaserRifle & );
public:
#if defined( CLIENT_DLL )
virtual bool ShouldPredict( void )
{
if ( GetOwner() &&
GetOwner() == C_BasePlayer::GetLocalPlayer() )
return true;
return BaseClass::ShouldPredict();
}
virtual void DrawCrosshair( void );
#endif
private:
float m_flInaccuracy;
float m_flAccuracyTime;
};
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CWeaponCombatLaserRifle::CWeaponCombatLaserRifle( void )
{
SetPredictionEligible( true );
m_flInaccuracy = 0;
m_flAccuracyTime = 0;
}
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponCombatLaserRifle, DT_WeaponCombatLaserRifle )
BEGIN_NETWORK_TABLE( CWeaponCombatLaserRifle, DT_WeaponCombatLaserRifle )
END_NETWORK_TABLE()
BEGIN_PREDICTION_DATA( CWeaponCombatLaserRifle )
END_PREDICTION_DATA()
LINK_ENTITY_TO_CLASS( weapon_combat_laserrifle, CWeaponCombatLaserRifle );
PRECACHE_WEAPON_REGISTER(weapon_combat_laserrifle);
//-----------------------------------------------------------------------------
// Purpose: Get the accuracy derived from weapon and player, and return it
//-----------------------------------------------------------------------------
const Vector& CWeaponCombatLaserRifle::GetBulletSpread( void )
{
static Vector cone = VECTOR_CONE_8DEGREES;
return cone;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponCombatLaserRifle::ItemBusyFrame( void )
{
BaseClass::ItemBusyFrame();
RecalculateAccuracy();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponCombatLaserRifle::ItemPostFrame( void )
{
CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() );
if (!pOwner)
return;
if ( UsesClipsForAmmo1() )
{
CheckReload();
}
RecalculateAccuracy();
// Handle firing
if ( GetShieldState() == SS_DOWN && !m_bInReload )
{
if ( (pOwner->m_nButtons & IN_ATTACK ) && (m_flNextPrimaryAttack <= gpGlobals->curtime) )
{
if ( m_iClip1 > 0 )
{
// Fire the plasma shot
PrimaryAttack();
}
else
{
Reload();
}
}
// Reload button (or fire button when we're out of ammo)
if ( m_flNextPrimaryAttack <= gpGlobals->curtime )
{
if ( pOwner->m_nButtons & IN_RELOAD )
{
Reload();
}
else if ( !((pOwner->m_nButtons & IN_ATTACK) || (pOwner->m_nButtons & IN_ATTACK2) || (pOwner->m_nButtons & IN_RELOAD)) )
{
if ( !m_iClip1 && HasPrimaryAmmo() )
{
Reload();
}
}
}
}
// Prevent shield post frame if we're not ready to attack, or we're charging
AllowShieldPostFrame( m_flNextPrimaryAttack <= gpGlobals->curtime || m_bInReload );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponCombatLaserRifle::PrimaryAttack( void )
{
CBaseTFPlayer *pPlayer = (CBaseTFPlayer*)GetOwner();
if (!pPlayer)
return;
WeaponSound(SINGLE);
// Fire the bullets
Vector vecSrc = pPlayer->Weapon_ShootPosition( );
Vector vecAiming;
pPlayer->EyeVectors( &vecAiming );
PlayAttackAnimation( GetPrimaryAttackActivity() );
// Reduce the spread if the player's ducking
Vector vecSpread = GetBulletSpread();
vecSpread *= m_flInaccuracy;
TFGameRules()->FireBullets( CTakeDamageInfo( this, pPlayer, weapon_combat_laserrifle_damage.GetFloat(), DMG_PLASMA), 1,
vecSrc, vecAiming, vecSpread, weapon_combat_laserrifle_range.GetFloat(), m_iPrimaryAmmoType, 0, entindex(), 0 );
m_flInaccuracy += 0.3;
m_flInaccuracy = clamp(m_flInaccuracy, 0, 1);
m_flNextPrimaryAttack = gpGlobals->curtime + GetFireRate();
m_iClip1 = m_iClip1 - 1;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float CWeaponCombatLaserRifle::GetFireRate( void )
{
float flFireRate = ( SequenceDuration() * 0.4 ) + SHARED_RANDOMFLOAT( 0.0, 0.035f );
CBaseTFPlayer *pPlayer = static_cast<CBaseTFPlayer*>( GetOwner() );
if ( pPlayer )
{
// Ducking players should fire more rapidly.
if ( pPlayer->GetFlags() & FL_DUCKING )
{
flFireRate *= weapon_combat_laserrifle_ducking_mod.GetFloat();
}
}
return flFireRate;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponCombatLaserRifle::RecalculateAccuracy( void )
{
CBaseTFPlayer *pPlayer = (CBaseTFPlayer*)GetOwner();
if (!pPlayer)
return;
m_flAccuracyTime += gpGlobals->frametime;
while ( m_flAccuracyTime > 0.05 )
{
if ( !(pPlayer->GetFlags() & FL_ONGROUND) )
{
m_flInaccuracy += 0.05;
}
else if ( pPlayer->GetFlags() & FL_DUCKING )
{
m_flInaccuracy -= 0.08;
}
/*
else if ( pPlayer->GetLocalVelocity().LengthSqr() > (100*100) )
{
// Never get worse than 1/2 accuracy from running
if ( m_flInaccuracy < 0.25 )
{
m_flInaccuracy += 0.01;
if ( m_flInaccuracy > 0.5 )
{
m_flInaccuracy = 0.5;
}
}
else if ( m_flInaccuracy > 0.25 )
{
m_flInaccuracy -= 0.01;
}
}
*/
else
{
m_flInaccuracy -= 0.04;
}
// Crouching prevents accuracy ever going beyond a point
if ( pPlayer->GetFlags() & FL_DUCKING )
{
m_flInaccuracy = clamp(m_flInaccuracy, 0, 0.8);
}
else
{
m_flInaccuracy = clamp(m_flInaccuracy, 0, 1);
}
m_flAccuracyTime -= 0.05;
#ifndef CLIENT_DLL
//if ( m_flInaccuracy )
//Msg("Inaccuracy %.2f (%.2f)\n", m_flInaccuracy, gpGlobals->curtime );
#endif
}
}
//-----------------------------------------------------------------------------
// Purpose: Match the anim speed to the weapon speed while crouching
//-----------------------------------------------------------------------------
float CWeaponCombatLaserRifle::GetDefaultAnimSpeed( void )
{
if ( GetOwner() && GetOwner()->IsPlayer() )
{
if ( GetOwner()->GetFlags() & FL_DUCKING )
return (1.0 + (1.0 - weapon_combat_laserrifle_ducking_mod.GetFloat()) );
}
return 1.0;
}
//-----------------------------------------------------------------------------
// Purpose: Draw the laser rifle effect
//-----------------------------------------------------------------------------
void CWeaponCombatLaserRifle::BulletWasFired( const Vector &vecStart, const Vector &vecEnd )
{
// Humans fire jazzed up bullets, Aliens fire laserbeams
if ( GetTeamNumber() == TEAM_HUMANS )
{
UTIL_Tracer( (Vector&)vecStart, (Vector&)vecEnd, entindex(), 1, 5000, false, "HLaserTracer" );
}
else
{
UTIL_Tracer( (Vector&)vecStart, (Vector&)vecEnd, entindex(), 1, 5000, false, "ALaserTracer" );
}
}
#ifdef CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose: Draw the weapon's crosshair
//-----------------------------------------------------------------------------
void CWeaponCombatLaserRifle::DrawCrosshair( void )
{
BaseClass::DrawCrosshair();
// Draw the targeting zone around the crosshair
int r, g, b, a;
gHUD.m_clrYellowish.GetColor( r, g, b, a );
// Check to see if we are in vgui mode
C_BaseTFPlayer *pPlayer = static_cast<C_BaseTFPlayer*>( GetOwner() );
if ( !pPlayer || pPlayer->IsInVGuiInputMode() )
return;
// Draw a crosshair & accuracy hoodad
int iBarWidth = XRES(10);
int iBarHeight = YRES(10);
int iTotalWidth = (iBarWidth * 2) + (40 * m_flInaccuracy) + XRES(10);
int iTotalHeight = (iBarHeight * 2) + (40 * m_flInaccuracy) + YRES(10);
// Horizontal bars
int iLeft = (ScreenWidth() - iTotalWidth) / 2;
int iMidHeight = (ScreenHeight() / 2);
Color dark( r, g, b, 32 );
Color light( r, g, b, 160 );
vgui::surface()->DrawSetColor( dark );
vgui::surface()->DrawFilledRect( iLeft, iMidHeight-1, iLeft+ iBarWidth, iMidHeight + 2 );
vgui::surface()->DrawFilledRect( iLeft + iTotalWidth - iBarWidth, iMidHeight-1, iLeft + iTotalWidth, iMidHeight + 2 );
vgui::surface()->DrawSetColor( light );
vgui::surface()->DrawFilledRect( iLeft, iMidHeight, iLeft + iBarWidth, iMidHeight + 1 );
vgui::surface()->DrawFilledRect( iLeft + iTotalWidth - iBarWidth, iMidHeight, iLeft + iTotalWidth, iMidHeight + 1 );
// Vertical bars
int iTop = (ScreenHeight() - iTotalHeight) / 2;
int iMidWidth = (ScreenWidth() / 2);
vgui::surface()->DrawSetColor( dark );
vgui::surface()->DrawFilledRect( iMidWidth-1, iTop, iMidWidth + 2, iTop + iBarHeight );
vgui::surface()->DrawFilledRect( iMidWidth-1, iTop + iTotalHeight - iBarHeight, iMidWidth + 2, iTop + iTotalHeight );
vgui::surface()->DrawSetColor( light );
vgui::surface()->DrawFilledRect( iMidWidth, iTop, iMidWidth + 1, iTop + iBarHeight );
vgui::surface()->DrawFilledRect( iMidWidth, iTop + iTotalHeight - iBarHeight, iMidWidth + 1, iTop + iTotalHeight );
}
#endif
@@ -0,0 +1,195 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Burst rifle & Shield combo
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "basetfplayer_shared.h"
#include "weapon_combatshield.h"
#include "weapon_combat_usedwithshieldbase.h"
#include "in_buttons.h"
#include "plasmaprojectile.h"
#if !defined( CLIENT_DLL )
#include "grenade_antipersonnel.h"
#else
#define CWeaponCombatPlasmaGrenadeLauncher C_WeaponCombatPlasmaGrenadeLauncher
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// Damage CVars
ConVar weapon_combat_plasmagrenadelauncher_damage( "weapon_combat_plasmagrenadelauncher_damage","40", FCVAR_REPLICATED, "Burst Rifle damage" );
ConVar weapon_combat_plasmagrenadelauncher_radius( "weapon_combat_plasmagrenadelauncher_radius","100", FCVAR_REPLICATED, "Burst Rifle maximum range" );
#define MAX_RIFLE_POWER 3.0
#define RIFLE_CHARGE_TIME 2.0
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CWeaponCombatPlasmaGrenadeLauncher : public CWeaponCombatUsedWithShieldBase
{
DECLARE_CLASS( CWeaponCombatPlasmaGrenadeLauncher, CWeaponCombatUsedWithShieldBase );
public:
DECLARE_NETWORKCLASS();
DECLARE_PREDICTABLE();
CWeaponCombatPlasmaGrenadeLauncher();
virtual void ItemPostFrame( void );
virtual void PrimaryAttack( void );
virtual float GetFireRate( void );
virtual void Precache( void );
// All predicted weapons need to implement and return true
virtual bool IsPredicted( void ) const
{
return true;
}
#if defined( CLIENT_DLL )
virtual bool ShouldPredict( void )
{
if ( GetOwner() &&
GetOwner() == C_BasePlayer::GetLocalPlayer() )
return true;
return BaseClass::ShouldPredict();
}
#endif
private:
CWeaponCombatPlasmaGrenadeLauncher( const CWeaponCombatPlasmaGrenadeLauncher & );
};
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponCombatPlasmaGrenadeLauncher, DT_WeaponCombatPlasmaGrenadeLauncher )
BEGIN_NETWORK_TABLE( CWeaponCombatPlasmaGrenadeLauncher, DT_WeaponCombatPlasmaGrenadeLauncher )
END_NETWORK_TABLE()
BEGIN_PREDICTION_DATA( CWeaponCombatPlasmaGrenadeLauncher )
END_PREDICTION_DATA()
LINK_ENTITY_TO_CLASS( weapon_combat_plasmagrenadelauncher, CWeaponCombatPlasmaGrenadeLauncher );
PRECACHE_WEAPON_REGISTER(weapon_combat_plasmagrenadelauncher);
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CWeaponCombatPlasmaGrenadeLauncher::CWeaponCombatPlasmaGrenadeLauncher()
{
m_bReloadsSingly = true;
SetPredictionEligible( true );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponCombatPlasmaGrenadeLauncher::Precache( void )
{
BaseClass::Precache();
#if !defined( CLIENT_DLL )
UTIL_PrecacheOther( "grenade_antipersonnel" );
#endif
PrecacheModel( "models/weapons/w_grenade.mdl" );
}
void CWeaponCombatPlasmaGrenadeLauncher::ItemPostFrame( void )
{
CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() );
if (!pOwner)
return;
if ( UsesClipsForAmmo1() )
{
CheckReload();
}
// Handle firing
if ( GetShieldState() == SS_DOWN && !m_bInReload )
{
if ( (pOwner->m_nButtons & IN_ATTACK ) && (m_flNextPrimaryAttack <= gpGlobals->curtime) )
{
if ( m_iClip1 > 0 )
{
// Fire the plasma shot
PrimaryAttack();
}
else
{
Reload();
}
}
// Reload button (or fire button when we're out of ammo)
if ( m_flNextPrimaryAttack <= gpGlobals->curtime )
{
if ( pOwner->m_nButtons & IN_RELOAD )
{
Reload();
}
else if ( !((pOwner->m_nButtons & IN_ATTACK) || (pOwner->m_nButtons & IN_ATTACK2) || (pOwner->m_nButtons & IN_RELOAD)) )
{
if ( !m_iClip1 && HasPrimaryAmmo() )
{
Reload();
}
}
}
}
// Prevent shield post frame if we're not ready to attack, or we're charging
AllowShieldPostFrame( m_flNextPrimaryAttack <= gpGlobals->curtime || m_bInReload );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponCombatPlasmaGrenadeLauncher::PrimaryAttack( void )
{
CBaseTFPlayer *pPlayer = (CBaseTFPlayer*)GetOwner();
if (!pPlayer)
return;
WeaponSound(SINGLE);
// Fire the bullets
Vector vecSrc = pPlayer->Weapon_ShootPosition( );
PlayAttackAnimation( GetPrimaryAttackActivity() );
// Launch the grenade
Vector vecForward;
pPlayer->EyeVectors( &vecForward );
Vector vecOrigin = pPlayer->EyePosition();
vecOrigin += (vecForward);
#if !defined( CLIENT_DLL )
float flSpeed = 1200;
CGrenadeAntiPersonnel* pGrenade = CGrenadeAntiPersonnel::Create(vecOrigin, vecForward * flSpeed, pPlayer );
pGrenade->SetModel( "models/weapons/w_grenade.mdl" );
pGrenade->SetBounceSound( "PlasmaGrenade.Bounce" );
pGrenade->SetDamage( weapon_combat_plasmagrenadelauncher_damage.GetFloat() );
pGrenade->SetDamageRadius( weapon_combat_plasmagrenadelauncher_radius.GetFloat() );
pGrenade->SetExplodeOnContact( true );
#endif
m_flNextPrimaryAttack = gpGlobals->curtime + GetFireRate();
m_iClip1 = m_iClip1 - 1;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float CWeaponCombatPlasmaGrenadeLauncher::GetFireRate( void )
{
return SequenceDuration() * 3;
}
@@ -0,0 +1,559 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Chargeable Plasma & Shield combo
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "basetfplayer_shared.h"
#include "weapon_combatshield.h"
#include "in_buttons.h"
#include "weapon_combat_usedwithshieldbase.h"
#include "plasmaprojectile.h"
#include "in_buttons.h"
#include "tf_shareddefs.h"
#if defined( CLIENT_DLL )
#include "iefx.h"
#include "dlight.h"
#include "clienteffectprecachesystem.h"
#include "beamdraw.h"
#define CWeaponCombatPlasmaRifle C_WeaponCombatPlasmaRifle
#define CWeaponCombatPlasmaRifleHuman C_WeaponCombatPlasmaRifleHuman
#define CWeaponCombatPlasmaRifleAlien C_WeaponCombatPlasmaRifleAlien
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#if defined( CLIENT_DLL )
class CChargeBall;
// Precache the effects
CLIENTEFFECT_REGISTER_BEGIN( PrecacheWeaponCombatPlasmaRifle )
CLIENTEFFECT_MATERIAL( "sprites/chargeball_team1" )
CLIENTEFFECT_MATERIAL( "sprites/chargeball_team2" )
CLIENTEFFECT_REGISTER_END()
#endif
// Damage CVars
ConVar weapon_combat_plasmarifle_damage( "weapon_combat_plasmarifle_damage","10", FCVAR_REPLICATED, "Plasma Rifle maximum damage" );
ConVar weapon_combat_plasmarifle_range( "weapon_combat_plasmarifle_range","500", FCVAR_REPLICATED, "Plasma Rifle maximum range" );
ConVar weapon_combat_plasmarifle_radius( "weapon_combat_plasmarifle_radius","90", FCVAR_REPLICATED, "Plasma Rifle explosion radius when charged" );
ConVar weapon_combat_plasmarifle_ducking_mod( "weapon_combat_plasmarifle_ducking_mod", "0.6f", FCVAR_REPLICATED, "Plasma Rifle ducking speed modifier" );
//-----------------------------------------------------------------------------
// Purpose: Shared viersion of CWeaponCombatPlasmaRifle
//-----------------------------------------------------------------------------
class CWeaponCombatPlasmaRifle : public CWeaponCombatUsedWithShieldBase
{
DECLARE_CLASS( CWeaponCombatPlasmaRifle, CWeaponCombatUsedWithShieldBase );
public:
DECLARE_NETWORKCLASS();
DECLARE_PREDICTABLE();
#if !defined( CLIENT_DLL )
DECLARE_DATADESC();
#endif
CWeaponCombatPlasmaRifle( void ) {}
virtual void ItemPostFrame( void );
virtual void PrimaryAttack( void );
virtual float GetFireRate( void );
virtual void Spawn();
virtual bool Deploy( void );
virtual bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL );
void ChargeThink( void );
virtual float GetDefaultAnimSpeed( void );
// All predicted weapons need to implement and return true
virtual bool IsPredicted( void ) const
{
return true;
}
private:
CWeaponCombatPlasmaRifle( const CWeaponCombatPlasmaRifle & );
public:
#if defined( CLIENT_DLL )
virtual bool ShouldPredict( void )
{
if ( GetOwner() &&
GetOwner() == C_BasePlayer::GetLocalPlayer() )
return true;
return BaseClass::ShouldPredict();
}
virtual void OnDataChanged( DataUpdateType_t updateType );
virtual int DrawModel( int flags );
virtual void ViewModelDrawn( CBaseViewModel *pBaseViewModel );
virtual void ClientThink( );
virtual bool IsTransparent( );
private:
// Purpose: Draws the charging effect
void DrawChargingEffect( float flSize, CBaseAnimating *pAttachedEnt );
CMaterialReference m_hMaterial;
#endif
private:
CNetworkVar( float, m_flPower );
CNetworkVar( bool, m_bCharging );
};
//-----------------------------------------------------------------------------
// Spawn weapon
//-----------------------------------------------------------------------------
void CWeaponCombatPlasmaRifle::Spawn()
{
BaseClass::Spawn();
m_flPower = 1;
m_bCharging = false;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponCombatPlasmaRifle::ItemPostFrame( void )
{
ChargeThink();
CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() );
if (!pOwner)
return;
if ( UsesClipsForAmmo1() )
{
CheckReload();
}
// Handle charge firing
if ( GetShieldState() == SS_DOWN && !m_bInReload )
{
if ( (pOwner->m_nButtons & IN_ATTACK ) && (m_flNextPrimaryAttack <= gpGlobals->curtime) )
{
if ( m_iClip1 > 0 )
{
// Fire the plasma shot
PrimaryAttack();
m_flPower = 1.0;
}
else
{
Reload();
}
}
// Reload button (or fire button when we're out of ammo)
if ( m_flNextPrimaryAttack <= gpGlobals->curtime )
{
if ( pOwner->m_nButtons & IN_RELOAD )
{
Reload();
}
else if ( !((pOwner->m_nButtons & IN_ATTACK) || (pOwner->m_nButtons & IN_ATTACK2) || (pOwner->m_nButtons & IN_RELOAD)) )
{
if ( !m_iClip1 && HasPrimaryAmmo() )
{
Reload();
}
}
}
}
// Prevent shield post frame if we're not ready to attack, or we're charging
AllowShieldPostFrame( m_flNextPrimaryAttack <= gpGlobals->curtime || m_bInReload );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponCombatPlasmaRifle::PrimaryAttack( void )
{
CBaseTFPlayer *pPlayer = (CBaseTFPlayer*)GetOwner();
if (!pPlayer)
return;
WeaponSound(SINGLE);
// Fire the bullets
Vector vecSrc = pPlayer->Weapon_ShootPosition( );
Vector vecAiming;
pPlayer->EyeVectors( &vecAiming );
PlayAttackAnimation( GetPrimaryAttackActivity() );
// Shift it down a bit so the firer can see it
Vector right, forward;
AngleVectors( pPlayer->EyeAngles() + pPlayer->m_Local.m_vecPunchAngle, &forward, &right, NULL );
Vector vecStartSpot = vecSrc;
Vector gunOffset = Vector(0,0,-8) + right * 12 + forward * 16;
CPowerPlasmaProjectile *pPlasma = CPowerPlasmaProjectile::CreatePredicted( vecStartSpot, vecAiming, gunOffset, DMG_ENERGYBEAM, pPlayer );
if ( pPlasma )
{
pPlasma->SetDamage( m_flPower * weapon_combat_plasmarifle_damage.GetFloat() );
pPlasma->m_hOwner = pPlayer;
pPlasma->SetPower( m_flPower );
// Calculate range based upon charge power
float flRange = weapon_combat_plasmarifle_range.GetFloat() + RemapVal( m_flPower, 1.0, MAX_RIFLE_POWER, 0, weapon_combat_plasmarifle_range.GetFloat() * 0.75 );
pPlasma->SetMaxRange( flRange );
pPlasma->Activate();
}
// Go explosive if fully charged
// if ( m_flPower >= MAX_RIFLE_POWER )
// {
// pPlasma->SetExplosive( weapon_combat_plasmarifle_radius.GetFloat() );
// pPlasma->SetPlasmaType( PLASMATYPE_PLASMABALL_EXPLOSIVE );
// }
m_flNextPrimaryAttack = gpGlobals->curtime + GetFireRate();
m_iClip1 = m_iClip1 - 1;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float CWeaponCombatPlasmaRifle::GetFireRate( void )
{
float flFireRate = ( SequenceDuration() * 0.4 ) + SHARED_RANDOMFLOAT( 0.0, 0.035f );
// Get the player.
CBaseTFPlayer *pPlayer = ( CBaseTFPlayer* )GetOwner();
if ( pPlayer )
{
// Fire more rapidly when we are ducking.
if ( pPlayer->GetFlags() & FL_DUCKING )
{
flFireRate *= weapon_combat_plasmarifle_ducking_mod.GetFloat();
}
}
return flFireRate;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CWeaponCombatPlasmaRifle::Deploy( void )
{
if ( BaseClass::Deploy() )
{
m_bCharging = true;
GainedNewTechnology(NULL);
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose: Our player just died
//-----------------------------------------------------------------------------
bool CWeaponCombatPlasmaRifle::Holster( CBaseCombatWeapon *pSwitchingTo )
{
if ( BaseClass::Holster(pSwitchingTo) )
{
m_bCharging = false;
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose: Match the anim speed to the weapon speed while crouching
//-----------------------------------------------------------------------------
float CWeaponCombatPlasmaRifle::GetDefaultAnimSpeed( void )
{
if ( GetOwner() && GetOwner()->IsPlayer() )
{
if ( GetOwner()->GetFlags() & FL_DUCKING )
return (1.0 + (1.0 - weapon_combat_plasmarifle_ducking_mod.GetFloat()) );
}
return 1.0;
}
//-----------------------------------------------------------------------------
// Purpose: Charge up over time
//-----------------------------------------------------------------------------
void CWeaponCombatPlasmaRifle::ChargeThink( void )
{
if ( !m_bCharging )
return;
if ( IsOwnerEMPed() )
{
m_flPower = 1;
}
else if ( m_iClip1 > 0 && m_flPower < MAX_RIFLE_POWER )
{
m_flPower = MIN( MAX_RIFLE_POWER, m_flPower + (((MAX_RIFLE_POWER-1.0) / RIFLE_CHARGE_TIME) * gpGlobals->frametime ) );
}
}
#if defined( CLIENT_DLL )
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponCombatPlasmaRifle::OnDataChanged( DataUpdateType_t updateType )
{
SetPredictionEligible( true );
BaseClass::OnDataChanged( updateType );
if (updateType == DATA_UPDATE_CREATED)
{
if ( GetTeamNumber() == 1 )
m_hMaterial.Init( "sprites/chargeball_team1", TEXTURE_GROUP_CLIENT_EFFECTS );
else
m_hMaterial.Init( "sprites/chargeball_team2", TEXTURE_GROUP_CLIENT_EFFECTS );
}
if (WeaponState() == WEAPON_IS_ACTIVE)
{
// Start thinking so we can manipulate the light
SetNextClientThink( CLIENT_THINK_ALWAYS );
}
else
{
SetNextClientThink( CLIENT_THINK_NEVER );
}
}
//-----------------------------------------------------------------------------
// Deal with dynamic lighting
//-----------------------------------------------------------------------------
void CWeaponCombatPlasmaRifle::ClientThink( )
{
BaseClass::ClientThink();
if (!inv_demo.GetInt())
{
C_BaseTFPlayer *pPlayer = (C_BaseTFPlayer *)GetOwner();
if ( !pPlayer || (pPlayer->GetHealth() <= 0) || !IsDormant() )
{
SetNextClientThink( CLIENT_THINK_NEVER );
return;
}
// FIXME: dl->origin should be based on the attachment point
dlight_t *dl = effects->CL_AllocDlight( entindex() );
dl->origin = GetRenderOrigin();
if (GetTeamNumber() == 1)
{
dl->color.r = 40;
dl->color.g = 60;
dl->color.b = 250;
}
else
{
dl->color.r = 250;
dl->color.g = 60;
dl->color.b = 40;
}
dl->color.exponent = 7;
dl->radius = 20 * m_flPower + 10;
dl->die = gpGlobals->curtime + 0.01;
}
}
//-----------------------------------------------------------------------------
// Purpose: Draws the charging effect
//-----------------------------------------------------------------------------
void CWeaponCombatPlasmaRifle::DrawChargingEffect( float flSize, CBaseAnimating *pAttachedEnt )
{
if (!pAttachedEnt)
return;
Vector vecMuzzleOrigin, vecBarrelOrigin;
QAngle angMuzzleAngles, angBarrelAngles;
int iMuzzle = pAttachedEnt->LookupAttachment( "muzzle" );
//int iBarrel = pAttachedEnt->LookupAttachment( "barrel" );
if ( pAttachedEnt->GetAttachment( iMuzzle, vecMuzzleOrigin, angMuzzleAngles ) )
{
// View model attachments are modified so you can place entities at the attachment
// point and when they are rendered (with a different FOV than the view model itself uses)
// they will render in the right spot when the view model is drawn.
//
// In this case though, we are rendering at the same time as the view model, so we want
// the attachment point before the correction has been applied.
pAttachedEnt->UncorrectViewModelAttachment( vecMuzzleOrigin );
// If I'm fully charged, put funky effects on the ball
materials->Bind( m_hMaterial, this );
if ( m_flPower >= MAX_RIFLE_POWER )
{
float frac = fmod( gpGlobals->curtime, 1.0 );
frac *= 2 * M_PI;
frac = sin( frac );
flSize += (frac * 2) - 1.5;
int colorFade = 190 + (int)( frac * 32.0f );
color32 color = { 0, 0, 0, 255 };
if ( GetTeamNumber() == 1 )
{
color.r = colorFade;
color.g = colorFade;
}
else
{
color.g = colorFade;
}
DrawSprite( vecMuzzleOrigin, flSize, flSize, color );
}
else
{
color32 color = { 255, 255, 255, 255 };
DrawSprite( vecMuzzleOrigin, flSize, flSize, color );
}
}
}
//-----------------------------------------------------------------------------
// We're transparent because we draw a transparent charging effect
//-----------------------------------------------------------------------------
bool CWeaponCombatPlasmaRifle::IsTransparent( )
{
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Draws the model
//-----------------------------------------------------------------------------
int CWeaponCombatPlasmaRifle::DrawModel( int flags )
{
int retval = BaseClass::DrawModel( flags );
if (retval == 0)
return 0;
if (IsCarrierAlive())
{
// FIXME: Maybe do some client-side simulation on the size?
// It may get jerky otherwise
// Draw the charging effect
float flSize = 10 * m_flPower + 5;
DrawChargingEffect( flSize, this );
}
return retval;
}
//-----------------------------------------------------------------------------
// Purpose: Draws the model
//-----------------------------------------------------------------------------
void CWeaponCombatPlasmaRifle::ViewModelDrawn( CBaseViewModel *pBaseViewModel )
{
// Draw the charging effect
float flSize = 4 * m_flPower + 1;
if ( m_iClip1 > 0 )
{
DrawChargingEffect( flSize, pBaseViewModel );
}
}
#endif
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponCombatPlasmaRifle, DT_WeaponCombatPlasmaRifle )
BEGIN_NETWORK_TABLE( CWeaponCombatPlasmaRifle, DT_WeaponCombatPlasmaRifle )
#if !defined( CLIENT_DLL )
SendPropFloat( SENDINFO( m_flPower ), 14, SPROP_ROUNDUP, 1.0f, MAX_RIFLE_POWER ),
SendPropInt( SENDINFO( m_bCharging ), 1, SPROP_UNSIGNED ),
#else
RecvPropFloat( RECVINFO( m_flPower ) ),
RecvPropInt( RECVINFO( m_bCharging ) ),
#endif
END_NETWORK_TABLE()
LINK_ENTITY_TO_CLASS( weapon_combat_plasmarifle_base, CWeaponCombatPlasmaRifle );
BEGIN_PREDICTION_DATA( CWeaponCombatPlasmaRifle )
DEFINE_PRED_FIELD_TOL( m_flPower, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, 0.05f ),
DEFINE_PRED_FIELD( m_bCharging, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
END_PREDICTION_DATA()
#if !defined( CLIENT_DLL )
BEGIN_DATADESC( CWeaponCombatPlasmaRifle )
// Function Pointers
DEFINE_FUNCTION( ChargeThink ),
END_DATADESC()
// PRECACHE_WEAPON_REGISTER(weapon_combat_plasmarifle_base);
#endif
//-----------------------------------------------------------------------------
// Purpose: Need to do different art on client vs server
//-----------------------------------------------------------------------------
class CWeaponCombatPlasmaRifleHuman : public CWeaponCombatPlasmaRifle
{
DECLARE_CLASS( CWeaponCombatPlasmaRifleHuman, CWeaponCombatPlasmaRifle );
public:
DECLARE_NETWORKCLASS();
DECLARE_PREDICTABLE();
CWeaponCombatPlasmaRifleHuman( void ) {}
private:
CWeaponCombatPlasmaRifleHuman( const CWeaponCombatPlasmaRifleHuman & );
};
//-----------------------------------------------------------------------------
// Purpose: Need to do different art on client vs server
//-----------------------------------------------------------------------------
class CWeaponCombatPlasmaRifleAlien : public CWeaponCombatPlasmaRifle
{
DECLARE_CLASS( CWeaponCombatPlasmaRifleAlien, CWeaponCombatPlasmaRifle );
public:
DECLARE_NETWORKCLASS();
DECLARE_PREDICTABLE();
CWeaponCombatPlasmaRifleAlien( void ) {}
private:
CWeaponCombatPlasmaRifleAlien( const CWeaponCombatPlasmaRifleAlien & );
};
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponCombatPlasmaRifleHuman, DT_WeaponCombatPlasmaRifleHuman )
BEGIN_NETWORK_TABLE( CWeaponCombatPlasmaRifleHuman, DT_WeaponCombatPlasmaRifleHuman )
END_NETWORK_TABLE()
BEGIN_PREDICTION_DATA( CWeaponCombatPlasmaRifleHuman )
END_PREDICTION_DATA()
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponCombatPlasmaRifleAlien, DT_WeaponCombatPlasmaRifleAlien )
BEGIN_NETWORK_TABLE( CWeaponCombatPlasmaRifleAlien, DT_WeaponCombatPlasmaRifleAlien )
END_NETWORK_TABLE()
BEGIN_PREDICTION_DATA( CWeaponCombatPlasmaRifleAlien )
END_PREDICTION_DATA()
LINK_ENTITY_TO_CLASS( weapon_combat_plasmarifle, CWeaponCombatPlasmaRifleHuman );
LINK_ENTITY_TO_CLASS( weapon_combat_plasmarifle_alien, CWeaponCombatPlasmaRifleAlien );
PRECACHE_WEAPON_REGISTER(weapon_combat_plasmarifle);
PRECACHE_WEAPON_REGISTER(weapon_combat_plasmarifle_alien);

Some files were not shown because too many files have changed in this diff Show More