Difference between revisions of "Throwable weapons"

From Team Fortress Wiki
Jump to: navigation, search
m (Target Dummy)
m (Repel: quick-fix thing was for not taking damage, removed)
Line 35: Line 35:
 
  pPlayer->ApplyAirBlastImpulse( vecToTarget * flForce + Vector( 0, 0, flForce ) );
 
  pPlayer->ApplyAirBlastImpulse( vecToTarget * flForce + Vector( 0, 0, flForce ) );
 
  pPlayer->ApplyPunchImpulseX( RandomInt( -50, -30 ) );<!--End-->
 
  pPlayer->ApplyPunchImpulseX( RandomInt( -50, -30 ) );<!--End-->
 
Enemies under the Quick-Fix's ubercharge were programmed to be immune to this force;
 
 
<!--Begin-->// {{botignore|Quick Fix}} Uber is immune
 
if ( pPlayer->m_Shared.InCond( TF_COND_MEGAHEAL ))
 
    return;<!--End-->
 
  
 
Enemies also take damage.
 
Enemies also take damage.

Revision as of 06:32, 24 April 2020

Throwable weapons were a new class of weapons that were being tested internally by Valve, but were either cut or abandoned.

Functionality

Throwable weapons were classed as either being "primable" or "chargeable";

// Primable is for timed explosions
// Charagable is for things like distance or power increases
// Can't really have both but can have neither

Slots

Throwable slots were apparently considered, with the experimental "Utility" slot making an appearance as well.

#ifdef STAGING_ONLY
CREATE_SIMPLE_WEAPON_TABLE( TFThrowablePrimary, tf_weapon_throwable_primary )
CREATE_SIMPLE_WEAPON_TABLE( TFThrowableSecondary, tf_weapon_throwable_secondary )
CREATE_SIMPLE_WEAPON_TABLE( TFThrowableMelee, tf_weapon_throwable_melee )
CREATE_SIMPLE_WEAPON_TABLE( TFThrowableUtility, tf_weapon_throwable_utility )
#endif

Throwables

Several varieties of throwable weapons have been discovered.

Repel

A throwable airblast. Throwing it would cause it to apply airblast force to any enemies within range of it, pushing them away and making their view shake;

// Apply AirBlast Force
Vector vecToTarget;
vecToTarget = pPlayer->GetAbsOrigin() - this->GetAbsOrigin();
vecToTarget.z = 0;
VectorNormalize( vecToTarget );
float flForce = 300.0f * m_flChargePercent + 350.0f;
pPlayer->ApplyAirBlastImpulse( vecToTarget * flForce + Vector( 0, 0, flForce ) );
pPlayer->ApplyPunchImpulseX( RandomInt( -50, -30 ) );

Enemies also take damage.

// Apply Damage to Victim
CTakeDamageInfo info;
info.SetAttacker( GetThrower() );
info.SetInflictor( this ); 
info.SetWeapon( GetLauncher() );
info.SetDamage( GetDamage() );
info.SetDamageCustom( GetCustomDamageType() );
info.SetDamagePosition( this->GetAbsOrigin() );
info.SetDamageType( DMG_CLUB | DMG_PREVENT_PHYSICS_FORCE );

pPlayer->DispatchTraceAttack( info, vecToTarget, &trace );
ApplyMultiDamage();

Brick

A brick. Highly reminiscent of Timesplitters. Hitting an enemy with it would deal some damage and shake up their view;

// Apply Damage to Victim
CTakeDamageInfo info;
info.SetAttacker( GetThrower() );
info.SetInflictor( this ); 
info.SetWeapon( GetLauncher() );
info.SetDamage( GetDamage() );
info.SetDamageCustom( GetCustomDamageType() );
info.SetDamagePosition( GetAbsOrigin() );
info.SetDamageType( DMG_CLUB );

pPlayer->DispatchTraceAttack( info, vecToTarget, &trace );
pPlayer->ApplyPunchImpulseX( RandomInt( 15, 20 ) );
ApplyMultiDamage();

Target Dummy

A portable target dummy. Throwing this would create a Target Dummy. Pretty self-explanatory.

void CTFProjectile_ThrowableTargetDummy::Explode()
{
    CTFPlayer *pPlayer = ToTFPlayer( GetThrower() );
    if ( !pPlayer )
        return;

    CTFTargetDummy::Create( GetAbsOrigin(), GetAbsAngles(), pPlayer );
    BaseClass::Explode();
}

For testing, the models/props_training/target_engineer.mdl and models/props_training/target_demoman.mdl plywood target models were used, and just as they do in training mode, the targets would break into gibs when enough damage has been done to them. It appears that they scrapped the idea before adding in the model selection for the target dummy;

#define DUMMY_MODEL "models/props_training/target_engineer.mdl"
#define DUMMY_DEMO_MODEL "models/props_training/target_demoman.mdl"

// TODO: Model Selection
if ( RandomInt( 0, 1 ) == 1 )
{
        SetModel( DUMMY_DEMO_MODEL );
        BuildGibList( m_aGibs, GetModelIndex(), 1.0f, COLLISION_GROUP_NONE );
}
else
{
        SetModel( DUMMY_MODEL );
}

The "Model Selection" mentioned in the code comment could have been the target dummy choosing the proper models/props_training/target_<class>.mdl model to match the thrower's class, but the actual functionality is not known.

Concussion Grenade

Return of the Concussion Grenade. It seems Valve had been playing around with trying to bring the Concussion Grenade back somehow.

Teleport Grenade

