Beispiel #1
0
void CGrenade::SG_Smoke(void)
{
	Vector vecDir;
	float flSmokeInterval[2];
	int iMaxSmokePuffs;

	if (UTIL_PointContents(pev->origin) != CONTENTS_WATER)
	{
		UTIL_MakeVectors(pev->angles);
		vecDir = gpGlobals->v_forward * RANDOM_FLOAT(3, 8);
		iMaxSmokePuffs = (int)(RANDOM_FLOAT(1.5, 3.5) * 100);
		flSmokeInterval[0] = vecDir.x * cos((float)m_angle * (180 / M_PI)) - vecDir.y * sin((float)m_angle * (180 / M_PI));
		flSmokeInterval[1] = vecDir.x * sin((float)m_angle * (180 / M_PI)) + vecDir.y * cos((float)m_angle * (180 / M_PI));
		m_angle = (m_angle + 30) % 360;
		PLAYBACK_EVENT_FULL(0, NULL, m_usEvent, 0, pev->origin, m_vSmokeDetonate, flSmokeInterval[0], flSmokeInterval[1], iMaxSmokePuffs, 4, m_bLightSmoke, 6);
	}
	else
		UTIL_Bubbles(pev->origin - Vector(64, 64, 64), pev->origin + Vector(64, 64, 64), 100);

	if (m_SGSmoke <= 20)
	{
		pev->nextthink = gpGlobals->time + 1;
		SetThink(&CGrenade::SG_Smoke);
		m_SGSmoke++;
	}
	else
	{
		pev->effects |= EF_NODRAW;
		UTIL_Remove(this);
	}
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CFlare::FlareThink( void )
{
	float	deltaTime = ( m_flTimeBurnOut - gpGlobals->curtime );

	if ( !m_bInActiveList && ( ( deltaTime > FLARE_BLIND_TIME ) || ( m_flTimeBurnOut == -1.0f ) ) )
	{
		AddToActiveFlares();
	}

	if ( m_flTimeBurnOut != -1.0f )
	{
		//Fading away
		if ( ( deltaTime <= FLARE_DECAY_TIME ) && ( m_bFading == false ) )
		{
			m_bFading = true;
			CSoundEnvelopeController::GetController().SoundChangePitch( m_pBurnSound, 60, deltaTime );
			CSoundEnvelopeController::GetController().SoundFadeOut( m_pBurnSound, deltaTime );
		}

		// if flare is no longer bright, remove it from active flare list
		if ( m_bInActiveList && ( deltaTime <= FLARE_BLIND_TIME ) )
		{
			RemoveFromActiveFlares();
		}

		//Burned out
		if ( m_flTimeBurnOut < gpGlobals->curtime )
		{
			UTIL_Remove( this );
			return;
		}
	}
	
	//Act differently underwater
	if ( GetWaterLevel() > 1 )
	{
		UTIL_Bubbles( GetAbsOrigin() + Vector( -2, -2, -2 ), GetAbsOrigin() + Vector( 2, 2, 2 ), 1 );
		m_bSmoke = false;
	}
	else
	{
		//Shoot sparks
		if ( random->RandomInt( 0, 8 ) == 1 )
		{
			g_pEffects->Sparks( GetAbsOrigin() );
		}
	}

	//Next update
	SetNextThink( gpGlobals->curtime + 0.1f );
}
Beispiel #3
0
//=========================================================
// HandleAnimEvent - catches the monster-specific messages
// that occur when tagged animation frames are played.
//=========================================================
void CIchthyosaur :: HandleAnimEvent( MonsterEvent_t *pEvent )
{
	int bDidAttack = FALSE;
	switch( pEvent->event )
	{
	case ICHTHYOSAUR_AE_SHAKE_RIGHT:
	case ICHTHYOSAUR_AE_SHAKE_LEFT:
		{
			if (m_hEnemy != NULL && FVisible( m_hEnemy ))
			{
				CBaseEntity *pHurt = m_hEnemy;

				if (m_flEnemyTouched < gpGlobals->time - 0.2 && (m_hEnemy->BodyTarget( pev->origin ) - pev->origin).Length() > (32+16+32))
					break;

				Vector vecShootDir = ShootAtEnemy( pev->origin );
				UTIL_MakeAimVectors ( pev->angles );

				if (DotProduct( vecShootDir, gpGlobals->v_forward ) > 0.707)
				{
					m_bOnAttack = TRUE;
					pHurt->pev->punchangle.z = -18;
					pHurt->pev->punchangle.x = 5;
					pHurt->pev->velocity = pHurt->pev->velocity - gpGlobals->v_right * 300;
					if (pHurt->IsPlayer())
					{
						pHurt->pev->angles.x += RANDOM_FLOAT( -35, 35 );
						pHurt->pev->angles.y += RANDOM_FLOAT( -90, 90 );
						pHurt->pev->angles.z = 0;
						pHurt->pev->fixangle = TRUE;
					}
					pHurt->TakeDamage( pev, pev, gSkillData.ichthyosaurDmgShake, DMG_SLASH );
				}
			}
			BiteSound();

			bDidAttack = TRUE;
		}
		break;
	default:
		CFlyingMonster::HandleAnimEvent( pEvent );
		break;
	}

	if (bDidAttack)
	{
		Vector vecSrc = pev->origin + gpGlobals->v_forward * 32;
		UTIL_Bubbles( vecSrc - Vector( 8, 8, 8 ), vecSrc + Vector( 8, 8, 8 ), 16 );
	}
}
Beispiel #4
0
void CGrenade::SG_Smoke( void )
{
    if( UTIL_PointContents( pev->origin ) == CONTENTS_WATER )
    {
        UTIL_Bubbles( pev->origin - Vector( 64, 64, 64 ), pev->origin + Vector( 64, 64, 64 ), 100 );
    }
    else
    {
        UTIL_MakeVectors( pev->angles );

        Vector randomDir = gpGlobals->v_forward * RANDOM_FLOAT( 3, 8 );

        m_fLightSmoke = (int)(( ( m_fLightSmoke * 180 / M_PI ) + 30 )) % 360;

        // TODO: Check me.
        PLAYBACK_EVENT_FULL( 0,
                             NULL,
                             m_usEvent,
                             0.0,
                             pev->origin,
                             m_SGExplosionPos,
                             randomDir.x * cos( 180 / M_PI ) - randomDir.y * cos( 180 / M_PI ),
                             randomDir.x * sin( 180 / M_PI ) + randomDir.y * sin( 180 / M_PI ),
                             cos( 180 / M_PI ) * 100.0,
                             4,
                             m_bSGMulti,
                             6 );
    }

    if( m_SGSmoke <= 20 )
    {
        pev->nextthink = gpGlobals->time + 1.0;
        SetThink( &CGrenade::SG_Smoke );

        ++m_SGSmoke;
    }
    else
    {
        pev->effects |= EF_NODRAW;

        // TODO: Implements this.
        //TheBots->RemoveGrenade( this );

        UTIL_Remove( this );
    }
}
Beispiel #5
0
void CGrenade::Smoke(void)
{
	if (UTIL_PointContents(pev->origin) != CONTENTS_WATER)
	{
		MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, pev->origin);
		WRITE_BYTE(TE_SMOKE);
		WRITE_COORD(pev->origin.x);
		WRITE_COORD(pev->origin.y);
		WRITE_COORD(pev->origin.z);
		WRITE_SHORT(g_sModelIndexSmoke);
		WRITE_BYTE(25);
		WRITE_BYTE(6);
		MESSAGE_END();
	}
	else
		UTIL_Bubbles(pev->origin - Vector(64, 64, 64), pev->origin + Vector(64, 64, 64), 100);

	UTIL_Remove(this);
}
Beispiel #6
0
void CGrenade::Smoke3_A(void)
{
	if (UTIL_PointContents(pev->origin) != CONTENTS_WATER)
	{
		MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, pev->origin);
		WRITE_BYTE(TE_SMOKE);
		WRITE_COORD(pev->origin.x + RANDOM_FLOAT(-128, 128));
		WRITE_COORD(pev->origin.y + RANDOM_FLOAT(-128, 128));
		WRITE_COORD(pev->origin.z + RANDOM_FLOAT(-10, 10));
		WRITE_SHORT(g_sModelIndexSmoke);
		WRITE_BYTE(15 + RANDOM_FLOAT(0, 10));
		WRITE_BYTE(12);
		MESSAGE_END();
	}
	else
		UTIL_Bubbles(pev->origin - Vector(64, 64, 64), pev->origin + Vector(64, 64, 64), 100);

	UTIL_Remove(this);
}
Beispiel #7
0
void CGrenade::Smoke( void )
{
	if (UTIL_PointContents ( pev->origin ) == CONTENTS_WATER)
	{
		UTIL_Bubbles( pev->origin - Vector( 64, 64, 64 ), pev->origin + Vector( 64, 64, 64 ), 100 );
	}
	else
	{
		MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin );
			WRITE_BYTE( TE_SMOKE );
			WRITE_COORD( pev->origin.x );
			WRITE_COORD( pev->origin.y );
			WRITE_COORD( pev->origin.z );
			WRITE_SHORT( g_sModelIndexSmoke );
			WRITE_BYTE( (pev->dmg - 50) * 0.80 ); // scale * 10
			WRITE_BYTE( 12  ); // framerate
		MESSAGE_END();
	}
	UTIL_Remove( this );
}
Beispiel #8
0
void CGrenade::Smoke3_B(void)
{
	if (UTIL_PointContents(pev->origin) != CONTENTS_WATER)
	{
		MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, pev->origin);
		WRITE_BYTE(TE_SMOKE);
		WRITE_COORD(pev->origin.x + RANDOM_FLOAT(-128, 128));
		WRITE_COORD(pev->origin.y + RANDOM_FLOAT(-128, 128));
		WRITE_COORD(pev->origin.z + RANDOM_FLOAT(-10, 10));
		WRITE_SHORT(g_sModelIndexSmoke);
		WRITE_BYTE(15 + RANDOM_FLOAT(0, 10));
		WRITE_BYTE(10);
		MESSAGE_END();
	}
	else
		UTIL_Bubbles(pev->origin - Vector(64, 64, 64), pev->origin + Vector(64, 64, 64), 100);

	pev->nextthink = gpGlobals->time + 0.15;
	SetThink(&CGrenade::Smoke3_A);
}
Beispiel #9
0
void CBaseGrenade::Smoke( void )
{
	Vector vecAbsOrigin = GetAbsOrigin();
	if ( UTIL_PointContents ( vecAbsOrigin, MASK_WATER ) & MASK_WATER )
	{
		UTIL_Bubbles( vecAbsOrigin - Vector( 64, 64, 64 ), vecAbsOrigin + Vector( 64, 64, 64 ), 100 );
	}
	else
	{
		CPVSFilter filter( vecAbsOrigin );

		te->Smoke( filter, 0.0, 
			&vecAbsOrigin, g_sModelIndexSmoke,
			m_DmgRadius * 0.03,
			24 );
	}
#if !defined( CLIENT_DLL )
	SetThink ( &CBaseGrenade::SUB_Remove );
#endif
	SetNextThink( gpGlobals->curtime );
}
Beispiel #10
0
void CGrenade::Smoke( void )
{
	if (UTIL_PointContents ( pev->origin ) == CONTENTS_WATER)
	{
		UTIL_Bubbles( pev->origin - Vector( 64, 64, 64 ), pev->origin + Vector( 64, 64, 64 ), 100 );
	}
	else
	{
		float theDamageModifier;
		int theUpgradeLevel = AvHPlayerUpgrade::GetWeaponUpgrade(this->pev->iuser3, this->pev->iuser4, &theDamageModifier);
		int theDamage = this->pev->dmg*theDamageModifier;
		
		MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin );
			WRITE_BYTE( TE_SMOKE );
			WRITE_COORD( pev->origin.x );
			WRITE_COORD( pev->origin.y );
			WRITE_COORD( pev->origin.z );
			WRITE_SHORT( g_sModelIndexSmoke );
			WRITE_BYTE( (theDamage - 50) * 0.80 ); // scale * 10
			WRITE_BYTE( 12  ); // framerate
		MESSAGE_END();
	}
	UTIL_Remove( this );
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CNPC_Ichthyosaur::PrescheduleThink( void )
{
	BaseClass::PrescheduleThink();
	
	//Ambient sounds
	/*
	if ( random->RandomInt( 0, 20 ) == 10 )
	{
		if ( random->RandomInt( 0, 1 ) )
		{
			ENVELOPE_CONTROLLER.SoundChangeVolume( m_pSwimSound, random->RandomFloat( 0.0f, 0.5f ), 1.0f );
		}
		else
		{
			ENVELOPE_CONTROLLER.SoundChangeVolume( m_pVoiceSound, random->RandomFloat( 0.0f, 0.5f ), 1.0f );
		}
	}
	*/

	//Pings
	if ( m_flNextPingTime < gpGlobals->curtime )
	{
		m_flNextPingTime = gpGlobals->curtime + random->RandomFloat( 3.0f, 8.0f );
	}
	
	//Growls
	if ( ( m_NPCState == NPC_STATE_COMBAT || m_NPCState == NPC_STATE_ALERT ) && ( m_flNextGrowlTime < gpGlobals->curtime ) )
	{
		m_flNextGrowlTime = gpGlobals->curtime + random->RandomFloat( 2.0f, 6.0f );
	}

	//Randomly emit bubbles
	if ( random->RandomInt( 0, 10 ) == 0 )
	{
		UTIL_Bubbles( GetAbsOrigin()+(GetHullMins()*0.5f), GetAbsOrigin()+(GetHullMaxs()*0.5f), 1 );
	}

	//Check our water level
	if ( GetWaterLevel() != 3 )
	{
		if ( GetWaterLevel() < 2 )
		{
			DevMsg( 2, "Came out of water\n" );
			
			if ( Beached() )
			{
				SetSchedule( SCHED_ICH_THRASH );

				Vector vecNewVelocity = GetAbsVelocity();
				vecNewVelocity[2] = 8.0f;
				SetAbsVelocity( vecNewVelocity );
			}
		}
		else
		{
			//TODO: Wake effects
		}
	}

	//If we have a victim, update them
	if ( m_pVictim != NULL )
	{
		//See if it's time to release the victim
		if ( m_flHoldTime < gpGlobals->curtime )
		{
			ReleaseVictim();
			return;
		}

		Bite();
	}
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CNPC_Ichthyosaur::Bite( void )
{
	//Don't allow another bite too soon
	if ( m_flNextBiteTime > gpGlobals->curtime )
		return;

	CBaseEntity *pHurt;
	
	//FIXME: E3 HACK - Always damage bullseyes if we're scripted to hit them
	if ( ( GetEnemy() != NULL ) && ( GetEnemy()->Classify() == CLASS_BULLSEYE ) )
	{
		pHurt = GetEnemy();
	}
	else
	{
		pHurt = CheckTraceHullAttack( 108, Vector(-32,-32,-32), Vector(32,32,32), 0, DMG_CLUB );
	}

	//Hit something
	if ( pHurt != NULL )
	{
		CTakeDamageInfo info( this, this, sk_ichthyosaur_melee_dmg.GetInt(), DMG_CLUB );

		if ( pHurt->IsPlayer() )
		{
			CBasePlayer *pPlayer = ToBasePlayer( pHurt );

			if ( pPlayer )
			{
				if ( ( ( m_flHoldTime < gpGlobals->curtime ) && ( pPlayer->m_iHealth < (pPlayer->m_iMaxHealth*0.5f)) ) || ( pPlayer->GetWaterLevel() < 1 ) )
				{
					//EnsnareVictim( pHurt );
				}
				else
				{
					info.SetDamage( sk_ichthyosaur_melee_dmg.GetInt() * 3 );
				}
				CalculateMeleeDamageForce( &info, GetAbsVelocity(), pHurt->GetAbsOrigin() );
				pHurt->TakeDamage( info );

				color32 red = {64, 0, 0, 255};
				UTIL_ScreenFade( pPlayer, red, 0.5, 0, FFADE_IN  );

				//Disorient the player
				QAngle angles = pPlayer->GetLocalAngles();

				angles.x += random->RandomInt( 60, 25 );
				angles.y += random->RandomInt( 60, 25 );
				angles.z = 0.0f;

				pPlayer->SetLocalAngles( angles );

				pPlayer->SnapEyeAngles( angles );
			}
		}
		else
		{
			CalculateMeleeDamageForce( &info, GetAbsVelocity(), pHurt->GetAbsOrigin() );
			pHurt->TakeDamage( info );
		}

		m_flNextBiteTime = gpGlobals->curtime + random->RandomFloat( 2.0f, 4.0f );

		//Bubbles!
		UTIL_Bubbles( pHurt->GetAbsOrigin()+Vector(-32.0f,-32.0f,-32.0f), pHurt->GetAbsOrigin()+Vector(32.0f,32.0f,0.0f), random->RandomInt( 16, 32 ) );
		
		// Play a random attack hit sound
		EmitSound( "NPC_Ichthyosaur.Bite" );

		if ( GetActivity() == ACT_MELEE_ATTACK1 )
		{
			SetActivity( (Activity) ACT_ICH_BITE_HIT );
		}
		
		return;
	}

	//Play the miss animation and sound
	if ( GetActivity() == ACT_MELEE_ATTACK1 )
	{
		SetActivity( (Activity) ACT_ICH_BITE_MISS );
	}

	//Miss sound
	EmitSound( "NPC_Ichthyosaur.BiteMiss" );
}
//-----------------------------------------------------------------------------
// Purpose: Burn targets around us
//-----------------------------------------------------------------------------
void CEntityFlame::FlameThink( void )
{
	// Assure that this function will be ticked again even if we early-out in the if below.
	SetNextThink( gpGlobals->curtime + FLAME_DAMAGE_INTERVAL );

	if ( m_hEntAttached )
	{
		if ( m_hEntAttached->GetFlags() & FL_TRANSRAGDOLL )
		{
			SetRenderColorA( 0 );
			return;
		}
	
		CAI_BaseNPC *pNPC = m_hEntAttached->MyNPCPointer();
		if ( pNPC && !pNPC->IsAlive() )
		{
			UTIL_Remove( this );
			// Notify the NPC that it's no longer burning!
			pNPC->Extinguish();
			return;
		}

		if( m_hEntAttached->GetWaterLevel() > 0 )
		{
			Vector mins, maxs;

			mins = m_hEntAttached->WorldSpaceCenter();
			maxs = mins;

			maxs.z = m_hEntAttached->WorldSpaceCenter().z;
			maxs.x += 32;
			maxs.y += 32;
			
			mins.z -= 32;
			mins.x -= 32;
			mins.y -= 32;

			UTIL_Bubbles( mins, maxs, 12 );
		}
	}
	else
	{
		UTIL_Remove( this );
		return;
	}

	// See if we're done burning, or our attached ent has vanished
	if ( m_flLifetime < gpGlobals->curtime || m_hEntAttached == NULL )
	{
		EmitSound( "General.StopBurning" );
		m_bPlayingSound = false;
		SetThink( &CEntityFlame::SUB_Remove );
		SetNextThink( gpGlobals->curtime + 0.5f );

		// Notify anything we're attached to
		if ( m_hEntAttached )
		{
			CBaseCombatCharacter *pAttachedCC = m_hEntAttached->MyCombatCharacterPointer();

			if( pAttachedCC )
			{
				// Notify the NPC that it's no longer burning!
				pAttachedCC->Extinguish();
			}
		}

		return;
	}

	if ( m_hEntAttached )
	{
		// Do radius damage ignoring the entity I'm attached to. This will harm things around me.
		RadiusDamage( CTakeDamageInfo( this, this, 4.0f, DMG_BURN ), GetAbsOrigin(), m_flSize/2, CLASS_NONE, m_hEntAttached );

		// Directly harm the entity I'm attached to. This is so we can precisely control how much damage the entity
		// that is on fire takes without worrying about the flame's position relative to the bodytarget (which is the
		// distance that the radius damage code uses to determine how much damage to inflict)
		m_hEntAttached->TakeDamage( CTakeDamageInfo( this, this, FLAME_DIRECT_DAMAGE, DMG_BURN | DMG_DIRECT ) );

		if( !m_hEntAttached->IsNPC() && hl2_episodic.GetBool() )
		{
			const int ENTITYFLAME_MOVE_AWAY_DIST = 24;
			// Make a sound near my origin, and up a little higher (in case I'm on the ground, so NPC's still hear it)
			CSoundEnt::InsertSound( SOUND_MOVE_AWAY, GetAbsOrigin(), ENTITYFLAME_MOVE_AWAY_DIST, 0.1f, this, SOUNDENT_CHANNEL_REPEATED_DANGER );
			CSoundEnt::InsertSound( SOUND_MOVE_AWAY, GetAbsOrigin() + Vector( 0, 0, 48.0f ), ENTITYFLAME_MOVE_AWAY_DIST, 0.1f, this, SOUNDENT_CHANNEL_REPEATING );
		}
	}
	else
	{
		RadiusDamage( CTakeDamageInfo( this, this, FLAME_RADIUS_DAMAGE, DMG_BURN ), GetAbsOrigin(), m_flSize/2, CLASS_NONE, NULL );
	}

	FireSystem_AddHeatInRadius( GetAbsOrigin(), m_flSize/2, 2.0f );

}  
Beispiel #14
0
//------------------------------------------------------------------------------
// Purpose :
// Input   :
// Output  :
//------------------------------------------------------------------------------
void CGrenadeBeam::GrenadeBeamTouch( CBaseEntity *pOther )
{
	//---------------------------------------------------------
	// Make sure I'm not caught in a corner, if so remove me
	//---------------------------------------------------------
	if (gpGlobals->curtime - m_flLastTouchTime < 0.01)
	{
		KillBeam();
		return;
	}
	m_flLastTouchTime = gpGlobals->curtime;

	// ---------------------------------------
	// If I have room for another hit, add it
	// ---------------------------------------
	if (m_nNumHits < GRENADEBEAM_MAXHITS)
	{
		m_pHitLocation[m_nNumHits] = GetLocalOrigin();
		m_nNumHits++;
	}
	// Otherwise copy over old hit, and force chaser into last hit position
	else
	{
		m_hBeamChaser->SetLocalOrigin( m_pHitLocation[0] );
		for (int i=0;i<m_nNumHits-1;i++)
		{
			m_pHitLocation[i] = m_pHitLocation[i+1];
		}
		m_pHitLocation[m_nNumHits-1]=GetLocalOrigin();
	}
	UpdateBeams();

	// --------------------------------------
	//  Smoke or bubbles effect
	// --------------------------------------
	if (UTIL_PointContents ( GetAbsOrigin() ) & MASK_WATER)
	{
		UTIL_Bubbles(GetAbsOrigin()-Vector(3,3,3),GetAbsOrigin()+Vector(3,3,3),10);
	}
	else 
	{
		UTIL_Smoke(GetAbsOrigin(), random->RandomInt(5, 10), 10);
	}

	// --------------------------------------------
	//  Play burn sounds
	// --------------------------------------------
	if (pOther->m_takedamage)
	{
		pOther->TakeDamage( CTakeDamageInfo( this, this, m_flDamage, DMG_BURN ) );
		KillBeam();
		return;
	}
	
	EmitSound( "GrenadeBeam.HitSound" );

	trace_t tr;
	Vector vDirection = GetAbsVelocity();
	VectorNormalize(vDirection);
	UTIL_TraceLine( GetAbsOrigin()-vDirection, GetAbsOrigin()+vDirection, MASK_SOLID, NULL, COLLISION_GROUP_NONE, &tr );
	UTIL_DecalTrace( &tr, "RedGlowFade" );
	UTIL_ImpactTrace( &tr, DMG_ENERGYBEAM );
}
Beispiel #15
0
//------------------------------------------------------------------------------
// Purpose : Draw attack beam and do damage / decals
// Input   :
// Output  :
//------------------------------------------------------------------------------
void CNPC_Stalker::DrawAttackBeam(void)
{
	if (!m_pBeam)
		return;

	// ---------------------------------------------
	//	Get beam end point
	// ---------------------------------------------
	Vector vecSrc = LaserStartPosition(GetAbsOrigin());
	trace_t tr;
	AI_TraceLine( vecSrc, vecSrc + m_vLaserDir * MAX_STALKER_FIRE_RANGE, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr);

	CalcBeamPosition();

	bool bInWater = (UTIL_PointContents ( tr.endpos, MASK_WATER ) & MASK_WATER)?true:false;
	// ---------------------------------------------
	//	Update the beam position
	// ---------------------------------------------
	m_pBeam->SetStartPos( tr.endpos );
	m_pBeam->RelinkBeam();

	Vector vAttachPos;
	GetAttachment(STALKER_LASER_ATTACHMENT,vAttachPos);

	Vector vecAimDir = tr.endpos - vAttachPos;
	VectorNormalize( vecAimDir );

	SetAim( vecAimDir );

	// --------------------------------------------
	//  Play burn sounds
	// --------------------------------------------
	CBaseCombatCharacter *pBCC = ToBaseCombatCharacter( tr.m_pEnt );
	if (pBCC)
	{
		if (gpGlobals->curtime > m_fNextDamageTime)
		{
			ClearMultiDamage();

			float damage = 0.0;
			switch (m_eBeamPower)
			{
				case STALKER_BEAM_LOW:
					damage = 1;
					break;
				case STALKER_BEAM_MED:
					damage = 3;
					break;
				case STALKER_BEAM_HIGH:
					damage = 10;
					break;
			}

			CTakeDamageInfo info( this, this, damage, DMG_SHOCK );
			CalculateMeleeDamageForce( &info, m_vLaserDir, tr.endpos );
			pBCC->DispatchTraceAttack( info, m_vLaserDir, &tr );
			ApplyMultiDamage();
			m_fNextDamageTime = gpGlobals->curtime + 0.1;
		}
		if (pBCC->Classify()!=CLASS_BULLSEYE)
		{
			if (!m_bPlayingHitFlesh)
			{
				CPASAttenuationFilter filter( m_pBeam,"NPC_Stalker.BurnFlesh" );
				filter.MakeReliable();

				EmitSound( filter, m_pBeam->entindex(),"NPC_Stalker.BurnFlesh" );
				m_bPlayingHitFlesh = true;
			}
			if (m_bPlayingHitWall)
			{
				StopSound( m_pBeam->entindex(), "NPC_Stalker.BurnWall" );
				m_bPlayingHitWall = false;
			}

			tr.endpos.z -= 24.0f;
			if (!bInWater)
			{
				DoSmokeEffect(tr.endpos + tr.plane.normal * 8);
			}
		}
	}
	
	if (!pBCC || pBCC->Classify()==CLASS_BULLSEYE)
	{
		if (!m_bPlayingHitWall)
		{
			CPASAttenuationFilter filter( m_pBeam, "NPC_Stalker.BurnWall" );
			filter.MakeReliable();

			EmitSound( filter, m_pBeam->entindex(), "NPC_Stalker.BurnWall" );
			m_bPlayingHitWall = true;
		}
		if (m_bPlayingHitFlesh)
		{
			StopSound(m_pBeam->entindex(), "NPC_Stalker.BurnFlesh" );
			m_bPlayingHitFlesh = false;
		}

		UTIL_DecalTrace( &tr, "RedGlowFade");
		UTIL_DecalTrace( &tr, "FadingScorch" );
		
		tr.endpos.z -= 24.0f;
		if (!bInWater)
		{
			DoSmokeEffect(tr.endpos + tr.plane.normal * 8);
		}
	}

	if (bInWater)
	{
		UTIL_Bubbles(tr.endpos-Vector(3,3,3),tr.endpos+Vector(3,3,3),10);
	}

	/*
	CBroadcastRecipientFilter filter;
	TE_DynamicLight( filter, 0.0, EyePosition(), 255, 0, 0, 5, 0.2, 0 );
	*/
}