GLProgramming.com

home :: about :: development guides :: irc :: forums :: search :: paste :: links :: contribute :: code dump

-> Click here to learn how to get live help <-


New Paste :: Recent Pastes:: Add Line Numbers


Combine Destruction code by Helk
//Taken from prop_combine_ball.cpp

//-----------------------------------------------------------------------------
// Purpose: Starts the lifetime countdown on the ball
// Input  : flDuration - number of seconds to live before exploding
//-----------------------------------------------------------------------------
void CPropCombineBall::StartLifetime( float flDuration )
{
    SetContextThink( &CPropCombineBall::ExplodeThink, gpGlobals->curtime + flDuration, s_pExplodeTimerContext );
}

//When lifetime is expired:
void CPropCombineBall::ExplodeThink( void )
{
    DoExplosion();    
}


//When we touch something

void CPropCombineBall::OnHitEntity( CBaseEntity *pHitEntity, float flSpeed, int index, gamevcollisionevent_t *pEvent )
{
    // Detonate on the strider + the bone followers in the strider
    if ( FClassnameIs( pHitEntity, "npc_strider" ) || 
        (pHitEntity->GetOwnerEntity() && FClassnameIs( pHitEntity->GetOwnerEntity(), "npc_strider" )) )
    {
        DoExplosion();
        return;
    }

    CTakeDamageInfo info( this, GetOwnerEntity(), GetAbsVelocity(), GetAbsOrigin(), sk_npc_dmg_combineball.GetFloat(), DMG_DISSOLVE );

    bool bIsDissolving = (pHitEntity->GetFlags() & FL_DISSOLVING) != 0;
    if ( !bIsDissolving && pHitEntity->PassesDamageFilter( info ) )
    {
        if( WasFiredByNPC() )
        {
            // Since Combine balls fired by NPCs do a metered dose of damage per impact, we have to ignore touches
            // for a little while after we hit someone, or the ball will immediately touch them again and do more
            // damage. 
            if( gpGlobals->curtime >= m_flNextDamageTime )
            {
                pHitEntity->TakeDamage( info );

                // Ignore touches briefly.
                m_flNextDamageTime = gpGlobals->curtime + 0.1f;
            }
        }
        else
        {
            if ( (m_nState == STATE_THROWN) && (pHitEntity->IsNPC() || dynamic_cast<CRagdollProp*>(pHitEntity) ))
            {
                EmitSound( "NPC_CombineBall.KillImpact" );
            }
            if ( (m_nState != STATE_HOLDING) )
            {
                DissolveEntity( pHitEntity );
            }
        }
    }

    Vector vecFinalVelocity;
    if ( IsInField() )
    {
        // Don't deflect when in a spawner field
        vecFinalVelocity = pEvent->preVelocity[index];
    }
    else
    {
        // Don't slow down when hitting other entities.
        vecFinalVelocity = pEvent->postVelocity[index];
        VectorNormalize( vecFinalVelocity );
        vecFinalVelocity *= GetSpeed();
    }
    PhysCallbackSetVelocity( pEvent->pObjects[index], vecFinalVelocity ); 
}



void CPropCombineBall::DoImpactEffect( const Vector &preVelocity, int index, gamevcollisionevent_t *pEvent )
{
    // Do that crazy impact effect!
    trace_t tr;
    CollisionEventToTrace( !index, pEvent, tr );
    
    CBaseEntity *pTraceEntity = pEvent->pEntities[index];
    UTIL_TraceLine( tr.startpos - preVelocity * 2.0f, tr.startpos + preVelocity * 2.0f, MASK_SOLID, pTraceEntity, COLLISION_GROUP_NONE, &tr );

    if ( tr.fraction < 1.0f )
    {
        // See if we hit the sky
        if ( tr.surface.flags & SURF_SKY )
        {
            DoExplosion();
            return;
        }

        // Send the effect over
        CEffectData    data;

        data.m_flRadius = 16;
        data.m_vNormal    = tr.plane.normal;
        data.m_vOrigin    = tr.endpos + tr.plane.normal * 1.0f;

        DispatchEffect( "cball_bounce", data );
    }

    EmitSound( "NPC_CombineBall.Impact" );
}



//The actual explosion code (just an effect)

void CPropCombineBall::DoExplosion( )
{
    // Tell the respawner to make a new one
    if ( GetSpawner() )
    {
        GetSpawner()->RespawnBallPostExplosion();
    }

    EmitSound( "NPC_CombineBall.Explosion" );

    UTIL_ScreenShake( GetAbsOrigin(), 20.0f, 150.0, 1.0, 1250.0f, SHAKE_START );

    CEffectData data;

    data.m_vOrigin = GetAbsOrigin();

    DispatchEffect( "cball_explode", data );

    //Shockring
    CBroadcastRecipientFilter filter2;
    te->BeamRingPoint( filter2, 0, GetAbsOrigin(),    //origin
        m_flRadius,    //start radius
        1024,        //end radius
        s_nExplosionTexture, //texture
        0,            //halo index
        0,            //start frame
        2,            //framerate
        0.2f,        //life
        64,            //width
        0,            //spread
        0,            //amplitude
        255,    //r
        255,    //g
        225,    //b
        32,        //a
        0,        //speed
        FBEAM_FADEOUT
        );

    //Shockring
    te->BeamRingPoint( filter2, 0, GetAbsOrigin(),    //origin
        m_flRadius,    //start radius
        1024,        //end radius
        s_nExplosionTexture, //texture
        0,            //halo index
        0,            //start frame
        2,            //framerate
        0.5f,        //life
        64,            //width
        0,            //spread
        0,            //amplitude
        255,    //r
        255,    //g
        225,    //b
        64,        //a
        0,        //speed
        FBEAM_FADEOUT
        );

    // Turn us off and wait because we need our trails to finish up properly
    SetAbsVelocity( vec3_origin );
    SetMoveType( MOVETYPE_NONE );
    AddSolidFlags( FSOLID_NOT_SOLID );

    m_bEmit = false;
 
    SetContextThink( &CPropCombineBall::SUB_Remove, gpGlobals->curtime + 0.5f, s_pRemoveContext );
    StopLoopingSounds();
}