//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFWeaponBaseGrenadeProj::Deflected( CBaseEntity *pDeflectedBy, Vector &vecDir ) { IPhysicsObject *pPhysicsObject = VPhysicsGetObject(); if ( pPhysicsObject ) { Vector vecOldVelocity, vecVelocity; pPhysicsObject->GetVelocity( &vecOldVelocity, NULL ); float flVel = vecOldVelocity.Length(); vecVelocity = vecDir; vecVelocity *= flVel; AngularImpulse angVelocity( ( 600, random->RandomInt( -1200, 1200 ), 0 ) ); // Now change grenade's direction. pPhysicsObject->SetVelocityInstantaneous( &vecVelocity, &angVelocity ); } CBaseCombatCharacter *pBCC = pDeflectedBy->MyCombatCharacterPointer(); IncremenentDeflected(); m_hDeflectOwner = pDeflectedBy; SetThrower( pBCC ); ChangeTeam( pDeflectedBy->GetTeamNumber() ); if ( !TFGameRules()->IsDeathmatch() ) m_nSkin = pDeflectedBy->GetTeamNumber() - 2; // TODO: Live TF2 adds white trail to reflected pipes and stickies. We need one as well. }
//----------------------------------------------------------------------------- // Purpose: Returns the magnitude of the entity's angular velocity. //----------------------------------------------------------------------------- void CPointVelocitySensor::SampleVelocity( void ) { if ( m_hTargetEntity == NULL ) return; Vector vecVelocity; if ( m_hTargetEntity->GetMoveType() == MOVETYPE_VPHYSICS ) { IPhysicsObject *pPhys = m_hTargetEntity->VPhysicsGetObject(); if ( pPhys != NULL ) { pPhys->GetVelocity( &vecVelocity, NULL ); } } else { vecVelocity = m_hTargetEntity->GetAbsVelocity(); } /* float flSpeed = VectorNormalize( vecVelocity ); float flDot = ( m_vecAxis != vec3_origin ) ? DotProduct( vecVelocity, m_vecAxis ) : 1.0f; */ // We want the component of the velocity vector in the direction of the axis, which since the // axis is normalized is simply their dot product (eg V . A = |V|*|A|*cos(theta) ) m_fPrevVelocity = ( m_vecAxis != vec3_origin ) ? DotProduct( vecVelocity, m_vecAxis ) : 1.0f; // if it's changed since the last frame, poke the output if ( m_fPrevVelocity != m_Velocity.Get() ) { m_Velocity.Set( m_fPrevVelocity, NULL, NULL ); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CNPC_CraneDriver::RunTask( const Task_t *pTask ) { switch( pTask->iTask ) { case TASK_WAIT_FOR_MOVEMENT: { // Is the magnet over the target, and are we not moving too fast? AngularImpulse angVel; Vector vecVelocity; CBaseEntity *pMagnet = m_hCrane->GetMagnet(); IPhysicsObject *pVehiclePhysics = pMagnet->VPhysicsGetObject(); pVehiclePhysics->GetVelocity( &vecVelocity, &angVel ); float flVelocity = 100; float flDistance = 90; // More accurate on forced drops if ( m_bForcedPickup || m_bForcedDropoff ) { flVelocity = 10; flDistance = 30; } if ( m_flDistanceToTarget < flDistance && m_hCrane->GetTurnRate() < 0.1 && vecVelocity.Length() < flVelocity ) { TaskComplete(); } } break; case TASK_CRANE_DROP_MAGNET: { // Wait for the magnet to get back up if ( m_flDropWait < gpGlobals->curtime && !m_hCrane->IsDropping() ) { TaskComplete(); } } break; case TASK_CRANE_TURN_MAGNET_OFF: { // We're waiting for the pause length before dropping whatever's on our magnet if ( gpGlobals->curtime > m_flReleaseAt ) { if ( m_bForcedDropoff ) { m_OnDroppedObject.FireOutput( this, this ); } m_hCrane->TurnMagnetOff(); TaskComplete(); } } break; default: BaseClass::RunTask( pTask ); break; } }
//----------------------------------------------------------------------------- // Purpose: Returns the magnitude of the entity's angular velocity. //----------------------------------------------------------------------------- float CPointAngularVelocitySensor::SampleAngularVelocity(CBaseEntity *pEntity) { if (pEntity->GetMoveType() == MOVETYPE_VPHYSICS) { IPhysicsObject *pPhys = pEntity->VPhysicsGetObject(); if (pPhys != NULL) { Vector vecVelocity; AngularImpulse vecAngVelocity; pPhys->GetVelocity(&vecVelocity, &vecAngVelocity); QAngle angles; pPhys->GetPosition( NULL, &angles ); float dt = gpGlobals->curtime - GetLastThink(); if ( dt == 0 ) dt = 0.1; // HACKHACK: We don't expect a real 'delta' orientation here, just enough of an error estimate to tell if this thing // is trying to move, but failing. QAngle delta = angles - m_lastOrientation; if ( ( delta.Length() / dt ) < ( vecAngVelocity.Length() * 0.01 ) ) { return 0.0f; } m_lastOrientation = angles; if ( m_bUseHelper == false ) { return vecAngVelocity.Length(); } else { Vector vLine = m_vecAxis - GetAbsOrigin(); VectorNormalize( vLine ); Vector vecWorldAngVelocity; pPhys->LocalToWorldVector( &vecWorldAngVelocity, vecAngVelocity ); float flDot = DotProduct( vecWorldAngVelocity, vLine ); return flDot; } } } else { QAngle vecAngVel = pEntity->GetLocalAngularVelocity(); float flMax = MAX(fabs(vecAngVel[PITCH]), fabs(vecAngVel[YAW])); return MAX(flMax, fabs(vecAngVel[ROLL])); } return 0; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CPhysicsCannister::Explode( CBaseEntity *pAttacker ) { // don't recurse m_takedamage = 0; Deactivate(); Vector velocity; AngularImpulse angVelocity; IPhysicsObject *pPhysics = VPhysicsGetObject(); pPhysics->GetVelocity( &velocity, &angVelocity ); PropBreakableCreateAll( GetModelIndex(), pPhysics, GetAbsOrigin(), GetAbsAngles(), velocity, angVelocity, 1.0, 20, COLLISION_GROUP_DEBRIS ); ExplosionCreate( GetAbsOrigin(), GetAbsAngles(), pAttacker, m_damage, 0, true ); UTIL_Remove( this ); }
//----------------------------------------------------------------------------- // Purpose: // Input : *pController - // *pObject - // deltaTime - // &linear - // &angular - // Output : IMotionEvent::simresult_e //----------------------------------------------------------------------------- IMotionEvent::simresult_e CAI_BasePhysicsFlyingBot::Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular ) { static int count; IPhysicsObject *pPhysicsObject = VPhysicsGetObject(); // Assert( pPhysicsObject ); if (!pPhysicsObject) return SIM_NOTHING; // move Vector actualVelocity; AngularImpulse actualAngularVelocity; pPhysicsObject->GetVelocity( &actualVelocity, &actualAngularVelocity ); linear = (m_vCurrentVelocity - actualVelocity) * (0.1 / deltaTime) * 10.0; /* DevMsg("Sim %d : %5.1f %5.1f %5.1f\n", count++, m_vCurrentVelocity.x - actualVelocity.x, m_vCurrentVelocity.y - actualVelocity.y, m_vCurrentVelocity.z - actualVelocity.z ); */ // do angles. Vector actualPosition; QAngle actualAngles; pPhysicsObject->GetPosition( &actualPosition, &actualAngles ); // FIXME: banking currently disabled, forces simple upright posture angular.x = (UTIL_AngleDiff( m_vCurrentBanking.z, actualAngles.z ) - actualAngularVelocity.x) * (1 / deltaTime); angular.y = (UTIL_AngleDiff( m_vCurrentBanking.x, actualAngles.x ) - actualAngularVelocity.y) * (1 / deltaTime); // turn toward target angular.z = UTIL_AngleDiff( m_fHeadYaw, actualAngles.y + actualAngularVelocity.z * 0.1 ) * (1 / deltaTime); // angular = m_vCurrentAngularVelocity - actualAngularVelocity; // DevMsg("Sim %d : %.1f %.1f %.1f (%.1f)\n", count++, actualAngles.x, actualAngles.y, actualAngles.z, m_fHeadYaw ); // FIXME: remove the stuff from MoveExecute(); // FIXME: check MOVE? ClampMotorForces( linear, angular ); return SIM_GLOBAL_ACCELERATION; // on my local axis. SIM_GLOBAL_ACCELERATION }
void C_PhysPropClientside::Break() { m_takedamage = DAMAGE_NO; IPhysicsObject *pPhysics = VPhysicsGetObject(); Vector velocity; AngularImpulse angVelocity; Vector origin; QAngle angles; AddSolidFlags( FSOLID_NOT_SOLID ); if ( pPhysics ) { pPhysics->GetVelocity( &velocity, &angVelocity ); pPhysics->GetPosition( &origin, &angles ); pPhysics->RecheckCollisionFilter(); } else { velocity = GetAbsVelocity(); QAngleToAngularImpulse( GetLocalAngularVelocity(), angVelocity ); origin = GetAbsOrigin(); angles = GetAbsAngles(); } breakablepropparams_t params( origin, angles, velocity, angVelocity ); params.impactEnergyScale = m_impactEnergyScale; params.defCollisionGroup = GetCollisionGroup(); if ( params.defCollisionGroup == COLLISION_GROUP_NONE ) { // don't automatically make anything COLLISION_GROUP_NONE or it will // collide with debris being ejected by breaking params.defCollisionGroup = COLLISION_GROUP_INTERACTIVE; } // no damage/damage force? set a burst of 100 for some movement params.defBurstScale = 100; // spwan break chunks PropBreakableCreateAll( GetModelIndex(), pPhysics, params, this, -1, false ); Release(); // destroy object }
void CGEGrenade::DelayThink() { if( gpGlobals->curtime > m_flDetonateTime ) { Explode(); return; } IPhysicsObject *pPhysicsObject = VPhysicsGetObject(); if ( pPhysicsObject ) { Vector vel; pPhysicsObject->GetVelocity( &vel, NULL ); if ( vel.Length() < 50.0f ) SetCollisionGroup( COLLISION_GROUP_MINE ); } SetNextThink( gpGlobals->curtime + 0.05 ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CTriggerPortalCleanser::TransferPhysicsObject( CBaseEntity *pFrom, CBaseEntity *pTo, bool wakeUp ) { IPhysicsObject *pVPhysics = pFrom->VPhysicsGetObject(); if ( !pVPhysics || pVPhysics->IsStatic() ) return false; Vector vecVelocity, vecAngular; pVPhysics->GetVelocity( &vecVelocity, &vecAngular ); // clear out the pointer so it won't get deleted pFrom->VPhysicsSwapObject( NULL ); // remove any AI behavior bound to it pVPhysics->RemoveShadowController(); // transfer to the new owner pTo->VPhysicsSetObject( pVPhysics ); pVPhysics->SetGameData( (void *)pTo ); pTo->VPhysicsUpdate( pVPhysics ); // may have been temporarily disabled by the old object pVPhysics->EnableMotion( true ); pVPhysics->EnableGravity( false ); // Slow down and push up the object. vecVelocity /= 2; vecAngular /= 2; vecVelocity.z += 10; pVPhysics->SetVelocity( &vecVelocity, &vecAngular ); // Update for the new entity solid type pVPhysics->RecheckCollisionFilter(); if ( wakeUp ) { pVPhysics->Wake(); } return true; }
//----------------------------------------------------------------------------- // 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; }
//----------------------------------------------------------------------------- // Purpose: Called when an entity starts touching us. // Input : pOther - The entity that is touching us. //----------------------------------------------------------------------------- void CTriggerPortalCleanser::StartTouch( CBaseEntity *pOther ) { if ( PassesTriggerFilters(pOther) ) { EHANDLE hOther; hOther = pOther; bool bAdded = false; if ( m_hTouchingEntities.Find( hOther ) == m_hTouchingEntities.InvalidIndex() ) { m_hTouchingEntities.AddToTail( hOther ); bAdded = true; } m_OnStartTouch.FireOutput(pOther, this); if ( bAdded && ( m_hTouchingEntities.Count() == 1 ) ) { // First entity to touch us that passes our filters m_OnStartTouchAll.FireOutput( pOther, this ); } if ( portal_cleanser_debug.GetBool() ) { Msg("%s START-TOUCH: for %s\n", GetDebugName(), pOther->GetDebugName() ); } if ( !pOther->IsPlayer() ) { CBaseAnimating *pAnim = pOther->GetBaseAnimating(); if ( !pAnim ) return; // Can't dissolve twice. if ( pAnim->IsDissolving() ) return; // Force player to drop this object. Pickup_ForcePlayerToDropThisObject( pOther ); if ( !FClassnameIs( pOther, "prop_physics" ) ) { if ( FClassnameIs( pOther, "simple_physics_prop" ) || FClassnameIs( pOther, "simple_physics_brush" ) ) { // simple_physics_prop ? return; } if ( portal_cleanser_debug.GetBool() ) { Msg("%s IS CREATING: simple_physics_prop\n", GetDebugName()); } // Other object needs to be replaced by simple_physics_prop. pOther = CreateSimplePhysicsObject( pOther ); // Dissolve the entity. CBaseAnimating *pAnim = pOther->GetBaseAnimating(); pAnim->Dissolve( NULL, gpGlobals->curtime, false, ENTITY_DISSOLVE_NORMAL ); if ( portal_cleanser_debug.GetBool() ) { Msg("%s DISSOLVE SIMPLE PHYSICS: %s\n", GetDebugName(), pOther->GetDebugName() ); } // Outputs m_hActivator = pOther; m_OnDissolve.FireOutput(m_hActivator, this); return; } IPhysicsObject *pPhysics = pOther->VPhysicsGetObject(); if ( pPhysics ) { // Dissolve the entity. pAnim->Dissolve( NULL, gpGlobals->curtime, false, ENTITY_DISSOLVE_NORMAL ); if ( portal_cleanser_debug.GetBool() ) { Msg("%s DISSOLVE PHYSICS: %s\n", GetDebugName(), pOther->GetDebugName() ); } // Turn off the gravity for this object. pPhysics->EnableGravity( false ); // Slow down and push up the object. Vector vecVelocity, vecAngular; pPhysics->GetVelocity( &vecVelocity, &vecAngular ); vecVelocity /= 2; vecAngular /= 2; vecVelocity.z += 10; pPhysics->SetVelocity( &vecVelocity, &vecAngular ); // Outputs m_hActivator = pOther; m_OnDissolve.FireOutput(m_hActivator, this); const char *pModelName = STRING( pOther->GetModelName() ); if ( Q_strstr( pModelName, "models/props/metal_box.mdl" ) ) { m_OnDissolveBox.FireOutput(m_hActivator, this); } } } } }
void CNPC_Dog::PullObject( bool bMantain ) { if ( m_hPhysicsEnt == NULL ) { TaskFail( "Ack! No Phys Object!"); return; } IPhysicsObject *pPhysObj = m_hPhysicsEnt->VPhysicsGetObject(); if ( pPhysObj == NULL ) { TaskFail( "Pulling object with no Phys Object?!" ); return; } if( pPhysObj->GetGameFlags() & FVPHYSICS_PLAYER_HELD ) { m_bHasObject = false; ClearBeams(); TaskFail("Player Grabbed Ball"); return; } CreateBeams(); Vector vGunPos; GetAttachment( m_iPhysGunAttachment, vGunPos ); float flDistance = ( vGunPos - m_hPhysicsEnt->WorldSpaceCenter() ).Length(); if ( bMantain == false ) { if ( flDistance <= DOG_CATCH_DISTANCE ) { m_hPhysicsEnt->SetOwnerEntity( this ); GetNavigator()->StopMoving(); //Fire Output! m_OnPickup.FireOutput( this, this ); m_bHasObject = true; ClearBeams(); TaskComplete(); return; } } Vector vDir = ( vGunPos - m_hPhysicsEnt->WorldSpaceCenter() ); Vector vCurrentVel; float flCurrentVel; AngularImpulse vCurrentAI; pPhysObj->GetVelocity( &vCurrentVel, &vCurrentAI ); flCurrentVel = vCurrentVel.Length(); VectorNormalize( vCurrentVel ); VectorNormalize( vDir ); float flVelMod = DOG_PULL_VELOCITY_MOD; if ( bMantain == true ) flVelMod *= 2; vCurrentVel = vCurrentVel * flCurrentVel * flVelMod; vCurrentAI = vCurrentAI * DOG_PULL_ANGULARIMP_MOD; pPhysObj->SetVelocity( &vCurrentVel, &vCurrentAI ); vDir = vDir * flDistance * (DOG_PULL_TO_GUN_VEL_MOD * 2); Vector vAngle( 0, 0, 0 ); pPhysObj->AddVelocity( &vDir, &vAngle ); }
//--------------------------------------------------------- //--------------------------------------------------------- void CNPC_Dog::RunTask( const Task_t *pTask ) { switch( pTask->iTask ) { case TASK_DOG_PICKUP_ITEM: { PullObject( false ); } break; case TASK_DOG_GET_PATH_TO_PHYSOBJ: { //Check this cause our object might have been deleted. if ( m_hPhysicsEnt == NULL ) FindPhysicsObject( NULL ); //And if we still can't find anything, then just go away. if ( m_hPhysicsEnt == NULL ) { TaskFail( "Can't find an object I like!" ); return; } IPhysicsObject *pPhysicsObject = m_hPhysicsEnt->VPhysicsGetObject(); Vector vecGoalPos; Vector vecDir; vecDir = GetLocalOrigin() - m_hPhysicsEnt->WorldSpaceCenter(); VectorNormalize(vecDir); vecDir.z = 0; if ( m_hPhysicsEnt->GetOwnerEntity() == NULL ) m_hPhysicsEnt->SetOwnerEntity( this ); if ( pPhysicsObject ) pPhysicsObject->RecheckCollisionFilter(); vecGoalPos = m_hPhysicsEnt->WorldSpaceCenter() + (vecDir * DOG_PHYSOBJ_MOVE_TO_DIST ); bool bBuiltRoute = false; //If I'm near my goal, then just walk to it. Activity aActivity = ACT_RUN; if ( ( vecGoalPos - GetLocalOrigin() ).Length() <= 128 ) aActivity = ACT_WALK; bBuiltRoute = GetNavigator()->SetGoal( AI_NavGoal_t( vecGoalPos, aActivity ), AIN_NO_PATH_TASK_FAIL ); if ( bBuiltRoute == true ) TaskComplete(); else { m_flTimeToCatch = gpGlobals->curtime + 0.1; m_flNextRouteTime = gpGlobals->curtime + 0.3; m_flNextSwat = gpGlobals->curtime + 0.1; if ( m_hUnreachableObjects.Find( m_hPhysicsEnt ) == -1 ) m_hUnreachableObjects.AddToTail( m_hPhysicsEnt ); m_hPhysicsEnt = NULL; GetNavigator()->ClearGoal(); } } break; case TASK_WAIT: { if ( IsWaitFinished() ) { TaskComplete(); } if ( m_hPhysicsEnt ) { if ( m_bHasObject == false ) { GetMotor()->SetIdealYawToTarget( m_hPhysicsEnt->GetAbsOrigin() ); GetMotor()->UpdateYaw(); } } break; } case TASK_DOG_LAUNCH_ITEM: if( IsActivityFinished() ) { if ( m_hPhysicsEnt ) { m_hPhysicsEnt->SetOwnerEntity( NULL ); } TaskComplete(); } break; case TASK_DOG_WAIT_FOR_TARGET_TO_FACE: { if ( CanTargetSeeMe() ) TaskComplete(); } break; case TASK_WAIT_FOR_MOVEMENT: { if ( GetState() == NPC_STATE_SCRIPT || IsInAScript() ) { BaseClass::RunTask( pTask ); return; } if ( m_hPhysicsEnt != NULL ) { IPhysicsObject *pPhysObj = m_hPhysicsEnt->VPhysicsGetObject(); if ( !pPhysObj ) { Warning( "npc_dog TASK_WAIT_FOR_MOVEMENT with NULL m_hPhysicsEnt->VPhysicsGetObject\n" ); } if ( pPhysObj && pPhysObj->GetGameFlags() & FVPHYSICS_PLAYER_HELD ) TaskFail( "Player picked it up!" ); //If the object is moving then my old goal might not be valid //cancel the schedule and make it restart again in a bit. if ( pPhysObj && pPhysObj->IsAsleep() == false && GetNavigator()->IsGoalActive() == false ) { Vector vecGoalPos; Vector vecDir; vecDir = GetLocalOrigin() - m_hPhysicsEnt->WorldSpaceCenter(); VectorNormalize(vecDir); vecDir.z = 0; vecGoalPos = m_hPhysicsEnt->WorldSpaceCenter() + (vecDir * DOG_PHYSOBJ_MOVE_TO_DIST ); GetNavigator()->ClearGoal(); float flDistance = (vecGoalPos - GetLocalOrigin()).Length(); //If I'm near my goal, then just walk to it. Activity aActivity = ACT_RUN; if ( ( vecGoalPos - GetLocalOrigin() ).Length() <= 128 ) aActivity = ACT_WALK; GetNavigator()->SetGoal( AI_NavGoal_t( vecGoalPos, aActivity ), AIN_NO_PATH_TASK_FAIL ); if ( flDistance <= DOG_PHYSOBJ_MOVE_TO_DIST ) { TaskComplete(); GetNavigator()->StopMoving(); } } } BaseClass::RunTask( pTask ); } break; case TASK_DOG_WAIT_FOR_OBJECT: { if ( m_hPhysicsEnt != NULL ) { if ( FVisible( m_hPhysicsEnt ) == false ) { m_flTimeToCatch = 0.0f; ClearBeams(); TaskFail( "Lost sight of the object!" ); m_hPhysicsEnt->SetOwnerEntity( NULL ); return; } m_hPhysicsEnt->SetOwnerEntity( this ); Vector vForward; AngleVectors( GetAbsAngles(), &vForward ); Vector vGunPos; GetAttachment( m_iPhysGunAttachment, vGunPos ); Vector vToObject = m_hPhysicsEnt->WorldSpaceCenter() - vGunPos; float flDistance = vToObject.Length(); VectorNormalize( vToObject ); SetAim( m_hPhysicsEnt->WorldSpaceCenter() - GetAbsOrigin() ); #ifdef SecobMod__Enable_Fixed_Multiplayer_AI CBasePlayer *pPlayer = UTIL_GetNearestVisiblePlayer(this); #else CBasePlayer *pPlayer = AI_GetSinglePlayer(); #endif //SecobMod__Enable_Fixed_Multiplayer_AI float flDistanceToPlayer = flDistance; if ( pPlayer ) { flDistanceToPlayer = (pPlayer->GetAbsOrigin() - m_hPhysicsEnt->WorldSpaceCenter()).Length(); } IPhysicsObject *pPhysObj = m_hPhysicsEnt->VPhysicsGetObject(); if ( !pPhysObj ) { Warning( "npc_dog: TASK_DOG_WAIT_FOR_OBJECT with m_hPhysicsEnt->VPhysicsGetObject == NULL\n" ); } if ( pPhysObj && !( pPhysObj->GetGameFlags() & FVPHYSICS_PLAYER_HELD ) && flDistanceToPlayer > ( flDistance * 2 ) ) { if ( m_flTimeToPull <= gpGlobals->curtime ) { Vector vCurrentVel; float flCurrentVel; AngularImpulse vCurrentAI; pPhysObj->GetVelocity( &vCurrentVel, &vCurrentAI ); flCurrentVel = vCurrentVel.Length(); VectorNormalize( vCurrentVel ); if ( pPhysObj && flDistance <= DOG_PULL_DISTANCE ) { Vector vDir = ( vGunPos - m_hPhysicsEnt->WorldSpaceCenter() ); VectorNormalize( vDir ); vCurrentVel = vCurrentVel * ( flCurrentVel * DOG_PULL_VELOCITY_MOD ); vCurrentAI = vCurrentAI * DOG_PULL_ANGULARIMP_MOD; pPhysObj->SetVelocity( &vCurrentVel, &vCurrentAI ); vDir = vDir * flDistance * DOG_PULL_TO_GUN_VEL_MOD; Vector vAngle( 0, 0, 0 ); pPhysObj->AddVelocity( &vDir, &vAngle ); CreateBeams(); } float flDot = DotProduct( vCurrentVel, vForward ); if ( flDistance >= DOG_PULL_DISTANCE && flDistance <= ( DOG_PULL_DISTANCE * 2 ) && flDot > -0.3 ) { if ( pPhysObj->IsAsleep() == false && !( pPhysObj->GetGameFlags() & FVPHYSICS_PLAYER_HELD ) ) { Vector vecGoalPos; Vector vecDir; vecDir = GetLocalOrigin() - m_hPhysicsEnt->WorldSpaceCenter(); VectorNormalize(vecDir); vecDir.z = 0; vecGoalPos = m_hPhysicsEnt->WorldSpaceCenter() + (vecDir * DOG_PHYSOBJ_MOVE_TO_DIST ); GetNavigator()->ClearGoal(); //If I'm near my goal, then just walk to it. Activity aActivity = ACT_RUN; if ( ( vecGoalPos - GetLocalOrigin() ).Length() <= 128 ) aActivity = ACT_WALK; GetNavigator()->SetGoal( AI_NavGoal_t( vecGoalPos, aActivity ), AIN_NO_PATH_TASK_FAIL ); } } } } float flDirDot = DotProduct( vToObject, vForward ); if ( flDirDot < 0.2 ) { GetMotor()->SetIdealYawToTarget( m_hPhysicsEnt->GetAbsOrigin() ); GetMotor()->UpdateYaw(); } if ( m_flTimeToCatch < gpGlobals->curtime && m_bDoWaitforObjectBehavior == false ) { m_hPhysicsEnt->SetOwnerEntity( NULL ); m_flTimeToCatch = 0.0f; ClearBeams(); TaskFail( "Done waiting!" ); } else if ( pPhysObj && ( flDistance <= DOG_CATCH_DISTANCE && !( pPhysObj->GetGameFlags() & FVPHYSICS_PLAYER_HELD ) ) ) { AngularImpulse vZero( 0, 0, 0 ); pPhysObj->SetVelocity( &vec3_origin, &vZero ); GetNavigator()->StopMoving(); //Fire Output! m_OnCatch.FireOutput( this, this ); m_bHasObject = true; ClearBeams(); TaskComplete(); } } else { GetNavigator()->StopMoving(); ClearBeams(); TaskFail("No Physics Object!"); } } break; case TASK_DOG_CATCH_OBJECT: if( IsActivityFinished() ) { m_flTimeToCatch = 0.0f; TaskComplete(); } break; default: BaseClass::RunTask( pTask ); break; } }
//----------------------------------------------------------------------------- // 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(); } }
Vector CASW_Simple_Alien::CalcDeathForceVector( const CTakeDamageInfo &info ) { // Already have a damage force in the data, use that. if ( info.GetDamageForce() != vec3_origin || (g_pGameRules->Damage_NoPhysicsForce(info.GetDamageType()))) { if( info.GetDamageType() & DMG_BLAST ) { float scale = random->RandomFloat( 0.85, 1.15 ); Vector force = info.GetDamageForce(); force.x *= scale; force.y *= scale; // Try to always exaggerate the upward force because we've got pretty harsh gravity force.z *= (force.z > 0) ? 1.15 : scale; return force; } return info.GetDamageForce(); } CBaseEntity *pForce = info.GetInflictor(); if ( !pForce ) { pForce = info.GetAttacker(); } if ( pForce ) { // Calculate an impulse large enough to push a 75kg man 4 in/sec per point of damage float forceScale = info.GetDamage() * 75 * 4; Vector forceVector; // If the damage is a blast, point the force vector higher than usual, this gives // the ragdolls a bodacious "really got blowed up" look. if( info.GetDamageType() & DMG_BLAST ) { // exaggerate the force from explosions a little (37.5%) forceVector = (GetLocalOrigin() + Vector(0, 0, WorldAlignSize().z) ) - pForce->GetLocalOrigin(); VectorNormalize(forceVector); forceVector *= 1.375f; } else { // taking damage from self? Take a little random force, but still try to collapse on the spot. if ( this == pForce ) { forceVector.x = random->RandomFloat( -1.0f, 1.0f ); forceVector.y = random->RandomFloat( -1.0f, 1.0f ); forceVector.z = 0.0; forceScale = random->RandomFloat( 1000.0f, 2000.0f ); } else { // UNDONE: Collision forces are baked in to CTakeDamageInfo now // UNDONE: Is this MOVETYPE_VPHYSICS code still necessary? if ( pForce->GetMoveType() == MOVETYPE_VPHYSICS ) { // killed by a physics object IPhysicsObject *pPhysics = VPhysicsGetObject(); if ( !pPhysics ) { pPhysics = pForce->VPhysicsGetObject(); } pPhysics->GetVelocity( &forceVector, NULL ); forceScale = pPhysics->GetMass(); } else { forceVector = GetLocalOrigin() - pForce->GetLocalOrigin(); VectorNormalize(forceVector); } } } return forceVector * forceScale; } return vec3_origin; }
void CNPC_Portal_FloorTurret::StartTouch( CBaseEntity *pOther ) { BaseClass::StartTouch( pOther ); IPhysicsObject *pOtherPhys = pOther->VPhysicsGetObject(); if ( !pOtherPhys ) return; if ( !m_pMotionController ) return; if ( m_pMotionController->Enabled() ) { m_pMotionController->Suspend( 2.0f ); IPhysicsObject *pTurretPhys = VPhysicsGetObject(); if ( !pOther->IsPlayer() && pOther->GetMoveType() == MOVETYPE_VPHYSICS && !(pTurretPhys && ((pTurretPhys->GetGameFlags() & FVPHYSICS_PLAYER_HELD) != 0)) ) { // Get a lateral impulse Vector vVelocityImpulse = GetAbsOrigin() - pOther->GetAbsOrigin(); vVelocityImpulse.z = 0.0f; if ( vVelocityImpulse.IsZero() ) { vVelocityImpulse.x = 1.0f; vVelocityImpulse.y = 1.0f; } VectorNormalize( vVelocityImpulse ); // If impulse is too much along the forward or back axis, skew it Vector vTurretForward, vTurretRight; GetVectors( &vTurretForward, &vTurretRight, NULL ); float fForwardDotImpulse = vTurretForward.Dot( vVelocityImpulse ); if ( fForwardDotImpulse > 0.7f || fForwardDotImpulse < -0.7f ) { vVelocityImpulse += vTurretRight; VectorNormalize( vVelocityImpulse ); } Vector vAngleImpulse( ( vTurretRight.Dot( vVelocityImpulse ) < 0.0f ) ? ( -1.6f ) : ( 1.6f ), RandomFloat( -0.5f, 0.5f ), RandomFloat( -0.5f, 0.5f ) ); vVelocityImpulse *= TURRET_FLOOR_PHYSICAL_FORCE_MULTIPLIER; vAngleImpulse *= TURRET_FLOOR_PHYSICAL_FORCE_MULTIPLIER; pTurretPhys->AddVelocity( &vVelocityImpulse, &vAngleImpulse ); // Check if another turret is hitting us CNPC_Portal_FloorTurret *pPortalFloor = dynamic_cast<CNPC_Portal_FloorTurret*>( pOther ); if ( pPortalFloor && pPortalFloor->m_lifeState == LIFE_ALIVE ) { Vector vTurretVelocity, vOtherVelocity; pTurretPhys->GetVelocity( &vTurretVelocity, NULL ); pOtherPhys->GetVelocity( &vOtherVelocity, NULL ); // If it's moving faster if ( vOtherVelocity.LengthSqr() > vTurretVelocity.LengthSqr() ) { // Make the turret falling onto this one talk pPortalFloor->EmitSound( GetTurretTalkName( PORTAL_TURRET_COLLIDE ) ); pPortalFloor->m_fNextTalk = gpGlobals->curtime + 1.2f; pPortalFloor->m_bDelayTippedTalk = true; // Delay out potential tipped talking so we can here the other turret talk m_fNextTalk = gpGlobals->curtime + 0.6f; m_bDelayTippedTalk = true; } } if ( pPortalFloor && m_bEnabled && m_bLaserOn && !m_bOutOfAmmo ) { // Award friendly fire achievement if we're a live turret being knocked over by another turret. IGameEvent *event = gameeventmanager->CreateEvent( "turret_hit_turret" ); if ( event ) { gameeventmanager->FireEvent( event ); } } } } }
Vector QUA_helicopter::CalcDamageForceVector( const CTakeDamageInfo &info ) { // Already have a damage force in the data, use that. if (info.GetDamageForce() != vec3_origin || (info.GetDamageType() & /*DMG_NO_PHYSICS_FORCE*/DMG_BLAST)) { //if( info.GetDamageType() & DMG_BLAST ) //{ // Fudge blast forces a little bit, so that each // victim gets a slightly different trajectory. // This simulates features that usually vary from // person-to-person variables such as bodyweight, // which are all indentical for characters using the same model. float scale = random->RandomFloat( 0.85, 1.15 ); Vector force = info.GetDamageForce(); force.x *= scale; force.y *= scale; // Try to always exaggerate the upward force because we've got pretty harsh gravity force.z *= (force.z > 0) ? 1.15 : scale; return force; //} return info.GetDamageForce(); } CBaseEntity *pForce = info.GetInflictor(); if ( !pForce ) { pForce = info.GetAttacker(); } if ( pForce ) { // Calculate an impulse large enough to push a 75kg man 4 in/sec per point of damage float forceScale = info.GetDamage() * 75 * 4; Vector forceVector; // If the damage is a blast, point the force vector higher than usual, this gives // the ragdolls a bodacious "really got blowed up" look. if( info.GetDamageType() & DMG_BLAST ) { // exaggerate the force from explosions a little (37.5%) forceVector = (GetLocalOrigin() + Vector(0, 0, WorldAlignSize().z) ) - pForce->GetLocalOrigin(); VectorNormalize(forceVector); forceVector *= 1.375f; } else { // taking damage from self? Take a little random force, but still try to collapse on the spot. if ( this == pForce ) { forceVector.x = random->RandomFloat( -1.0f, 1.0f ); forceVector.y = random->RandomFloat( -1.0f, 1.0f ); forceVector.z = 0.0; forceScale = random->RandomFloat( 1000.0f, 2000.0f ); } else { // UNDONE: Collision forces are baked in to CTakeDamageInfo now // UNDONE: Is this MOVETYPE_VPHYSICS code still necessary? if ( pForce->GetMoveType() == MOVETYPE_VPHYSICS ) { // killed by a physics object IPhysicsObject *pPhysics = VPhysicsGetObject(); if ( !pPhysics ) { pPhysics = pForce->VPhysicsGetObject(); } pPhysics->GetVelocity( &forceVector, NULL ); forceScale = pPhysics->GetMass(); } else { forceVector = GetLocalOrigin() - pForce->GetLocalOrigin(); VectorNormalize(forceVector); } } } return forceVector * forceScale; } return vec3_origin; }