//----------------------------------------------------------------------------- // Purpose: This think function simulates (moves/collides) the HeadcrabCanister while in // the world. //----------------------------------------------------------------------------- void CEnvHeadcrabCanister::HeadcrabCanisterWorldThink( void ) { // Get the current time. float flTime = gpGlobals->curtime; Vector vecStartPosition = GetAbsOrigin(); // Update HeadcrabCanister position for swept collision test. Vector vecEndPosition; QAngle vecEndAngles; m_Shared.GetPositionAtTime( flTime, vecEndPosition, vecEndAngles ); if ( !m_bIncomingSoundStarted && !HasSpawnFlags( SF_NO_IMPACT_SOUND ) ) { float flDistSq = ENV_HEADCRABCANISTER_INCOMING_SOUND_TIME * m_Shared.m_flFlightSpeed; flDistSq *= flDistSq; if ( vecEndPosition.DistToSqr(m_vecImpactPosition) <= flDistSq ) { // Figure out if we're close enough to play the incoming sound EmitSound( "HeadcrabCanister.IncomingSound" ); m_bIncomingSoundStarted = true; } } TestForCollisionsAgainstEntities( vecEndPosition ); if ( m_Shared.DidImpact( flTime ) ) { if ( !m_bHasDetonated ) { Detonate(); m_bHasDetonated = true; } if ( !HasSpawnFlags( SF_REMOVE_ON_IMPACT ) ) { Landed(); } return; } // Always move full movement. SetAbsOrigin( vecEndPosition ); // Touch triggers along the way PhysicsTouchTriggers( &vecStartPosition ); SetNextThink( gpGlobals->curtime + 0.2f ); SetAbsAngles( vecEndAngles ); if ( !m_bHasDetonated ) { if ( vecEndPosition.DistToSqr( m_vecImpactPosition ) < BoundingRadius() * BoundingRadius() ) { Detonate(); m_bHasDetonated = true; } } }
//----------------------------------------------------------------------------- // Purpose: This stops its motion in the skybox //----------------------------------------------------------------------------- void CEnvHeadcrabCanister::HeadcrabCanisterSkyboxOnlyThink( void ) { Vector vecEndPosition; QAngle vecEndAngles; m_Shared.GetPositionAtTime( gpGlobals->curtime, vecEndPosition, vecEndAngles ); UTIL_SetOrigin( this, vecEndPosition ); SetAbsAngles( vecEndAngles ); if ( !HasSpawnFlags( SF_NO_IMPACT_SOUND ) ) { CPASAttenuationFilter filter( this, ATTN_NONE ); EmitSound( filter, entindex(), "HeadcrabCanister.SkyboxExplosion" ); } if ( m_nSkyboxCannisterCount != 0 ) { if ( --m_nSkyboxCannisterCount <= 0 ) { SetThink( NULL ); return; } } float flRefireTime = enginerandom->RandomFloat( m_flMinRefireTime, m_flMaxRefireTime ) + ENV_HEADCRABCANISTER_TRAIL_TIME; SetThink( &CEnvHeadcrabCanister::HeadcrabCanisterSkyboxRestartThink ); SetNextThink( gpGlobals->curtime + flRefireTime ); }
//----------------------------------------------------------------------------- // Compute position //----------------------------------------------------------------------------- void C_EnvHeadcrabCanister::ClientThink() { Vector vecEndPosition; QAngle vecEndAngles; m_Shared.GetPositionAtTime( gpGlobals->curtime, vecEndPosition, vecEndAngles ); SetAbsOrigin( vecEndPosition ); SetAbsAngles( vecEndAngles ); }
//----------------------------------------------------------------------------- // Purpose: This think function should be called at the time when the HeadcrabCanister // will be leaving the skybox and entering the world. //----------------------------------------------------------------------------- void CEnvHeadcrabCanister::HeadcrabCanisterSkyboxThink( void ) { // Use different position computation m_Shared.ConvertFromSkyboxToWorld(); Vector vecEndPosition; QAngle vecEndAngles; m_Shared.GetPositionAtTime( gpGlobals->curtime, vecEndPosition, vecEndAngles ); UTIL_SetOrigin( this, vecEndPosition ); SetAbsAngles( vecEndAngles ); RemoveEFlags( EFL_IN_SKYBOX ); // Switch to the actual-scale model SetupWorldModel(); // Futz with the smoke trail to get it working across the boundary m_hTrail->SetSkybox( vec3_origin, 1.0f ); // Now we start looking for collisions SetThink( &CEnvHeadcrabCanister::HeadcrabCanisterWorldThink ); SetNextThink( gpGlobals->curtime + 0.01f ); }
//----------------------------------------------------------------------------- // Fires the canister! //----------------------------------------------------------------------------- void CEnvHeadcrabCanister::InputFireCanister( inputdata_t &inputdata ) { if (m_bLaunched) return; m_bLaunched = true; if ( HasSpawnFlags( SF_START_IMPACTED ) ) { StartSpawningHeadcrabs( 0.01f ); return; } // Play a firing sound CPASAttenuationFilter filter( this, ATTN_NONE ); if ( !HasSpawnFlags( SF_NO_LAUNCH_SOUND ) ) { EmitSound( filter, entindex(), "HeadcrabCanister.LaunchSound" ); } // Place the canister CE_CSkyCamera *pCamera = PlaceCanisterInWorld(); // Hook up a smoke trail CE_CSpriteTrail *trail = CE_CSpriteTrail::SpriteTrailCreate( "sprites/smoke.vmt", GetAbsOrigin(), true ); trail->SetTransparency( kRenderTransAdd, 224, 224, 255, 255, kRenderFxNone ); trail->SetAttachment( BaseEntity(), 0 ); trail->SetStartWidth( 32.0 ); trail->SetEndWidth( 200.0 ); trail->SetStartWidthVariance( 15.0f ); trail->SetTextureResolution( 0.002 ); trail->SetLifeTime( ENV_HEADCRABCANISTER_TRAIL_TIME ); trail->SetMinFadeLength( 1000.0f ); m_hTrail.Set(trail->BaseEntity()); if ( pCamera && m_Shared.IsInSkybox() ) { m_hTrail->SetSkybox( pCamera->m_skyboxData->origin, pCamera->m_skyboxData->scale ); } // Fire that output! m_OnLaunched.Set( BaseEntity(), BaseEntity(), BaseEntity() ); }
//----------------------------------------------------------------------------- // Place the canister in the world //----------------------------------------------------------------------------- CE_CSkyCamera *CEnvHeadcrabCanister::PlaceCanisterInWorld() { CE_CSkyCamera *pCamera = NULL; // Are we launching from a point? If so, use that point. if ( m_iszLaunchPositionName != NULL_STRING ) { // Get the launch position entity CEntity *pLaunchPos = g_helpfunc.FindEntityByName( (CBaseEntity *)NULL, m_iszLaunchPositionName ); if ( !pLaunchPos ) { Warning("%s (%s) could not find an entity matching LaunchPositionName of '%s'\n", GetEntityName(), GetDebugName(), STRING(m_iszLaunchPositionName) ); SUB_Remove(); } else { SetupWorldModel(); Vector vecForward, vecImpactDirection; GetVectors( &vecForward, NULL, NULL ); VectorMultiply( vecForward, -1.0f, vecImpactDirection ); m_Shared.InitInWorld( gpGlobals->curtime, pLaunchPos->GetAbsOrigin(), GetAbsAngles(), vecImpactDirection, m_vecImpactPosition, true ); SetThink( &CEnvHeadcrabCanister::HeadcrabCanisterWorldThink ); SetNextThink( gpGlobals->curtime ); } } else if ( DetectInSkybox() ) { pCamera = GetEntitySkybox(); SetModel( ENV_HEADCRABCANISTER_SKYBOX_MODEL ); SetSolid( SOLID_NONE ); Vector vecForward; GetVectors( &vecForward, NULL, NULL ); vecForward *= -1.0f; m_Shared.InitInSkybox( gpGlobals->curtime, m_vecImpactPosition, GetAbsAngles(), vecForward, m_vecImpactPosition, pCamera->m_skyboxData->origin, pCamera->m_skyboxData->scale ); AddEFlags( EFL_IN_SKYBOX ); SetThink( &CEnvHeadcrabCanister::HeadcrabCanisterSkyboxOnlyThink ); SetNextThink( gpGlobals->curtime + m_Shared.GetEnterWorldTime() + TICK_INTERVAL ); } else { Vector vecStartPosition, vecDirection; QAngle vecStartAngles; ComputeWorldEntryPoint( &vecStartPosition, &vecStartAngles, &vecDirection ); // Figure out which skybox to place the entity in. pCamera = GetCurrentSkyCamera(); if ( pCamera ) { m_Shared.InitInSkybox( gpGlobals->curtime, vecStartPosition, vecStartAngles, vecDirection, m_vecImpactPosition, pCamera->m_skyboxData->origin, pCamera->m_skyboxData->scale ); if ( m_Shared.IsInSkybox() ) { SetModel( ENV_HEADCRABCANISTER_SKYBOX_MODEL ); SetSolid( SOLID_NONE ); AddEFlags( EFL_IN_SKYBOX ); SetThink( &CEnvHeadcrabCanister::HeadcrabCanisterSkyboxThink ); SetNextThink( gpGlobals->curtime + m_Shared.GetEnterWorldTime() ); } else { SetThink( &CEnvHeadcrabCanister::HeadcrabCanisterWorldThink ); SetNextThink( gpGlobals->curtime ); } } else { m_Shared.InitInWorld( gpGlobals->curtime, vecStartPosition, vecStartAngles, vecDirection, m_vecImpactPosition ); SetThink( &CEnvHeadcrabCanister::HeadcrabCanisterWorldThink ); SetNextThink( gpGlobals->curtime ); } } Vector vecEndPosition; QAngle vecEndAngles; m_Shared.GetPositionAtTime( gpGlobals->curtime, vecEndPosition, vecEndAngles ); SetAbsOrigin( vecEndPosition ); SetAbsAngles( vecEndAngles ); return pCamera; }