The Teleport Grenade would teleport the user to wherever the grenade was thrown.

// Try a few spots
FOR_EACH_VEC_BACK( m_vecTrailingPos, i )
{
   // Try positions starting with the current, and moving back in time a bit
   Vector vecStart = m_vecTrailingPos[i];
   UTIL_TraceHull( vecStart, vecStart, VEC_HULL_MIN, VEC_HULL_MAX, nMask, &traceFilter, &traceHull );

   if ( !traceHull.DidHit() )
   {
       // Place a teleport effect where they came from
       const Vector& vecOrigin = pThrower->GetAbsOrigin();
       CPVSFilter pvsFilter( vecOrigin );
       TE_TFParticleEffect( pvsFilter, 0.f, GetExplodeEffectParticle(), vecOrigin, vec3_angle );

       // Move 'em!
       pThrower->Teleport( &vecStart, &pThrower->GetAbsAngles(), NULL );

       // Do a zoom effect
       pThrower->SetFOV( pThrower, 0.f, 0.3f, 120.f );

       // Screen flash
       color32 fadeColor = { 255, 255, 255, 100 };
       UTIL_ScreenFade( pThrower, fadeColor, 0.25f, 0.4f, FFADE_IN );

       if ( TFGameRules() )
       {
           TFGameRules()->HaveAllPlayersSpeakConceptIfAllowed( MP_CONCEPT_PLAYER_SPELL_TELEPORT, ( pThrower->GetTeamNumber() == TF_TEAM_RED ) ? TF_TEAM_BLUE : TF_TEAM_RED );
       }
   }
}

Chain Grenade

Also referred to in code as the Gravity Grenade. A trap style grenade, it functioned similar to a black hole, dragging anyone within range closer to it.

void CTFProjectile_GravityGrenade::PulseTrap( void )
{
   const int nMaxEnts = 32;

   Vector vecPos = GetAbsOrigin();
   CBaseEntity *pObjects[ nMaxEnts ];
   int nCount = UTIL_EntitiesInSphere( pObjects, nMaxEnts, vecPos, GetDamageRadius(), FL_CLIENT );

   // Iterate through sphere's contents
   for ( int i = 0; i < nCount; i++ )
   {
       CBaseCombatCharacter *pEntity = pObjects[i]->MyCombatCharacterPointer();
       if ( !pEntity )
           continue;

       if ( InSameTeam( pEntity ) )
           continue;

       if ( !FVisible( pEntity, MASK_OPAQUE ) )
           continue;

       // Draw player toward us
       Vector vecSourcePos = pEntity->GetAbsOrigin();
       Vector vecTargetPos = GetAbsOrigin();
       Vector vecVelocity = ( vecTargetPos - vecSourcePos ) * 2.f;
       vecVelocity.z += 50.f;

       if ( pEntity->GetFlags() & FL_ONGROUND )
       {
           vecVelocity.z += 150.f;
           pEntity->SetGroundEntity( NULL );
           pEntity->SetGroundChangeTime( gpGlobals->curtime + 0.5f );
       }

       pEntity->Teleport( NULL, NULL, &vecVelocity );
   }

   // NDebugOverlay::Sphere( vecPos, GetDamageRadius(), 0, 255, 0, false, 0.35f );

   PulseEffects();
}

Smoke Grenade

Similar to the aforementioned Concussion Grenade, the Smoke Grenade would have been a second go at trying to bring back the Smoke Bomb from the early development days.

Throwing Knife

Throwing Knives were tested as well. They would do crits if they hit someone from behind and much like arrows and some other certain projectiles, throwing knives would stick out of the person you hit.

// Is from behind?
bool bIsFromBehind = DotProduct( toEnt, entForward ) > 0.7071f;

// Apply Damage to Victim
CTakeDamageInfo info;
info.SetAttacker( GetThrower() );
info.SetInflictor( this );
info.SetWeapon( GetLauncher() );
info.SetDamageCustom( GetCustomDamageType() );
info.SetDamagePosition( GetAbsOrigin() );

int iDamageType = DMG_CLUB;
if ( bIsFromBehind )
{
    iDamageType |= DMG_CRITICAL;
}

info.SetDamageType( iDamageType );
info.SetDamage( bIsFromBehind ? GetBackHitDamage() : GetDamage() );

pVictim->DispatchTraceAttack( info, toEnt, &trace );
ApplyMultiDamage();

CreateStickyAttachmentToTarget( pOwner, pVictim, &trace );

Snowball

The only evidence to the existence of the Snowball is the MODEL_SNOWBALL enum entry from the enumerator used to store model defines for arrow projectiles;

The comments in the code below were added for this article to help clarify what things are and were not written by Valve.

enum arrow_models
{
   MODEL_ARROW_REGULAR, // Regular arrow
   MODEL_ARROW_BUILDING_REPAIR, // Rescue Ranger projectile
   MODEL_SNOWBALL, // Snowball?
   MODEL_FESTIVE_ARROW_REGULAR, // Festive arrow
   MODEL_SYRINGE, // Syringe Gun projectile
   MODEL_FESTIVE_HEALING_BOLT, // Festive Crusader's Crossbow
   MODEL_BREAD_MONSTER, // Self-Aware Beauty Mark and the other breadmonster Jar item
   MODEL_GRAPPLINGHOOK, // Grappling Hook

   // Staging
   MODEL_THROWING_KNIFE, // Throwing Knife, mentioned above

   TF_ARROW_MODEL_COUNT // # of models in this enumerator which would be 9
};