//----------------------------------------------------------------------------- // Purpose: Check that the selected position is buildable //----------------------------------------------------------------------------- bool CBaseObject::IsPlacementPosValid( void ) { bool bValid = CalculatePlacementPos(); if ( !bValid ) { return false; } CTFPlayer *pPlayer = GetOwner(); if ( !pPlayer ) { return false; } #ifndef CLIENT_DLL if ( !EstimateValidBuildPos() ) return false; #endif // Verify that the entire object can fit here // Important! here we want to collide with players and other buildings, but not dropped weapons trace_t tr; UTIL_TraceEntity( this, m_vecBuildOrigin, m_vecBuildOrigin, MASK_SOLID, NULL, COLLISION_GROUP_PLAYER, &tr ); if ( tr.fraction < 1.0f ) return false; // Make sure we can see the final position UTIL_TraceLine( pPlayer->EyePosition(), m_vecBuildOrigin + Vector(0,0,m_vecBuildMaxs[2] * 0.5), MASK_PLAYERSOLID_BRUSHONLY, pPlayer, COLLISION_GROUP_NONE, &tr ); if ( tr.fraction < 1.0 ) { return false; } return true; }
void CTFBaseRocket::FlyThink( void ) { if ( gpGlobals->curtime > m_flCollideWithTeammatesTime && m_bCollideWithTeammates == false ) { m_bCollideWithTeammates = true; } if ( tf2c_homing_rockets.GetBool() || ( tf2c_homing_deflected_rockets.GetBool() && m_iDeflected ) ) { // Find the closest visible enemy player. CUtlVector<CTFPlayer *> vecPlayers; int count = CollectPlayers( &vecPlayers, TEAM_ANY, true ); float flClosest = FLT_MAX; Vector vecClosestTarget = vec3_origin; for ( int i = 0; i < count; i++ ) { CTFPlayer *pPlayer = vecPlayers[i]; if ( pPlayer == GetOwnerEntity() ) continue; if ( pPlayer->GetTeamNumber() == GetTeamNumber() && !TFGameRules()->IsDeathmatch() ) continue; Vector vecTarget; QAngle angTarget; if ( GetWeaponID() == TF_WEAPON_COMPOUND_BOW ) { int iBone = pPlayer->LookupBone( "bip_head" ); pPlayer->GetBonePosition( iBone, vecTarget, angTarget );; } else { vecTarget = pPlayer->EyePosition(); } if ( FVisible( vecTarget ) ) { float flDistSqr = ( vecTarget - GetAbsOrigin() ).LengthSqr(); if ( flDistSqr < flClosest ) { flClosest = flDistSqr; vecClosestTarget = vecTarget; } } } // Head towards him. if ( vecClosestTarget != vec3_origin ) { Vector vecTarget = vecClosestTarget; Vector vecDir = vecTarget - GetAbsOrigin(); VectorNormalize( vecDir ); float flSpeed = GetAbsVelocity().Length(); QAngle angForward; VectorAngles( vecDir, angForward ); SetAbsAngles( angForward ); SetAbsVelocity( vecDir * flSpeed ); } } SetNextThink( gpGlobals->curtime + 0.1f ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFlameThrower::PrimaryAttack() { // Are we capable of firing again? if ( m_flNextPrimaryAttack > gpGlobals->curtime ) return; // Get the player owning the weapon. CTFPlayer *pOwner = ToTFPlayer( GetPlayerOwner() ); if ( !pOwner ) return; if ( !CanAttack() ) { #if defined ( CLIENT_DLL ) StopFlame(); #endif m_iWeaponState = FT_STATE_IDLE; return; } CalcIsAttackCritical(); // Because the muzzle is so long, it can stick through a wall if the player is right up against it. // Make sure the weapon can't fire in this condition by tracing a line between the eye point and the end of the muzzle. trace_t trace; Vector vecEye = pOwner->EyePosition(); Vector vecMuzzlePos = GetVisualMuzzlePos(); CTraceFilterIgnoreObjects traceFilter( this, COLLISION_GROUP_NONE ); UTIL_TraceLine( vecEye, vecMuzzlePos, MASK_SOLID, &traceFilter, &trace ); if ( trace.fraction < 1.0 && ( !trace.m_pEnt || trace.m_pEnt->m_takedamage == DAMAGE_NO ) ) { // there is something between the eye and the end of the muzzle, most likely a wall, don't fire, and stop firing if we already are if ( m_iWeaponState > FT_STATE_IDLE ) { #if defined ( CLIENT_DLL ) StopFlame(); #endif m_iWeaponState = FT_STATE_IDLE; } return; } switch ( m_iWeaponState ) { case FT_STATE_IDLE: case FT_STATE_AIRBLASTING: { // Just started, play PRE and start looping view model anim pOwner->DoAnimationEvent( PLAYERANIMEVENT_ATTACK_PRE ); SendWeaponAnim( ACT_VM_PRIMARYATTACK ); m_flStartFiringTime = gpGlobals->curtime + 0.16; // 5 frames at 30 fps m_iWeaponState = FT_STATE_STARTFIRING; } break; case FT_STATE_STARTFIRING: { // if some time has elapsed, start playing the looping third person anim if ( gpGlobals->curtime > m_flStartFiringTime ) { m_iWeaponState = FT_STATE_FIRING; m_flNextPrimaryAttackAnim = gpGlobals->curtime; } } break; case FT_STATE_FIRING: { if ( gpGlobals->curtime >= m_flNextPrimaryAttackAnim ) { pOwner->DoAnimationEvent( PLAYERANIMEVENT_ATTACK_PRIMARY ); m_flNextPrimaryAttackAnim = gpGlobals->curtime + 1.4; // fewer than 45 frames! } } break; default: break; } #ifdef CLIENT_DLL // Restart our particle effect if we've transitioned across water boundaries if ( m_iParticleWaterLevel != -1 && pOwner->GetWaterLevel() != m_iParticleWaterLevel ) { if ( m_iParticleWaterLevel == WL_Eyes || pOwner->GetWaterLevel() == WL_Eyes ) { RestartParticleEffect(); } } #endif #ifdef CLIENT_DLL // Handle the flamethrower light if (tf2c_muzzlelight.GetBool()) { dlight_t *dl = effects->CL_AllocDlight(LIGHT_INDEX_MUZZLEFLASH + index); dl->origin = vecMuzzlePos; dl->color.r = 255; dl->color.g = 100; dl->color.b = 10; dl->die = gpGlobals->curtime + 0.01f; dl->radius = 240.f; dl->decay = 512.0f; dl->style = 5; } #endif #if !defined (CLIENT_DLL) // Let the player remember the usercmd he fired a weapon on. Assists in making decisions about lag compensation. pOwner->NoteWeaponFired(); pOwner->SpeakWeaponFire(); CTF_GameStats.Event_PlayerFiredWeapon( pOwner, m_bCritFire ); // Move other players back to history positions based on local player's lag lagcompensation->StartLagCompensation( pOwner, pOwner->GetCurrentCommand() ); #endif float flFiringInterval = m_pWeaponInfo->GetWeaponData( m_iWeaponMode ).m_flTimeFireDelay; CALL_ATTRIB_HOOK_FLOAT( flFiringInterval, mult_postfiredelay ); // Don't attack if we're underwater if ( pOwner->GetWaterLevel() != WL_Eyes ) { // Find eligible entities in a cone in front of us. Vector vOrigin = pOwner->Weapon_ShootPosition(); Vector vForward, vRight, vUp; QAngle vAngles = pOwner->EyeAngles() + pOwner->GetPunchAngle(); AngleVectors( vAngles, &vForward, &vRight, &vUp ); #define NUM_TEST_VECTORS 30 #ifdef CLIENT_DLL bool bWasCritical = m_bCritFire; #endif // Burn & Ignite 'em int iDmgType = g_aWeaponDamageTypes[ GetWeaponID() ]; m_bCritFire = IsCurrentAttackACrit(); if ( m_bCritFire ) { iDmgType |= DMG_CRITICAL; } #ifdef CLIENT_DLL if ( bWasCritical != m_bCritFire ) { RestartParticleEffect(); } #endif #ifdef GAME_DLL // create the flame entity int iDamagePerSec = m_pWeaponInfo->GetWeaponData( m_iWeaponMode ).m_nDamage; float flDamage = (float)iDamagePerSec * flFiringInterval; CALL_ATTRIB_HOOK_FLOAT( flDamage, mult_dmg ); CTFFlameEntity::Create( GetFlameOriginPos(), pOwner->EyeAngles(), this, iDmgType, flDamage ); #endif } #ifdef GAME_DLL // Figure how much ammo we're using per shot and add it to our remainder to subtract. (We may be using less than 1.0 ammo units // per frame, depending on how constants are tuned, so keep an accumulator so we can expend fractional amounts of ammo per shot.) // Note we do this only on server and network it to client. If we predict it on client, it can get slightly out of sync w/server // and cause ammo pickup indicators to appear float flAmmoPerSecond = TF_FLAMETHROWER_AMMO_PER_SECOND_PRIMARY_ATTACK; CALL_ATTRIB_HOOK_FLOAT( flAmmoPerSecond, mult_flame_ammopersec ); m_flAmmoUseRemainder += flAmmoPerSecond * flFiringInterval; // take the integer portion of the ammo use accumulator and subtract it from player's ammo count; any fractional amount of ammo use // remains and will get used in the next shot int iAmmoToSubtract = (int) m_flAmmoUseRemainder; if ( iAmmoToSubtract > 0 ) { pOwner->RemoveAmmo( iAmmoToSubtract, m_iPrimaryAmmoType ); m_flAmmoUseRemainder -= iAmmoToSubtract; // round to 2 digits of precision m_flAmmoUseRemainder = (float) ( (int) (m_flAmmoUseRemainder * 100) ) / 100.0f; } #endif m_flNextPrimaryAttack = gpGlobals->curtime + flFiringInterval; m_flTimeWeaponIdle = gpGlobals->curtime + flFiringInterval; #if !defined (CLIENT_DLL) lagcompensation->FinishLagCompensation( pOwner ); #endif }