Throwable weapons
“Ok guys, bad news: we lost that last one.” This article documents experimental content for Team Fortress 2. It may contain speculation, broken links or errors. |
Throwable weapons were a new class of weapons that were being tested internally by Valve, but were either cut or abandoned.
Contents
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 under the Quick-Fix's ubercharge were programmed to be immune to this force;
// Quick Fix Uber is immune if ( pPlayer->m_Shared.InCond( TF_COND_MEGAHEAL )) return;
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.
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 };
|