const Vector &C_EnvParticleScript::GetSortOrigin()
{
	return GetAbsOrigin();
}
void C_EnergyWave::ComputePoint( float s, float t, Vector& pt, Vector& normal, float& opacity )
{
	int is = (int)s;
	int it = (int)t;
	if( is >= EWAVE_NUM_HORIZONTAL_POINTS )
		is -= 1;

	if( it >= EWAVE_NUM_VERTICAL_POINTS )
		it -= 1;

	int idx[16];
	ComputeIndices( is, it, idx );

	// The patch equation is:
	// px = S * M * Gx * M^T * T^T 
	// py = S * M * Gy * M^T * T^T 
	// pz = S * M * Gz * M^T * T^T 
	// where S = [s^3 s^2 s 1], T = [t^3 t^2 t 1]
	// M is the patch type matrix, in my case I'm using a catmull-rom
	// G is the array of control points. rows have constant t
	static VMatrix catmullRom( -0.5, 1.5, -1.5, 0.5,
								1, -2.5, 2, -0.5,
								-0.5, 0, 0.5, 0,
								0, 1, 0, 0 );

	VMatrix controlPointsX, controlPointsY, controlPointsZ, controlPointsO;

	Vector pos;
	for (int i = 0; i < 4; ++i)
	{
		for (int j = 0; j < 4; ++j)
		{
			const Vector& v = m_EWaveEffect.GetPoint( idx[i * 4 + j] );

			controlPointsX[j][i] = v.x;
			controlPointsY[j][i] = v.y;
			controlPointsZ[j][i] = v.z;

			controlPointsO[j][i] = m_EWaveEffect.ComputeOpacity( v, GetAbsOrigin() );
		}
	}

	float fs = s - is;
	float ft = t - it;

	VMatrix temp, mgm[4];
	MatrixTranspose( catmullRom, temp );
	MatrixMultiply( controlPointsX, temp, mgm[0] );
	MatrixMultiply( controlPointsY, temp, mgm[1] );
	MatrixMultiply( controlPointsZ, temp, mgm[2] );
	MatrixMultiply( controlPointsO, temp, mgm[3] );

	MatrixMultiply( catmullRom, mgm[0], mgm[0] );
	MatrixMultiply( catmullRom, mgm[1], mgm[1] );
	MatrixMultiply( catmullRom, mgm[2], mgm[2] );
	MatrixMultiply( catmullRom, mgm[3], mgm[3] );

	Vector4D svec, tvec;
	float ft2 = ft * ft;
	tvec[0] = ft2 * ft; tvec[1] = ft2; tvec[2] = ft; tvec[3] = 1.0f;

 	float fs2 = fs * fs;
	svec[0] = fs2 * fs; svec[1] = fs2; svec[2] = fs; svec[3] = 1.0f;

	Vector4D tmp;
	Vector4DMultiply( mgm[0], tvec, tmp );
	pt[0] = DotProduct4D( tmp, svec );
	Vector4DMultiply( mgm[1], tvec, tmp );
	pt[1] = DotProduct4D( tmp, svec );
	Vector4DMultiply( mgm[2], tvec, tmp );
	pt[2] = DotProduct4D( tmp, svec );

	Vector4DMultiply( mgm[3], tvec, tmp );
	opacity = DotProduct4D( tmp, svec );

	if ((s == 0.0f) || (t == 0.0f) ||
		(s == (EWAVE_NUM_HORIZONTAL_POINTS-1.0f)) || (t == (EWAVE_NUM_VERTICAL_POINTS-1.0f)) )
	{
		opacity = 0.0f;
	}

	if ((s <= 0.3) || (t < 0.3))
	{
		opacity *= 0.35f;
	}
	if ((s == (EWAVE_NUM_HORIZONTAL_POINTS-0.7f)) || (t == (EWAVE_NUM_VERTICAL_POINTS-0.7f)) )
	{
		opacity *= 0.35f;
	}

	if (opacity < 0.0f)
		opacity = 0.0f;
	else if (opacity > 255.0f)
		opacity = 255.0f;

	// Normal computation
	Vector4D dsvec, dtvec;
	dsvec[0] = 3.0f * fs2; dsvec[1] = 2.0f * fs; dsvec[2] = 1.0f; dsvec[3] = 0.0f;
	dtvec[0] = 3.0f * ft2; dtvec[1] = 2.0f * ft; dtvec[2] = 1.0f; dtvec[3] = 0.0f;

	Vector ds, dt;
	Vector4DMultiply( mgm[0], tvec, tmp );
	ds[0] = DotProduct4D( tmp, dsvec );
	Vector4DMultiply( mgm[1], tvec, tmp );
	ds[1] = DotProduct4D( tmp, dsvec );
	Vector4DMultiply( mgm[2], tvec, tmp );
	ds[2] = DotProduct4D( tmp, dsvec );

	Vector4DMultiply( mgm[0], dtvec, tmp );
	dt[0] = DotProduct4D( tmp, svec );
	Vector4DMultiply( mgm[1], dtvec, tmp );
	dt[1] = DotProduct4D( tmp, svec );
	Vector4DMultiply( mgm[2], dtvec, tmp );
	dt[2] = DotProduct4D( tmp, svec );

	CrossProduct( ds, dt, normal );
	VectorNormalize( normal );
}
void CWeaponStunStick::Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator )
{
	switch( pEvent->event )
	{
		case EVENT_WEAPON_MELEE_HIT:
		{
			// Trace up or down based on where the enemy is...
			// But only if we're basically facing that direction
			Vector vecDirection;
			AngleVectors( GetAbsAngles(), &vecDirection );

			CBaseEntity *pEnemy = pOperator->MyNPCPointer() ? pOperator->MyNPCPointer()->GetEnemy() : NULL;
			if ( pEnemy )
			{
				Vector vecDelta;
				VectorSubtract( pEnemy->WorldSpaceCenter(), pOperator->Weapon_ShootPosition(), vecDelta );
				VectorNormalize( vecDelta );
				
				Vector2D vecDelta2D = vecDelta.AsVector2D();
				Vector2DNormalize( vecDelta2D );
				if ( DotProduct2D( vecDelta2D, vecDirection.AsVector2D() ) > 0.8f )
				{
					vecDirection = vecDelta;
				}
			}

			Vector vecEnd;
			VectorMA( pOperator->Weapon_ShootPosition(), 32, vecDirection, vecEnd );
			// Stretch the swing box down to catch low level physics objects
			CBaseEntity *pHurt = pOperator->CheckTraceHullAttack( pOperator->Weapon_ShootPosition(), vecEnd, 
				Vector(-16,-16,-40), Vector(16,16,16), GetDamageForActivity( GetActivity() ), DMG_CLUB, 0.5f, false );
			
			// did I hit someone?
			if ( pHurt )
			{
				// play sound
				WeaponSound( MELEE_HIT );

				CBasePlayer *pPlayer = ToBasePlayer( pHurt );

				CNPC_MetroPolice *pCop = dynamic_cast<CNPC_MetroPolice *>(pOperator);
				bool bFlashed = false;

				if ( pCop != NULL && pPlayer != NULL )
				{
					// See if we need to knock out this target
					if ( pCop->ShouldKnockOutTarget( pHurt ) )
					{
						float yawKick = random->RandomFloat( -48, -24 );

						//Kick the player angles
						pPlayer->ViewPunch( QAngle( -16, yawKick, 2 ) );

						color32 white = {255,255,255,255};
						UTIL_ScreenFade( pPlayer, white, 0.2f, 1.0f, FFADE_OUT|FFADE_PURGE|FFADE_STAYOUT );
						bFlashed = true;
						
						pCop->KnockOutTarget( pHurt );

						break;
					}
					else
					{
						// Notify that we've stunned a target
						pCop->StunnedTarget( pHurt );
					}
				}
				
				// Punch angles
				if ( pPlayer != NULL && !(pPlayer->GetFlags() & FL_GODMODE) )
				{
					float yawKick = random->RandomFloat( -48, -24 );

					//Kick the player angles
					pPlayer->ViewPunch( QAngle( -16, yawKick, 2 ) );

					Vector	dir = pHurt->GetAbsOrigin() - GetAbsOrigin();

					// If the player's on my head, don't knock him up
					if ( pPlayer->GetGroundEntity() == pOperator )
					{
						dir = vecDirection;
						dir.z = 0;
					}

					VectorNormalize(dir);

					dir *= 500.0f;

					//If not on ground, then don't make them fly!
					if ( !(pPlayer->GetFlags() & FL_ONGROUND ) )
						 dir.z = 0.0f;

					//Push the target back
					pHurt->ApplyAbsVelocityImpulse( dir );

					if ( !bFlashed )
					{
						color32 red = {128,0,0,128};
						UTIL_ScreenFade( pPlayer, red, 0.5f, 0.1f, FFADE_IN );
					}
					
					// Force the player to drop anyting they were holding
					pPlayer->ForceDropOfCarriedPhysObjects();
				}
				
				// do effect?
			}
			else
			{
				WeaponSound( MELEE_MISS );
			}
		}
		break;
		default:
			BaseClass::Operator_HandleAnimEvent( pEvent, pOperator );
			break;
	}
}
void CNPC_Zombine::GatherGrenadeConditions( void )
{
	if ( m_iGrenadeCount <= 0 )
		return;

	if ( g_flZombineGrenadeTimes > gpGlobals->curtime )
		return;

	if ( m_flGrenadePullTime > gpGlobals->curtime )
		return;

	if ( m_flSuperFastAttackTime >= gpGlobals->curtime )
		return;
	
	if ( HasGrenade() )
		return;

	if ( GetEnemy() == NULL )
		return;

	if ( FVisible( GetEnemy() ) == false )
		return;

	if ( IsSprinting() )
		return;

	if ( IsOnFire() )
		return;
	
	if ( IsRunningDynamicInteraction() == true )
		return;

	if ( m_ActBusyBehavior.IsActive() )
		return;

	//Secobmod FixMe
	//CBasePlayer *pPlayer = AI_GetSinglePlayer();
	CBasePlayer *pPlayer = UTIL_GetNearestPlayer(GetAbsOrigin()); 

	if ( pPlayer && pPlayer->FVisible( this ) )
	{
		float flLengthToPlayer = (pPlayer->GetAbsOrigin() - GetAbsOrigin()).Length();
		float flLengthToEnemy = flLengthToPlayer;

		if ( pPlayer != GetEnemy() )
		{
			flLengthToEnemy = ( GetEnemy()->GetAbsOrigin() - GetAbsOrigin()).Length();
		}

		if ( flLengthToPlayer <= GRENADE_PULL_MAX_DISTANCE && flLengthToEnemy <= GRENADE_PULL_MAX_DISTANCE )
		{
			float flPullChance = 1.0f - ( flLengthToEnemy / GRENADE_PULL_MAX_DISTANCE );
			m_flGrenadePullTime = gpGlobals->curtime + 0.5f;

			if ( flPullChance >= random->RandomFloat( 0.0f, 1.0f ) )
			{
				g_flZombineGrenadeTimes = gpGlobals->curtime + 10.0f;
				SetCondition( COND_ZOMBINE_GRENADE );
			}
		}
	}
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CPropAPC::Event_Killed( const CTakeDamageInfo &info )
{
	m_OnDeath.FireOutput( info.GetAttacker(), this );

	Vector vecAbsMins, vecAbsMaxs;
	CollisionProp()->WorldSpaceAABB( &vecAbsMins, &vecAbsMaxs );

	Vector vecNormalizedMins, vecNormalizedMaxs;
	CollisionProp()->WorldToNormalizedSpace( vecAbsMins, &vecNormalizedMins );
	CollisionProp()->WorldToNormalizedSpace( vecAbsMaxs, &vecNormalizedMaxs );

	Vector vecAbsPoint;
	CPASFilter filter( GetAbsOrigin() );
	for (int i = 0; i < 5; i++)
	{
		CollisionProp()->RandomPointInBounds( vecNormalizedMins, vecNormalizedMaxs, &vecAbsPoint );
		te->Explosion( filter, random->RandomFloat( 0.0, 1.0 ),	&vecAbsPoint, 
			g_sModelIndexFireball, random->RandomInt( 4, 10 ), 
			random->RandomInt( 8, 15 ), 
			( i < 2 ) ? TE_EXPLFLAG_NODLIGHTS : TE_EXPLFLAG_NOPARTICLES | TE_EXPLFLAG_NOFIREBALLSMOKE | TE_EXPLFLAG_NODLIGHTS,
			100, 0 );
	}

	// TODO: make the gibs spawn in sync with the delayed explosions
	int nGibs = random->RandomInt( 1, 4 );
	for ( int i = 0; i < nGibs; i++)
	{
		// Throw a flaming, smoking chunk.
		CGib *pChunk = CREATE_ENTITY( CGib, "gib" );
		pChunk->Spawn( "models/gibs/hgibs.mdl" );
		pChunk->SetBloodColor( DONT_BLEED );

		QAngle vecSpawnAngles;
		vecSpawnAngles.Random( -90, 90 );
		pChunk->SetAbsOrigin( vecAbsPoint );
		pChunk->SetAbsAngles( vecSpawnAngles );

		int nGib = random->RandomInt( 0, APC_MAX_CHUNKS - 1 );
		pChunk->Spawn( s_pChunkModelName[nGib] );
		pChunk->SetOwnerEntity( this );
		pChunk->m_lifeTime = random->RandomFloat( 6.0f, 8.0f );
		pChunk->SetCollisionGroup( COLLISION_GROUP_DEBRIS );
		IPhysicsObject *pPhysicsObject = pChunk->VPhysicsInitNormal( SOLID_VPHYSICS, pChunk->GetSolidFlags(), false );
		
		// Set the velocity
		if ( pPhysicsObject )
		{
			pPhysicsObject->EnableMotion( true );
			Vector vecVelocity;

			QAngle angles;
			angles.x = random->RandomFloat( -20, 20 );
			angles.y = random->RandomFloat( 0, 360 );
			angles.z = 0.0f;
			AngleVectors( angles, &vecVelocity );
			
			vecVelocity *= random->RandomFloat( 300, 900 );
			vecVelocity += GetAbsVelocity();

			AngularImpulse angImpulse;
			angImpulse = RandomAngularImpulse( -180, 180 );

			pChunk->SetAbsVelocity( vecVelocity );
			pPhysicsObject->SetVelocity(&vecVelocity, &angImpulse );
		}

		CEntityFlame *pFlame = CEntityFlame::Create( pChunk, false );
		if ( pFlame != NULL )
		{
			pFlame->SetLifetime( pChunk->m_lifeTime );
		}
	}

	UTIL_ScreenShake( vecAbsPoint, 25.0, 150.0, 1.0, 750.0f, SHAKE_START );

	if( hl2_episodic.GetBool() )
	{
		// EP1 perf hit
		Ignite( 6, false );
	}
	else
	{
		Ignite( 60, false );
	}

	m_lifeState = LIFE_DYING;

	// Spawn a lesser amount if the player is close
	m_iRocketSalvoLeft = DEATH_VOLLEY_ROCKET_COUNT;
	m_flRocketTime = gpGlobals->curtime;
}
Exemple #6
0
//------------------------------------------------------------------------------
// Purpose: Samples the player's inputs and fires outputs based on what buttons
//			are currently held down.
//------------------------------------------------------------------------------
void CGameUI::Think( void )
{
	CBasePlayer *pPlayer = m_player;

	// If player is gone, stop thinking
	if (pPlayer == NULL)
	{
		SetNextThink( TICK_NEVER_THINK );
		return;
	}

	// If we're forcing an update, state with a clean button state
	if ( m_bForceUpdate )
	{
		m_nLastButtonState = pPlayer->m_nButtons;
	}

	// ------------------------------------------------
	// Check that toucher is facing the UI within
	// the field of view tolerance.  If not disconnect
	// ------------------------------------------------
	if (m_flFieldOfView > -1)
	{
		Vector vPlayerFacing;
		pPlayer->EyeVectors( &vPlayerFacing );
		Vector vPlayerToUI =  GetAbsOrigin() - pPlayer->WorldSpaceCenter();
		VectorNormalize(vPlayerToUI);

		float flDotPr = DotProduct(vPlayerFacing,vPlayerToUI);
		if (flDotPr < m_flFieldOfView)
		{
			Deactivate( pPlayer );
			return;
		}
	}

	pPlayer->AddFlag( FL_ONTRAIN );
	SetNextThink( gpGlobals->curtime );

	// Deactivate if they jump or press +use.
	// FIXME: prevent the use from going through in player.cpp
	if ((( pPlayer->m_afButtonPressed & IN_USE ) && ( m_spawnflags & SF_GAMEUI_USE_DEACTIVATES )) ||
		(( pPlayer->m_afButtonPressed & IN_JUMP ) && ( m_spawnflags & SF_GAMEUI_JUMP_DEACTIVATES )))
	{
		Deactivate( pPlayer );
		return;
	}

	// Determine what's different
	int nButtonsChanged = ( pPlayer->m_nButtons ^ m_nLastButtonState );

	//
	// Handle all our possible input triggers
	//

	if ( nButtonsChanged & IN_MOVERIGHT )
	{
		if ( m_nLastButtonState & IN_MOVERIGHT )
		{
			m_unpressedMoveRight.FireOutput( pPlayer, this, 0 );
		}
		else
		{
			m_pressedMoveRight.FireOutput( pPlayer, this, 0 );
		}
	}

	if ( nButtonsChanged & IN_MOVELEFT )
	{
		if ( m_nLastButtonState & IN_MOVELEFT )
		{
			m_unpressedMoveLeft.FireOutput( pPlayer, this, 0 );
		}
		else
		{
			m_pressedMoveLeft.FireOutput( pPlayer, this, 0 );
		}
	}

	if ( nButtonsChanged & IN_FORWARD )
	{
		if ( m_nLastButtonState & IN_FORWARD )
		{
			m_unpressedForward.FireOutput( pPlayer, this, 0 );
		}
		else
		{
			m_pressedForward.FireOutput( pPlayer, this, 0 );
		}
	}

	if ( nButtonsChanged & IN_BACK )
	{
		if ( m_nLastButtonState & IN_BACK )
		{
			m_unpressedBack.FireOutput( pPlayer, this, 0 );
		}
		else
		{
			m_pressedBack.FireOutput( pPlayer, this, 0 );
		}
	}

	if ( nButtonsChanged & IN_ATTACK )
	{
		if ( m_nLastButtonState & IN_ATTACK )
		{
			m_unpressedAttack.FireOutput( pPlayer, this, 0 );
		}
		else
		{
			m_pressedAttack.FireOutput( pPlayer, this, 0 );
		}
	}

	if ( nButtonsChanged & IN_ATTACK2 )
	{
		if ( m_nLastButtonState & IN_ATTACK2 )
		{
			m_unpressedAttack2.FireOutput( pPlayer, this, 0 );
		}
		else
		{
			m_pressedAttack2.FireOutput( pPlayer, this, 0 );
		}
	}

	// Setup for the next frame
	m_nLastButtonState = pPlayer->m_nButtons;

	float x = 0, y = 0, attack = 0, attack2 = 0;
	if ( pPlayer->m_nButtons & IN_MOVERIGHT )
	{
		x = 1;
	}
	else if ( pPlayer->m_nButtons & IN_MOVELEFT )
	{
		x = -1;
	}

	if ( pPlayer->m_nButtons & IN_FORWARD )
	{
		y = 1;
	}
	else if ( pPlayer->m_nButtons & IN_BACK )
	{
		y = -1;
	}

	if ( pPlayer->m_nButtons & IN_ATTACK )
	{
		attack = 1;
	}

	if ( pPlayer->m_nButtons & IN_ATTACK2 )
	{
		attack2 = 1;
	}

	//
	// Fire the analog outputs if they changed.
	//
	if ( m_bForceUpdate || ( m_xaxis.Get() != x ) )
	{
		m_xaxis.Set( x, pPlayer, this );
	}

	if ( m_bForceUpdate || ( m_yaxis.Get() != y ) )
	{
		m_yaxis.Set( y, pPlayer, this );
	}

	if ( m_bForceUpdate || ( m_attackaxis.Get() != attack ) )
	{
		m_attackaxis.Set( attack, pPlayer, this );
	}

	if ( m_bForceUpdate || ( m_attack2axis.Get() != attack2 ) )
	{
		m_attack2axis.Set( attack2, pPlayer, this );
	}

	m_bForceUpdate = false;
}
// CONSIDER: if player in water state, autoset and underwater soundscape? 
void CEnvSoundscape::UpdateForPlayer( ss_update_t &update )
{
	if ( !IsEnabled() )
	{
		if ( update.pCurrentSoundscape == this )
		{
			update.pCurrentSoundscape = NULL;
			update.currentDistance = 0;
			update.bInRange = false;
		}
		return;
	}

	// calc range from sound entity to player
	Vector target = EarPosition();
	float range = (update.playerPosition - target).Length();
	
	if ( update.pCurrentSoundscape == this )
	{
		update.currentDistance = range;
		update.bInRange = false;
		if ( m_flRadius > range || m_flRadius == -1 )
		{
			trace_t tr;

			update.traceCount++;
			UTIL_TraceLine( target, update.playerPosition, MASK_SOLID_BRUSHONLY|MASK_WATER, update.pPlayer, COLLISION_GROUP_NONE, &tr );
			if ( tr.fraction == 1 && !tr.startsolid )
			{
				update.bInRange = true;
			}
		}
	}
	else
	{
		if ( (!update.bInRange || range < update.currentDistance ) && (m_flRadius > range || m_flRadius == -1) )
		{
			trace_t tr;

			update.traceCount++;
			UTIL_TraceLine( target, update.playerPosition, MASK_SOLID_BRUSHONLY|MASK_WATER, update.pPlayer, COLLISION_GROUP_NONE, &tr );

			if ( tr.fraction == 1 && !tr.startsolid )
			{
				audioparams_t &audio = update.pPlayer->GetAudioParams();
				WriteAudioParamsTo( audio );
				update.pCurrentSoundscape = this;
				update.bInRange = true;
				update.currentDistance = range;
			}
		}
	}


	if ( soundscape_debug.GetBool() )
	{
		// draw myself
		NDebugOverlay::Box(GetAbsOrigin(), Vector(-10,-10,-10), Vector(10,10,10),  255, 0, 255, 64, NDEBUG_PERSIST_TILL_NEXT_SERVER );

 		if ( update.pPlayer )
		{
			audioparams_t &audio = update.pPlayer->GetAudioParams();
			if ( audio.entIndex != entindex() )
			{
				if ( InRangeOfPlayer( update.pPlayer ) )
				{
					NDebugOverlay::Line( GetAbsOrigin(), update.pPlayer->WorldSpaceCenter(), 255, 255, 255, true, NDEBUG_PERSIST_TILL_NEXT_SERVER );
				}
				else
				{
					NDebugOverlay::Line( GetAbsOrigin(), update.pPlayer->WorldSpaceCenter(), 255, 0, 0, true, NDEBUG_PERSIST_TILL_NEXT_SERVER  );
				}
			}
			else
			{
				if ( InRangeOfPlayer( update.pPlayer ) )
				{
					NDebugOverlay::Line( GetAbsOrigin(), update.pPlayer->WorldSpaceCenter(), 0, 255, 0, true, NDEBUG_PERSIST_TILL_NEXT_SERVER  );
				}
  				else
				{
					NDebugOverlay::Line( GetAbsOrigin(), update.pPlayer->WorldSpaceCenter(), 255, 170, 0, true, NDEBUG_PERSIST_TILL_NEXT_SERVER  );
				}

				// also draw lines to each sound position.
				// we don't store the number of local sound positions, just a bitvector of which ones are on.
				unsigned int soundbits = audio.localBits.Get();
				float periodic = 2.0f * sin((fmod(gpGlobals->curtime,2.0f) - 1.0f) * M_PI); // = -4f .. 4f
				for (int ii = 0 ; ii < NUM_AUDIO_LOCAL_SOUNDS ; ++ii )
				{
					if ( soundbits & (1 << ii) )
					{
						const Vector &soundLoc = audio.localSound.Get(ii);
						NDebugOverlay::Line( GetAbsOrigin(), soundLoc, 0, 32 , 255 , false, NDEBUG_PERSIST_TILL_NEXT_SERVER );
						NDebugOverlay::Cross3D( soundLoc, 16.0f + periodic, 0, 0, 255, false, NDEBUG_PERSIST_TILL_NEXT_SERVER );
					}
				}
			}
		}

		NDebugOverlay::EntityTextAtPosition( GetAbsOrigin(), 0, STRING(m_soundscapeName), NDEBUG_PERSIST_TILL_NEXT_SERVER );
	}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CCrossbowBolt::BoltTouch( CBaseEntity *pOther )
{
	if ( pOther->IsSolidFlagSet(FSOLID_VOLUME_CONTENTS | FSOLID_TRIGGER) )
	{
		// Some NPCs are triggers that can take damage (like antlion grubs). We should hit them.
		if ( ( pOther->m_takedamage == DAMAGE_NO ) || ( pOther->m_takedamage == DAMAGE_EVENTS_ONLY ) )
			return;
	}

	if ( pOther->m_takedamage != DAMAGE_NO )
	{
		trace_t	tr, tr2;
		tr = BaseClass::GetTouchTrace();
		Vector	vecNormalizedVel = GetAbsVelocity();

		ClearMultiDamage();
		VectorNormalize( vecNormalizedVel );

#if defined(HL2_EPISODIC)
		//!!!HACKHACK - specific hack for ep2_outland_10 to allow crossbow bolts to pass through her bounding box when she's crouched in front of the player
		// (the player thinks they have clear line of sight because Alyx is crouching, but her BBOx is still full-height and blocks crossbow bolts.
		if( GetOwnerEntity() && GetOwnerEntity()->IsPlayer() && pOther->Classify() == CLASS_PLAYER_ALLY_VITAL && FStrEq(STRING(gpGlobals->mapname), "ep2_outland_10") )
		{
			// Change the owner to stop further collisions with Alyx. We do this by making her the owner.
			// The player won't get credit for this kill but at least the bolt won't magically disappear!
			SetOwnerEntity( pOther );
			return;
		}
#endif//HL2_EPISODIC

		if( GetOwnerEntity() && GetOwnerEntity()->IsPlayer() && pOther->IsNPC() )
		{
			CTakeDamageInfo	dmgInfo( this, GetOwnerEntity(), sk_plr_dmg_crossbow.GetFloat(), DMG_NEVERGIB );
			dmgInfo.AdjustPlayerDamageInflictedForSkillLevel();
			CalculateMeleeDamageForce( &dmgInfo, vecNormalizedVel, tr.endpos, 0.7f );
			dmgInfo.SetDamagePosition( tr.endpos );
			pOther->DispatchTraceAttack( dmgInfo, vecNormalizedVel, &tr );

			CBasePlayer *pPlayer = ToBasePlayer( GetOwnerEntity() );
			if ( pPlayer )
			{
				gamestats->Event_WeaponHit( pPlayer, true, "weapon_crossbow", dmgInfo );
			}

		}
		else
		{
			CTakeDamageInfo	dmgInfo( this, GetOwnerEntity(), sk_plr_dmg_crossbow.GetFloat(), DMG_BULLET | DMG_NEVERGIB );
			CalculateMeleeDamageForce( &dmgInfo, vecNormalizedVel, tr.endpos, 0.7f );
			dmgInfo.SetDamagePosition( tr.endpos );
			pOther->DispatchTraceAttack( dmgInfo, vecNormalizedVel, &tr );
		}

		ApplyMultiDamage();

		//Adrian: keep going through the glass.
		if ( pOther->GetCollisionGroup() == COLLISION_GROUP_BREAKABLE_GLASS )
			 return;

		/*if ( !pOther->IsAlive() )
		{
			// We killed it! 
			const surfacedata_t *pdata = physprops->GetSurfaceData( tr.surface.surfaceProps );
			if ( pdata->game.material == CHAR_TEX_GLASS )
			{
				return;
			}
		}*/

		SetAbsVelocity( Vector( 0, 0, 0 ) );

		// play body "thwack" sound
		EmitSound( "Weapon_Crossbow.BoltHitBody" );

		Vector vForward;

		AngleVectors( GetAbsAngles(), &vForward );
		VectorNormalize ( vForward );

		UTIL_TraceLine( GetAbsOrigin(),	GetAbsOrigin() + vForward * 128, MASK_BLOCKLOS, pOther, COLLISION_GROUP_NONE, &tr2 );

		if ( tr2.fraction != 1.0f )
		{
//			NDebugOverlay::Box( tr2.endpos, Vector( -16, -16, -16 ), Vector( 16, 16, 16 ), 0, 255, 0, 0, 10 );
//			NDebugOverlay::Box( GetAbsOrigin(), Vector( -16, -16, -16 ), Vector( 16, 16, 16 ), 0, 0, 255, 0, 10 );

			if ( tr2.m_pEnt == NULL || ( tr2.m_pEnt && tr2.m_pEnt->GetMoveType() == MOVETYPE_NONE ) )
			{
				CEffectData	data;

				data.m_vOrigin = tr2.endpos;
				data.m_vNormal = vForward;
				data.m_nEntIndex = tr2.fraction != 1.0f;
			
				DispatchEffect( "BoltImpact", data );
			}
		}
		
		SetTouch( NULL );
		SetThink( NULL );

		if ( !g_pGameRules->IsMultiplayer() )
		{
			UTIL_Remove( this );
		}
	}
	else
	{
		trace_t	tr;
		tr = BaseClass::GetTouchTrace();

		// See if we struck the world
		if ( pOther->GetMoveType() == MOVETYPE_NONE && !( tr.surface.flags & SURF_SKY ) )
		{
			EmitSound( "Weapon_Crossbow.BoltHitWorld" );

			// if what we hit is static architecture, can stay around for a while.
			Vector vecDir = GetAbsVelocity();
			float speed = VectorNormalize( vecDir );

			// See if we should reflect off this surface
			float hitDot = DotProduct( tr.plane.normal, -vecDir );
			
			if ( ( hitDot < 0.5f ) && ( speed > 100 ) )
			{
				Vector vReflection = 2.0f * tr.plane.normal * hitDot + vecDir;
				
				QAngle reflectAngles;

				VectorAngles( vReflection, reflectAngles );

				SetLocalAngles( reflectAngles );

				SetAbsVelocity( vReflection * speed * 0.75f );

				// Start to sink faster
				SetGravity( 1.0f );
			}
			else
			{
				SetThink( &CCrossbowBolt::SUB_Remove );
				SetNextThink( gpGlobals->curtime + 2.0f );
				
				//FIXME: We actually want to stick (with hierarchy) to what we've hit
				SetMoveType( MOVETYPE_NONE );
			
				Vector vForward;

				AngleVectors( GetAbsAngles(), &vForward );
				VectorNormalize ( vForward );

				CEffectData	data;

				data.m_vOrigin = tr.endpos;
				data.m_vNormal = vForward;
				data.m_nEntIndex = 0;
			
				DispatchEffect( "BoltImpact", data );
				
				UTIL_ImpactTrace( &tr, DMG_BULLET );

				AddEffects( EF_NODRAW );
				SetTouch( NULL );
				SetThink( &CCrossbowBolt::SUB_Remove );
				SetNextThink( gpGlobals->curtime + 2.0f );

				if ( m_pGlowSprite != NULL )
				{
					m_pGlowSprite->TurnOn();
					m_pGlowSprite->FadeAndDie( 3.0f );
				}
			}
			
			// Shoot some sparks
			if ( UTIL_PointContents( GetAbsOrigin() ) != CONTENTS_WATER)
			{
				g_pEffects->Sparks( GetAbsOrigin() );
			}
		}
		else
		{
			// Put a mark unless we've hit the sky
			if ( ( tr.surface.flags & SURF_SKY ) == false )
			{
				UTIL_ImpactTrace( &tr, DMG_BULLET );
			}

			UTIL_Remove( this );
		}
	}

	if ( g_pGameRules->IsMultiplayer() )
	{
//		SetThink( &CCrossbowBolt::ExplodeThink );
//		SetNextThink( gpGlobals->curtime + 0.1f );
	}
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CWeaponCrossbow::FireBolt()
{
	if ( m_iClip1 <= 0 )
	{
		if ( !m_bFireOnEmpty )
			Reload();
		else
		{
			WeaponSound( EMPTY );
			m_flNextPrimaryAttack = 0.15;
		}

		return;
	}

	CBasePlayer *pOwner = ToBasePlayer(GetOwner());
	
	if ( !pOwner )
		return;

#ifndef CLIENT_DLL

	pOwner->RumbleEffect(RUMBLE_357, 0, RUMBLE_FLAG_RESTART);

	Vector vecAiming	= pOwner->GetAutoaimVector(0);
	Vector vecSrc		= pOwner->Weapon_ShootPosition();

	QAngle angAiming;
	VectorAngles( vecAiming, angAiming );

#if defined(HL2_EPISODIC)
	// !!!HACK - the other piece of the Alyx crossbow bolt hack for Outland_10 (see ::BoltTouch() for more detail)
	if( FStrEq(STRING(gpGlobals->mapname), "ep2_outland_10") )
	{
		trace_t tr;
		UTIL_TraceLine( vecSrc, vecSrc + vecAiming * 24.0f, MASK_SOLID, pOwner, COLLISION_GROUP_NONE, &tr );

		if( tr.m_pEnt != NULL && tr.m_pEnt->Classify() == CLASS_PLAYER_ALLY_VITAL )
		{
			// If Alyx is right in front of the player, make sure the bolt starts outside of the player's BBOX, or the bolt
			// will instantly collide with the player after the owner of the bolt is switched to Alyx in ::BoltTouch(). We 
			// avoid this altogether by making it impossible for the bolt to collide with the player.
			vecSrc += vecAiming * 24.0f;
		}
	}
#endif

	CCrossbowBolt *pBolt = CCrossbowBolt::BoltCreate( vecSrc, angAiming, pOwner );

	if ( pOwner->GetWaterLevel() == 3 )
		pBolt->SetAbsVelocity(vecAiming * BOLT_WATER_VELOCITY);
	else
		pBolt->SetAbsVelocity(vecAiming * BOLT_AIR_VELOCITY);

#endif

	m_iClip1--;

	pOwner->ViewPunch(QAngle( -2, 0, 0 ));

	WeaponSound(SINGLE);
	WeaponSound(SPECIAL2);

#ifndef CLIENT_DLL
	CSoundEnt::InsertSound(SOUND_COMBAT, GetAbsOrigin(), 200, 0.2);
#endif

	SendWeaponAnim(ACT_VM_PRIMARYATTACK);

	// HEV suit - indicate out of ammo condition
	if ( !m_iClip1 && pOwner->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 )
		pOwner->SetSuitUpdate("!HEV_AMO0", FALSE, 0);

	m_flNextPrimaryAttack = m_flNextSecondaryAttack	= gpGlobals->curtime + 0.75;

	DoLoadEffect();
	SetChargerState(CHARGER_STATE_DISCHARGE);
}
Exemple #10
0
//-----------------------------------------------------------------------------
// Chooses an item when the player is full
//-----------------------------------------------------------------------------
void CItem_DynamicResupply::SpawnFullItem( CItem_DynamicResupply *pMaster, CBasePlayer *pPlayer, int iDebug )
{
	// Can we not actually spawn the item?
	if ( !HasSpawnFlags(SF_DYNAMICRESUPPLY_ALWAYS_SPAWN) )
		return;

	float flRatio[NUM_AMMO_ITEMS];
	int i;
	float flTotalProb = 0.0f;
	for ( i = 0; i < NUM_AMMO_ITEMS; ++i )
	{
		int iAmmoType = GetAmmoDef()->Index( g_DynamicResupplyAmmoItems[i].sAmmoDef );
		bool bCanSpawn = pPlayer->Weapon_GetWpnForAmmo( iAmmoType ) != NULL;

		if ( bCanSpawn && ( g_DynamicResupplyAmmoItems[i].flFullProbability != 0 ) && ( pMaster->m_flDesiredAmmo[i] != 0.0f ) )
		{
			flTotalProb += g_DynamicResupplyAmmoItems[i].flFullProbability;
			flRatio[i] = flTotalProb;
		}
		else
		{
			flRatio[i] = -1.0f;
		}
	}

	if ( flTotalProb == 0.0f )
	{
		// If we're supposed to fallback to just a health vial, do that and finish.
		if ( pMaster->HasSpawnFlags(SF_DYNAMICRESUPPLY_FALLBACK_TO_VIAL) )
		{
			CBaseEntity::Create( "item_healthvial", GetAbsOrigin(), GetAbsAngles(), this );

			if ( iDebug )
			{
				Msg("Player is full, spawning item_healthvial due to spawnflag.\n");
			}
			return;
		}

		// Otherwise, spawn the first ammo item in the list
		flRatio[0] = 1.0f;
		flTotalProb = 1.0f;
	}
	
	float flChoice = random->RandomFloat( 0.0f, flTotalProb ); 
	for ( i = 0; i < NUM_AMMO_ITEMS; ++i )
	{
		if ( flChoice <= flRatio[i] )
		{
			CBaseEntity::Create( g_DynamicResupplyAmmoItems[i].sEntityName, GetAbsOrigin(), GetAbsAngles(), this );

			if ( iDebug )
			{
				Msg("Player is full, spawning %s \n", g_DynamicResupplyAmmoItems[i].sEntityName );
			}
			return;
		}
	}

	if ( iDebug )
	{
		Msg("Player is full on all health + ammo, is not spawning.\n" );
	}
}
Exemple #11
0
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CSprite::Spawn( void )
{
	SetSolid( SOLID_NONE );
	SetMoveType( MOVETYPE_NONE );
	m_flFrame = 0;

	Precache();
	SetModel( STRING( GetModelName() ) );
	CollisionProp()->SetSurroundingBoundsType( USE_GAME_CODE );

	m_flMaxFrame = (float)modelinfo->GetModelFrameCount( GetModel() ) - 1;
	AddEffects( EF_NOSHADOW | EF_NORECEIVESHADOW );

#if !defined( CLIENT_DLL )
	if ( m_flGlowProxySize > MAX_GLOW_PROXY_SIZE )
	{
		// Clamp on Spawn to prevent per-frame spew
		DevWarning( "env_sprite at setpos %0.0f %0.0f %0.0f has invalid glow size %f - clamping to %f\n",
			GetAbsOrigin().x, GetAbsOrigin().y, GetAbsOrigin().z, m_flGlowProxySize.Get(), MAX_GLOW_PROXY_SIZE );
		m_flGlowProxySize = MAX_GLOW_PROXY_SIZE;
	}
	if ( GetEntityName() != NULL_STRING && !(m_spawnflags & SF_SPRITE_STARTON) )
	{
		TurnOff();
	}
	else
#endif
	{
		TurnOn();
	}
	
	// Worldcraft only sets y rotation, copy to Z
	if ( GetLocalAngles().y != 0 && GetLocalAngles().z == 0 )
	{
		QAngle angles = GetLocalAngles();

		angles.z = angles.y;
		angles.y = 0;

		SetLocalAngles( angles );
	}

	// Clamp our scale if necessary
	float scale = m_flSpriteScale;
	
	if ( scale < 0 || scale > MAX_SPRITE_SCALE )
	{
#if !defined( CLIENT_DLL ) 
		DevMsg( "LEVEL DESIGN ERROR: Sprite %s with bad scale %f [0..%f]\n", GetDebugName(), m_flSpriteScale, MAX_SPRITE_SCALE );
#endif
		scale = clamp( m_flSpriteScale, 0, MAX_SPRITE_SCALE );
	}

	//Set our state
	SetBrightness( GetRenderAlpha() );
	SetScale( scale );

#if defined( CLIENT_DLL )
	m_flStartScale = m_flDestScale = m_flSpriteScale;
	m_nStartBrightness = m_nDestBrightness = m_nBrightness;
#endif

}
Exemple #12
0
void CSqueakGrenade::SuperBounceTouch( CBaseEntity *pOther )
{
	float	flpitch;

	TraceResult tr = UTIL_GetGlobalTrace();

	// don't hit the guy that launched this grenade
	if( pev->owner && pOther->edict() == pev->owner )
		return;

	// at least until we've bounced once
	pev->owner = NULL;

	pev->angles.x = 0;
	pev->angles.z = 0;

	// avoid bouncing too much
	if( m_flNextHit > gpGlobals->time )
		return;

	// higher pitch as squeeker gets closer to detonation time
	flpitch = 155.0 - 60.0 * ( ( m_flDie - gpGlobals->time ) / SQUEEK_DETONATE_DELAY );

	if( pOther->pev->takedamage && m_flNextAttack < gpGlobals->time )
	{
		// attack!

		// make sure it's me who has touched them
		if( tr.pHit == pOther->edict() )
		{
			// and it's not another squeakgrenade
			if( tr.pHit->v.modelindex != pev->modelindex )
			{
				// ALERT( at_console, "hit enemy\n");
				g_MultiDamage.Clear();
				pOther->TraceAttack( CTakeDamageInfo( this, gSkillData.GetSnarkDmgBite(), DMG_SLASH ), gpGlobals->v_forward, &tr );
				if( m_hOwner != NULL )
					g_MultiDamage.ApplyMultiDamage( this, m_hOwner );
				else
					g_MultiDamage.ApplyMultiDamage( this, this );

				pev->dmg += gSkillData.GetSnarkDmgPop(); // add more explosion damage
														 // m_flDie += 2.0; // add more life

														 // make bite sound
				EMIT_SOUND_DYN( this, CHAN_WEAPON, "squeek/sqk_deploy1.wav", 1.0, ATTN_NORM, 0, ( int ) flpitch );
				m_flNextAttack = gpGlobals->time + 0.5;
			}
		}
		else
		{
			// ALERT( at_console, "been hit\n");
		}
	}

	m_flNextHit = gpGlobals->time + 0.1;
	m_flNextHunt = gpGlobals->time;

	if( g_pGameRules->IsMultiplayer() )
	{
		// in multiplayer, we limit how often snarks can make their bounce sounds to prevent overflows.
		if( gpGlobals->time < m_flNextBounceSoundTime )
		{
			// too soon!
			return;
		}
	}

	if( !( pev->flags & FL_ONGROUND ) )
	{
		// play bounce sound
		float flRndSound = RANDOM_FLOAT( 0, 1 );

		if( flRndSound <= 0.33 )
			EMIT_SOUND_DYN( this, CHAN_VOICE, "squeek/sqk_hunt1.wav", 1, ATTN_NORM, 0, ( int ) flpitch );
		else if( flRndSound <= 0.66 )
			EMIT_SOUND_DYN( this, CHAN_VOICE, "squeek/sqk_hunt2.wav", 1, ATTN_NORM, 0, ( int ) flpitch );
		else
			EMIT_SOUND_DYN( this, CHAN_VOICE, "squeek/sqk_hunt3.wav", 1, ATTN_NORM, 0, ( int ) flpitch );
		CSoundEnt::InsertSound( bits_SOUND_COMBAT, GetAbsOrigin(), 256, 0.25 );
	}
	else
	{
		// skittering sound
		CSoundEnt::InsertSound( bits_SOUND_COMBAT, GetAbsOrigin(), 100, 0.1 );
	}

	m_flNextBounceSoundTime = gpGlobals->time + 0.5;// half second.
}
Exemple #13
0
void CSqueakGrenade::HuntThink( void )
{
	// ALERT( at_console, "think\n" );

	if( !IsInWorld() )
	{
		SetTouch( NULL );
		UTIL_Remove( this );
		return;
	}

	StudioFrameAdvance();
	pev->nextthink = gpGlobals->time + 0.1;

	// explode when ready
	if( gpGlobals->time >= m_flDie )
	{
		g_vecAttackDir = pev->velocity.Normalize();
		pev->health = -1;
		Killed( CTakeDamageInfo( this, 0, 0 ), GIB_NORMAL );
		return;
	}

	// float
	if( GetWaterLevel() != WATERLEVEL_DRY )
	{
		if( pev->movetype == MOVETYPE_BOUNCE )
		{
			pev->movetype = MOVETYPE_FLY;
		}
		pev->velocity = pev->velocity * 0.9;
		pev->velocity.z += 8.0;
	}
	else if( pev->movetype == MOVETYPE_FLY )
	{
		pev->movetype = MOVETYPE_BOUNCE;
	}

	// return if not time to hunt
	if( m_flNextHunt > gpGlobals->time )
		return;

	m_flNextHunt = gpGlobals->time + 2.0;

	CBaseEntity *pOther = NULL;
	Vector vecDir;
	TraceResult tr;

	Vector vecFlat = pev->velocity;
	vecFlat.z = 0;
	vecFlat = vecFlat.Normalize();

	UTIL_MakeVectors( pev->angles );

	if( m_hEnemy == NULL || !m_hEnemy->IsAlive() )
	{
		// find target, bounce a bit towards it.
		Look( 512 );
		m_hEnemy = BestVisibleEnemy();
	}

	// squeek if it's about time blow up
	if( ( m_flDie - gpGlobals->time <= 0.5 ) && ( m_flDie - gpGlobals->time >= 0.3 ) )
	{
		EMIT_SOUND_DYN( this, CHAN_VOICE, "squeek/sqk_die1.wav", 1, ATTN_NORM, 0, 100 + RANDOM_LONG( 0, 0x3F ) );
		CSoundEnt::InsertSound( bits_SOUND_COMBAT, GetAbsOrigin(), 256, 0.25 );
	}

	// higher pitch as squeeker gets closer to detonation time
	float flpitch = 155.0 - 60.0 * ( ( m_flDie - gpGlobals->time ) / SQUEEK_DETONATE_DELAY );
	if( flpitch < 80 )
		flpitch = 80;

	if( m_hEnemy != NULL )
	{
		if( FVisible( m_hEnemy ) )
		{
			vecDir = m_hEnemy->EyePosition() - GetAbsOrigin();
			m_vecTarget = vecDir.Normalize();
		}

		float flVel = pev->velocity.Length();
		float flAdj = 50.0 / ( flVel + 10.0 );

		if( flAdj > 1.2 )
			flAdj = 1.2;

		// ALERT( at_console, "think : enemy\n");

		// ALERT( at_console, "%.0f %.2f %.2f %.2f\n", flVel, m_vecTarget.x, m_vecTarget.y, m_vecTarget.z );

		pev->velocity = pev->velocity * flAdj + m_vecTarget * 300;
	}

	if( pev->flags & FL_ONGROUND )
	{
		pev->avelocity = Vector( 0, 0, 0 );
	}
	else
	{
		if( pev->avelocity == Vector( 0, 0, 0 ) )
		{
			pev->avelocity.x = RANDOM_FLOAT( -100, 100 );
			pev->avelocity.z = RANDOM_FLOAT( -100, 100 );
		}
	}

	if( ( GetAbsOrigin() - m_posPrev ).Length() < 1.0 )
	{
		pev->velocity.x = RANDOM_FLOAT( -100, 100 );
		pev->velocity.y = RANDOM_FLOAT( -100, 100 );
	}
	m_posPrev = GetAbsOrigin();

	pev->angles = UTIL_VecToAngles( pev->velocity );
	pev->angles.z = 0;
	pev->angles.x = 0;
}
//------------------------------------------------------------------------------
// Purpose :
//------------------------------------------------------------------------------
void CLookDoor::MoveThink(void)
{
	// --------------------------------
	// Make sure we have a looker
	// --------------------------------
	if (m_hLooker == NULL)
	{
		m_hLooker = (CBaseEntity*)gEntList.FindEntityByName( NULL, m_target );

		if (m_hLooker == NULL)
		{
			return;
		}
	}

	//--------------------------------------
	// Calculate an orgin for the door
	//--------------------------------------
	Vector vOrigin = WorldSpaceCenter() - GetAbsOrigin();

	// If FROM_OPEN flag is set, door proximity is measured
	// from the open and not the closed position
	if (FBitSet (m_spawnflags, SF_LDOOR_FROM_OPEN))
	{
		vOrigin += m_vecPosition2;
	}

	// ------------------------------------------------------
	//  First add movement based on proximity
	// ------------------------------------------------------
	float flProxMove = 0;
	if (m_flProximityDistance > 0)
	{
		float flDist = (m_hLooker->GetAbsOrigin() - vOrigin).Length()-m_flProximityOffset;
		if (flDist < 0) flDist = 0;

		if (flDist < m_flProximityDistance)
		{
			if (FBitSet (m_spawnflags, SF_LDOOR_THRESHOLD))
			{
				flProxMove = 1.0;
			}
			else
			{
				flProxMove = 1-flDist/m_flProximityDistance;
			}
		}
	}

	// ------------------------------------------------------
	//  Then add movement based on view angle
	// ------------------------------------------------------
	float flViewMove = 0;
	if (m_flFieldOfView > 0)
	{
		// ----------------------------------------
		// Check that toucher is facing the target
		// ----------------------------------------
		Assert( dynamic_cast< CBaseCombatCharacter* >( m_hLooker.Get() ) );
		CBaseCombatCharacter* pBCC = (CBaseCombatCharacter*)m_hLooker.Get();
		Vector vTouchDir = pBCC->EyeDirection3D( );
		Vector vTargetDir =  vOrigin - pBCC->EyePosition();
		VectorNormalize(vTargetDir);

		float flDotPr = DotProduct(vTouchDir,vTargetDir);
		if (flDotPr < m_flFieldOfView)
		{
			flViewMove = 0.0;
		}
		else
		{
			flViewMove = (flDotPr-m_flFieldOfView)/(1.0 - m_flFieldOfView);
		}
	}

	//---------------------------------------
	// Summate the two moves
	//---------------------------------------
	float flMove = flProxMove + flViewMove;
	if (flMove > 1.0)
	{
		flMove = 1.0;
	}

	// If behavior is inverted do the reverse
	if (FBitSet (m_spawnflags, SF_LDOOR_INVERT))
	{
		flMove = 1-flMove;
	}

	// Move the door
	SetPosition( flMove );
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
bool CNPC_VehicleDriver::OverridePathMove( float flInterval )
{
	// Setup our initial path data if we've just started running a path
	if ( !m_pCurrentWaypoint )
	{
		m_vecPrevPoint = GetAbsOrigin();
		m_vecPrevPrevPoint = GetAbsOrigin();
		m_vecDesiredPosition = GetNavigator()->GetCurWaypointPos();	
		CalculatePostPoints();
	
		// Init our two waypoints
		m_Waypoints[0] = new CVehicleWaypoint( m_vecPrevPrevPoint, m_vecPrevPoint, m_vecDesiredPosition, m_vecPostPoint );
		m_Waypoints[1] = new CVehicleWaypoint( m_vecPrevPoint, m_vecDesiredPosition, m_vecPostPoint, m_vecPostPostPoint );
		m_pCurrentWaypoint = m_Waypoints[0];
		m_pNextWaypoint = m_Waypoints[1];

		m_flDistanceAlongSpline = 0.2;
	}

	// Have we reached our target? See if we've passed the current waypoint's plane.
	Vector vecAbsMins, vecAbsMaxs;
	CollisionProp()->WorldSpaceAABB( &vecAbsMins, &vecAbsMaxs );
	if ( BoxOnPlaneSide( vecAbsMins, vecAbsMaxs, &m_pCurrentWaypoint->planeWaypoint ) == 3 )
	{
		if ( WaypointReached() )
			return true;
	}

	// Did we bypass it and reach the next one already?
	if ( m_pNextWaypoint && BoxOnPlaneSide( vecAbsMins, vecAbsMaxs, &m_pNextWaypoint->planeWaypoint ) == 3 )
	{
		if ( WaypointReached() )
			return true;
	}

	// We may have just teleported, so check to make sure we have a waypoint
	if ( !m_pCurrentWaypoint || !m_pNextWaypoint )
		return false;

	// Figure out which spline we're trucking along
	CVehicleWaypoint *pCurrentSplineBeingTraversed = m_pCurrentWaypoint;
	if ( m_flDistanceAlongSpline > 1 )
	{
		pCurrentSplineBeingTraversed = m_pNextWaypoint;
	}

	// Get our current speed, and check it against the length of the spline to know how far to advance our marker
	AngularImpulse angVel;
	Vector vecVelocity;
	IPhysicsObject *pVehiclePhysics = m_hVehicleEntity->VPhysicsGetObject();

	if( !pVehiclePhysics )
	{
		// I think my vehicle has been destroyed.
		return false;
	}

	pVehiclePhysics->GetVelocity( &vecVelocity, &angVel );
	float flSpeed = vecVelocity.Length();
	float flIncTime = gpGlobals->curtime - GetLastThink();
	float flIncrement = flIncTime * (flSpeed / pCurrentSplineBeingTraversed->GetLength());

	// Now advance our point along the spline
	m_flDistanceAlongSpline = clamp( m_flDistanceAlongSpline + flIncrement, 0, 2);
	if ( m_flDistanceAlongSpline > 1 )
	{
		// We crossed the spline boundary
		pCurrentSplineBeingTraversed = m_pNextWaypoint;
	}

	Vector vSplinePoint = pCurrentSplineBeingTraversed->GetPointAt( m_flDistanceAlongSpline > 1 ? m_flDistanceAlongSpline-1 : m_flDistanceAlongSpline );
	Vector vSplineTangent = pCurrentSplineBeingTraversed->GetTangentAt( m_flDistanceAlongSpline > 1 ? m_flDistanceAlongSpline-1 : m_flDistanceAlongSpline );

	// Now that we've got the target spline point & tangent, use it to decide what our desired velocity is.
	// If we're close to the tangent, just use the tangent. Otherwise, Lerp towards it.
	Vector vecToDesired = (vSplinePoint - GetAbsOrigin());
	float flDistToDesired = VectorNormalize( vecToDesired );
	float flTangentLength = VectorNormalize( vSplineTangent );

	if ( flDistToDesired > (flTangentLength * 0.75) )
	{
		m_vecDesiredVelocity = vecToDesired * flTangentLength;
	}
	else
	{
		VectorLerp( vSplineTangent, vecToDesired * flTangentLength, (flDistToDesired / (flTangentLength * 0.5)), m_vecDesiredVelocity );
	}

	// Decrease speed according to the turn we're trying to make
	Vector vecRight;
	m_hVehicleEntity->GetVectors( NULL, &vecRight, NULL );
	Vector vecNormVel = m_vecDesiredVelocity;
	VectorNormalize( vecNormVel );
	float flDotRight = DotProduct( vecRight, vecNormVel );
	flSpeed = (1.0 - fabs(flDotRight));
	// Don't go slower than we've been told to go
	if ( flSpeed < m_flDriversMinSpeed )
	{
		flSpeed = m_flDriversMinSpeed;
	}
	m_vecDesiredVelocity = vecNormVel * (flSpeed * m_flMaxSpeed);

	// Bunch o'debug
	if ( g_debug_vehicledriver.GetInt() & DRIVER_DEBUG_PATH )
	{
		NDebugOverlay::Box( m_vecPrevPrevPoint, -Vector(15,15,15), Vector(15,15,15), 192,0,0, true, 0.1);
		NDebugOverlay::Box( m_vecPrevPoint, -Vector(20,20,20), Vector(20,20,20), 255,0,0, true, 0.1);
		NDebugOverlay::Box( m_vecPostPoint, -Vector(20,20,20), Vector(20,20,20), 0,192,0, true, 0.1);
		NDebugOverlay::Box( m_vecPostPostPoint, -Vector(20,20,20), Vector(20,20,20), 0,128,0, true, 0.1);
		NDebugOverlay::Box( vSplinePoint, -Vector(10,10,10), Vector(10,10,10), 0,0,255, true, 0.1);
		NDebugOverlay::Line( vSplinePoint, vSplinePoint + (vSplineTangent * 40), 0,0,255, true, 0.1);

		//NDebugOverlay::HorzArrow( pCurrentSplineBeingTraversed->splinePoints[0], pCurrentSplineBeingTraversed->splinePoints[1], 30, 255,255,255,0, false, 0.1f );
		//NDebugOverlay::HorzArrow( pCurrentSplineBeingTraversed->splinePoints[1], pCurrentSplineBeingTraversed->splinePoints[2], 20, 255,255,255,0, false, 0.1f );
		//NDebugOverlay::HorzArrow( pCurrentSplineBeingTraversed->splinePoints[2], pCurrentSplineBeingTraversed->splinePoints[3], 10, 255,255,255,0, false, 0.1f );

		// Draw the plane we're checking against for waypoint passing
		Vector vecPlaneRight;
		CrossProduct( m_pCurrentWaypoint->planeWaypoint.normal, Vector(0,0,1), vecPlaneRight );
		Vector vecPlane = m_pCurrentWaypoint->splinePoints[2];
		NDebugOverlay::Line( vecPlane + (vecPlaneRight * -100), vecPlane + (vecPlaneRight * 100), 255,0,0, true, 0.1);

		// Draw the next plane too
		CrossProduct( m_pNextWaypoint->planeWaypoint.normal, Vector(0,0,1), vecPlaneRight );
		vecPlane = m_pNextWaypoint->splinePoints[2];
		NDebugOverlay::Line( vecPlane + (vecPlaneRight * -100), vecPlane + (vecPlaneRight * 100), 192,0,0, true, 0.1);
	}

	if ( g_debug_vehicledriver.GetInt() & DRIVER_DEBUG_PATH_SPLINE )
	{
		for ( int i = 0; i < 10; i++ )
		{
			Vector vecTarget = m_pCurrentWaypoint->GetPointAt( 0.1 * i );
			Vector vecTangent = m_pCurrentWaypoint->GetTangentAt( 0.1 * i );
			VectorNormalize(vecTangent);
			NDebugOverlay::Box( vecTarget, -Vector(10,10,10), Vector(10,10,10), 255,0,0, true, 0.1 );
			NDebugOverlay::Line( vecTarget, vecTarget + (vecTangent * 10), 255,255,0, true, 0.1);
		}
	}

	return true;
}
Exemple #16
0
//-----------------------------------------------------------------------------
// Run all of the AI for elements within the range iStart to iEnd 
//-----------------------------------------------------------------------------
void CNPC_Blob::DoBlobBatchedAI( int iStart, int iEnd )
{
	float flInterval = gpGlobals->curtime - GetLastThink();

	// Local fields for sin-wave movement variance
	float flMySine;
	float flAmplitude = npc_blob_sin_amplitude.GetFloat();
	float flMyAmplitude;
	Vector vecRight;
	Vector vecForward;

	// Local fields for attract/repel
	float minDistSqr = Square( m_flMinElementDist );
	float flBlobSpeed = blob_element_speed.GetFloat();
	float flSpeed;

	// Local fields for speed limiting
	float flMinSpeed = blob_element_speed.GetFloat() * 0.5f;
	float flMaxSpeed = blob_element_speed.GetFloat() * 1.5f;
	bool bEnforceSpeedLimit;
	bool bEnforceRelativePositions;
	bool bDoMovementVariation;
	bool bDoOrientation = npc_blob_use_orientation.GetBool();
	float flIdleSpeedFactor = npc_blob_idle_speed_factor.GetFloat();

	// Group cohesion
	float flBlobRadiusSqr = Square( blob_radius.GetFloat() + 48.0f ); // Four feet of fudge

	// Build a right-hand vector along which we'll add some sine wave data to give each
	// element a unique insect-like undulation along an axis perpendicular to their path,
	// which makes the entire group look far less orderly
	if( GetEnemy() != NULL )
	{
		// If I have an enemy, the right-hand vector is perpendicular to a straight line 
		// from the group's centroid to the enemy's origin.
		vecForward = GetEnemy()->GetAbsOrigin() - m_vecCentroid;
		VectorNormalize( vecForward );
		vecRight.x = vecForward.y;
		vecRight.y = -vecForward.x;
	}
	else
	{
		// If there is no enemy, wobble along the axis from the centroid to me.
		vecForward = GetAbsOrigin() - m_vecCentroid;
		VectorNormalize( vecForward );
		vecRight.x = vecForward.y;
		vecRight.y = -vecForward.x;
	}

	//--
	// MAIN LOOP - Run all of the elements in the set iStart to iEnd
	//--
	for( int i = iStart ; i < iEnd ; i++ )
	{
		CBlobElement *pThisElement = m_Elements[ i ];

		//--
		// Initial movement
		//--
		// Start out with bEnforceSpeedLimit set to false. This is because an element
		// can't overspeed if it's moving undisturbed towards its target entity or 
		// target location. An element can only under or overspeed when it is repelled 
		// by multiple other elements in the group. See "Relative Positions" below.
		//
		// Initialize some 'defaults' that may be changed for each iteration of this loop
		bEnforceSpeedLimit = false;
		bEnforceRelativePositions = true;
		bDoMovementVariation = true;
		flSpeed = flBlobSpeed;

		switch( pThisElement->GetActiveMovementRule() )
		{
		case BLOB_MOVE_DONT_MOVE:
			{
				pThisElement->SetElementVelocity( vec3_origin, true );

				trace_t tr;
				Vector vecOrigin = pThisElement->GetAbsOrigin();

				UTIL_TraceLine( vecOrigin, vecOrigin - Vector( 0, 0, 16), MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );

				if( tr.fraction < 1.0f )
				{
					QAngle angles;

					VectorAngles( tr.plane.normal, angles );

					float flSwap = angles.x;

					angles.x = -angles.y;
					angles.y = flSwap;

					pThisElement->SetAbsAngles( angles );
				}
			}
			continue;
			break;

		case BLOB_MOVE_TO_TARGET_LOCATION:
			{
				Vector vecDiff = pThisElement->GetAbsOrigin() - pThisElement->m_vecTargetLocation;

				if( vecDiff.Length2DSqr() <= Square(80.0f) )
				{
					// Don't shove this guy around any more, let him get to his goal position.
					flSpeed *= 0.5f;
					bEnforceRelativePositions = false;
					bDoMovementVariation = false;
				}

				pThisElement->MoveTowardsTargetLocation( flSpeed );
			}
			break;

		case BLOB_MOVE_TO_TARGET_ENTITY:
			{
				if( !IsMoving() && GetEnemy() == NULL )
				{
					if( pThisElement->GetAbsOrigin().DistToSqr( GetAbsOrigin() ) <= flBlobRadiusSqr )
					{
						flSpeed = (flSpeed * flIdleSpeedFactor) * pThisElement->m_flRandomEightyPercent;
					}
				}
				pThisElement->MoveTowardsTargetEntity( flSpeed );
			}
			break;

		default:
			Msg("ERROR: Blob Element with unspecified Movement Rule\n");
			break;
		}

		//---
		// Relative positions
		//--
		// Check this element against ALL other elements. If the two elements are closer
		// than the allowed minimum distance, repel this element away. (The other element
		// will repel when its AI runs). A single element can be repelled by many other 
		// elements. This is why bEnforceSpeedLimit is set to true if any of the repelling
		// code runs for this element. Multiple attempts to repel an element in the same
		// direction will cause overspeed. Conflicting attempts to repel an element in opposite
		// directions will cause underspeed.
		Vector vecDir = Vector( 0, 0, 0 );
		Vector vecThisElementOrigin = pThisElement->GetAbsOrigin();

		if( bEnforceRelativePositions )
		{
			for( int j = 0 ; j < m_Elements.Count() ; j++ )
			{
				// This is the innermost loop! We should optimize here, if anywhere.

				// If this element is on the wall, then don't be repelled by anyone. Repelling
				// elements that are trying to climb a wall usually make them look like they 
				// fall off the wall a few times while climbing.
				if( pThisElement->m_bOnWall )
					continue;

				CBlobElement *pThatElement = m_Elements[ j ];
				if( i != j )
				{
					Vector vecThatElementOrigin = pThatElement->GetAbsOrigin();
					float distSqr = vecThisElementOrigin.DistToSqr( vecThatElementOrigin );

					if( distSqr < minDistSqr )
					{
						// Too close to the other element. Move away.
						float flRepelSpeed;
						Vector vecRepelDir = ( vecThisElementOrigin - vecThatElementOrigin );

						vecRepelDir.NormalizeInPlace();
						flRepelSpeed = (flSpeed * ( 1.0f - ( distSqr / minDistSqr ) ) ) * pThatElement->GetSinePhase(); 
						pThisElement->AddElementVelocity( vecRepelDir * flRepelSpeed, true );

						// Since we altered this element's velocity after it was initially set, there's a chance
						// that the sums of multiple vectors will cause the element to over or underspeed, so 
						// mark it for speed limit enforcement
						bEnforceSpeedLimit = true;
					}
				}
			}
		}

		//--
		// Movement variation
		//--
		if( bDoMovementVariation )
		{
			flMySine = sin( gpGlobals->curtime * pThisElement->GetSineFrequency() );
			flMyAmplitude = flAmplitude * pThisElement->GetSineAmplitude();
			pThisElement->AddElementVelocity( vecRight * (flMySine * flMyAmplitude), true );
		}

		// Avoidance
		for( int a = 0 ; a < m_iNumAvoidOrigins ; a++ )
		{
			Vector vecAvoidDir = pThisElement->GetAbsOrigin() - m_vecAvoidOrigin[ a ];

			if( vecAvoidDir.LengthSqr() <= (m_flAvoidRadiusSqr * pThisElement->m_flRandomEightyPercent) )
			{
				VectorNormalize( vecAvoidDir );
				pThisElement->AddElementVelocity( vecAvoidDir * (flSpeed * 2.0f), true );
				break;
			}
		}

		//--
		// Speed limits
		//---
		if( bEnforceSpeedLimit == true )
		{
			pThisElement->EnforceSpeedLimits( flMinSpeed, flMaxSpeed );
		}

		//--
		// Wall crawling
		//--
		pThisElement->ModifyVelocityForSurface( flInterval, flSpeed );

		// For identifying stuck elements.
		pThisElement->m_vecPrevOrigin = pThisElement->GetAbsOrigin(); 

		pThisElement->m_flDistFromCentroidSqr = pThisElement->m_vecPrevOrigin.DistToSqr( m_vecCentroid );

		// Orientation
		if( bDoOrientation )
		{
			QAngle angles;
			VectorAngles( pThisElement->GetAbsVelocity(), angles );
			pThisElement->SetAbsAngles( angles );
		}

/*
		//--
		// Stragglers/Group integrity
		//
		if( pThisElement->m_flDistFromCentroidSqr > flStragglerDistSqr )
		{
			NDebugOverlay::Line( pThisElement->GetAbsOrigin(), m_vecCentroid, 255, 0, 0, false, 0.025f );
		}
*/
	}
}
//-----------------------------------------------------------------------------
// Purpose: This takes the current place the NPC's trying to get to, figures out
//			what keys to press to get the vehicle to go there, and then sends
//			them to the vehicle.
//-----------------------------------------------------------------------------
void CNPC_VehicleDriver::DriveVehicle( void )
{
	AngularImpulse angVel;
	Vector vecVelocity;
	IPhysicsObject *pVehiclePhysics = m_hVehicleEntity->VPhysicsGetObject();
	if ( !pVehiclePhysics )
		return;
	pVehiclePhysics->GetVelocity( &vecVelocity, &angVel );
	float flSpeed = VectorNormalize( vecVelocity );

	// If we have no target position to drive to, brake to a halt
	if ( !m_flMaxSpeed || m_vecDesiredPosition == vec3_origin )
	{
		if ( flSpeed > 1 )
		{
			m_pVehicleInterface->NPC_Brake();
		}
		return;
	}

	if ( g_debug_vehicledriver.GetInt() & DRIVER_DEBUG_PATH )
	{
		NDebugOverlay::Box(m_vecDesiredPosition, -Vector(20,20,20), Vector(20,20,20), 0,255,0, true, 0.1);
		NDebugOverlay::Line(GetAbsOrigin(), GetAbsOrigin() + m_vecDesiredVelocity, 0,255,0, true, 0.1);
	}

	m_flGoalSpeed = VectorNormalize(m_vecDesiredVelocity);

	// Is our target in front or behind us?
	Vector vecForward, vecRight;
	m_hVehicleEntity->GetVectors( &vecForward, &vecRight, NULL );
	float flDot = DotProduct( vecForward, m_vecDesiredVelocity );
	bool bBehind = ( flDot < 0 );
	float flVelDot = DotProduct( vecVelocity, m_vecDesiredVelocity );
	bool bGoingWrongWay = ( flVelDot < 0 );

	// Figure out whether we should accelerate / decelerate
	if ( bGoingWrongWay || (flSpeed < m_flGoalSpeed) )
	{
		// If it's behind us, go backwards not forwards
		if ( bBehind )
		{
			m_pVehicleInterface->NPC_ThrottleReverse();
		}
		else
		{
			m_pVehicleInterface->NPC_ThrottleForward();
		}
	}
	else
	{
		// Brake if we're go significantly too fast
		if ( (flSpeed - 200) > m_flGoalSpeed )
		{
			m_pVehicleInterface->NPC_Brake();
		}
		else
		{
			m_pVehicleInterface->NPC_ThrottleCenter();
		}
	}

	// Do we need to turn?
	float flDotRight = DotProduct( vecRight, m_vecDesiredVelocity );
	if ( bBehind )
	{
		// If we're driving backwards, flip our turning
		flDotRight *= -1;
	}
	// Map it to the vehicle's steering
	flDotRight *= (m_flSteering / 90);

	if ( flDotRight < 0 )
	{
		// Turn left
		m_pVehicleInterface->NPC_TurnLeft( -flDotRight );
	}
	else if ( flDotRight > 0 )
	{
		// Turn right
		m_pVehicleInterface->NPC_TurnRight( flDotRight );
	}
	else
	{
		m_pVehicleInterface->NPC_TurnCenter();
	}
}
void CNPC_Roller::Unstick( void )
{
	CBaseEntity		*pList[ 16 ];
	IPhysicsObject	*pPhysObj;
	int				i;
	Vector			vecDirToEnemy;
	Vector			vecDirToObject;

	m_flWaitFinished = gpGlobals->curtime;

	int count = UTIL_EntitiesInBox( pList, 16, GetAbsOrigin() - vecDelta, GetAbsOrigin() + vecDelta, 0 );

	m_vecUnstickDirection = vec3_origin;

	for( i = 0 ; i < count ; i++ )
	{
		pPhysObj = pList[ i ]->VPhysicsGetObject();

		if( !pPhysObj || pList[ i ]->m_iClassname == m_iClassname )
		{
			// Only consider physics objects. Exclude rollers.
			continue;
		}

		if( pPhysObj->GetMass() <= ROLLER_MAX_PUSH_MASS )
		{
			// Try to bash this physics object.
			trace_t tr;

			AI_TraceLine( GetAbsOrigin(), pList[ i ]->GetAbsOrigin(), MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); 

			if( tr.fraction == 1.0 || tr.m_pEnt == pList[ i ] )
			{
				// Roll towards this item if the trace hits nothing, or
				// the trace hits the object.
				Vector vecBashDir;

				vecBashDir = pList[ i ]->GetAbsOrigin() - GetAbsOrigin();
				VectorNormalize( vecBashDir );
				vecBashDir.z = 0.0;

				//NDebugOverlay::Line( GetAbsOrigin(), pList[ i ]->GetAbsOrigin(), 0,255,0, true, 2 );

				m_vecUnstickDirection = vecBashDir * 80;

				return;
			}
		}
	}

	// No physics objects. Just pick a direction with some clearance and go there.

#define ROLLER_UNSTICK_DIST 80
	Vector vecDirections[ 4 ] = 
	{
		Vector(  0,	ROLLER_UNSTICK_DIST, 0 ),
		Vector(  ROLLER_UNSTICK_DIST,	0, 0 ),
		Vector(  0, -ROLLER_UNSTICK_DIST, 0 ),
		Vector( -ROLLER_UNSTICK_DIST,  0, 0 )
	};

	trace_t tr;

	for( i = 0 ; i < 4 ; i++ )
	{
		AI_TraceLine( GetAbsOrigin(), GetAbsOrigin() + vecDirections[ i ], MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); 

		if( tr.fraction == 1.0 )
		{
			m_vecUnstickDirection = vecDirections[ i ];

			//NDebugOverlay::Line( GetLocalOrigin(), GetLocalOrigin() + m_vecUnstickDirection, 255,255,0, true, 2 );

			// Roll in this direction for a couple of seconds.
			Msg( "unsticking!\n" );
			return;
		}
	}
}
	void AddEntity( void )
	{
		Vector	direction = GetAbsOrigin() - m_vecLastOrigin;
		float	flDist = VectorNormalize( direction );

		int	numBubbles = (int) ( flDist * BUBBLES_PER_INCH );

		if ( numBubbles < 1 )
			numBubbles = 1;

		// Make bubbles
		SimpleParticle *sParticle;

		Vector	offset;

		for ( int i = 0; i < numBubbles; i++ )
		{
			offset = m_vecLastOrigin + ( direction * ( flDist / numBubbles ) * i ) + RandomVector( -2.5f, 2.5f );

			sParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), m_pEmitter->GetPMaterial( "effects/bubble" ), offset );

			if ( sParticle )
			{
				sParticle->m_flLifetime		= 0.0f;
				sParticle->m_flDieTime		= random->RandomFloat( 0.75f, 1.25f );

				sParticle->m_flRoll			= 0;
				sParticle->m_flRollDelta	= 0;

				unsigned char color = random->RandomInt( 128, 255 );

				sParticle->m_uchColor[0]	= color;
				sParticle->m_uchColor[1]	= color;
				sParticle->m_uchColor[2]	= color;
				sParticle->m_uchStartAlpha	= 255;
				sParticle->m_uchEndAlpha	= 0;
				sParticle->m_uchStartSize	= random->RandomInt( 1, 2 );
				sParticle->m_uchEndSize		= sParticle->m_uchStartSize;
				
				sParticle->m_vecVelocity	= ( direction * 64.0f ) + Vector( 0, 0, 32 );
			}
			
			sParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), m_pEmitter->GetPMaterial( "effects/splash2" ), offset );

			if ( sParticle )
			{
				sParticle->m_flLifetime		= 0.0f;
				sParticle->m_flDieTime		= 0.2f;

				sParticle->m_flRoll			= random->RandomInt( 0, 360 );
				sParticle->m_flRollDelta	= random->RandomInt( -4, 4 );;

				unsigned char color = random->RandomInt( 200, 255 );

				sParticle->m_uchColor[0]	= color;
				sParticle->m_uchColor[1]	= color;
				sParticle->m_uchColor[2]	= color;
				sParticle->m_uchStartAlpha	= 128;
				sParticle->m_uchEndAlpha	= 0;
				sParticle->m_uchStartSize	= 2;
				sParticle->m_uchEndSize		= sParticle->m_uchStartSize * 4;
				
				sParticle->m_vecVelocity	= ( direction * 64.0f ) + Vector( 0, 0, 32 );
			}
		}

		// Save our last position
		m_vecLastOrigin = GetAbsOrigin();

		BaseClass::AddEntity();
	}
