void CFlowConvoyNode::InitConvoyCoaches()
{
	float distance = m_splitCoachIndex>0 ? m_splitDistanceOnPath : m_distanceOnPath;

	for (int i=m_coaches.size()-1; i>=0; --i)
	{
		if(m_splitCoachIndex>0 && i==m_splitCoachIndex-1)
			distance=m_distanceOnPath; // find the first train part end distance
		
		distance += m_coaches[i].m_coachOffset;
		m_coaches[i].m_distanceOnPath=distance;			
		distance += m_coaches[i].m_coachOffset;

		IPhysicalEntity* pPhysics = m_coaches[i].m_pEntity->GetPhysics();
		pe_params_flags flags;
		flags.flagsOR = pef_monitor_poststep|pef_fixed_damping;
		pPhysics->SetParams(&flags);

		pe_params_foreign_data pfd;
		pfd.iForeignFlagsOR = 0; //PFF_ALWAYS_VISIBLE;
		pPhysics->SetParams(&pfd);

		pe_simulation_params sp;
		sp.mass = -1;
		sp.damping = sp.dampingFreefall = 0;
		pPhysics->SetParams(&sp);
	}
}
void CGameVolume_Water::CreatePhysicsArea(const uint32 segmentIndex, const Matrix34& baseMatrix, const Vec3* pVertices, uint32 vertexCount, const bool isRiver, const float streamSpeed)
{
	//Destroy previous physics if any
	if(segmentIndex == 0)
	{
		DestroyPhysicsAreas();
	}

	SWaterSegment& segment = m_segments[segmentIndex];

	IWaterVolumeRenderNode* pWaterRenderNode = segment.m_pWaterRenderNode;
	Vec3 waterFlow(ZERO);

	CRY_ASSERT (segment.m_pWaterArea == NULL);
	CRY_ASSERT (pWaterRenderNode != NULL);

	pWaterRenderNode->SetMatrix( Matrix34::CreateIdentity() ); 
	segment.m_pWaterArea = pWaterRenderNode->SetAndCreatePhysicsArea( &pVertices[0], vertexCount );

	IPhysicalEntity* pWaterArea = segment.m_pWaterArea;
	if( pWaterArea )
	{
		const Quat entityWorldRot = Quat(baseMatrix);

		pe_status_pos posStatus;
		pWaterArea->GetStatus( &posStatus );

		const Vec3 areaPosition = baseMatrix.GetTranslation() + ((entityWorldRot * posStatus.pos) - posStatus.pos);

		pe_params_pos position;
		position.pos = areaPosition;
		position.q = entityWorldRot;
		pWaterArea->SetParams( &position);

		pe_params_buoyancy pb;
		pb.waterPlane.n = entityWorldRot * Vec3( 0, 0, 1 );
		pb.waterPlane.origin = areaPosition;

		if(isRiver)
		{
			int i = segmentIndex;
			int j = vertexCount - 1 - segmentIndex;
			pb.waterFlow = ((pVertices[1]-pVertices[0]).GetNormalized() + (pVertices[2]-pVertices[3]).GetNormalized()) / 2.f * streamSpeed;
		}
		pWaterArea->SetParams( &pb);

		pe_params_foreign_data pfd;
		pfd.pForeignData = pWaterRenderNode;
		pfd.iForeignData = PHYS_FOREIGN_ID_WATERVOLUME;
		pfd.iForeignFlags = 0;
		pWaterArea->SetParams(&pfd);

		segment.m_physicsLocalAreaCenter = posStatus.pos;
	}
}
示例#3
0
void CPlayerStateJump::OnExit( CPlayer& player, const bool isHeavyWeapon )
{
	if (m_jumpAction)
	{
		m_jumpAction->TriggerExit();
		m_jumpAction->Release();
		m_jumpAction = NULL;
	}

	IPhysicalEntity* pPhysEnt = player.GetEntity()->GetPhysics();
	if (pPhysEnt != NULL)
	{
		SAnimatedCharacterParams params = player.m_pAnimatedCharacter->GetParams();
		pe_player_dynamics pd;
		pd.kAirControl		= player.GetAirControl();
		pd.kAirResistance	= player.GetAirResistance();
		params.inertia		= player.GetInertia();

		if(player.IsRemote() && (g_pGameCVars->pl_velocityInterpAirControlScale > 0))
		{
			pd.kAirControl = g_pGameCVars->pl_velocityInterpAirControlScale;
		}

		pPhysEnt->SetParams(&pd);

		// Let Animated character handle the inertia
		player.SetAnimatedCharacterParams(params);
	}

	SetJumpState( player, JState_None );
}
示例#4
0
//------------------------------------------------------------------------
void CParachute::PhysicalizeCanvas(bool enable)
{
    IEntity* pCanvas = m_pEntitySystem->GetEntity(m_canvasId);
    if (!pCanvas)
        return;

    if (enable)
    {
        SEntityPhysicalizeParams params;
        params.type = PE_RIGID;
        params.mass = 0;
        pCanvas->Physicalize(params);

        IPhysicalEntity* pPhysics = pCanvas->GetPhysics();
        if (!pPhysics)
            return;

        // add parachute physics geometry
        m_paraPhysIds.clear();
        m_paraPhysIds.resize(8);

        for(int iCel=0; iCel<7; iCel++)
        {
            SWing *pCel = &m_aCels[iCel];

            m_paraPhysIds.push_back( AddCel(pPhysics, iCel+1, pCel) );

            pCel->fSurface = pCel->vSize.x * pCel->vSize.y;

            pCel->pLiftPointsMap = &m_LiftPointsMap;
            pCel->pDragPointsMap = &m_DragPointsMap;
        }
        Vec3 minExt(0.0f,0.0f,0.95f), maxExt(0.5f,0.3f,1.9f);
        m_paraPhysIds.push_back( AddBox(&minExt, &maxExt, 70.0f) );

        pe_params_part pp;
        pp.partid = m_paraPhysIds.back();
        pp.flagsAND = ~(geom_collides);
        pPhysics->SetParams(&pp);

        pe_status_dynamics stats;
        pPhysics->GetStatus(&stats);
        CryLog("Parachute mass: %f", stats.mass);
    }
    else
    {
        IPhysicalEntity* pPhysics = pCanvas->GetPhysics();
        if (pPhysics)
        {
            // remove parachute geometry
            for (std::vector<int>::iterator it = m_paraPhysIds.begin(); it != m_paraPhysIds.end(); ++it)
            {
                pPhysics->RemoveGeometry(*it);
            }
        }
        m_paraPhysIds.clear();
    }
}
//------------------------------------------------------------------------
void CVehicleMovementHelicopter::Physicalize()
{
	CVehicleMovementBase::Physicalize();

	IPhysicalEntity * pPhysicalEntity = GetPhysics();

	pe_params_flags pf;
	pf.flagsOR = pef_ignore_areas;
	pPhysicalEntity->SetParams(&pf);

	pe_simulation_params simParams;
	simParams.iSimClass = SC_ACTIVE_RIGID;
	simParams.damping = 0.0f;
	simParams.dampingFreefall = 0.0f;
	simParams.gravity = Vec3(0.0f, 0.0f, 0.0f);
	simParams.minEnergy = 0.0f;
	pPhysicalEntity->SetParams(&simParams);
}
示例#6
0
//------------------------------------------------------------------------
void CGunTurret::UpdatePhysics()
{
	int slots[] = {eIGS_Aux0,eIGS_Aux1,eIGS_ThirdPerson};
	int slots_num = 3;

	if(m_destroyed)
	{
		slots[1] = eIGS_Destroyed;
		slots_num = 2;
	}

	if(IEntity *pParent = GetEntity()->GetParent())
	{
		IPhysicalEntity *pParentPhysics = pParent->GetPhysics();
		IEntityPhysicalProxy *pPhysicsProxy = (IEntityPhysicalProxy *)GetEntity()->GetProxy(ENTITY_PROXY_PHYSICS);

		if(pParentPhysics && pPhysicsProxy)
		{
			Matrix34 localTM = GetEntity()->GetLocalTM();
			localTM.OrthonormalizeFast();
			Quat localQ = Quat(localTM);

			for(int i=0; i<slots_num; ++i)
			{
				pe_params_part params;

				params.partid = slots[i] + pPhysicsProxy->GetPartId0();

				const Matrix34 &slotTM = GetEntity()->GetSlotLocalTM(slots[i], false);

				params.pos = slotTM.GetTranslation();
				params.q = Quat(slotTM);

				params.pos = localTM * params.pos;
				params.q = localQ * params.q;
				pParentPhysics->SetParams(&params);
			}
		}
	}
	else
	{
		if(IPhysicalEntity *pPhysics = GetEntity()->GetPhysics())
		{
			for(int i=0; i<slots_num; ++i)
			{
				pe_params_part params;
				params.partid = slots[i];

				Matrix34 slotTM = GetEntity()->GetSlotLocalTM(slots[i], false);
				params.pMtx3x4 = &slotTM;

				pPhysics->SetParams(&params);
			}
		}
	}
}
示例#7
0
void CBaseGrabHandler::IgnoreCollision(EntityId eID,unsigned int flags,bool ignore)
{
	IEntity *pGrab = gEnv->pEntitySystem->GetEntity(eID);
	IPhysicalEntity *ppGrab = pGrab ? pGrab->GetPhysics() : NULL;

	if(!ppGrab) return;

	if(ignore)
	{
		// NOTE Dez 14, 2006: <pvl> this whole block just fills in
		// a request structure and passes it to physics
		IEntity *pEnt = m_pActor->GetEntity();

		pe_action_add_constraint ac;
		ac.flags = constraint_inactive|constraint_ignore_buddy;
		ac.pBuddy = pEnt->GetPhysics();
		ac.pt[0].Set(0,0,0);

		ICharacterInstance *pCharacter = pEnt->GetCharacter(0);
		IPhysicalEntity *pPhysEnt = pCharacter?pCharacter->GetISkeletonPose()->GetCharacterPhysics(-1):NULL;

		if(pPhysEnt)
		{
			pe_simulation_params sp;
			pPhysEnt->GetParams(&sp);

			if(sp.iSimClass <= 2)
				ac.pBuddy = pPhysEnt;
		}

		ppGrab->Action(&ac);
	}
	else
	{
		// NOTE Dez 14, 2006: <pvl> the same as the other branch - just
		// fill in a request and pass it to the physics engine
		pe_action_update_constraint uc;
		uc.bRemove = 1;

		ppGrab->Action(&uc);
	}

	// NOTE Dez 14, 2006: <pvl> flag manipulation is basically a legacy
	// code - probably not used anymore, scheduled for removal.
	if(flags)
	{
		pe_params_part pp;
		pp.flagsAND = pp.flagsColliderAND = ~flags;
		pp.flagsOR = pp.flagsColliderOR = flags * (ignore?0:1);

		pe_status_nparts status_nparts;

		for(pp.ipart = ppGrab->GetStatus(&status_nparts)-1; pp.ipart>=0; pp.ipart--)
			ppGrab->SetParams(&pp);
	}
}
示例#8
0
void CPlayerStateUtil::PhySetFly( CPlayer& player )
{
	IPhysicalEntity* pPhysEnt = player.GetEntity()->GetPhysics();
	if (pPhysEnt != NULL)
	{
		pe_player_dynamics pd;
		pd.bSwimming = true;
		pd.kAirControl = 1.0f;
		pd.kAirResistance = 0.0f;
		pd.gravity.zero();
		pPhysEnt->SetParams(&pd);
	}
}
示例#9
0
void CPlayerStateUtil::PhySetNoFly( CPlayer& player, const Vec3& gravity )
{
	IPhysicalEntity* pPhysEnt = player.GetEntity()->GetPhysics();
	if (pPhysEnt != NULL)
	{
		pe_player_dynamics pd;
		pd.kAirControl = player.GetAirControl();
		pd.kAirResistance = player.GetAirResistance();
		pd.bSwimming = false;
		pd.gravity = gravity;
		player.m_actorPhysics.gravity = gravity;

		pPhysEnt->SetParams(&pd);
	}
}
//------------------------------------------------------------------------
void CVehicleMovementTank::SetLatFriction(float latFric)
{
	// todo: do calculation per-wheel?
	IPhysicalEntity* pPhysics = GetPhysics();  
	int numWheels = m_pVehicle->GetWheelCount();    

	pe_params_wheel params;
	params.kLatFriction = latFric;

	for (int i=0; i<numWheels; ++i)
	{    
		params.iWheel = i;    
		pPhysics->SetParams(&params, THREAD_SAFE);
	}

	m_latFriction = latFric;
}
示例#11
0
//------------------------------------------------------------------------
bool CNetworkedPhysicsEntity::SetAspectProfile( EEntityAspects aspect, uint8 profile )
{
	bool bRetVal = false;
	if (aspect == eEA_Physics)
	{
		switch (profile)
		{
			case ePhys_PhysicalizedRigid:
			{
				if (m_physicsType!=ePhys_PhysicalizedRigid)
				{
					m_physicsParams.type = PE_RIGID;
					GetEntity()->Physicalize(m_physicsParams);
					m_physicsType = ePhys_PhysicalizedRigid;
					GetEntity()->GetPhysics()->SetParams(m_physicsParams.pBuoyancy);
				}
				bRetVal = true;
				break;
			}
			case ePhys_PhysicalizedStatic:
			{
				if (m_physicsType != ePhys_PhysicalizedStatic)
				{
					m_physicsParams.type = PE_STATIC;
					GetEntity()->Physicalize(m_physicsParams);
					m_physicsType = ePhys_PhysicalizedStatic;
				}
				bRetVal = true;
				break;
			}
			case ePhys_NotPhysicalized:
			{
				if (m_physicsType!=ePhys_NotPhysicalized)
				{
					SEntityPhysicalizeParams params;
					params.type = PE_NONE;
					GetEntity()->Physicalize(params);
					m_physicsType = ePhys_NotPhysicalized;
				}
				bRetVal = true;
				break;
			}
			default:
				{
					CryLog("Unsupported physicalization type in CNetworkedPhysicsEntity!");
				}
		}
	}

	IPhysicalEntity * pPhysEnt = GetEntity()->GetPhysics();
	if(pPhysEnt)
	{
			// Turn off some collisions
			// NB: by leaving pe_params_part.ipart undefined, all the geom flags will changed
			pe_params_part pp;
			pp.flagsAND = ~(geom_colltype_ray|geom_colltype_player|geom_colltype_explosion|geom_colltype_debris|geom_colltype_foliage_proxy);
			pPhysEnt->SetParams(&pp);

			pe_simulation_params psp;
			psp.damping = 0.5f;
			pPhysEnt->SetParams(&psp);

			//Add a bit of angular velocity so it doesn't look bizzare.
			pe_action_set_velocity physicsAction;
			physicsAction.w.Set((rnd()-0.5f)*15.0f, (rnd()-0.5f)*15.0f, (rnd()-0.5f)*15.0f);
			pPhysEnt->Action(&physicsAction);
	}

	return bRetVal;
}
//------------------------------------------------------------------------
void CVehicleDamageBehaviorBlowTire::Activate(bool activate)
{
  if (activate == m_isActive)
    return;

  if (activate && m_pVehicle->IsDestroyed())
    return;

	if (activate)
	{
		// NOTE: stance and physics position when getting into vehicles is set wrong
		if (!gEnv->pSystem->IsSerializingFile())
			DamagePlayers();
	}

  IVehicleComponent* pComponent = m_pVehicle->GetComponent(m_component.c_str());
  if (!pComponent)
    return;

  IVehiclePart* pPart = pComponent->GetPart(0);
  if (!pPart)
    return;

  // if IVehicleWheel available, execute full damage behavior. if null, only apply effects
  IVehicleWheel* pWheel = pPart->GetIWheel();
  
  if (activate)
  {
    IEntity* pEntity = m_pVehicle->GetEntity();
    IPhysicalEntity* pPhysics = pEntity->GetPhysics();
    const Matrix34& wheelTM = pPart->GetLocalTM(false);
    const SVehicleStatus& status = m_pVehicle->GetStatus();

    if (pWheel)
    { 
      const pe_cargeomparams* pParams = pWheel->GetCarGeomParams();  
            
      // handle destroyed wheel
      pe_params_wheel wheelParams;
      wheelParams.iWheel = pWheel->GetWheelIndex();            
      wheelParams.minFriction = wheelParams.maxFriction = 0.5f * pParams->maxFriction;      
      pPhysics->SetParams(&wheelParams); 
      
      if (IVehicleMovement* pMovement = m_pVehicle->GetMovement())
      { 
        SVehicleMovementEventParams params;
        params.pComponent = pComponent;
        params.iValue = pWheel->GetWheelIndex();
        pMovement->OnEvent(IVehicleMovement::eVME_TireBlown, params);
      }

      if (status.speed > 0.1f)
      {
        // add angular impulse
        pe_action_impulse angImp;
        float amount = m_pVehicle->GetMass() * status.speed * Random(0.25f, 0.45f) * -sgn(wheelTM.GetTranslation().x);
        angImp.angImpulse = pEntity->GetWorldTM().TransformVector(Vec3(0,0,amount));    
        pPhysics->Action(&angImp);
      }
      
      m_aiImmobilizedTimer = m_pVehicle->SetTimer(-1, AI_IMMOBILIZED_TIME*1000, this);  
    }

    if (!gEnv->pSystem->IsSerializingFile())
    {
      // add linear impulse       
      pe_action_impulse imp;
      imp.point = pPart->GetWorldTM().GetTranslation();

      float amount = m_pVehicle->GetMass() * Random(0.1f, 0.15f);

      if (pWheel)
      {
        amount *= max(0.5f, min(10.f, status.speed));

        if (status.speed < 0.1f)
          amount = -0.5f*amount;
      }
      else    
        amount *= 0.5f;

      imp.impulse = pEntity->GetWorldTM().TransformVector(Vec3(0,0,amount));
      pPhysics->Action(&imp);     

      // effect
      IParticleEffect* pEffect = gEnv->pParticleManager->FindEffect(TIRE_BLOW_EFFECT);
      if (pEffect)
      {
        int slot = pEntity->LoadParticleEmitter(-1, pEffect);
        if (slot > -1)
        { 
          float rotation = pWheel ? 0.5f * gf_PI * -sgn(wheelTM.GetTranslation().x) : gf_PI;
          Matrix34 tm = Matrix34::CreateRotationZ(rotation);        
          tm.SetTranslation(wheelTM.GetTranslation());        
          pEntity->SetSlotLocalTM(slot, tm);
        }
      }

			// remove affected decals
			{
				Vec3 pos = pPart->GetWorldTM().GetTranslation();
				AABB aabb = pPart->GetLocalBounds();
				float radius = aabb.GetRadius();
				Vec3 vRadius(radius,radius,radius);
        AABB areaBox(pos-vRadius, pos+vRadius);
        
        IRenderNode * pRenderNode = NULL;				
        if (IEntityRenderProxy *pRenderProxy = (IEntityRenderProxy*)pEntity->GetProxy(ENTITY_PROXY_RENDER))
					pRenderNode = pRenderProxy->GetRenderNode();

        gEnv->p3DEngine->DeleteDecalsInRange(&areaBox, pRenderNode);
			}
    }    
  }
  else
  { 
    if (pWheel)
    {
      // restore wheel properties        
      IPhysicalEntity* pPhysics = m_pVehicle->GetEntity()->GetPhysics();    
      pe_params_wheel wheelParams;

      for (int i=0; i<m_pVehicle->GetWheelCount(); ++i)
      { 
        const pe_cargeomparams* pParams = m_pVehicle->GetWheelPart(i)->GetIWheel()->GetCarGeomParams();

        wheelParams.iWheel = i;
        wheelParams.bBlocked = 0;
        wheelParams.suspLenMax = pParams->lenMax;
        wheelParams.bDriving = pParams->bDriving;      
        wheelParams.minFriction = pParams->minFriction;
        wheelParams.maxFriction = pParams->maxFriction;
        pPhysics->SetParams(&wheelParams);
      }

			if (IVehicleMovement* pMovement = m_pVehicle->GetMovement())
			{ 
				SVehicleMovementEventParams params;
				params.pComponent = pComponent;
				params.iValue = pWheel->GetWheelIndex();
				// reset the particle status
				pMovement->OnEvent(IVehicleMovement::eVME_TireRestored, params);
			}
    }  
    
    m_aiImmobilizedTimer = -1;
  }

  m_isActive = activate;      
}
int CFlowConvoyNode::OnPhysicsPostStep(const EventPhys * pEvent)
{
	FUNCTION_PROFILER(GetISystem(), PROFILE_GAME);

  if(m_bFirstUpdate)
    return 0; //after QuickLoad OnPhysicsPostStep called before ProcessEvent

	const EventPhysPostStep *pPhysPostStepEvent = (const EventPhysPostStep *)pEvent;

	IPhysicalEntity *pEventPhysEnt = pPhysPostStepEvent->pEntity;

	Vec3 posBack, posFront, posCenter;

	for (size_t i = 0; i < m_coaches.size(); ++i)
	{
		IPhysicalEntity *pPhysEnt = m_coaches[i].m_pEntity->GetPhysics();

		if (pEventPhysEnt == pPhysEnt)
		{
			if (m_ShiftTime > 0.0f)
			{
				m_speed = m_speed * (1.0f - breakValue * pPhysPostStepEvent->dt / m_MaxShiftTime);
				m_ShiftTime -= pPhysPostStepEvent->dt;
			}
			else
			{
				m_speed = m_speed + min(1.0f, (pPhysPostStepEvent->dt / 5.0f)) * (m_desiredSpeed - m_speed);
			}
		

			float speed = (m_splitCoachIndex > 0 && (int)i >= m_splitCoachIndex) ? m_splitSpeed : m_speed;
			float distance = (m_coaches[i].m_distanceOnPath += pPhysPostStepEvent->dt * speed);
			
			if(m_splitCoachIndex>0)
			{//train splitted
				if(i==m_splitCoachIndex-1) // update m_distanceOnPath for serialization
					m_distanceOnPath=distance-m_coaches[i].m_coachOffset;
				else if(i==m_coaches.size()-1) // update m_splitDistanceOnPath for serialization
					m_splitDistanceOnPath=distance-m_coaches[i].m_coachOffset;
			}
			else
			{//train in one piece
				if(i==m_coaches.size()-1)// update m_distanceOnPath for serialization
					m_distanceOnPath=distance-m_coaches[i].m_coachOffset;
			}

			posBack  = m_path.GetPointAlongPath(distance - m_coaches[i].m_wheelDistance, m_coaches[i].m_backWheelIterator[0]);
			posFront = m_path.GetPointAlongPath(distance + m_coaches[i].m_wheelDistance, m_coaches[i].m_frontWheelIterator[0]);
			posCenter = (posBack+posFront)*0.5f;


			Vec3 posDiff = posFront - posBack;
			float magnitude = posDiff.GetLength();

			if (magnitude > FLT_EPSILON)
			{
				posDiff *= 1.0f / magnitude;

				pe_params_pos ppos;
				ppos.pos = posCenter;
				ppos.q = Quat::CreateRotationVDir(posDiff);
				if (m_bXAxisFwd)
					ppos.q *= Quat::CreateRotationZ(gf_PI*-0.5f);
				pPhysEnt->SetParams(&ppos, 0 /* bThreadSafe=0 */); // as we are calling from the physics thread

				Vec3 futurePositionBack, futurePositionFront;
				futurePositionBack  = m_path.GetPointAlongPath(distance + PATH_DERIVATION_TIME * speed - m_coaches[i].m_wheelDistance, m_coaches[i].m_backWheelIterator[1]);
				futurePositionFront = m_path.GetPointAlongPath(distance + PATH_DERIVATION_TIME * speed + m_coaches[i].m_wheelDistance, m_coaches[i].m_frontWheelIterator[1]);

				Vec3 futurePosDiff = futurePositionFront - futurePositionBack;
				magnitude = futurePosDiff.GetLength();

				if (magnitude > FLT_EPSILON)
				{
					futurePosDiff *= 1.0f / magnitude;

					pe_action_set_velocity setVel;
					setVel.v = ((futurePositionBack+ futurePositionFront)*0.5f - posCenter) * (1.0f/PATH_DERIVATION_TIME);

					//Vec3 dir=(posFront-posBack).GetNormalized();
					//Vec3 future_dir=(futurePositionFront-futurePositionBack).GetNormalized();
					Vec3 w=posDiff.Cross(futurePosDiff);
					float angle=cry_asinf(w.GetLength());
					setVel.w=(angle/PATH_DERIVATION_TIME)*w.GetNormalized();
					pPhysEnt->Action(&setVel, 0 /* bThreadSafe=0 */); // as we are calling from the physics thread
					break;
				}
			}
		}
	}

	// Done processing once we reach end of path
	if (m_atEndOfPath)
		m_processNode = false;

	return 0;
}
//------------------------------------------------------------------------
void CVehicleMovementHelicopter::OnEvent(EVehicleMovementEvent event, const SVehicleMovementEventParams& params)
{
	switch (event)
	{
	case eVME_Repair:
		{
			if(params.fValue < 0.25)
			{
				m_damageActual = 0.0f;
				m_damage = 0.0f;
			}
		}
		break;

  case eVME_Collision:
    {
      if (0)
      {
        m_isEnginePowered = false;

        pe_simulation_params simParams;
        simParams.dampingFreefall = 0.01f;
        simParams.gravity = Vec3(0.0f, 0.0f, -9.8f);
        GetPhysics()->SetParams(&simParams);
      }
    }
    break;

	case eVME_GroundCollision:
		{
			const float stopOver = 1.0f;
		}
		break;

	case eVME_Damage:
		{
      if (!m_pVehicle->IsIndestructable())
      {
			  const float stopOver = 1.0f;

			  m_damage = params.fValue;

        if (m_damage > 0.95f)
        {
          m_isEngineDisabled	= true;
          m_isEnginePowered	= false;

          StopExhaust();
          StopSounds();

					IPhysicalEntity * pPhysicalEntity = GetPhysics();

          pe_action_impulse impulse;
          impulse.angImpulse = Vec3(0.1f, 100.f, 0.0f);
          pPhysicalEntity->Action(&impulse);

          pe_simulation_params simParams;
          simParams.dampingFreefall = 0.01f;
          simParams.gravity = Vec3(0.0f, 0.0f, -9.8f);
          pPhysicalEntity->SetParams(&simParams);

          SVehicleEventParams eventParams;
          eventParams.entityId = 0;
          m_pVehicle->BroadcastVehicleEvent(eVE_Destroyed, eventParams);

          if (m_pVehicle)
          {
            if (IEntity *entity = m_pVehicle->GetEntity())
            {
              if (IAIObject *aiobject = entity->GetAI())
              {
                aiobject->Event(AIEVENT_DISABLE, NULL);
              }
            }
          }
        }
      }
		}
		break;

	case eVME_WarmUpEngine:
		m_enginePower = m_enginePowerMax;
		break;

	//case eVME_Turbulence:
	//	m_turbulence = max(m_turbulence, params.fValue);
	//	break;

	default:
		CVehicleMovementBase::OnEvent(event, params);
		break; 
	}
}
示例#15
0
void CPlayerStateJump::StartJump( CPlayer& player, const bool isHeavyWeapon, const float fVerticalSpeedModifier )
{
	const SActorPhysics& actorPhysics = player.GetActorPhysics();
	const SPlayerStats& stats = *player.GetActorStats();
	const float onGroundTime = 0.2f;

	float g = actorPhysics.gravity.len();

	const float jumpHeightScale = 1.0f;
	const float jumpHeight = player.GetActorParams().jumpHeight * jumpHeightScale;

	float playerZ = player.GetEntity()->GetWorldPos().z;
	float expectedJumpEndHeight = playerZ + jumpHeight;

	pe_player_dimensions dimensions;
	IPhysicalEntity *pPhysics = player.GetEntity()->GetPhysics();
	if (pPhysics && pPhysics->GetParams(&dimensions))
	{
		float physicsBottom = dimensions.heightCollider - dimensions.sizeCollider.z;
		if (dimensions.bUseCapsule)
		{
			physicsBottom -= dimensions.sizeCollider.x;
		}
		expectedJumpEndHeight += physicsBottom;
	}

	float jumpSpeed = 0.0f;

 	if (g > 0.0f)
	{
		jumpSpeed = sqrt_tpl(2.0f*jumpHeight*(1.0f/g)) * g;

		if( isHeavyWeapon )
		{
			jumpSpeed *= g_pGameCVars->pl_movement.nonCombat_heavy_weapon_speed_scale;
		}
	}

	//this is used to easily find steep ground
	float slopeDelta = (Vec3Constants<float>::fVec3_OneZ - actorPhysics.groundNormal).len();

	SetJumpState(player, JState_Jump);

	Vec3 jumpVec(ZERO);

	bool bNormalJump = true;
	
	player.PlaySound(CPlayer::ESound_Jump);

	OnSpecialMove(player, IPlayerEventListener::eSM_Jump);

	CCCPOINT_IF( player.IsClient(),   PlayerMovement_LocalPlayerNormalJump);
	CCCPOINT_IF(!player.IsClient(), PlayerMovement_NonLocalPlayerNormalJump);

	{
		// This was causing the vertical jumping speed to be much slower.
		float verticalMult = max(1.0f - m_jumpLock, 0.3f);

		const Quat baseQuat = player.GetBaseQuat();
		jumpVec += baseQuat.GetColumn2() * jumpSpeed * verticalMult;
		jumpVec.z += fVerticalSpeedModifier;

#ifdef STATE_DEBUG
		if (g_pGameCVars->pl_debugInterpolation > 1)
		{
			CryWatch("Jumping: vec from player BaseQuat only = (%f, %f, %f)", jumpVec.x, jumpVec.y, jumpVec.z);
		}
#endif
		
		if (g_pGameCVars->pl_adjustJumpAngleWithFloorNormal && actorPhysics.groundNormal.len2() > 0.0f)
		{
			float vertical = clamp_tpl((actorPhysics.groundNormal.z - 0.25f) / 0.5f, 0.0f, 1.0f);
			Vec3 modifiedJumpDirection = LERP(actorPhysics.groundNormal, Vec3(0,0,1), vertical);
			jumpVec = modifiedJumpDirection * jumpVec.len();
		}

#ifdef STATE_DEBUG
		if (g_pGameCVars->pl_debugInterpolation > 1)
		{
			CryWatch("Jumping (%f, %f, %f)", jumpVec.x, jumpVec.y, jumpVec.z);
		}
#endif
	}

	NETINPUT_TRACE(player.GetEntityId(), jumpVec);

	FinalizeVelocity( player, jumpVec );

	if (!player.IsRemote())
	{
		player.HasJumped(player.GetMoveRequest().velocity);
	}

	IPhysicalEntity* pPhysEnt = player.GetEntity()->GetPhysics();
	if (pPhysEnt != NULL)
	{
		SAnimatedCharacterParams params = player.m_pAnimatedCharacter->GetParams();
		pe_player_dynamics pd;
		pd.kAirControl = player.GetAirControl()* g_pGameCVars->pl_jump_control.air_control_scale;
		pd.kAirResistance = player.GetAirResistance() * g_pGameCVars->pl_jump_control.air_resistance_scale;

		params.inertia = player.GetInertia() * g_pGameCVars->pl_jump_control.air_inertia_scale;

		if(player.IsRemote() && (g_pGameCVars->pl_velocityInterpAirControlScale > 0))
		{
			pd.kAirControl = g_pGameCVars->pl_velocityInterpAirControlScale;
		}

		pPhysEnt->SetParams(&pd);

		// Let Animated character handle the inertia
		player.SetAnimatedCharacterParams(params);
	}

#if 0
	if (debugJumping)
	{
		Vec3 entityPos = m_player.GetEntity()->GetWorldPos();
		gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine(entityPos, ColorB(255,255,255,255), entityPos, ColorB(255,255,0,255), 2.0f);
		gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine(entityPos+Vec3(0,0,2), ColorB(255,255,255,255), entityPos+Vec3(0,0,2) + desiredVel, ColorB(0,255,0,255), 2.0f);
		gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine(entityPos, ColorB(255,255,255,255), entityPos + jumpVec, ColorB(0,255,255,255), 2.0f);
		gEnv->pRenderer->DrawLabel(entityPos - entityRight * 1.0f + Vec3(0,0,3.0f), 1.5f, "Velo[%2.3f = %2.3f, %2.3f, %2.3f]", m_request.velocity.len(), m_request.velocity.x, m_request.velocity.y, m_request.velocity.z);
	}
#endif

	m_expectedJumpEndHeight = expectedJumpEndHeight;
	m_bSprintJump = player.IsSprinting();
}
void CStickyProjectile::Stick(const SStickParams& stickParams)
{
	if(!gEnv->bServer && ((m_flags&eSF_HandleLocally)==0))
		return;

	// Must have physics.
	if(!stickParams.m_pTarget)
		return;

	// Don't stick to Breakables.
	if(ISurfaceType *pSurfaceType = gEnv->p3DEngine->GetMaterialManager()->GetSurfaceType(stickParams.m_targetMatId))
	{
		if (pSurfaceType->GetBreakability() == 1)
			return;
	}

	// Ignore water collision
	if ( CProjectile::GetMaterialLookUp().IsMaterial( stickParams.m_targetMatId, CProjectile::SMaterialLookUp::eType_Water ) )
		return;

	// Don't stick to particles type physics.
	const int peType = stickParams.m_pTarget->GetType();
	if( peType == PE_PARTICLE )
		return;

	const int iForiegnData = stickParams.m_pTarget->GetiForeignData();
	IEntity* pTargetEntity = iForiegnData==PHYS_FOREIGN_ID_ENTITY ? (IEntity*)stickParams.m_pTarget->GetForeignData(PHYS_FOREIGN_ID_ENTITY) : NULL;
	if( pTargetEntity )
	{
		const EntityId targetEntityId = pTargetEntity->GetId();

		// Don't stick to owner.
		if(targetEntityId==stickParams.m_ownerId)
			return;

		//Do not attach to other projectiles
		if(g_pGame->GetWeaponSystem()->GetProjectile(targetEntityId))
			return;

		// Do Stick.
		if(!StickToEntity(stickParams, pTargetEntity))
			return;
	}
	else
	{
		// Without an entity, we expect the object to not be moving. So if it isn't the terrain or a static, then don't stick to it.
		if( iForiegnData!=PHYS_FOREIGN_ID_TERRAIN && iForiegnData!=PHYS_FOREIGN_ID_STATIC )
			return;

		// Do Stick.
		if(!StickToStatic(stickParams))
			return;
	}

	//////////////////////////////////////////////////////////////////////////

	IEntity* pProjectileEntity = stickParams.m_pProjectile->GetEntity();
	if(CWeapon* pWeapon = stickParams.m_pProjectile->GetWeapon())
	{
		pWeapon->OnProjectileCollided( pProjectileEntity->GetId(), stickParams.m_pTarget, stickParams.m_stickPosition );
	}

	if((m_flags&eSF_HandleLocally)==0)
	{
		CHANGED_NETWORK_STATE(stickParams.m_pProjectile, eEA_GameServerStatic);
	}

	SendHitInfo(stickParams.m_pProjectile, pTargetEntity);

	IPhysicalEntity* pPhysEnt = pProjectileEntity->GetPhysics();
	if(((m_flags&eSF_IsStuck)!=0) && pPhysEnt)
	{
		pe_params_part pp;
		pp.flagsAND = ~geom_colltype_explosion;
		pp.flagsColliderAND = ~geom_colltype_solid;
		pp.mass = 0.0f;
		pPhysEnt->SetParams(&pp);
	}
}
void CVehicleWeaponControlled::Update(SEntityUpdateContext& ctx, int update)
{
	IVehicle *pVehicle = m_vehicleId ? gEnv->pGame->GetIGameFramework()->GetIVehicleSystem()->GetVehicle(m_vehicleId) : NULL; 
  if (!m_vehicleId && GetEntity()->GetParent())
  {
    IEntity *entity = GetEntity();
    
    if (entity)
    {
      IEntity *parent = entity->GetParent();
      if (parent)
      {
				m_vehicleId = parent->GetId();
        pVehicle = gEnv->pGame->GetIGameFramework()->GetIVehicleSystem()->GetVehicle(parent->GetId());
      }
    }
  }



  if (pVehicle)
  {
		IVehiclePart *pPart = pVehicle->GetWeaponParentPart(GetEntityId());
		if(pPart)
		{
			if(IVehiclePart *pParentPart = pPart->GetParent())
			{
				CRY_ASSERT(pVehicle->GetEntity());

				if(ICharacterInstance *characterInst = pVehicle->GetEntity()->GetCharacter(pParentPart->GetSlot()))
				{
					if(ISkeletonPose* pose = characterInst->GetISkeletonPose())
					{
						IDefaultSkeleton& rIDefaultSkeleton = characterInst->GetIDefaultSkeleton();
						int16 joint = rIDefaultSkeleton.GetJointIDByName(pPart->GetName());
						const QuatT &jQuat = pose->GetAbsJointByID(joint);

						Matrix34 localT(jQuat);
						localT.SetTranslation(jQuat.t/* - Vec3(0.0f, 0.75f, 0.0f)*/);

						Matrix34 vehicleWorldTm = pVehicle->GetEntity()->GetWorldTM();
						Matrix34 mat = vehicleWorldTm * localT;
						Vec3 vehicleSide2 = pPart->GetParent()->GetLocalTM(true, true).GetTranslation();

						CPlayer *pl = this->GetOwnerPlayer();

						Matrix33 mat2;
						if (!m_destination.IsEquivalent(ZERO))
						{
							Vec3 diff = GetDestination() - mat.GetTranslation(); //pPart->GetWorldTM().GetTranslation();
							diff.Normalize();

							Matrix33 loc(mat);
							loc.Invert();

							Vec3 diffLocal = loc.TransformVector(diff);

							Matrix33 desMat;
							desMat.SetRotationVDir(diffLocal, 0.0f);

							Vec3 test = GetEntity()->GetLocalTM().GetColumn0();

							Ang3 testTM(desMat);

							float za = testTM.x - m_Angles.x;
							za = (za < 0.0f) ? -gf_PI : gf_PI;
							za *= 0.05f * ctx.fFrameTime;

							m_Angles.x += za;
							Limit(m_Angles.x, -gf_PI * 0.33f, gf_PI * 0.33f);

							if (testTM.z > m_Angles.z + 0.05f)
							{
								m_Angles.z += gf_PI * factor1 * ctx.fFrameTime;        
							}
							else if (testTM.z < m_Angles.z - 0.05f)
							{
								m_Angles.z -= gf_PI * factor1 * ctx.fFrameTime;        
							}
							else
							{
								m_Angles.z = testTM.z;
							}

							Limit(m_Angles.z, -gf_PI * 0.33f, gf_PI * 0.33f);
							mat2.SetRotationXYZ(m_Angles);
						}
						else
						{
							if (!m_FireBlocked)
							{
								m_Angles.x = m_Angles.x - ctx.fFrameTime * factor2 * m_Angles.x;
								m_Angles.z = m_Angles.z - ctx.fFrameTime * factor2 * m_Angles.z;
							}
							mat2.SetRotationXYZ(m_Angles);
						}

						mat = mat * mat2; 


						GetEntity()->SetWorldTM(mat);


						if (pl)
						{
							Matrix34 worldGunMat = vehicleWorldTm * localT;

							if (!pl->IsDead())
							{

								Vec3 trans = worldGunMat.GetTranslation() - worldGunMat.GetColumn2() * 0.7f;
								worldGunMat.SetTranslation(trans);

								pl->GetEntity()->SetWorldTM(worldGunMat);


								float dot = mat.GetColumn1().dot(worldGunMat.GetColumn0());
								Update3PAnim(pl, 0.5f - dot * 0.5f, ctx.fFrameTime, mat);
							}
							else
							{

								ICharacterInstance* pCharacter = pl->GetEntity()->GetCharacter(0);
								int boneId = pCharacter ? pCharacter->GetIDefaultSkeleton().GetJointIDByName("Spine03") : 7;

								pl->LinkToMountedWeapon(0);
								if (IVehicleSeat* seat = pVehicle->GetSeatForPassenger(pl->GetEntityId()))
								{
									seat->Exit(false, true);
								}

								Matrix33 rot(worldGunMat);
								Vec3 offset(0.0f, 0.0f, 0.70f);
								Vec3 transformedOff = rot.TransformVector(offset);
								Vec3 trans = worldGunMat.GetTranslation();
								trans -= transformedOff;
								worldGunMat.SetTranslation(trans);
								pl->GetEntity()->SetWorldTM(worldGunMat);
								pl->GetEntity()->SetPos(worldGunMat.GetTranslation()); //worldGunMat.GetTranslation());
								pl->RagDollize(true);

								if (boneId > -1)
								{
									IPhysicalEntity *physEnt = pl->GetEntity()->GetPhysics();
									if (physEnt)
									{
										pe_simulation_params simulationParams;
										physEnt->GetParams(&simulationParams);

										pe_params_pos pos;
										pos.pos = GetEntity()->GetPos();
										physEnt->SetParams(&pos);

										pe_action_impulse impulse;
										impulse.ipart = boneId;
										impulse.angImpulse = Vec3(0.0f, 0.0f, 1.0f);
										impulse.impulse = worldGunMat.GetColumn1() * -1.5f * simulationParams.mass;
										physEnt->Action(&impulse);
									}
								}

								StopUse(GetOwnerId());

								SetOwnerId(0);
								StopFire();

								m_FireBlocked = true;
							} // IsDead
						} // pl
					} // pose
				} // characterInst
			} // pParentPart
		} // pPart
	} // pVehicle

  Base::Update(ctx, update);
  RequireUpdate(eIUS_General);
}
void CPickAndThrowProxy::Physicalize()
{
	IEntity* pPlayerEntity = m_player.GetEntity();
	IPhysicalEntity* pPlayerPhysics = pPlayerEntity->GetPhysics();

	const bool bPhysicsChanged = (pPlayerPhysics != m_pLastPlayerPhysics);

	// Don't create it again if already exists and its associated physic entity is the same
	if ((m_pPickNThrowProxy && !bPhysicsChanged) || !g_pGameCVars->pl_pickAndThrow.useProxies)
		return;

	CRY_ASSERT(m_pParams != NULL);
	if (!m_pParams)
		return;

	if (bPhysicsChanged)
		Unphysicalize();

	pe_params_pos pp;
	pp.pos = pPlayerEntity->GetWorldPos();
	pp.iSimClass = SC_ACTIVE_RIGID;
	IPhysicalEntity* pPickNThrowProxy = gEnv->pPhysicalWorld->CreatePhysicalEntity(PE_ARTICULATED, &pp, pPlayerEntity, PHYS_FOREIGN_ID_ENTITY);

	phys_geometry *pGeom = NULL;
	switch(m_pParams->proxyShape)
	{
	case ePS_Capsule :
		{
			primitives::capsule prim;
			prim.axis.Set(0,0,1);
			prim.center.zero();
			prim.r = m_pParams->fRadius; 
			prim.hh = m_pParams->fHeight;
			IGeometry *pPrimGeom = gEnv->pPhysicalWorld->GetGeomManager()->CreatePrimitive(primitives::capsule::type, &prim);
			pGeom = gEnv->pPhysicalWorld->GetGeomManager()->RegisterGeometry(pPrimGeom, 0);

			pGeom->nRefCount = 0;
			pPrimGeom->Release();
		} break;
	case ePS_Sphere :
		{
			primitives::sphere prim;
			prim.center.zero();
			prim.r = m_pParams->fRadius; 
			IGeometry *pPrimGeom = gEnv->pPhysicalWorld->GetGeomManager()->CreatePrimitive(primitives::sphere::type, &prim);
			pGeom = gEnv->pPhysicalWorld->GetGeomManager()->RegisterGeometry(pPrimGeom, 0);

			pGeom->nRefCount = 0;
			pPrimGeom->Release();
		} break;
	case ePS_Cylinder :
		{
			primitives::cylinder prim;
			prim.axis.Set(0,0,1);
			prim.center.zero();
			prim.r = m_pParams->fRadius; 
			prim.hh = m_pParams->fHeight;
			IGeometry *pPrimGeom = gEnv->pPhysicalWorld->GetGeomManager()->CreatePrimitive(primitives::cylinder::type, &prim);
			pGeom = gEnv->pPhysicalWorld->GetGeomManager()->RegisterGeometry(pPrimGeom, 0);

			pGeom->nRefCount = 0;
			pPrimGeom->Release();
		} break;
	default:
		CRY_ASSERT_MESSAGE(false, "Invalid proxy shape?");
	}

	if (pGeom)
	{
		CRY_ASSERT(pPlayerEntity->GetPhysics() && (pPlayerEntity->GetPhysics()->GetType() == PE_LIVING));
		pe_params_articulated_body pab;
		pab.pHost = pPlayerPhysics;
		m_pLastPlayerPhysics = pPlayerPhysics;
		pab.posHostPivot = m_pParams->vPosPivot;
		pab.bGrounded = 1;
		pab.nJointsAlloc = 1;
		pPickNThrowProxy->SetParams(&pab);

		pe_articgeomparams gp;
		gp.pos.zero();
		gp.flags = CPickAndThrowProxy::geom_colltype_proxy;
		gp.flagsCollider = 0;
		gp.mass = 0.0f;
		pPickNThrowProxy->AddGeometry(pGeom, &gp);

		m_pPickNThrowProxy = pPickNThrowProxy;
	}
}
void CVehicleMovementHelicopter::ProcessAI(const float deltaTime)
{
	FUNCTION_PROFILER( GetISystem(), PROFILE_GAME );

	CryAutoCriticalSection lk(m_lock);
	SVehiclePhysicsStatus* physStatus = &m_physStatus[k_physicsThread];
		
	if (m_arcade.m_handling.maxSpeedForward>0.f) // Use the new handling code
	{
		//ResetActions();
		m_movementAction.Clear();
		m_movementAction.isAI = true;

		SVehiclePhysicsHelicopterProcessAIParams params;
		params.pPhysStatus = physStatus;
		params.pInputAction = &m_inputAction;
		params.pAiRequest = &m_aiRequest;
		params.dt = deltaTime;
		params.aiRequiredVel = m_CurrentVel;
		params.aiCurrentSpeed = m_CurrentSpeed;
		params.aiYawResponseScalar = m_yawResponseScalar;
		m_yawResponseScalar = 1.f;
	
		// Use helper class to process the AI input
		// It will return a requested velocity, and change the input
		m_arcade.ProcessAI(params);

		// Get the output velocity
		m_CurrentVel = params.aiRequiredVel;
		m_CurrentSpeed = params.aiCurrentSpeed;
		return;
	}
	////////////////////// OLD DEPRECATED CODE :( //////////////////////////////////

	m_movementAction.Clear();
	ResetActions();

	// Our current state
	const Vec3 worldPos =  physStatus->pos;
	const Matrix33 worldMat( physStatus->q);
	const Matrix33 localMat( physStatus->q.GetInverted());
	const Ang3 worldAngles = Ang3::GetAnglesXYZ(worldMat);
	const Ang3 localAngles = Ang3::GetAnglesXYZ(localMat);

	const Vec3 currentVel = physStatus->v;
	const Vec3 currentVel2D(currentVel.x, currentVel.y, 0.0f);
	m_CurrentSpeed = m_CurrentVel.len(); //currentVel.len();
  float currentSpeed2d = currentVel2D.len();

	// +ve direction mean rotation anti-clocwise about the z axis - 0 means along y
	float currentDir = worldAngles.z;

	// to avoid singularity
	const Vec3 vWorldDir = worldMat.GetRow(1);
	const Vec3 vSideWays = worldMat.GetRow(0);
	const Vec3 vWorldDir2D =  Vec3( vWorldDir.x,  vWorldDir.y, 0.0f ).GetNormalizedSafe();

	// Our inputs
	float desiredSpeed = m_aiRequest.HasDesiredSpeed() ? m_aiRequest.GetDesiredSpeed() : 0.0f;
	Limit(desiredSpeed, -m_maxSpeed, m_maxSpeed);

	const Vec3 desiredMoveDir = m_aiRequest.HasMoveTarget() ? (m_aiRequest.GetMoveTarget() - worldPos).GetNormalizedSafe() : vWorldDir;
	Vec3 desiredMoveDir2D = Vec3(desiredMoveDir.x, desiredMoveDir.y, 0.0f);
	desiredMoveDir2D = desiredMoveDir2D.GetNormalizedSafe(desiredMoveDir2D);

	const Vec3 desiredVel = desiredMoveDir * desiredSpeed; 
	const Vec3 desiredVel2D(desiredVel.x, desiredVel.y, 0.0f);

  Vec3 desiredLookDir(desiredMoveDir);

  if (m_aiRequest.HasDesiredBodyDirectionAtTarget())
  {
	    desiredLookDir = m_aiRequest.GetDesiredBodyDirectionAtTarget().GetNormalizedSafe(desiredMoveDir);
  }
  else if (m_aiRequest.HasLookTarget())
  {
    desiredLookDir = (m_aiRequest.GetLookTarget() - worldPos).GetNormalizedSafe(desiredMoveDir);  
  }


	//const Vec3 desiredLookDir = m_aiRequest.HasLookTarget() ? (m_aiRequest.GetLookTarget() - worldPos).GetNormalizedSafe() : desiredMoveDir;
	const Vec3 desiredLookDir2D = Vec3(desiredLookDir.x, desiredLookDir.y, 0.0f).GetNormalizedSafe(vWorldDir2D);

  Vec3 prediction = m_aiRequest.HasBodyTarget() ? m_aiRequest.GetBodyTarget() : ZERO;

  prediction = (prediction.IsEquivalent(ZERO)) ? desiredMoveDir2D : prediction - worldPos;
  prediction.z = 0.0f;

  float speedLimit = prediction.GetLength2D();

	if(speedLimit > 0.0f)
	{
		prediction *= 1.0f / speedLimit;
	}

  Vec3 tempDir = currentVel2D.IsEquivalent(ZERO) ? localMat.GetRow(1) : currentVel2D;
  tempDir.z = 0.0f;
  tempDir.NormalizeFast();

	float dotProd = tempDir.dot(prediction);
	Limit(dotProd, FLT_EPSILON, 1.0f);

	float accel = m_enginePowerMax * min(2.0f,  1.0f / dotProd); // * dotProd;

	if (!m_aiRequest.HasDesiredBodyDirectionAtTarget())
	{
		dotProd *= dotProd;
		dotProd *= dotProd;
		float tempf = min(max(speedLimit * speedLimit, 2.0f), m_maxSpeed * dotProd);
		Limit(desiredSpeed, -tempf, tempf);
	}
	else if (dotProd < 0.0125f)
	{
		Limit(desiredSpeed, -m_maxSpeed * 0.25f, m_maxSpeed * 0.25f);
	}
  
  float posNeg = (float)__fsel(desiredSpeed - m_CurrentSpeed, 1.0f, -5.0f);

  if (desiredVel2D.GetLengthSquared() > FLT_EPSILON)
  {
	  m_CurrentSpeed = m_CurrentSpeed + posNeg * accel * deltaTime;
  }
  else
  {
    m_CurrentSpeed = m_CurrentSpeed + posNeg * accel * deltaTime;
  }

	if (posNeg > 0.0f && m_CurrentSpeed > desiredSpeed)
	{
		m_CurrentSpeed = desiredSpeed;
	}
	else if (posNeg < 0.0f && m_CurrentSpeed < desiredSpeed)
	{
		m_CurrentSpeed = desiredSpeed;
	}

	
	// ---------------------------- Rotation ----------------------------
	
	float desiredDir = (desiredLookDir2D.GetLengthSquared() > 0.0f) ? atan2f(-desiredLookDir2D.x, desiredLookDir2D.y) : atan2f(-vWorldDir2D.x, vWorldDir2D.y);
	while (currentDir < desiredDir - gf_PI)
		currentDir += 2.0f * gf_PI;
	while (currentDir > desiredDir + gf_PI)
		currentDir -= 2.0f * gf_PI;

	// ---------------------------- Yaw ----------------------------

	Ang3 dirDiff(0.0f, 0.0f, desiredDir - currentDir);
	dirDiff.RangePI();
	float absDiff   = fabsf(dirDiff.z);

	float rotSpeed		= (float)__fsel(dirDiff.z, m_yawPerRoll, -m_yawPerRoll);
	m_actionYaw		= m_actionYaw + deltaTime * (rotSpeed - m_actionYaw);

	float temp = fabsf(m_actionYaw);

	float multiplier = ((absDiff / (temp + 0.001f)) + 1.0f) * 0.5f;
	
	m_actionYaw	*= (float)__fsel(absDiff - temp, 1.0f, multiplier);

	// ---------------------------- Yaw ------------------------------

	m_CurrentVel = desiredMoveDir * m_CurrentSpeed;

  // ---------------------------- Pitch ----------------------------

  if (m_CurrentVel.GetLengthSquared2D() > 0.1f)
  {
    CalculatePitch(worldAngles, desiredMoveDir, currentSpeed2d, desiredSpeed, deltaTime);
  }
  else
  {
    Quat rot;
    rot.SetRotationVDir(desiredLookDir, 0.0f);
    float desiredXRot = Ang3::GetAnglesXYZ(rot).x + m_steeringDamage.x;

    m_actionPitch = worldAngles.x + (desiredXRot - worldAngles.x) * deltaTime/* * 10.0f*/;
    Limit(m_actionPitch, -m_maxPitchAngle * 2.0f, m_maxPitchAngle * 2.0f);
  }


	// ---------------------------- Roll ----------------------------
	float rollSpeed = GetRollSpeed();

	rollSpeed *= deltaTime;
	rollSpeed		= (float)__fsel(absDiff - rollSpeed, rollSpeed, absDiff);
	float roll		=(float) __fsel(dirDiff.z, -rollSpeed, rollSpeed);

	float speedPerUnit	   = 1.5f;
	float desiredRollSpeed = absDiff * speedPerUnit * (float)__fsel(dirDiff.z, 1.0f, -1.0f);
  
	desiredRollSpeed = -m_actionYaw * 2.5f;
  desiredRollSpeed += m_steeringDamage.y;

	m_actionRoll = m_actionRoll + deltaTime * (desiredRollSpeed - m_actionRoll);
	Limit(m_actionRoll, -m_maxRollAngle + m_steeringDamage.y, m_maxRollAngle - m_steeringDamage.y);
	m_actionRoll *= m_rollDamping;
	// ---------------------------- Roll ----------------------------


	// ---------------------------- Convert and apply ----------------------------
	Ang3 angles(m_actionPitch, m_actionRoll, worldAngles.z + deltaTime * m_actionYaw);
	
	pe_params_pos paramPos;
	paramPos.q.SetRotationXYZ(angles);
	paramPos.q.Normalize();

	IPhysicalEntity * pPhysicalEntity = GetPhysics();
	pPhysicalEntity->SetParams(&paramPos, 1);

	pe_action_set_velocity vel;
	vel.v = m_CurrentVel + m_netPosAdjust;
	pPhysicalEntity->Action(&vel, 1);

	// ---------------------------- Convert and apply ----------------------------

  m_rpmScale = max(0.2f, cry_fabsf(m_CurrentSpeed / m_maxSpeed));
}
//------------------------------------------------------------------------
void CVehicleDamageBehaviorDetachPart::OnDamageEvent(EVehicleDamageBehaviorEvent event, const SVehicleDamageBehaviorEventParams& behaviorParams)
{
	if (event == eVDBE_Repair)
		return;

	if (!m_detachedEntityId && behaviorParams.componentDamageRatio >= 1.0f)
	{
    CVehiclePartBase* pPart = (CVehiclePartBase*)m_pVehicle->GetPart(m_partName.c_str());
    if (!pPart || !pPart->GetStatObj())
      return;

		if (max(1.f-behaviorParams.randomness, pPart->GetDetachProbability()) < cry_random(0.0f, 1.0f)) 
			return;

		IEntity* pDetachedEntity = SpawnDetachedEntity();
		if (!pDetachedEntity)
			return;

		m_detachedEntityId = pDetachedEntity->GetId();

    const Matrix34& partWorldTM = pPart->GetWorldTM();
    pDetachedEntity->SetWorldTM(partWorldTM);
		
    MovePartToTheNewEntity(pDetachedEntity, pPart);
		
		SEntityPhysicalizeParams physicsParams;
		physicsParams.mass = pPart->GetMass();
		physicsParams.type = PE_RIGID;    		    
		physicsParams.nSlot = 0;
		pDetachedEntity->Physicalize(physicsParams);
  
    IPhysicalEntity* pPhysics = pDetachedEntity->GetPhysics();
    if (pPhysics)
    {
      pe_params_part params;      
      params.flagsOR = geom_collides|geom_floats;
      params.flagsColliderAND = ~geom_colltype3;
      params.flagsColliderOR = geom_colltype0;
      pPhysics->SetParams(&params);

      pe_action_add_constraint ac;
      ac.flags = constraint_inactive|constraint_ignore_buddy;
      ac.pBuddy = m_pVehicle->GetEntity()->GetPhysics();
      ac.pt[0].Set(0,0,0);
      pPhysics->Action(&ac);
			
			// after 1s, remove the constraint again
			m_pVehicle->SetTimer(-1, 1000, this);
    
		  // set the impulse
		  const Vec3& velocity = m_pVehicle->GetStatus().vel;  				  		  
		  Vec3 baseForce = m_pVehicle->GetEntity()->GetWorldTM().TransformVector(pPart->GetDetachBaseForce());
		  baseForce *= cry_random(6.0f, 10.0f);
  		
      pe_action_impulse actionImpulse;
		  actionImpulse.impulse = physicsParams.mass * (velocity + baseForce);
      actionImpulse.angImpulse = physicsParams.mass * Vec3(cry_random(-1.0f,1.0f), cry_random(-1.0f,1.0f), cry_random(-1.0f,1.0f));
      actionImpulse.iApplyTime = 1;
		  
      pPhysics->Action(&actionImpulse);		
    }

		// copy vehicle's material to new entity (fixes detaching parts from vehicles with different paints),
		// or specify the destroyed material if it exists

		IStatObj* pExternalStatObj = pPart->GetExternalGeometry(false);	// Get undamaged external geometry (if any)
		IMaterial *pMaterial = pExternalStatObj ? pExternalStatObj->GetMaterial() : m_pVehicle->GetEntity()->GetMaterial();

		if(event == eVDBE_VehicleDestroyed || event == eVDBE_Hit)
		{
			if (pExternalStatObj)
			{
				if (IStatObj* pStatObj = pPart->GetExternalGeometry(true))     // Try to get the destroyed, external geometry material
					pMaterial = pStatObj->GetMaterial();
			}
			else if (m_pVehicle->GetDestroyedMaterial())  // If there is no external geometry, try the vehicle's destroyed material
			{
				pMaterial = m_pVehicle->GetDestroyedMaterial();
			}
		}

		pDetachedEntity->SetMaterial(pMaterial);
		
		AttachParticleEffect(pDetachedEntity, m_pEffect);

		if (m_notifyMovement)
		{
			SVehicleMovementEventParams params;
			params.iValue = pPart->GetIndex();
			m_pVehicle->GetMovement()->OnEvent(IVehicleMovement::eVME_PartDetached, params);
		}
	}
}