//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHarpoon::HarpoonTouch( CBaseEntity *pOther ) { // If we've stuck something, freeze. Make sure we hit it along our velocity. if ( pOther->GetCollisionGroup() != TFCOLLISION_GROUP_SHIELD ) { // Perform the collision response... const trace_t &tr = CBaseEntity::GetTouchTrace( ); Vector vecNewVelocity; PhysicsClipVelocity (GetAbsVelocity(), tr.plane.normal, vecNewVelocity, 2.0 - GetFriction()); SetAbsVelocity( vecNewVelocity ); } else { // Move away from the shield... // Fling it out a little extra along the plane normal Vector vecCenter; AngleVectors( pOther->GetAbsAngles(), &vecCenter ); Vector vecNewVelocity; VectorMultiply( vecCenter, 400.0f, vecNewVelocity ); SetAbsVelocity( vecNewVelocity ); } if ( !pOther->IsBSPModel() && !pOther->GetBaseAnimating() ) return; // At this point, it shouldn't affect player movement SetCollisionGroup( COLLISION_GROUP_DEBRIS ); // Remove myself soon SetThink( SUB_Remove ); SetNextThink( gpGlobals->curtime + 30.0 ); m_hImpaledTarget = pOther; // Should I impale something? if ( pOther->GetBaseAnimating() ) { CheckLinkedHarpoon(); if ( pOther->GetMoveType() != MOVETYPE_NONE ) { ImpaleTarget( pOther ); return; } } CheckLinkedHarpoon(); EmitSound( "Harpoon.Impact" ); // Stop moving SetMoveType( MOVETYPE_NONE ); }
void CStickyBomb::Touch( CBaseEntity *pOther ) { // Don't stick if already stuck if ( GetMoveType() == MOVETYPE_FLYGRAVITY ) { trace_t tr = GetTouchTrace(); // stickies don't stick to each other or sky if ( FClassnameIs(pOther, "grenade_stickybomb") || (tr.surface.flags & SURF_SKY) ) { // bounce Vector vecNewVelocity; PhysicsClipVelocity( GetAbsVelocity(), tr.plane.normal, vecNewVelocity, 1.0 ); SetAbsVelocity( vecNewVelocity ); } else { SetAbsVelocity( vec3_origin ); SetMoveType( MOVETYPE_NONE ); if ( pOther->entindex() != 0 ) { // set up notification if the parent is deleted before we explode g_pNotify->AddEntity( this, pOther ); if ( (tr.surface.flags & SURF_HITBOX) && modelinfo->GetModelType( pOther->GetModel() ) == mod_studio ) { CBaseAnimating *pOtherAnim = dynamic_cast<CBaseAnimating *>(pOther); if ( pOtherAnim ) { matrix3x4_t bombWorldSpace; MatrixCopy( EntityToWorldTransform(), bombWorldSpace ); // get the bone info so we can follow the bone FollowEntity( pOther ); SetOwnerEntity( pOther ); m_boneIndexAttached = pOtherAnim->GetHitboxBone( tr.hitbox ); matrix3x4_t boneToWorld; pOtherAnim->GetBoneTransform( m_boneIndexAttached, boneToWorld ); // transform my current position/orientation into the hit bone's space // UNDONE: Eventually we need to intersect with the mesh here // REVISIT: maybe do something like the decal code to find a spot on // the mesh. matrix3x4_t worldToBone, localMatrix; MatrixInvert( boneToWorld, worldToBone ); ConcatTransforms( worldToBone, bombWorldSpace, localMatrix ); MatrixAngles( localMatrix, m_boneAngles.GetForModify(), m_bonePosition.GetForModify() ); return; } } SetParent( pOther ); } } } }
void CBaseGrenadeProjectile::ResolveFlyCollisionCustom( trace_t &trace, Vector &vecVelocity ) { //Assume all surfaces have the same elasticity float flSurfaceElasticity = 1.0; //Don't bounce off of players with perfect elasticity if( trace.m_pEnt && trace.m_pEnt->IsPlayer() ) { flSurfaceElasticity = 0.3; } // if its breakable glass and we kill it, don't bounce. // give some damage to the glass, and if it breaks, pass // through it. bool breakthrough = false; if( trace.m_pEnt && FClassnameIs( trace.m_pEnt, "func_breakable" ) ) { breakthrough = true; } if( trace.m_pEnt && FClassnameIs( trace.m_pEnt, "func_breakable_surf" ) ) { breakthrough = true; } if (breakthrough) { CTakeDamageInfo info( this, this, 10, DMG_CLUB ); trace.m_pEnt->DispatchTraceAttack( info, GetAbsVelocity(), &trace ); ApplyMultiDamage(); if( trace.m_pEnt->m_iHealth <= 0 ) { // slow our flight a little bit Vector vel = GetAbsVelocity(); vel *= 0.4; SetAbsVelocity( vel ); return; } } float flTotalElasticity = GetElasticity() * flSurfaceElasticity; flTotalElasticity = clamp( flTotalElasticity, 0.0f, 0.9f ); // NOTE: A backoff of 2.0f is a reflection Vector vecAbsVelocity; PhysicsClipVelocity( GetAbsVelocity(), trace.plane.normal, vecAbsVelocity, 2.0f ); vecAbsVelocity *= flTotalElasticity; // Get the total velocity (player + conveyors, etc.) VectorAdd( vecAbsVelocity, GetBaseVelocity(), vecVelocity ); float flSpeedSqr = DotProduct( vecVelocity, vecVelocity ); // Stop if on ground. if ( trace.plane.normal.z > 0.7f ) // Floor { // Verify that we have an entity. CBaseEntity *pEntity = trace.m_pEnt; Assert( pEntity ); SetAbsVelocity( vecAbsVelocity ); if ( flSpeedSqr < ( 30 * 30 ) ) { if ( pEntity->IsStandable() ) { SetGroundEntity( pEntity ); } // Reset velocities. SetAbsVelocity( vec3_origin ); SetLocalAngularVelocity( vec3_angle ); //align to the ground so we're not standing on end QAngle angle; VectorAngles( trace.plane.normal, angle ); // rotate randomly in yaw angle[1] = random->RandomFloat( 0, 360 ); // TODO: rotate around trace.plane.normal SetAbsAngles( angle ); } else { Vector vecDelta = GetBaseVelocity() - vecAbsVelocity; Vector vecBaseDir = GetBaseVelocity(); VectorNormalize( vecBaseDir ); float flScale = vecDelta.Dot( vecBaseDir ); VectorScale( vecAbsVelocity, ( 1.0f - trace.fraction ) * gpGlobals->frametime, vecVelocity ); VectorMA( vecVelocity, ( 1.0f - trace.fraction ) * gpGlobals->frametime, GetBaseVelocity() * flScale, vecVelocity ); PhysicsPushEntity( vecVelocity, &trace ); } } else { // If we get *too* slow, we'll stick without ever coming to rest because // we'll get pushed down by gravity faster than we can escape from the wall. if ( flSpeedSqr < ( 30 * 30 ) ) { // Reset velocities. SetAbsVelocity( vec3_origin ); SetLocalAngularVelocity( vec3_angle ); } else { SetAbsVelocity( vecAbsVelocity ); } } BounceSound(); }