void CNPC_Dog::CleanCatchAndThrow( bool bClearTimers ) { if ( m_hPhysicsEnt ) { if ( m_bHasObject == true ) { IPhysicsObject *pPhysObj = m_hPhysicsEnt->VPhysicsGetObject(); m_hPhysicsEnt->SetParent( NULL ); m_hPhysicsEnt->SetOwnerEntity( NULL ); Vector vGunPos; QAngle angGunAngles; GetAttachment( m_iPhysGunAttachment, vGunPos, angGunAngles ); if ( pPhysObj ) { pPhysObj->Wake(); pPhysObj->RemoveShadowController(); pPhysObj->SetPosition( vGunPos, angGunAngles, true ); } else { Warning( "CleanCatchAndThrow: m_hPhysicsEnt->VPhysicsGetObject == NULL!\n" ); } m_hPhysicsEnt->SetMoveType( (MoveType_t)m_iContainerMoveType ); if ( pPhysObj ) { pPhysObj->RecheckCollisionFilter(); } ClearBeams(); } m_hPhysicsEnt = NULL; } if ( bClearTimers == true ) { m_bDoCatchThrowBehavior = false; m_bDoWaitforObjectBehavior = false; m_flTimeToCatch = 0.0f; m_flNextSwat = 0.0f; SetCondition( COND_DOG_LOST_PHYSICS_ENTITY ); } }
//----------------------------------------------------------------------------- // 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; }
// UNDONE: Is this worth it?, just recreate the object instead? (that happens when this returns false anyway) // recreating works, but is more expensive and won't inherit properties (velocity, constraints, etc) bool TransferPhysicsObject( CBaseEntity *pFrom, CBaseEntity *pTo ) { IPhysicsObject *pVPhysics = pFrom->VPhysicsGetObject(); if ( !pVPhysics || pVPhysics->IsStatic() ) return false; // 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( true ); // Update for the new entity solid type pVPhysics->RecheckCollisionFilter(); return true; }
void CNPC_Dog::ThrowObject( const char *pAttachmentName ) { if ( m_hPhysicsEnt ) { m_bHasObject = false; IPhysicsObject *pPhysObj = m_hPhysicsEnt->VPhysicsGetObject(); if ( pPhysObj ) { Vector vGunPos; QAngle angGunAngles; AngularImpulse angVelocity = RandomAngularImpulse( -250 , -250 ) / pPhysObj->GetMass(); InvalidateBoneCache(); int iAttachment = LookupAttachment( pAttachmentName ); if ( iAttachment == 0 ) iAttachment = m_iPhysGunAttachment; GetAttachment( iAttachment, vGunPos, angGunAngles ); pPhysObj->Wake(); if ( pPhysObj->GetShadowController() ) { m_hPhysicsEnt->SetParent( NULL ); m_hPhysicsEnt->SetMoveType( (MoveType_t)m_iContainerMoveType ); m_hPhysicsEnt->SetOwnerEntity( this ); pPhysObj->RemoveShadowController(); pPhysObj->SetPosition( m_hPhysicsEnt->GetLocalOrigin(), m_hPhysicsEnt->GetLocalAngles(), true ); pPhysObj->RecheckCollisionFilter(); pPhysObj->RecheckContactPoints(); } if ( m_hThrowTarget == NULL ) #ifdef SecobMod__Enable_Fixed_Multiplayer_AI m_hThrowTarget = UTIL_GetNearestVisiblePlayer(this); #else m_hThrowTarget = AI_GetSinglePlayer(); #endif //SecobMod__Enable_Fixed_Multiplayer_AI Vector vThrowDirection; if ( m_hThrowTarget ) { Vector vThrowOrigin = m_hThrowTarget->GetAbsOrigin(); if ( m_hThrowTarget->IsPlayer() ) vThrowOrigin = vThrowOrigin + Vector( random->RandomFloat( -128, 128 ), random->RandomFloat( -128, 128 ), 0 ); Vector vecToss = VecCheckToss( this, vGunPos, vThrowOrigin, m_flThrowArcModifier, 1.0f, true ); if( vecToss == vec3_origin ) { // Fix up an impossible throw so dog will at least toss the box in the target's general direction instead of dropping it. // Also toss it up in the air so it will fall down and break. (Just throw the box up at a 45 degree angle) Vector forward, up; GetVectors( &forward, NULL, &up ); vecToss = forward + up; VectorNormalize( vecToss ); vecToss *= pPhysObj->GetMass() * 30.0f; } vThrowDirection = vecToss + ( m_hThrowTarget->GetSmoothedVelocity() / 2 ); Vector vLinearDrag; Vector unitVel = vThrowDirection; VectorNormalize( unitVel ); float flTest = 1000 / vThrowDirection.Length(); float flDrag = pPhysObj->CalculateLinearDrag( vThrowDirection ); vThrowDirection = vThrowDirection + ( unitVel * ( flDrag * flDrag ) ) / flTest; pPhysObj->SetVelocity( &vThrowDirection, &angVelocity ); m_flTimeToCatch = gpGlobals->curtime + dog_max_wait_time.GetFloat(); //Don't start pulling until the object is away from me. //We base the time on the throw velocity. m_flTimeToPull = gpGlobals->curtime + ( 1000 / vThrowDirection.Length() ); } //Fire Output! m_OnThrow.FireOutput( this, this ); ClearBeams(); if ( m_bBeamEffects == true ) { EmitSound( "Weapon_PhysCannon.Launch" ); CBeam *pBeam = CBeam::BeamCreate( "sprites/orangelight1.vmt", 1.8 ); if ( pBeam != NULL ) { pBeam->PointEntInit( m_hPhysicsEnt->WorldSpaceCenter(), this ); pBeam->SetEndAttachment( m_iPhysGunAttachment ); pBeam->SetWidth( 6.4 ); pBeam->SetEndWidth( 12.8 ); pBeam->SetBrightness( 255 ); pBeam->SetColor( 255, 255, 255 ); pBeam->LiveForTime( 0.2f ); pBeam->RelinkBeam(); pBeam->SetNoise( 2 ); } Vector shotDir = ( m_hPhysicsEnt->WorldSpaceCenter() - vGunPos ); VectorNormalize( shotDir ); CPVSFilter filter( m_hPhysicsEnt->WorldSpaceCenter() ); te->GaussExplosion( filter, 0.0f, m_hPhysicsEnt->WorldSpaceCenter() - ( shotDir * 4.0f ), RandomVector(-1.0f, 1.0f), 0 ); } } } }
//------------------------------------------------------------------------------ // Purpose : // Input : // Output : //------------------------------------------------------------------------------ void CNPC_CombineDropship::PrescheduleThink( void ) { BaseClass::PrescheduleThink(); // keep track of think time deltas for burn calc below float dt = gpGlobals->curtime - m_flLastTime; m_flLastTime = gpGlobals->curtime; switch( m_iLandState ) { case LANDING_NO: { if ( IsActivityFinished() && (GetActivity() != ACT_DROPSHIP_FLY_IDLE_EXAGG && GetActivity() != ACT_DROPSHIP_FLY_IDLE_CARGO) ) { if ( m_hContainer ) { SetIdealActivity( (Activity)ACT_DROPSHIP_FLY_IDLE_CARGO ); } else { SetIdealActivity( (Activity)ACT_DROPSHIP_FLY_IDLE_EXAGG ); } } DoRotorWash(); } break; case LANDING_LEVEL_OUT: { // Approach the drop point Vector vecToTarget = (GetDesiredPosition() - GetAbsOrigin()); float flDistance = vecToTarget.Length(); // If we're slowing, make it look like we're slowing /* if ( IsActivityFinished() && GetActivity() != ACT_DROPSHIP_DESCEND_IDLE ) { SetActivity( (Activity)ACT_DROPSHIP_DESCEND_IDLE ); } */ // Are we there yet? float flSpeed = GetAbsVelocity().Length(); if ( flDistance < 70 && flSpeed < 100 ) { m_flLandingSpeed = flSpeed; m_iLandState = LANDING_DESCEND; // save off current angles so we can work them out over time QAngle angles = GetLocalAngles(); m_existPitch = angles.x; m_existRoll = angles.z; } DoRotorWash(); } break; case LANDING_DESCEND: { float flAltitude; SetLocalAngularVelocity( vec3_angle ); // Ensure we land on the drop point Vector vecToTarget = (GetDesiredPosition() - GetAbsOrigin()); float flDistance = vecToTarget.Length(); float flRampedSpeed = m_flLandingSpeed * (flDistance / 70); Vector vecVelocity = (flRampedSpeed / flDistance) * vecToTarget; vecVelocity.z = -75; SetAbsVelocity( vecVelocity ); flAltitude = GetAltitude(); if ( IsActivityFinished() && GetActivity() != ACT_DROPSHIP_DESCEND_IDLE ) { SetActivity( (Activity)ACT_DROPSHIP_DESCEND_IDLE ); } if ( flAltitude < 72 ) { QAngle angles = GetLocalAngles(); // Level out quickly. angles.x = UTIL_Approach( 0.0, angles.x, 0.2 ); angles.z = UTIL_Approach( 0.0, angles.z, 0.2 ); SetLocalAngles( angles ); } else { // randomly move as if buffeted by ground effects // gently flatten ship from starting pitch/yaw m_existPitch = UTIL_Approach( 0.0, m_existPitch, 1 ); m_existRoll = UTIL_Approach( 0.0, m_existRoll, 1 ); QAngle angles = GetLocalAngles(); angles.x = m_existPitch + ( sin( gpGlobals->curtime * 3.5f ) * DROPSHIP_MAX_LAND_TILT ); angles.z = m_existRoll + ( sin( gpGlobals->curtime * 3.75f ) * DROPSHIP_MAX_LAND_TILT ); SetLocalAngles( angles ); // figure out where to face (nav point) Vector targetDir = GetDesiredPosition() - GetAbsOrigin(); // NDebugOverlay::Cross3D( m_pGoalEnt->GetAbsOrigin(), -Vector(2,2,2), Vector(2,2,2), 255, 0, 0, false, 20 ); QAngle targetAngles = GetAbsAngles(); targetAngles.y += UTIL_AngleDiff(UTIL_VecToYaw( targetDir ), targetAngles.y); // orient ship towards path corner on the way down angles = GetAbsAngles(); angles.y = UTIL_Approach(targetAngles.y, angles.y, 2 ); SetAbsAngles( angles ); } if ( flAltitude <= 0.5f ) { m_iLandState = LANDING_TOUCHDOWN; // upon landing, make sure ship is flat QAngle angles = GetLocalAngles(); angles.x = 0; angles.z = 0; SetLocalAngles( angles ); // TODO: Release cargo anim SetActivity( (Activity)ACT_DROPSHIP_DESCEND_IDLE ); } DoRotorWash(); // place danger sounds 1 foot above ground to get troops to scatter if they are below dropship Vector vecBottom = GetAbsOrigin(); vecBottom.z += WorldAlignMins().z; Vector vecSpot = vecBottom + Vector(0, 0, -1) * (GetAltitude() - 12 ); CSoundEnt::InsertSound( SOUND_DANGER, vecSpot, 400, 0.2, this, 0 ); CSoundEnt::InsertSound( SOUND_PHYSICS_DANGER, vecSpot, 400, 0.2, this, 1 ); // NDebugOverlay::Cross3D( vecSpot, -Vector(4,4,4), Vector(4,4,4), 255, 0, 255, false, 10.0f ); // now check to see if player is below us, if so, cause heat damage to them (i.e. get them to move) trace_t tr; Vector vecBBoxMin = CRATE_BBOX_MIN; // use flat box for check vecBBoxMin.z = -5; Vector vecBBoxMax = CRATE_BBOX_MAX; vecBBoxMax.z = 5; Vector pEndPoint = vecBottom + Vector(0, 0, -1) * ( GetAltitude() - 12 ); AI_TraceHull( vecBottom, pEndPoint, vecBBoxMin, vecBBoxMax, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr ); if ( tr.fraction < 1.0f ) { if ( tr.GetEntityIndex() == 1 ) // player??? { CTakeDamageInfo info( this, this, 20 * dt, DMG_BURN ); CBasePlayer *pPlayer = UTIL_PlayerByIndex(1); pPlayer->TakeDamage( info ); } } } break; case LANDING_TOUCHDOWN: { if ( IsActivityFinished() && ( GetActivity() != ACT_DROPSHIP_DESCEND_IDLE ) ) { SetActivity( (Activity)ACT_DROPSHIP_DESCEND_IDLE ); } m_iLandState = LANDING_UNLOADING; m_flTroopDeployPause = gpGlobals->curtime + DROPSHIP_PAUSE_B4_TROOP_UNLOAD; m_flTimeTakeOff = m_flTroopDeployPause + DROPSHIP_DEPLOY_TIME; } break; case LANDING_UNLOADING: { // pause before dropping troops if ( gpGlobals->curtime > m_flTroopDeployPause ) { if ( m_hContainer ) // don't drop troops if we don't have a crate any more { SpawnTroops(); m_flTroopDeployPause = m_flTimeTakeOff + 2; // only drop once } } // manage engine wash and volume if ( m_flTimeTakeOff - gpGlobals->curtime < 0.5f ) { m_engineThrust = UTIL_Approach( 1.0f, m_engineThrust, 0.1f ); DoRotorWash(); } else { float idleVolume = 0.2f; m_engineThrust = UTIL_Approach( idleVolume, m_engineThrust, 0.04f ); if ( m_engineThrust > idleVolume ) { DoRotorWash(); // make sure we're kicking up dust/water as long as engine thrust is up } } if( gpGlobals->curtime > m_flTimeTakeOff ) { m_iLandState = LANDING_LIFTOFF; SetActivity( (Activity)ACT_DROPSHIP_LIFTOFF ); m_engineThrust = 1.0f; // ensure max volume once we're airborne if ( m_bIsFiring ) { StopCannon(); // kill cannon sounds if they are on } // detach container from ship if ( m_hContainer && m_leaveCrate ) { m_hContainer->SetParent(NULL); m_hContainer->SetMoveType( (MoveType_t)m_iContainerMoveType ); // If the container has a physics object, remove it's shadow IPhysicsObject *pPhysicsObject = m_hContainer->VPhysicsGetObject(); if ( pPhysicsObject ) { pPhysicsObject->RemoveShadowController(); } m_hContainer = NULL; } } } break; case LANDING_LIFTOFF: { // give us some clearance before changing back to larger hull -- keeps ship from getting stuck on // things like the player, etc since we "pop" the hull... if ( GetAltitude() > 120 ) { m_OnFinishedDropoff.FireOutput( this, this ); m_iLandState = LANDING_NO; // change bounding box back to normal ship hull Vector vecBBMin, vecBBMax; ExtractBbox( SelectHeaviestSequence( ACT_DROPSHIP_DEPLOY_IDLE ), vecBBMin, vecBBMax ); UTIL_SetSize( this, vecBBMin, vecBBMax ); Relink(); } } break; case LANDING_SWOOPING: { // Did we lose our pickup target? if ( !m_hPickupTarget ) { m_iLandState = LANDING_NO; } else { // Decrease altitude and speed to hit the target point. Vector vecToTarget = (GetDesiredPosition() - GetAbsOrigin()); float flDistance = vecToTarget.Length(); // Start cheating when we get near it if ( flDistance < 50 ) { /* if ( flDistance > 10 ) { // Cheat and ensure we touch the target float flSpeed = GetAbsVelocity().Length(); Vector vecVelocity = vecToTarget; VectorNormalize( vecVelocity ); SetAbsVelocity( vecVelocity * min(flSpeed,flDistance) ); } else */ { // Grab the target m_hContainer = m_hPickupTarget; m_hPickupTarget = NULL; m_iContainerMoveType = m_hContainer->GetMoveType(); // If the container has a physics object, move it to shadow IPhysicsObject *pPhysicsObject = m_hContainer->VPhysicsGetObject(); if ( pPhysicsObject ) { pPhysicsObject->SetShadow( Vector(1e4,1e4,1e4), AngularImpulse(1e4,1e4,1e4), false, false ); pPhysicsObject->UpdateShadow( GetAbsOrigin(), GetAbsAngles(), false, 0 ); } int iIndex = 0;//LookupAttachment("Cargo"); /* Vector vecOrigin; QAngle vecAngles; GetAttachment( iIndex, vecOrigin, vecAngles ); m_hContainer->SetAbsOrigin( vecOrigin ); m_hContainer->SetAbsAngles( vec3_angle ); */ m_hContainer->SetAbsOrigin( GetAbsOrigin() ); m_hContainer->SetParent(this, iIndex); m_hContainer->SetMoveType( MOVETYPE_PUSH ); m_hContainer->RemoveFlag( FL_ONGROUND ); m_hContainer->Relink(); m_hContainer->SetAbsAngles( vec3_angle ); m_OnFinishedPickup.FireOutput( this, this ); m_iLandState = LANDING_NO; } } } DoRotorWash(); } break; } DoCombatStuff(); if ( GetActivity() != GetIdealActivity() ) { //Msg( "setactivity" ); SetActivity( GetIdealActivity() ); } }