//-----------------------------------------------------------------------------
// Purpose: Stick to an entity (using hierarchy if we can)
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CWeaponStriderBuster::StickToEntity( CBaseEntity *pOther )
{
	// Make sure the object is travelling fast enough to stick
	if ( m_flCollisionSpeedSqr > 50 && !m_bNoseDiving )
	{
		// See if this is a valid strider bit
		if ( ShouldStickToEntity( pOther ) )
		{
			// Attempt to constraint to it
			if ( CreateConstraintToObject( pOther ) )
			{
				// Only works for striders, at the moment
				CBaseEntity *pFollowParent = pOther->GetOwnerEntity();
				if ( pFollowParent == NULL )
					return false;

				// Allows us to identify our constrained object later
				SetOwnerEntity( pFollowParent );

				// Make a sound
				EmitSound( "Weapon_StriderBuster.StickToEntity" );
				
				DispatchParticleEffect( "striderbuster_attach", GetAbsOrigin(), GetAbsAngles(), NULL );

				if( striderbuster_use_particle_flare.GetBool() )
				{
					// We don't have to save any pointers or handles to this because it's parented to the buster.
					// So it will die when the buster dies. Yay.
					CParticleSystem *pFlare = (CParticleSystem *) CreateEntityByName( "info_particle_system" );
					
					if ( pFlare != NULL )
					{
						pFlare->KeyValue( "start_active", "1" );
						pFlare->KeyValue( "effect_name", "striderbuster_attached_pulse" );
						pFlare->SetParent( this );
						pFlare->SetLocalOrigin( vec3_origin );
						DispatchSpawn( pFlare );
						pFlare->Activate();
					}
				}
				else
				{
					// Create a glow sprite
					m_hGlowSprite = CSprite::SpriteCreate( "sprites/orangeflare1.vmt", GetLocalOrigin(), false );

					Assert( m_hGlowSprite );
					if ( m_hGlowSprite != NULL )
					{
						m_hGlowSprite->TurnOn();
						m_hGlowSprite->SetTransparency( kRenderWorldGlow, 255, 255, 255, 255, kRenderFxNoDissipation );
						m_hGlowSprite->SetAbsOrigin( GetAbsOrigin() );
						m_hGlowSprite->SetScale( 5.0f );
						m_hGlowSprite->m_nRenderFX = kRenderFxStrobeFaster;
						m_hGlowSprite->SetGlowProxySize( 16.0f );
						m_hGlowSprite->SetParent( this );
					}
				}

				// Stop touching things
				SetTouch( NULL );

				// Must be a strider
				CNPC_Strider *pStrider = dynamic_cast<CNPC_Strider *>(pFollowParent);
				if ( pStrider == NULL )
					return false;

				// Notify the strider we're attaching to him
				pStrider->StriderBusterAttached( this );
				
				m_OnAttachToStrider.FireOutput( this, this );

				// Start the ping sound.
				SetContextThink( &CWeaponStriderBuster::BusterPingThink, gpGlobals->curtime + BUSTER_PING_SOUND_FREQ, s_pBusterPingThinkContext );
				
				// Don't autodelete this one!
				WeaponManager_RemoveManaged( this );

				return true;
			}

			return false;
		}
	}

	return false;
}
// CONSIDER: if player in water state, autoset and underwater soundscape? 
void CEnvSoundscape::Update()
{
	bool bUpdated = UpdatePlayersInPVS();

	if ( !IsEnabled() )
		return;

	// Only update soundscapes in multiplayer when the PVS gets updated
	if ( g_pGameRules->IsMultiplayer() && !bUpdated && !soundscape_debug.GetBool() )
		return;

	bool bDebugThis = soundscape_debug.GetInt() == 1;

	for ( int i=0; i < m_hPlayersInPVS.Count(); i++ )
	{
		CBasePlayer *pPlayer = m_hPlayersInPVS[i];
		if ( !pPlayer )
			continue;

		if ( !InRangeOfPlayer( pPlayer ) )
			continue;

		// check to see if this is the sound entity that is 
		// currently affecting this player
		audioparams_t &audio = pPlayer->GetAudioParams();

		// if we got this far, we're looking at an entity that is contending
		// for current player sound. the closest entity to player wins.
		CEnvSoundscape *pCurrent = (CEnvSoundscape *)audio.ent.Get();
		if ( !pCurrent || 
			!pCurrent->IsEnabled() || 
			!pCurrent->InRangeOfPlayer( pPlayer ) ) 
		{
			// The old one is obscured or out of range.. take over.
			WriteAudioParamsTo( audio );
		}
		else if ( pCurrent && 
			EarPosition().DistTo( pPlayer->EarPosition() ) < pCurrent->EarPosition().DistTo( pPlayer->EarPosition() ) )
		{
			// new entity is closer to player, so it wins.
			WriteAudioParamsTo( audio );
		}

		if ( !bDebugThis )
		{
			bDebugThis = soundscape_debug.GetInt() == 2;
		}
	} 

	if ( bDebugThis )
	{

		// draw myself
		NDebugOverlay::Box(GetAbsOrigin(), Vector(-10,-10,-10), Vector(10,10,10),  255, 0, 255, 64, NDEBUG_PERSIST_TILL_NEXT_SERVER );

		// Don't use GetLocalPlayer(), because that prevents multiplayer games using this for testing with a single client in the game
		CBasePlayer *pPlayer = UTIL_PlayerByIndex(1);
 		if ( pPlayer )
		{
			audioparams_t &audio = pPlayer->GetAudioParams();
			if ( audio.ent.Get() != this )
			{
				if ( InRangeOfPlayer( pPlayer ) )
				{
					NDebugOverlay::Line( GetAbsOrigin(), pPlayer->WorldSpaceCenter(), 255, 255, 255, true, NDEBUG_PERSIST_TILL_NEXT_SERVER );
				}
				else
				{
					NDebugOverlay::Line( GetAbsOrigin(), pPlayer->WorldSpaceCenter(), 255, 0, 0, true, NDEBUG_PERSIST_TILL_NEXT_SERVER  );
				}
			}
			else
			{
				if ( InRangeOfPlayer( pPlayer ) )
				{
					NDebugOverlay::Line( GetAbsOrigin(), pPlayer->WorldSpaceCenter(), 0, 255, 0, true, NDEBUG_PERSIST_TILL_NEXT_SERVER  );
				}
  				else
				{
					NDebugOverlay::Line( GetAbsOrigin(), pPlayer->WorldSpaceCenter(), 255, 170, 0, true, NDEBUG_PERSIST_TILL_NEXT_SERVER  );
				}

				// also draw lines to each sound position.
				// we don't store the number of local sound positions, just a bitvector of which ones are on.
				unsigned int soundbits = audio.localBits.Get();
				float periodic = 2.0f * sin((fmod(gpGlobals->curtime,2.0f) - 1.0f) * M_PI); // = -4f .. 4f
				for (int ii = 0 ; ii < NUM_AUDIO_LOCAL_SOUNDS ; ++ii )
				{
					if ( soundbits & (1 << ii) )
					{
						const Vector &soundLoc = audio.localSound.Get(ii);
						NDebugOverlay::Line( GetAbsOrigin(), soundLoc, 0, 32 , 255 , false, NDEBUG_PERSIST_TILL_NEXT_SERVER );
						NDebugOverlay::Cross3D( soundLoc, 16.0f + periodic, 0, 0, 255, false, NDEBUG_PERSIST_TILL_NEXT_SERVER );
					}
				}
			}
		}

		NDebugOverlay::EntityTextAtPosition( GetAbsOrigin(), 0, STRING(m_soundscapeName), NDEBUG_PERSIST_TILL_NEXT_SERVER );
	}

}
//-----------------------------------------------------------------------------
// Purpose: Intercept damage and decide whether or not we want to trigger
// Input  : &info - 
//-----------------------------------------------------------------------------
int CWeaponStriderBuster::OnTakeDamage( const CTakeDamageInfo &info )
{
	// If we're attached, any damage from the player makes us trigger
	CBaseEntity *pInflictor = info.GetInflictor();
	CBaseEntity *pAttacker = info.GetAttacker();
	bool bInflictorIsPlayer = ( pInflictor != NULL && pInflictor->IsPlayer() );
	bool bAttackerIsPlayer = ( pAttacker != NULL && pAttacker->IsPlayer() );

	if ( GetParent() && GetParent()->ClassMatches( g_iszVehicle ) )
	{
		return 0;
	}

	// Only take damage from a player, for the moment
	if ( striderbuster_allow_all_damage.GetBool() || ( IsAttachedToStrider() && ( bAttackerIsPlayer || bInflictorIsPlayer ) ) )
	{
		Detonate();
		return 0;
	}

	if ( pAttacker && ( pAttacker->Classify() == CLASS_COMBINE || pAttacker->Classify() == CLASS_COMBINE_HUNTER ) )
	{
		if ( VPhysicsGetObject() && !VPhysicsGetObject()->IsMoveable() )
		{
			return 0;
		}
	}

	// Hunters are able to destroy strider busters
	if ( hunter_hate_held_striderbusters.GetBool() || hunter_hate_thrown_striderbusters.GetBool() || hunter_hate_attached_striderbusters.GetBool() )
	{
		if ( ( GetHealth() > 0 ) && ( pInflictor != NULL ) && FClassnameIs( pInflictor, "hunter_flechette" ) )
		{
			//
			// Flechette impacts don't hurt the striderbuster unless it's attached to a strider,
			// but the explosions always do. This is so that held or thrown striderbusters fly
			// awry because of the flechette, but attached striderbusters break instantly to make
			// the hunters more effective at defending the strider.
			//
			if ( IsAttachedToStrider() || !( info.GetDamageType() & DMG_NEVERGIB ) )
			{
				if( striderbuster_die_detach.GetBool() && IsAttachedToStrider() )
				{
					// Make the buster fall off and break.
					m_takedamage = DAMAGE_NO;

					CNPC_Strider *pStrider = dynamic_cast<CNPC_Strider *>(GetOwnerEntity());
					Assert( pStrider != NULL );
					pStrider->StriderBusterDetached( this );
					DestroyConstraint();

					// Amplify some lateral force.
					Vector vecForce = info.GetDamageForce();
					vecForce.z = 0.0f;
					VPhysicsGetObject()->ApplyForceCenter( vecForce * 5.0f );

					SetContextThink( NULL, gpGlobals->curtime, s_pBusterPingThinkContext );

					SetThink( &CWeaponStriderBuster::BusterDetachThink );
					SetNextThink( gpGlobals->curtime );
					m_iBusterFlags |= STRIDERBUSTER_FLAG_KNOCKED_OFF_STRIDER;

					return 0;
				}
				else
				{
					// Destroy the buster in place
					// Make sure they know it blew up prematurely.
					EmitSound( "Weapon_StriderBuster.Dud_Detonate" );
					DispatchParticleEffect( "striderbuster_break_flechette", GetAbsOrigin(), GetAbsAngles() );
					SetHealth( 0 );

					Shatter( info.GetAttacker() );
					return 0;
				}
			}

			if ( info.GetDamage() < 5 )
			{
				bool bFirst = ( m_CarryAngles.x == 45 && m_CarryAngles.y == 0 && m_CarryAngles.z == 0);
				float sinTime = sin( gpGlobals->curtime );
				bool bSubtractX = ( bFirst ) ? ( sinTime < 0 ) : ( m_CarryAngles.x < 45 );

				m_CarryAngles.x += ( 10.0 + 10.0 * fabsf( sinTime ) + random->RandomFloat( -2.5, 2.5 ) + random->RandomFloat( -2.5, 2.5 ) ) * ( ( bSubtractX ) ? -1.0 : 1.0 );
				m_CarryAngles.y = 15 * ( sin( gpGlobals->curtime ) + cos( gpGlobals->curtime * 0.5 ) ) * .5  + random->RandomFloat( -15, 15 );
				m_CarryAngles.z = 7.5 * ( sin( gpGlobals->curtime ) + sin( gpGlobals->curtime * 2.0 ) ) * .5 + random->RandomFloat( -7.5, 7.5 );
			}

			return 1;
		}
	}
	
	// Allow crushing damage
	if ( info.GetDamageType() & DMG_CRUSH )
		return BaseClass::OnTakeDamage( info );

	return 0;
}
Exemple #23
0
	virtual Vector BodyTarget( const Vector &posSrc, bool bNoisy = true ) { return GetAbsOrigin(); }
