Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/sr2echa/TF2-Source-Code/llms.txt

Use this file to discover all available pages before exploring further.

TF2 projectiles are discrete entities spawned when a weapon fires. They live in the server DLL, replicate a minimal networked state to the client, and resolve collision, damage, and effects on touch. The full hierarchy is documented at the top of game/shared/tf/tf_projectile_base.h.

Class hierarchy

CBaseProjectile
├── CTFBaseProjectile          (tf_projectile_base.h — shared)
│   ├── CTFProjectile_Nail
│   ├── CTFProjectile_Dart
│   ├── CTFProjectile_Syringe
│   └── CTFProjectile_EnergyRing
├── CTFBaseRocket              (tf_weaponbase_rocket.h)
│   ├── CTFProjectile_Rocket   (tf_projectile_rocket.h)
│   ├── CTFProjectile_Flare
│   └── CTFProjectile_Arrow    (tf_projectile_arrow.h)
└── CBaseGrenade
    └── CTFWeaponBaseGrenadeProj
        └── CTFGrenadePipebombProjectile

Projectile types

ClassLaunched byDeflectableCrit support
CTFProjectile_RocketRocket LauncherYesYes (m_bCritical)
CTFGrenadePipebombProjectileGrenade / Stickybomb LaunchersNoYes
CTFProjectile_ArrowHuntsman, CrossbowNoYes (m_bCritical)
CTFProjectile_FlareFlare GunNoYes
CTFProjectile_EnergyBallRighteous Bison / PomsonNoYes
CTFProjectile_NailNailgun (legacy)NoYes

CTFBaseProjectile — shared base

CTFBaseProjectile (shared between client and server) holds the minimum networked state:
class CTFBaseProjectile : public CBaseProjectile
{
public:
    bool   IsCritical( void ) const         { return m_bCritical; }
    virtual void SetCritical( bool bCritical ) { m_bCritical = bCritical; }

    CBaseEntity *GetLauncher( void ) { return m_hLauncher; }
    virtual float GetGravity( void ) { return 0.001f; }

    // Server only
    virtual void  ProjectileTouch( CBaseEntity *pOther );
    virtual float GetDamage()               { return m_flDamage; }
    virtual void  SetDamage( float flDamage ) { m_flDamage = flDamage; }
    virtual int   GetProjectileType( void ) { return TF_PROJECTILE_NONE; }

private:
    int   m_iWeaponID;
    bool  m_bCritical;
};
m_vInitialVelocity is networked so the client can reproduce the flight path for interpolation without a full physics simulation.

CTFProjectile_Rocket

Rockets implement IScorer to correctly attribute assisted kills:
class CTFProjectile_Rocket : public CTFBaseRocket, public IScorer
{
public:
    static CTFProjectile_Rocket *Create( CBaseEntity *pLauncher,
        const Vector &vecOrigin, const QAngle &vecAngles,
        CBaseEntity *pOwner = NULL, CBaseEntity *pScorer = NULL );

    virtual void RocketTouch( CBaseEntity *pOther ) OVERRIDE;
    virtual bool IsDeflectable() { return true; }
    virtual void Deflected( CBaseEntity *pDeflectedBy, Vector &vecDir );
    virtual int  GetDamageType();
};
IsDeflectable() returns true, allowing the Pyro’s airblast to call Deflected() and reverse the rocket’s ownership and direction. The m_bDirectHit flag changes GetWeaponID() to return TF_WEAPON_ROCKETLAUNCHER_DIRECTHIT, enabling separate damage scaling for direct hits.

CTFProjectile_Arrow

Arrows embed into surfaces and players via bone attachment:
class CTFProjectile_Arrow : public CTFBaseRocket, public IScorer
{
public:
    virtual bool StrikeTarget( mstudiobbox_t *pBox, CBaseEntity *pOther );
    virtual void OnArrowImpact( mstudiobbox_t *pBox, CBaseEntity *pOther,
                                CBaseEntity *pAttacker );
    bool         PositionArrowOnBone( mstudiobbox_t *pBox,
                                      CBaseAnimating *pOtherAnim );
    virtual bool CanHeadshot();
    void         BuildingHealingArrow( CBaseEntity *pOther );
};
StrikeTarget selects the hit hitbox, PositionArrowOnBone parents the arrow entity to the struck bone so it moves with ragdolls and players. BuildingHealingArrow handles the Crusader’s Crossbow bolt healing buildings.

Critical hit detection

All projectile types propagate crit state through m_bCritical (a CNetworkVar on rockets). The launcher sets this flag via SetCritical() before spawning the projectile, based on CalcIsAttackCritical() in the weapon class. On touch/impact the projectile passes the flag into the CTakeDamageInfo struct to apply the 3× crit multiplier.
Mini-crits and full crits are differentiated via damage type flags (DMG_CRITICAL) rather than a separate projectile class, so the same entity handles both cases.

Build docs developers (and LLMs) love