mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-08-11 03:09:36 +00:00
1
This commit is contained in:
@@ -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
|
||||
}
|
||||
@@ -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()
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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 );
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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 );
|
||||
}
|
||||
@@ -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
|
||||
@@ -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()
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
@@ -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
@@ -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 );
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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.
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
@@ -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
|
||||
@@ -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()
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
Reference in New Issue
Block a user