//-----------------------------------------------------------------------------
// Purpose: Give the buster a slight attraction to striders.
//			Ported back from the magnade.
//-----------------------------------------------------------------------------
void CWeaponStriderBuster::BusterFlyThink()
{
	if (IsAttachedToStrider())
		return; // early out. Think no more.

	// If we're nosediving, forget about magnetism.
	if ( m_bNoseDiving )
	{
		if ( VPhysicsGetObject() )
			VPhysicsGetObject()->ApplyForceCenter( Vector( 0, 0, striderbuster_dive_force.GetFloat() ) );
		SetNextThink(gpGlobals->curtime + 0.01f);
		return;
	}

	// seek?	
	const float magradius = 38.0 * sk_striderbuster_magnet_multiplier.GetFloat(); // radius of strider hull times multiplier
	if (magradius > 0 &&
		GetMoveType() == MOVETYPE_VPHYSICS &&
		VPhysicsGetObject()
		)
	{
		// find the nearest enemy.
		CBaseEntity *pList[16];
		Vector origin = GetAbsOrigin();

		// do a find in box ( a little faster than sphere )
		int count;
		{
			Vector mins,maxs;
			mins = origin; 
			mins -= magradius;
			
			maxs = origin; 
			maxs += magradius;

			count = UTIL_EntitiesInBox(pList, 16, mins, maxs, FL_NPC); 
		}

		float magradiusSq = Square( magradius );	
		float nearestDistSq = magradiusSq + 1;
		int bestFit = -1;
		Vector toTarget; // will be garbage unless something good is found
		CNPC_Strider *pBestStrider  = NULL;

		for ( int ii = 0 ; ii < count ; ++ii )
		{
			CNPC_Strider *pStrider = dynamic_cast<CNPC_Strider *>(pList[ii]);
			if ( pStrider && !pStrider->CarriedByDropship() ) // ShouldStickToEntity() doesn't work because the strider NPC isn't what we glue to
			{
				// get distance squared
				VectorSubtract( pStrider->GetAdjustedOrigin(), GetAbsOrigin(), toTarget );

				//NDebugOverlay::Line( GetAbsOrigin(), GetAbsOrigin() + toTarget, 128, 0, 128, false, 0.1 );

				float dSq = toTarget.LengthSqr();
				if (dSq < nearestDistSq)
				{
					bestFit = ii; nearestDistSq = dSq;
					pBestStrider = pStrider;
				}
			}
		}

		if (bestFit >= 0) // we found something and should attract towards it. (hysterisis later?)
		{
			if ( striderbuster_debugseek.GetBool() )
			{
				NDebugOverlay::Circle( GetAbsOrigin() + toTarget, magradius, 255, 255, 255, 255, true, .1 );
				NDebugOverlay::Cross3D( GetAbsOrigin() + toTarget, magradius, 255, 255, 255, true, .1 );
			}

			// force magnitude. 
			float magnitude = GetMass() * striderbuster_magnetic_force_strider.GetFloat();
			int falloff = striderbuster_falloff_power.GetInt();
			switch (falloff) 
			{
			case 1:
				VPhysicsGetObject()->ApplyForceCenter( toTarget * (magnitude / nearestDistSq) ); // dividing through by distance squared normalizes toTarget and gives a linear falloff
				break;
			case 2:
				VPhysicsGetObject()->ApplyForceCenter( toTarget * (magnitude / (nearestDistSq * sqrtf(nearestDistSq))) ); // dividing through by distance cubed normalizes toTarget and gives a quadratic falloff
				break;
			case 3:
				VPhysicsGetObject()->ApplyForceCenter( toTarget * (magnitude / (nearestDistSq * nearestDistSq)) ); // dividing through by distance fourth normalizes toTarget and gives a cubic falloff
				break;
			case 4:
				{
					Vector toTarget;
					pBestStrider->GetAttachment( "buster_target", toTarget );

					if ( striderbuster_debugseek.GetBool() )
					{
						NDebugOverlay::Cross3D( toTarget, magradius, 255, 0, 255, true, .1 );
						NDebugOverlay::Cross3D( toTarget, magradius, 255, 0, 255, true, .1 );
					}

					toTarget -= GetAbsOrigin();
					toTarget.NormalizeInPlace();
					VPhysicsGetObject()->ApplyForceCenter( toTarget * magnitude );

				}
				break;
			default: // arbitrary powers
				VPhysicsGetObject()->ApplyForceCenter( toTarget * (magnitude * powf(nearestDistSq,(falloff+1.0f)/2)) );  // square root for distance instead of squared, add one to normalize toTarget 
				break;
			}
		}

		SetNextThink(gpGlobals->curtime + 0.01f);
	}
}
//-----------------------------------------------------------------------------
// Purpose: Draws the object
//-----------------------------------------------------------------------------
int C_NPC_Barnacle::InternalDrawModel( int flags )
{
	if ( !GetModel() )
		return 0;

	// Make sure hdr is valid for drawing
	if ( !GetModelPtr() )
		return 0;

	// UNDONE: With a bit of work on the model->world transform, we can probably
	// move the frustum culling into the client DLL entirely.  Then TestVisibility()
	// can just return true/false and only be called when frustumcull is set.
	if ( flags & STUDIO_FRUSTUMCULL )
	{
		switch ( TestVisibility() )
		{
		// not visible, don't draw
		case VIS_NOT_VISIBLE:
			return 0;
		
		// definitely visible, disable engine check
		case VIS_IS_VISIBLE:
			flags &= ~STUDIO_FRUSTUMCULL;
			break;
		
		default:
		case VIS_USE_ENGINE:
			break;
		}
	}

	Vector vecMins, vecMaxs;
	GetRenderBounds( vecMins, vecMaxs );
	int drawn = modelrender->DrawModel( 
		flags, 
		this,
		GetModelInstance(),
		index, 
		GetModel(),
		GetAbsOrigin(),
		GetAbsAngles(),
		GetSequence(),
		m_nSkin,
		m_nBody,
		m_nHitboxSet,
		&GetAbsMins(),
		&GetAbsMaxs() );

	if ( vcollide_wireframe.GetBool() )
	{
		if ( IsRagdoll() )
		{
			m_pRagdoll->DrawWireframe();
		}
		else
		{
			vcollide_t *pCollide = modelinfo->GetVCollide( GetModelIndex() );
			if ( pCollide && pCollide->solidCount == 1 )
			{
				static color32 debugColor = {0,255,255,0};
				matrix3x4_t matrix;
				AngleMatrix( GetAbsAngles(), GetAbsOrigin(), matrix );
				engine->DebugDrawPhysCollide( pCollide->solids[0], NULL, matrix, debugColor );
			}
		}
	}

	return drawn;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CNPC_VehicleDriver::RunTask( const Task_t *pTask )
{
	switch( pTask->iTask )
	{
	case TASK_RANGE_ATTACK1:
		{
			// Vehicle driver has no animations, so fire a burst at the target
			CBaseEntity *pEnemy = GetEnemy();
			if ( pEnemy )
			{
				// TODO: Get a bodytarget from the firing point of the gun in the vehicle
				Vector vecTarget = GetEnemy()->BodyTarget( GetAbsOrigin(), false );
				m_pVehicleInterface->NPC_AimPrimaryWeapon( vecTarget );
				m_pVehicleInterface->NPC_PrimaryFire();
				TaskComplete();
			}
			else
			{
				TaskFail(FAIL_NO_ENEMY);
				return;
			}
		}
		break;

	case TASK_RANGE_ATTACK2:
		{
			// Vehicle driver has no animations, so fire a burst at the target
			CBaseEntity *pEnemy = GetEnemy();
			if ( pEnemy )
			{
				// TODO: Get a bodytarget from the firing point of the gun in the vehicle
				Vector vecTarget = GetEnemy()->BodyTarget( GetAbsOrigin(), false );
				m_pVehicleInterface->NPC_AimSecondaryWeapon( vecTarget );
				m_pVehicleInterface->NPC_SecondaryFire();
				TaskComplete();
			}
			else
			{
				TaskFail(FAIL_NO_ENEMY);
				return;
			}
		}
		break;

	case TASK_WAIT_FOR_MOVEMENT:
		{
			BaseClass::RunTask( pTask );

			if ( HasCondition(COND_SEE_ENEMY) )
			{
				// we can see the enemy
				if ( HasCondition(COND_CAN_RANGE_ATTACK2) )
				{
					ChainRunTask( TASK_RANGE_ATTACK2, pTask->flTaskData );
				}
				if ( HasCondition(COND_CAN_RANGE_ATTACK1) )
				{
					ChainRunTask( TASK_RANGE_ATTACK1, pTask->flTaskData );
				}
			}
		}
		break;

	default:
		BaseClass::RunTask( pTask );
		break;
	}
}
int CWeaponStunStick::WeaponMeleeAttack1Condition( float flDot, float flDist )
{
	// Attempt to lead the target (needed because citizens can't hit manhacks with the crowbar!)
	CAI_BaseNPC *pNPC	= GetOwner()->MyNPCPointer();
	CBaseEntity *pEnemy = pNPC->GetEnemy();
	if (!pEnemy)
		return COND_NONE;

	Vector vecVelocity;
	AngularImpulse angVelocity;
	pEnemy->GetVelocity( &vecVelocity, &angVelocity );

	// Project where the enemy will be in a little while, add some randomness so he doesn't always hit
	float dt = sk_crowbar_lead_time.GetFloat();
	dt += random->RandomFloat( -0.3f, 0.2f );
	if ( dt < 0.0f )
		dt = 0.0f;

	Vector vecExtrapolatedPos;
	VectorMA( pEnemy->WorldSpaceCenter(), dt, vecVelocity, vecExtrapolatedPos );

	Vector vecDelta;
	VectorSubtract( vecExtrapolatedPos, pNPC->WorldSpaceCenter(), vecDelta );

	if ( fabs( vecDelta.z ) > 70 )
	{
		return COND_TOO_FAR_TO_ATTACK;
	}

	Vector vecForward = pNPC->BodyDirection2D( );
	vecDelta.z = 0.0f;
	float flExtrapolatedDot = DotProduct2D( vecDelta.AsVector2D(), vecForward.AsVector2D() );
	if ((flDot < 0.7) && (flExtrapolatedDot < 0.7))
	{
		return COND_NOT_FACING_ATTACK;
	}

	float flExtrapolatedDist = Vector2DNormalize( vecDelta.AsVector2D() );

	if( pEnemy->IsPlayer() )
	{
		//Vector vecDir = pEnemy->GetSmoothedVelocity();
		//float flSpeed = VectorNormalize( vecDir );

		// If player will be in front of me in one-half second, clock his arse.
		Vector vecProjectEnemy = pEnemy->GetAbsOrigin() + (pEnemy->GetAbsVelocity() * 0.35);
		Vector vecProjectMe = GetAbsOrigin();

		if( (vecProjectMe - vecProjectEnemy).Length2D() <= 48.0f )
		{
			return COND_CAN_MELEE_ATTACK1;
		}
	}
/*
	if( metropolice_move_and_melee.GetBool() )
	{
		if( pNPC->IsMoving() )
		{
			flTargetDist *= 1.5f;
		}
	}
*/
	float flTargetDist = 48.0f;
	if ((flDist > flTargetDist) && (flExtrapolatedDist > flTargetDist))
	{
		return COND_TOO_FAR_TO_ATTACK;
	}

	return COND_CAN_MELEE_ATTACK1;
}
//-----------------------------------------------------------------------------
// Purpose: We've hit a waypoint. Handle it, and return true if this is the
//			end of the path.
//-----------------------------------------------------------------------------
bool CNPC_VehicleDriver::WaypointReached( void )
{
	// We reached our current waypoint.
	m_vecPrevPrevPoint = m_vecPrevPoint;
	m_vecPrevPoint = GetAbsOrigin();

	// If we've got to our goal, we're done here.
	if ( GetNavigator()->CurWaypointIsGoal() )
	{
		// Necessary for InPass outputs to be fired, is a no-op otherwise
		GetNavigator()->AdvancePath();
	
		// Stop pathing
		ClearWaypoints();
		TaskComplete();
		SetGoalEnt( NULL );
		return true;
	}

	AI_Waypoint_t *pCurWaypoint = GetNavigator()->GetPath()->GetCurWaypoint();
	if ( !pCurWaypoint )
		return false;

	// Check to see if the waypoint wants us to change speed
	if ( pCurWaypoint->Flags() & bits_WP_TO_PATHCORNER )
	{
		CBaseEntity *pEntity = pCurWaypoint->hPathCorner;
		if ( pEntity )
		{
			if ( pEntity->m_flSpeed > 0 )
			{
				if ( pEntity->m_flSpeed <= 1.0 )
				{
					m_flDriversMaxSpeed = pEntity->m_flSpeed;
					RecalculateSpeeds();
				}
				else
				{
					Warning("path_track %s tried to tell the npc_vehicledriver to set speed to %.3f. npc_vehicledriver only accepts values between 0 and 1.\n", STRING(pEntity->GetEntityName()), pEntity->m_flSpeed );
				}
			}
		}
	}

	// Get the waypoints for the next part of the path
	GetNavigator()->AdvancePath();
	if ( !GetNavigator()->GetPath()->GetCurWaypoint() )
	{
		ClearWaypoints();
		TaskComplete();
		SetGoalEnt( NULL );
		return true;
	}

	m_vecDesiredPosition = GetNavigator()->GetCurWaypointPos();	
	CalculatePostPoints();

	// Move to the next waypoint
	delete m_pCurrentWaypoint;
	m_pCurrentWaypoint = m_pNextWaypoint;
	m_Waypoints[1] = new CVehicleWaypoint( m_vecPrevPoint, m_vecDesiredPosition, m_vecPostPoint, m_vecPostPostPoint );
	m_pNextWaypoint = m_Waypoints[1];

	// Drop the spline marker back
	m_flDistanceAlongSpline = MAX( 0, m_flDistanceAlongSpline - 1.0 );

	CheckForTeleport();

	return false;
}
Exemple #29
0
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_FireSmoke::AddFlames( void )
{
#if PARTICLE_FIRE

	if ( ( gpGlobals->frametime != 0.0f ) && ( m_flScaleRegister > 0.0f ) )
	{

		Vector	offset;
		float	scalar;

		scalar = 32.0f*m_flScaleRegister;
		offset[0] = Helper_RandomFloat( -scalar, scalar );
		offset[1] = Helper_RandomFloat( -scalar, scalar );
		offset[2] = 0.0f;

		CSmartPtr<CSimpleEmitter> pEmitter = CSimpleEmitter::Create( "C_FireSmoke" );
		pEmitter->SetSortOrigin( GetAbsOrigin()+offset );

		SimpleParticle *sParticle;

		//for ( int i = 0; i < 1; i++ )
		{
			scalar = 32.0f*m_flScaleRegister;
			offset[0] = Helper_RandomFloat( -scalar, scalar );
			offset[1] = Helper_RandomFloat( -scalar, scalar );
			offset[2] = 12.0f*m_flScaleRegister;

			sParticle = (SimpleParticle *) pEmitter->AddParticle( sizeof(SimpleParticle), pEmitter->GetPMaterial( VarArgs("sprites/flamelet%d", Helper_RandomInt( 1, 5 ) ) ), GetAbsOrigin()+offset );

			if ( sParticle )
			{
				sParticle->m_flLifetime		= 0.0f;
				sParticle->m_flDieTime		= 0.25f;

				sParticle->m_flRoll			= Helper_RandomInt( 0, 360 );
				sParticle->m_flRollDelta	= Helper_RandomFloat( -4.0f, 4.0f );

				float alpha = Helper_RandomInt( 128, 255 );

				sParticle->m_uchColor[0]	= alpha;
				sParticle->m_uchColor[1]	= alpha;
				sParticle->m_uchColor[2]	= alpha;
				sParticle->m_uchStartAlpha	= 255;
				sParticle->m_uchEndAlpha	= 0;
				sParticle->m_uchStartSize	= 64.0f*m_flScaleRegister;
				sParticle->m_uchEndSize		= 0;
				
				float speedScale = ((GetAbsOrigin()+offset)-GetAbsOrigin()).Length2D() / (32.0f*m_flScaleRegister);
				sParticle->m_vecVelocity	= Vector( Helper_RandomFloat( -32.0f, 32.0f ), Helper_RandomFloat( -32.0f, 32.0f ), Helper_RandomFloat( 32.0f, 128.0f )*speedScale );
			}
		}

		pEmitter->Release();
	}

#endif

//#if !PARTICLE_FIRE

	float alpha	= 1.0f;

	//Update the child flame alpha
	for ( int i = 0; i < NUM_CHILD_FLAMES; i++ )
	{
		if ( m_entFlames[i].GetScale() > 1e-3f )
		{
			m_entFlames[i].SetRenderColor( ( 255.0f * alpha ), ( 255.0f * alpha ), ( 255.0f * alpha ) );
			m_entFlames[i].SetBrightness( 255.0f * alpha );

			Assert( m_entFlames[i].GetRenderHandle() != INVALID_CLIENT_RENDER_HANDLE );
			m_entFlames[i].AddToLeafSystem();
		}
	}

	if ( m_nFlags & bitsFIRESMOKE_VISIBLE_FROM_ABOVE )
	{
		for ( int i = 0; i < NUM_CHILD_FLAMES; i++ )
		{
			if ( m_entFlamesFromAbove[i].GetScale() > 1e-3f )
			{
				m_entFlamesFromAbove[i].SetRenderColor( ( 255.0f * alpha ), ( 255.0f * alpha ), ( 255.0f * alpha ) );
				m_entFlamesFromAbove[i].SetBrightness( 255.0f * alpha );

				Assert( m_entFlamesFromAbove[i].GetRenderHandle() != INVALID_CLIENT_RENDER_HANDLE );
				m_entFlamesFromAbove[i].AddToLeafSystem();
			}
		}
	}

//#endif

}
Exemple #30
0
void CBreakable::Precache( void )
{
	const char *pGibName = "WoodChunks";

    switch (m_Material) 
	{
	case matWood:
		pGibName = "WoodChunks";
		break;

	case matUnbreakableGlass:
	case matGlass:
		pGibName = "GlassChunks";
		break;

	case matMetal:
		pGibName = "MetalChunks";
		break;

	case matRocks:
		pGibName = "ConcreteChunks";
		break;

#ifdef HL1_DLL
	case matComputer:
		pGibName = "ComputerGibs";
		break;

	case matCeilingTile:
		pGibName = "CeilingTile";
		break;

	case matFlesh:
		pGibName = "FleshGibs";
		break;

	case matCinderBlock:
		pGibName = "CinderBlocks";
		break;

	case matWeb:
		pGibName = "WebGibs";
		break;
#else

	case matCinderBlock:
		pGibName = "ConcreteChunks";
		break;
#endif

	default:
		Warning("%s (%s) at (%.3f %.3f %.3f) using obsolete or unknown material type.\n", GetClassname(), GetDebugName(), GetAbsOrigin().x, GetAbsOrigin().y, GetAbsOrigin().z );
		pGibName = "WoodChunks";
		break;
	}

	if ( m_iszGibModel != NULL_STRING )
	{
		pGibName = STRING(m_iszGibModel);

#ifdef HL1_DLL
		PrecacheModel( pGibName );
#endif
	}

	m_iszModelName = MAKE_STRING( pGibName );

	// Precache the spawn item's data
	if ( !CommandLine()->CheckParm("-makereslists"))
	{
		if ( m_iszSpawnObject != NULL_STRING )
		{
			UTIL_PrecacheOther( STRING( m_iszSpawnObject ) );
		}
	}
	else
	{
		// Actually, precache all possible objects...
		for ( size_t i = 0; i < ARRAYSIZE(pSpawnObjects) ; ++i )
		{
			if ( !pSpawnObjects[ i ] )
				continue;

			if ( !Q_strnicmp( pSpawnObjects[ i ], "unused", Q_strlen( "unused" ) ) )
				continue;

			UTIL_PrecacheOther( pSpawnObjects[ i ] );
		}	
	}

	PrecacheScriptSound( "Breakable.MatGlass" );
	PrecacheScriptSound( "Breakable.MatWood" );
	PrecacheScriptSound( "Breakable.MatMetal" );
	PrecacheScriptSound( "Breakable.MatFlesh" );
	PrecacheScriptSound( "Breakable.MatConcrete" );
	PrecacheScriptSound( "Breakable.Computer" );
	PrecacheScriptSound( "Breakable.Crate" );
	PrecacheScriptSound( "Breakable.Glass" );
	PrecacheScriptSound( "Breakable.Metal" );
	PrecacheScriptSound( "Breakable.Flesh" );
	PrecacheScriptSound( "Breakable.Concrete" );
	PrecacheScriptSound( "Breakable.Ceiling" );
}