1114 lines
29 KiB
C++
1114 lines
29 KiB
C++
#include "stdafx.h"
|
|
#include "xvehicleproxy.h"
|
|
#include "XVehicle.h"
|
|
//#include <IAgent.h>
|
|
#include <IAISystem.h>
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
// isn't it obvious
|
|
// state->bodystate 1 - helicopter droping people,
|
|
// ignore objects below, only terrain is used for altettude calculations
|
|
// use target altitude for reference - NOT terrain
|
|
// state->bodystate 2 - add deviation - move erratically when under fire
|
|
// state->bodystate 3 - attacking
|
|
// state->bodystate 4 - special path - sticking to the tagpoint - ignore flightAltitude and obstacles
|
|
// state->fStickDist<1.0f - must be attacking - stuck to target
|
|
void CXVehicleProxy::MoveLikeAHelicopter(SOBJECTSTATE * state)
|
|
{
|
|
//MoveLikeAHelicopter2(state);
|
|
//return;
|
|
|
|
bool bAttacking = (state->bodystate == 3);//state->fStickDist>1.0f); // attacking
|
|
|
|
Vec3d angles = m_pEntity->GetAngles();
|
|
|
|
Vec3d movement;
|
|
|
|
float tScale = m_pGame->GetSystem()->GetITimer()->GetFrameTime();
|
|
if(tScale>.1f) //to prevent stuff when debuggin
|
|
tScale = .1f;
|
|
|
|
movement(0,0,0);
|
|
|
|
if(state->fValueAux<0.0f) // is landed - don't move
|
|
{
|
|
Vec3d curPos = m_pEntity->GetPos();
|
|
// movement.z=UpdateAltitude( m_Movement, 2, tScale, 0);
|
|
// m_pEntity->SetAngles(m_Direction,false);
|
|
// m_pEntity->SetAngles(angles,false);
|
|
|
|
float desiredAlt = m_pGame->GetSystem()->GetI3DEngine()->GetTerrainElevation( curPos.x, curPos.y );
|
|
float waterAltitude = m_pGame->GetSystem()->GetI3DEngine()->GetWaterLevel(m_pEntity);
|
|
|
|
if( waterAltitude > desiredAlt )
|
|
desiredAlt = waterAltitude;
|
|
desiredAlt -= state->fValueAux;
|
|
|
|
movement.z = desiredAlt - curPos.z;
|
|
|
|
DemperVect(m_Movement, movement, tScale*11.1f);
|
|
|
|
pe_action_move motion;
|
|
// motion.dir.set(0,0,0);
|
|
motion.dir = m_Movement;
|
|
if(m_pEntity->GetPhysics())
|
|
m_pEntity->GetPhysics()->Action(&motion);
|
|
|
|
angles.x = 0;
|
|
angles.y = 0;
|
|
|
|
DemperVect(m_Direction, angles, tScale*10.3f);
|
|
|
|
m_pEntity->SetAngles(m_Direction,false);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
Vec3d dir = angles;
|
|
dir=ConvertToRadAngles(dir);
|
|
|
|
// handle turning
|
|
if (state->turnleft || state->turnright)
|
|
{
|
|
angles.z+=state->fValue;
|
|
}
|
|
|
|
if( state->dodge )
|
|
{
|
|
movement = state->vMoveDir*m_fForwardSpeed;
|
|
}
|
|
else
|
|
{
|
|
movement = state->vTargetPos - m_pEntity->GetPos();
|
|
movement.z = 0.0f; // don't care about target Z position - fly on desired altitude
|
|
|
|
|
|
if(state->fStickDist>0)
|
|
{
|
|
// movement = state->vTargetPos - (m_pEntity->GetPos() + m_Movement*5);
|
|
// movement.z = 0.0f; // don't care about target Z position - fly on desired altitude
|
|
|
|
float deltaDist = movement.Length() - state->fStickDist;
|
|
|
|
if( deltaDist < -.1f )
|
|
{
|
|
movement.Normalize();
|
|
movement *= -m_fForwardSpeed;
|
|
|
|
if( deltaDist > -m_fForwardSpeed )
|
|
movement *= (-deltaDist/m_fForwardSpeed);
|
|
}
|
|
else if( deltaDist > .1f )
|
|
{
|
|
movement.Normalize();
|
|
movement *= m_fForwardSpeed;
|
|
if( deltaDist < m_fForwardSpeed )
|
|
movement *= (deltaDist/m_fForwardSpeed);
|
|
}
|
|
else
|
|
movement(0,0,0);
|
|
|
|
/*
|
|
float curM = m_Movement.len2();
|
|
float newM = movement.len2();
|
|
if( curM>newM*2.0f )
|
|
{
|
|
|
|
// movement = -m_Movement + movement;
|
|
|
|
Vec3d curNrm = m_Movement.normalized();
|
|
Vec3d newNrm = movement.normalized();
|
|
|
|
if( curNrm.Dot(newNrm) > .5 || curNrm.Dot(newNrm) < -.5 )
|
|
movement = -m_Movement*(sqrtf(curM) - sqrtf(newM));
|
|
}
|
|
*/
|
|
}
|
|
else
|
|
if(state->vMoveDir.Length())
|
|
{
|
|
movement.Normalize();
|
|
movement*=m_fForwardSpeed;
|
|
/*
|
|
if(movement.Length()*3 > m_fForwardSpeed*3)
|
|
{
|
|
movement.Normalize();
|
|
movement*=m_fForwardSpeed;
|
|
}
|
|
else
|
|
movement *= .33f;
|
|
// else
|
|
*/
|
|
}
|
|
else
|
|
movement(0,0,0);
|
|
|
|
//
|
|
// add strafe
|
|
if(state->left || state->right)
|
|
{
|
|
Vec3d ang = m_pEntity->GetAngles();
|
|
ang=ConvertToRadAngles(ang);
|
|
Vec3d leftdir = state->vTargetPos - m_pEntity->GetPos();
|
|
leftdir.Normalize();
|
|
// Vec3d leftdir = ang;
|
|
Matrix44 mat;
|
|
mat.SetIdentity();
|
|
if (state->left)
|
|
{
|
|
//mat.RotateMatrix_fix(Vec3d(0,0,90));
|
|
mat=Matrix44::CreateRotationZYX(-Vec3d(0,0,90)*gf_DEGTORAD)*mat; //NOTE: angles in radians and negated
|
|
}
|
|
else
|
|
{
|
|
//mat.RotateMatrix_fix(Vec3d(0,0,-90));
|
|
mat=Matrix44::CreateRotationZYX(-Vec3d(0,0,-90)*gf_DEGTORAD)*mat; //NOTE: angles in radians and negated
|
|
}
|
|
leftdir = mat.TransformPointOLD(leftdir);
|
|
movement += leftdir*m_fBackwardSpeed;
|
|
}
|
|
|
|
float absMinAlt = m_MinAltitude;
|
|
if(bAttacking) // attacking
|
|
absMinAlt = state->vTargetPos.z + state->fValueAux;
|
|
else if( state->bodystate==1 ) // dropping people
|
|
absMinAlt = state->vTargetPos.z + state->fValueAux;
|
|
else if( state->bodystate==4 ) // special - stick to tagPoint
|
|
{
|
|
absMinAlt = state->vTargetPos.z;
|
|
state->fValueAux = 0;
|
|
}
|
|
|
|
// if state->bodystate==1 - ignore objects below, only terrain is used for altettude calculations
|
|
float deltaA=UpdateAltitude( m_Movement, state->fValueAux, absMinAlt,
|
|
// (state->fStickDist>1.0f||state->bodystate==1 ? state->vTargetPos.z : m_MinAltitude), // if attacking or dropping - don't go lower tham target
|
|
(state->bodystate!=1)&&(state->bodystate!=4));
|
|
|
|
|
|
m_ReverseTime += m_pGame->GetSystem()->GetITimer()->GetFrameTime();
|
|
if( m_ReverseTime>4.1f) // if last change was long ago
|
|
{
|
|
float fwdVal = HelyEvaluatePosition(m_pEntity->GetPos()+m_Movement*3.5);
|
|
if(m_pEntity->GetPos().z + 5 < fwdVal) // if high obstacles-terrain in direstion of movement
|
|
{
|
|
// - try to change strafing dir when attacking
|
|
SendSignal( 0, "CHANGESTRAFE", m_pEntity );
|
|
m_ReverseTime = 0.0f;
|
|
}
|
|
}
|
|
movement.z = deltaA;
|
|
if( state->bodystate == 2 ) // add deviation - move erratically
|
|
{
|
|
UpdateDeviation( state->vTargetPos, tScale );
|
|
movement += m_Deviation;
|
|
}
|
|
}
|
|
|
|
if(state->bodystate!=1 && state->bodystate!=4)
|
|
movement += HelyAvoidCollision()*40.0f;
|
|
|
|
angles.x = 0;
|
|
angles.y = 0;
|
|
|
|
// generate random floating illusion
|
|
// if( state->bodystate == 1 )
|
|
{
|
|
m_fAngle+=tScale;
|
|
}
|
|
|
|
|
|
|
|
// Add random floating illusion
|
|
Vec3d hoverPos, hoverAngle;
|
|
UpdateHover( hoverPos, hoverAngle, m_fAngle );
|
|
// scale it down with speed
|
|
movement += hoverPos;//*(1.0f-m_fThrust/m_fForwardSpeed);
|
|
angles += hoverAngle;//*(1.0f-m_fThrust/m_fForwardSpeed);
|
|
|
|
//movement.z = 0;
|
|
Vec3d tmpS=movement;
|
|
Vec3d tmpT=m_Movement;
|
|
|
|
// if there is high m_fForwardSpeed make less smoothing to allow hely to respond faster
|
|
if(m_fForwardSpeed>35)
|
|
{
|
|
DemperVect(m_Movement, movement, tScale*m_fForwardSpeed*10.0f);
|
|
}
|
|
else
|
|
{
|
|
if(bAttacking) // attacking
|
|
DemperVect(m_Movement, movement, tScale*m_fForwardSpeed*.5f); // low smoothing
|
|
else
|
|
if(state->fStickDist>0)
|
|
DemperVect(m_Movement, movement, tScale*25.1f);
|
|
else
|
|
DemperVect(m_Movement, movement, tScale*m_fForwardSpeed*0.5f);
|
|
}
|
|
//m_Movement = movement;
|
|
|
|
if( tmpS.z>20 ) // alarm - need to go up immediately to awoid ground/object collision
|
|
DemperVect(tmpT, tmpS, tScale*25.0f);
|
|
else
|
|
{
|
|
if( m_Movement.z>7 )
|
|
DemperVect(tmpT, tmpS, tScale*50.5f);
|
|
// m_Movement.z = 7 + (m_Movement.z-7)*.3;
|
|
/*
|
|
if( tmpS.z<0 ) // going down - smooth it more
|
|
DemperVect(tmpT, tmpS, tScale*5.5f);
|
|
else // doing up - not much smoothing, to avoid getting into terrain/obstacles
|
|
DemperVect(tmpT, tmpS, tScale*5.1f);
|
|
*/
|
|
DemperVect(tmpT, tmpS, tScale*5.5f);
|
|
if( state->bodystate==1 && tmpT.z<-5.0f ) // when dropping people - limit for descending speed
|
|
// tmpT.z = -2;
|
|
tmpT.z /= 5.0f;
|
|
}
|
|
|
|
m_Movement.z = tmpT.z;
|
|
|
|
// m_Movement = movement;
|
|
|
|
//
|
|
// tilt in direction of movement
|
|
Vec3d horizontMovment = m_Movement;
|
|
horizontMovment.z = 0.0f;
|
|
float tilt = GetLengthSquared(horizontMovment);
|
|
if( tilt )
|
|
{
|
|
Vec3d tVector;
|
|
// tilt = 20.0f*tilt/(m_fForwardSpeed*m_fForwardSpeed);
|
|
tilt = (2.0f*m_fForwardSpeed)*tilt/(m_fForwardSpeed*m_fForwardSpeed);
|
|
if( tilt>30 )
|
|
tilt = 30;
|
|
tVector( tilt, 0.0f, 0.0f );
|
|
Vec3d vMoveNorm = m_Movement;
|
|
vMoveNorm=ConvertVectorToCameraAngles(vMoveNorm);
|
|
|
|
// vMoveNorm.Snap360();
|
|
Vec3d ang = m_pEntity->GetAngles();
|
|
// ang.Snap360();
|
|
Matrix44 mat;
|
|
mat.SetIdentity();
|
|
mat=Matrix44::CreateRotationZYX(-Vec3d(0,0,vMoveNorm.z-m_pEntity->GetAngles().z)*gf_DEGTORAD)*mat; //NOTE: angles in radians and negated
|
|
tVector = GetTransposed44(mat)*(tVector);
|
|
|
|
angles += tVector;
|
|
}
|
|
//
|
|
// add tilt if rotating/turning
|
|
if(state->vMoveDir.Length())
|
|
{
|
|
Vec3d vMoveNorm = state->vMoveDir;
|
|
float zcross = dir.x * vMoveNorm.y - dir.y * vMoveNorm.x;
|
|
zcross *=30.f;
|
|
if ((m_fTilt < 30.f) && (m_fTilt > -30.f))
|
|
m_fTilt += (zcross-m_fTilt)*0.03f;
|
|
}
|
|
else
|
|
{
|
|
if (fabs(m_fTilt) > 0)
|
|
m_fTilt-=m_fTilt*0.051f;
|
|
}
|
|
|
|
angles.y += m_fTilt;
|
|
|
|
|
|
tmpT = m_Direction;
|
|
tmpS = angles;
|
|
DemperVect(m_Direction, angles, tScale*7.3f);
|
|
DemperVect(tmpT, tmpS, tScale*65.5f);
|
|
m_Direction.z = tmpT.z;
|
|
|
|
// DemperVect(m_Direction, angles, tScale*7.3f);
|
|
|
|
|
|
|
|
//m_Direction.Set(0,0,0);
|
|
|
|
m_pEntity->SetAngles(m_Direction,false);
|
|
// m_pEntity->SetAngles(angles,false);
|
|
|
|
pe_action_move motion;
|
|
// motion.dir.set(0,0,0);
|
|
motion.dir = m_Movement;
|
|
|
|
if(m_pEntity->GetPhysics())
|
|
m_pEntity->GetPhysics()->Action(&motion);
|
|
}
|
|
|
|
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
// generate random floating illusion
|
|
void CXVehicleProxy::UpdateHover( Vec3d& posOffset, Vec3d& angOffset, const float t )
|
|
{
|
|
float floatingAmpl = 2.0f;
|
|
float scale = .4f;
|
|
|
|
float c1 = floatingAmpl*cry_sinf(m_fAngle*.24f)*cry_cosf(1.6f*m_fAngle);
|
|
float c2 = floatingAmpl*cry_cosf(m_fAngle*.6f)*cry_sinf(1.2f*m_fAngle);
|
|
angOffset.x = c1*floatingAmpl;
|
|
angOffset.y = c2*floatingAmpl*3.4f;
|
|
angOffset.z = (c1+c2)*floatingAmpl*0.0f;
|
|
posOffset.x = ((c1+c2)/2.f)*0.01f;
|
|
posOffset.y = c2*0.01f;
|
|
posOffset.z = c1*0.0012f;
|
|
posOffset *= 50.0f;
|
|
angOffset *= .5f;
|
|
}
|
|
|
|
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
//
|
|
// desiredAltitude - alr above terrain
|
|
// absMinAlt - never go below
|
|
float CXVehicleProxy::UpdateAltitude( const Vec3d& moveDir, float desiredAltitude, float absMinAlt,
|
|
bool useObjects )
|
|
{
|
|
Vec3d curPos = m_pEntity->GetPos();
|
|
float allowedObjectDist = 7.0f;
|
|
float objectsDist=-1000, fwdObjectDist=-1000;
|
|
float minPossibleAlt=0; // never go below this
|
|
Vec3d fwdPos = m_pEntity->GetPos() + moveDir*5.0f;
|
|
float terrainAltitude = -1000;
|
|
|
|
if(useObjects) // get terrain/ objects below in box
|
|
{
|
|
terrainAltitude = HelyGetTerrainElevation( curPos, fwdPos, 15 );
|
|
objectsDist = GetObjectsBelowHeight( curPos, allowedObjectDist, .6f );
|
|
fwdObjectDist = GetObjectsBelowHeight( fwdPos, allowedObjectDist, .6f );
|
|
if(objectsDist < fwdObjectDist)
|
|
objectsDist = (objectsDist + fwdObjectDist)*.5f;
|
|
}
|
|
else // get only terrain below in small box
|
|
{
|
|
terrainAltitude = HelyGetTerrainElevation( curPos, curPos, 1 );
|
|
}
|
|
|
|
float waterAltitude = m_pGame->GetSystem()->GetI3DEngine()->GetWaterLevel(m_pEntity);
|
|
|
|
if( terrainAltitude < waterAltitude )
|
|
terrainAltitude = waterAltitude;
|
|
|
|
if(terrainAltitude<objectsDist)
|
|
minPossibleAlt = objectsDist;
|
|
else
|
|
minPossibleAlt = terrainAltitude;
|
|
|
|
desiredAltitude = desiredAltitude + terrainAltitude;
|
|
|
|
// don't go too close to objects below
|
|
if( desiredAltitude<objectsDist+6.1f )
|
|
desiredAltitude = objectsDist+6.1f;
|
|
// don't go lower desired absolute flight altitude
|
|
if( desiredAltitude<absMinAlt )
|
|
desiredAltitude = absMinAlt;
|
|
|
|
//float deltaAltitude = desiredAltitude - (curPos.z - terrainAltitude);
|
|
float deltaAltitude = desiredAltitude - curPos.z;
|
|
|
|
float scale = 1.0f;
|
|
|
|
|
|
if( deltaAltitude > 1.0f )
|
|
scale = 1.0f;
|
|
else if( deltaAltitude > 0.0f )
|
|
scale *= scale;
|
|
|
|
// if moving down - make it smooth
|
|
if(deltaAltitude>-15 && deltaAltitude<0)
|
|
scale = (1.0f+deltaAltitude/15.0f);
|
|
|
|
// cup the force
|
|
if(deltaAltitude>7.0f)
|
|
deltaAltitude = 7.0f;
|
|
else if(deltaAltitude<-7.0f)
|
|
deltaAltitude = -7.0f;
|
|
|
|
if( (curPos.z - 5) < minPossibleAlt) // if in ground or objects - froce go up
|
|
{
|
|
if(m_Movement.z < 0 ) // if moving down
|
|
m_Movement.z *= .5f; // slow it
|
|
scale = 1.0f;
|
|
float upInput = -((curPos.z - 5) - minPossibleAlt); // deeper in something - more up force
|
|
if( upInput<10 )
|
|
deltaAltitude = 17 + 5.0f*upInput/10.0f;
|
|
else
|
|
deltaAltitude = 17 + upInput*5.0f;
|
|
if(deltaAltitude>30)
|
|
deltaAltitude = 30;
|
|
}
|
|
return deltaAltitude*scale;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
//
|
|
//returns height of the hiest static entity object in self bbox extended down by depth
|
|
float CXVehicleProxy::GetObjectsBelowHeight( const Vec3d& pos, const float depth, const float scale )
|
|
{
|
|
Vec3d bbox[2];
|
|
float theHeight = -1000;
|
|
float selfButtom;
|
|
|
|
m_pEntity->GetBBox( bbox[0], bbox[1] );
|
|
|
|
selfButtom = bbox[0].z;
|
|
bbox[0].z -= depth;
|
|
|
|
// vectorf vMin = bbox[0];
|
|
// vectorf vMax = bbox[1];
|
|
|
|
vectorf vMin = pos + (bbox[0]-m_pEntity->GetPos())*scale;
|
|
vectorf vMax = pos + (bbox[1]-m_pEntity->GetPos())*scale;
|
|
|
|
|
|
IPhysicalEntity **ppList = NULL;
|
|
int iNumEntites;
|
|
// object types - bitmask 0-terrain 1-static, 2-sleeping, 3-physical, 4-living
|
|
iNumEntites = m_pGame->GetSystem()->GetIPhysicalWorld()->GetEntitiesInBox(vMin, vMax, ppList, 1);
|
|
|
|
for(int i=0; i<iNumEntites; i++)
|
|
{
|
|
pe_status_pos status;
|
|
// Get bbox (status) from physics engine
|
|
if(ppList[i]->GetType()==PE_LIVING)
|
|
continue;
|
|
ppList[i]->GetStatus(&status);
|
|
|
|
if(m_pGame->h_drawbelow->GetIVal() != 0 )
|
|
m_pGame->GetSystem()->GetIRenderer()->Draw3dBBox( status.BBox[0] + status.pos, status.BBox[1] + status.pos);
|
|
|
|
status.BBox[1].z += status.pos.z;
|
|
if(theHeight<status.BBox[1].z)
|
|
theHeight = status.BBox[1].z;
|
|
}
|
|
|
|
//return 10;
|
|
return theHeight;
|
|
// return selfButtom - theHeight;
|
|
}
|
|
|
|
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
void CXVehicleProxy::UpdateDeviation( const Vec3d& targetPos, const float tScale )
|
|
{
|
|
float speed=12.3f;
|
|
m_DeviationTime -= tScale;
|
|
|
|
|
|
// m_Deviation.Set(0,0,0);
|
|
//return;
|
|
|
|
|
|
if(m_DeviationTime<0)
|
|
{
|
|
|
|
{
|
|
Vec3d ang = m_pEntity->GetAngles();
|
|
ang=ConvertToRadAngles(ang);
|
|
Vec3d leftdir = targetPos - m_pEntity->GetPos();
|
|
leftdir.Normalize();
|
|
// Vec3d leftdir = ang;
|
|
Matrix44 mat;
|
|
mat.SetIdentity();
|
|
if (rand()%100<50)
|
|
{
|
|
//mat.RotateMatrix_fix(Vec3d(0,0,90));
|
|
mat=Matrix44::CreateRotationZYX(-Vec3d(0,0,90)*gf_DEGTORAD)*mat; //NOTE: angles in radians and negated
|
|
}
|
|
else
|
|
{
|
|
//mat.RotateMatrix_fix(Vec3d(0,0,-90));
|
|
mat=Matrix44::CreateRotationZYX(-Vec3d(0,0,-90)*gf_DEGTORAD)*mat; //NOTE: angles in radians and negated
|
|
}
|
|
leftdir = mat.TransformPointOLD(leftdir);
|
|
m_Deviation = leftdir*m_fBackwardSpeed;
|
|
}
|
|
|
|
/*
|
|
m_Deviation.x = rand()/(float)RAND_MAX*speed;
|
|
m_Deviation.y = rand()/(float)RAND_MAX*speed;
|
|
m_Deviation.z = rand()/(float)RAND_MAX*speed*.3;
|
|
m_DeviationTime = rand()/(float)RAND_MAX*5.0f;
|
|
*/
|
|
m_DeviationTime = rand()/(float)RAND_MAX*5.0f;
|
|
// if(m_DeviationTime<0)
|
|
// m_DeviationTime -= 3.0f;
|
|
// else
|
|
// m_DeviationTime += 3.0f;
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
void CXVehicleProxy::DemperVect( Vec3d& current, const Vec3d& target, const float tScale )
|
|
{
|
|
//Vec3d v = (target - current)*tScale*dempCoeff;
|
|
Vec3d v = (target - current);//*tScale*dempCoeff;
|
|
v.Normalize();
|
|
v*=tScale;
|
|
float tmp;
|
|
|
|
tmp = current.x + v.x;
|
|
if( (tmp>target.x && tmp>current.x) || (tmp<target.x && tmp<current.x) )
|
|
current.x = target.x;
|
|
else
|
|
current.x = tmp;
|
|
tmp = current.y + v.y;
|
|
if( (tmp>target.y && tmp>current.y) || (tmp<target.y && tmp<current.y) )
|
|
current.y = target.y;
|
|
else
|
|
current.y = tmp;
|
|
tmp = current.z + v.z;
|
|
if( (tmp>target.z && tmp>current.z) || (tmp<target.z && tmp<current.z) )
|
|
current.z = target.z;
|
|
else
|
|
current.z = tmp;
|
|
}
|
|
|
|
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
// avoiding rockets helicopter
|
|
Vec3d CXVehicleProxy::UpdateThreatHeli( void* threat )
|
|
{
|
|
IEntity* theThreatingEntity = (IEntity*)threat;
|
|
float safeHeight = 8.0f;
|
|
|
|
if( m_Movement.z<0 )
|
|
safeHeight -= m_Movement.z;
|
|
|
|
if(!theThreatingEntity)
|
|
return Vec3d(0,0,0);
|
|
// Create a new status object. The fields are initialized for us
|
|
pe_status_dynamics status;
|
|
// Get a pointer to the physics engine
|
|
IPhysicalEntity *physEnt = theThreatingEntity->GetPhysics();
|
|
// Get new player status from physics engine
|
|
if (physEnt && physEnt->GetStatus(&status))
|
|
{
|
|
// Get our current velocity, default will be (0,0,0)
|
|
Vec3d vel = (Vec3d)status.v;
|
|
Vec3d dir = m_pEntity->GetPos() - theThreatingEntity->GetPos();
|
|
|
|
if(vel.x == 0 && vel.y == 0 && vel.z == 0)
|
|
return Vec3d(0,0,0);
|
|
|
|
// dirN.Normalize();
|
|
// vel.Normalize();
|
|
|
|
float fdot = dir.Dot(vel);
|
|
|
|
if ( fdot < 0 )
|
|
{
|
|
// its behind him
|
|
return Vec3d(0,0,0);
|
|
}
|
|
|
|
float t = ( dir.x*vel.x + dir.y*vel.y + dir.z*vel.z )/( vel.x*vel.x + vel.y*vel.y + vel.z*vel.z );
|
|
Vec3d x = vel*t;
|
|
|
|
dir = dir - x;
|
|
|
|
if( dir.x == 0 && dir.y == 0 && dir.z == 0 ) // rocket goes exactly at self pos (probably newer will happen) Jus move somewhere
|
|
dir.x = 1;
|
|
else
|
|
if( GetLengthSquared(dir) > 120 ) // too far away
|
|
return Vec3d(0,0,0);
|
|
|
|
|
|
Vec3d curMovementDirHor = m_Movement;
|
|
Vec3d dirHor = dir;
|
|
curMovementDirHor.z = 0;
|
|
curMovementDirHor.Normalize();
|
|
dirHor.z = 0;
|
|
dirHor.Normalize();
|
|
dirHor += curMovementDirHor;
|
|
if(GetLengthSquared(dirHor)<1) // prefer to move verticaly - correction direction is too different from current movement direction
|
|
dir.z *= 50.55f;
|
|
|
|
dir.Normalize();
|
|
|
|
if(dir.z < .4f && CanGoDown(safeHeight)) // tend to go down - duck
|
|
{
|
|
if( fabs(dir.z) < .3f )
|
|
dir.z = -.3f;
|
|
else
|
|
dir.z -= .25f;
|
|
dir.z *= 1.55f;
|
|
dir.Normalize();
|
|
}
|
|
|
|
if( dir.z < 0.0f ) // check to avoid going in ground/trees/whatever
|
|
{
|
|
if(!CanGoDown(safeHeight))
|
|
{
|
|
dir.z = .0f;
|
|
dir.Normalize();
|
|
}
|
|
}
|
|
return dir;
|
|
|
|
// return Vec3d(1,0,0);
|
|
}
|
|
else
|
|
{
|
|
return Vec3d(0,0,0);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool CXVehicleProxy::CanGoDown( const float deltaHeight )
|
|
{
|
|
float depth = GetObjectsBelowHeight( m_pEntity->GetPos(), deltaHeight );
|
|
Vec3d curPos = m_pEntity->GetPos();
|
|
float terrainAltitude = HelyGetTerrainElevation(curPos, curPos, 2);
|
|
//m_pGame->GetSystem()->GetI3DEngine()->GetTerrainElevation( curPos.x, curPos.y );
|
|
|
|
return curPos.z-terrainAltitude > deltaHeight && curPos.z-depth > deltaHeight;
|
|
}
|
|
|
|
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
float CXVehicleProxy::HelyEvaluatePosition( const Vec3d& pos )
|
|
{
|
|
float value = HelyGetTerrainElevation( pos, pos, 3 );
|
|
float objects = GetObjectsBelowHeight( pos, 7, .6f );
|
|
|
|
if( objects>value )
|
|
return objects;
|
|
else
|
|
return value;
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
float CXVehicleProxy::HelyGetTerrainElevation( const Vec3d& pos, const Vec3d& fwdPos, float boxSize )
|
|
{
|
|
float terrainAltitude = m_pGame->GetSystem()->GetI3DEngine()->GetTerrainElevation( pos.x, pos.y );
|
|
float fwdTerrainAltitude = m_pGame->GetSystem()->GetI3DEngine()->GetTerrainElevation( fwdPos.x, fwdPos.y );
|
|
if( terrainAltitude < fwdTerrainAltitude )
|
|
terrainAltitude = (fwdTerrainAltitude + terrainAltitude)*.5f;
|
|
fwdTerrainAltitude = m_pGame->GetSystem()->GetI3DEngine()->GetTerrainElevation( pos.x+boxSize, pos.y+boxSize );
|
|
if( terrainAltitude < fwdTerrainAltitude )
|
|
terrainAltitude = fwdTerrainAltitude;
|
|
fwdTerrainAltitude = m_pGame->GetSystem()->GetI3DEngine()->GetTerrainElevation( pos.x+boxSize, pos.y-boxSize );
|
|
if( terrainAltitude < fwdTerrainAltitude )
|
|
terrainAltitude = fwdTerrainAltitude;
|
|
fwdTerrainAltitude = m_pGame->GetSystem()->GetI3DEngine()->GetTerrainElevation( pos.x-boxSize, pos.y+boxSize );
|
|
if( terrainAltitude < fwdTerrainAltitude )
|
|
terrainAltitude = fwdTerrainAltitude;
|
|
fwdTerrainAltitude = m_pGame->GetSystem()->GetI3DEngine()->GetTerrainElevation( pos.x-boxSize, pos.y-boxSize );
|
|
if( terrainAltitude < fwdTerrainAltitude )
|
|
terrainAltitude = fwdTerrainAltitude;
|
|
|
|
return terrainAltitude;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool CXVehicleProxy::IsTargetVisible( const Vec3d& selfPos, const Vec3d& targetPos )
|
|
{
|
|
|
|
//return true;
|
|
|
|
// trace reay to target, skiping self
|
|
ray_hit hit;
|
|
if (! m_pGame->GetSystem()->GetIPhysicalWorld()->RayWorldIntersection(selfPos,targetPos-selfPos,
|
|
ent_terrain|ent_static|ent_sleeping_rigid,
|
|
rwi_stop_at_pierceable,&hit,1,m_pEntity->GetPhysics()))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
Vec3d CXVehicleProxy::HeliAttackAdvance( SOBJECTSTATE &state )
|
|
{
|
|
|
|
//return m_pEntity->GetPos();
|
|
|
|
|
|
Vec3d targetPos = state.vTargetPos;
|
|
Vec3d curPos = m_pEntity->GetPos();
|
|
float curValue = HelyEvaluatePosition( curPos );
|
|
|
|
Vec3d curTargetDir = targetPos - curPos;
|
|
curTargetDir.z=0;
|
|
curTargetDir.normalize();
|
|
|
|
Vec3d candidatePos;
|
|
float candidateValue;
|
|
Vec3d bestPos = curPos;
|
|
float bestValue;
|
|
float dist = 35;
|
|
float fAlt = state.fValueAux;
|
|
|
|
if(!IsTargetVisible(curPos, targetPos+Vec3d( 0,0,1 )))
|
|
curValue += 200;
|
|
bestValue = curValue;
|
|
|
|
if(state.fStickDist>0)
|
|
dist = state.fStickDist;
|
|
|
|
// check point behind target
|
|
candidatePos = targetPos + curTargetDir*dist;
|
|
candidateValue = HelyEvaluatePosition(candidatePos);
|
|
if( candidateValue<bestValue )
|
|
{
|
|
if(!IsTargetVisible(candidatePos+Vec3d( 0,0,fAlt ), targetPos+Vec3d( 0,0,1 )))
|
|
candidateValue += 200;
|
|
if( candidateValue<bestValue )
|
|
{
|
|
bestPos = candidatePos;
|
|
bestValue = candidateValue;
|
|
}
|
|
}
|
|
|
|
// check point to left
|
|
candidatePos = targetPos + Vec3d(curTargetDir.y, -curTargetDir.x, 0)*dist;
|
|
candidateValue = HelyEvaluatePosition(candidatePos);
|
|
if( candidateValue<bestValue )
|
|
{
|
|
if(!IsTargetVisible(candidatePos+Vec3d( 0,0,fAlt ), targetPos+Vec3d( 0,0,1 )))
|
|
candidateValue += 200;
|
|
if( candidateValue<bestValue )
|
|
{
|
|
bestPos = candidatePos;
|
|
bestValue = candidateValue;
|
|
}
|
|
}
|
|
|
|
// check point to right
|
|
candidatePos = targetPos + Vec3d(-curTargetDir.y, curTargetDir.x, 0)*dist;
|
|
candidateValue = HelyEvaluatePosition(candidatePos);
|
|
if( candidateValue<bestValue )
|
|
{
|
|
if(!IsTargetVisible(candidatePos+Vec3d( 0,0,fAlt ), targetPos+Vec3d( 0,0,1 )))
|
|
candidateValue += 200;
|
|
if( candidateValue<bestValue )
|
|
{
|
|
bestPos = candidatePos;
|
|
bestValue = candidateValue;
|
|
}
|
|
}
|
|
|
|
//check some random points around target
|
|
for( int i=0; i<5; i++ )
|
|
{
|
|
float dir=(float)(rand()%360);
|
|
candidatePos = targetPos + Vec3d(cry_cosf( DEG2RAD(dir) ), cry_sinf( DEG2RAD(dir) ), 0)*dist;
|
|
candidateValue = HelyEvaluatePosition(candidatePos);
|
|
if( candidateValue<bestValue )
|
|
{
|
|
if(!IsTargetVisible(candidatePos+Vec3d( 0,0,fAlt ), targetPos+Vec3d( 0,0,1 )))
|
|
candidateValue += 200;
|
|
if( candidateValue<bestValue )
|
|
{
|
|
bestPos = candidatePos;
|
|
bestValue = candidateValue;
|
|
}
|
|
}
|
|
}
|
|
|
|
return bestPos;
|
|
}
|
|
|
|
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
Vec3d CXVehicleProxy::HelyAvoidCollision( float distance )
|
|
{
|
|
//IAISystem
|
|
//IAIObject *obstVehicle = m_pGame->GetSystem()->GetAISystem()->GetNearestObjectOfType( m_pEntity->GetPos(), AIOBJECT_VEHICLE, avoidDist );
|
|
IAIObject *obstVehicle = m_pGame->GetSystem()->GetAISystem()->GetNearestObjectOfType( m_pEntity->GetPos(), AIOBJECT_VEHICLE, distance, m_pEntity->GetAI());
|
|
Vec3d correction(0,0,0);
|
|
|
|
if( obstVehicle )
|
|
{
|
|
correction = m_pEntity->GetPos() - obstVehicle->GetPos();
|
|
float scale = correction.len();
|
|
|
|
if(scale>distance)
|
|
{
|
|
return correction;
|
|
}
|
|
|
|
correction.normalize();
|
|
correction *= (distance - scale)/distance;
|
|
}
|
|
|
|
return correction;
|
|
}
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
Vec3d CXVehicleProxy::BoatAvoidCollision( float range )
|
|
{
|
|
//IAISystem
|
|
//IAIObject *obstVehicle = m_pGame->GetSystem()->GetAISystem()->GetNearestObjectOfType( m_pEntity->GetPos(), AIOBJECT_VEHICLE, avoidDist );
|
|
IAIObject *obstVehicle = m_pGame->GetSystem()->GetAISystem()->GetNearestObjectOfType( m_pEntity->GetPos(), AIOBJECT_VEHICLE, range, m_pEntity->GetAI());
|
|
Vec3d correction(0,0,0);
|
|
float crossLimit = 0.0f;
|
|
|
|
if( obstVehicle )
|
|
{
|
|
|
|
IUnknownProxy* pProxy = obstVehicle->GetProxy();
|
|
CXVehicleProxy* pVProxy=NULL;
|
|
|
|
if(!pProxy->QueryProxy(AIPROXY_VEHICLE, (void**)&pVProxy))
|
|
return correction;
|
|
// it's helicopter or
|
|
// it's player's boat/car
|
|
//
|
|
if(!pVProxy->m_pVehicle || !pVProxy->m_pVehicle->m_bAIDriver)
|
|
{
|
|
crossLimit = .5f;
|
|
// return correction;
|
|
// return CarAvoidCollision( range );
|
|
}
|
|
|
|
IUnknownProxy *obsProxy = obstVehicle->GetProxy();
|
|
IPhysicalEntity* phys=obsProxy->GetPhysics();
|
|
|
|
pe_status_dynamics status;
|
|
phys->GetStatus( &status );
|
|
Vec3d colliderVel = status.v;
|
|
GetPhysics()->GetStatus( &status );
|
|
Vec3d selfVel = status.v;
|
|
Vec3d diff = obstVehicle->GetPos() - m_pEntity->GetPos();
|
|
Vec3d relVel = colliderVel - selfVel;
|
|
|
|
relVel.z=0;
|
|
diff.z=0;
|
|
|
|
float scaleVel = relVel.len2()*.05f;
|
|
|
|
if(scaleVel<.1f)
|
|
scaleVel = .1f;
|
|
|
|
float distance = diff.len();
|
|
relVel.normalize();
|
|
diff.normalize();
|
|
|
|
float dotZ = diff.x*relVel.x + diff.y*relVel.y;
|
|
|
|
if(dotZ>0.0f)
|
|
return correction;
|
|
|
|
selfVel.z=0;
|
|
selfVel.normalize();
|
|
|
|
// float crossZ = diff.x*relVel.y - diff.y*relVel.x;
|
|
float crossZ = diff.x*selfVel.y - diff.y*selfVel.x;
|
|
|
|
if( crossZ < -crossLimit )
|
|
correction = Vec3d( selfVel.y, -selfVel.x, 0.0f );
|
|
else if( crossZ > crossLimit )
|
|
correction = Vec3d( -selfVel.y, selfVel.x, 0.0f );
|
|
|
|
|
|
float scaleAng = 1.0f - dotZ;
|
|
float scaleDist = 10.0f*(range - distance)/range;
|
|
correction *= scaleAng*scaleDist*scaleVel;
|
|
}
|
|
|
|
return correction;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
Vec3d CXVehicleProxy::CarAvoidCollision( float range )
|
|
{
|
|
//IAISystem
|
|
//IAIObject *obstVehicle = m_pGame->GetSystem()->GetAISystem()->GetNearestObjectOfType( m_pEntity->GetPos(), AIOBJECT_VEHICLE, avoidDist );
|
|
IAIObject *obstVehicle = m_pGame->GetSystem()->GetAISystem()->GetNearestObjectOfType( m_pEntity->GetPos(), AIOBJECT_VEHICLE, range, m_pEntity->GetAI());
|
|
Vec3d correction(0,0,0);
|
|
|
|
|
|
if( obstVehicle )
|
|
{
|
|
IUnknownProxy *obsProxy = obstVehicle->GetProxy();
|
|
IPhysicalEntity* phys=obsProxy->GetPhysics();
|
|
|
|
pe_status_dynamics status;
|
|
phys->GetStatus( &status );
|
|
Vec3d colliderVel = status.v;
|
|
GetPhysics()->GetStatus( &status );
|
|
Vec3d selfVel = status.v;
|
|
Vec3d diff = obstVehicle->GetPos() - m_pEntity->GetPos();
|
|
Vec3d relVel = colliderVel - selfVel;
|
|
|
|
relVel.z=0;
|
|
diff.z=0;
|
|
|
|
float scaleVel = relVel.len2()*.05f;
|
|
|
|
if(scaleVel<.1f)
|
|
scaleVel = .1f;
|
|
|
|
float distance = diff.len();
|
|
relVel.normalize();
|
|
diff.normalize();
|
|
|
|
float dotZ = diff.x*relVel.x + diff.y*relVel.y;
|
|
|
|
if(dotZ>-0.1f) // moving away from obstacel -- do nothing
|
|
return correction;
|
|
|
|
selfVel.z=0;
|
|
selfVel.normalize();
|
|
|
|
// float crossZ = diff.x*relVel.y - diff.y*relVel.x;
|
|
float crossZ = diff.x*selfVel.y - diff.y*selfVel.x;
|
|
|
|
/*
|
|
if( crossZ<0 )
|
|
correction = Vec3d( diff.y, -diff.x, 0.0f );
|
|
else
|
|
correction = Vec3d( -diff.y, diff.x, 0.0f );
|
|
*/
|
|
if( crossZ<0 )
|
|
correction = Vec3d( selfVel.y, -selfVel.x, 0.0f );
|
|
else
|
|
correction = Vec3d( -selfVel.y, selfVel.x, 0.0f );
|
|
|
|
|
|
float scaleAng = 1.0f - dotZ;
|
|
float scaleDist = 10.0f*(range - distance)/range;
|
|
|
|
|
|
correction *= scaleAng*scaleDist*scaleVel;
|
|
/*
|
|
|
|
IUnknownProxy *obsProxy = obstVehicle->GetProxy();
|
|
IPhysicalEntity* obstPhys=obsProxy->GetPhysics();
|
|
|
|
pe_status_dynamics status;
|
|
obstPhys->GetStatus( &status );
|
|
|
|
Vec3d obsVel = status.v;
|
|
|
|
obstPhys = GetPhysics();
|
|
obstPhys->GetStatus( &status );
|
|
Vec3d selfVel = status.v;
|
|
|
|
selfVel.z = 0.0f;
|
|
|
|
|
|
Vec3d relVel = obsVel - selfVel;
|
|
Vec3d diff = obstVehicle->GetPos() - m_pEntity->GetPos();
|
|
relVel.z = 0.0f;
|
|
diff.z = 0.0f;
|
|
float velScale = relVel.len2()*.01f;
|
|
float distance = diff.len();
|
|
|
|
selfVel.normalize();
|
|
relVel.normalize();
|
|
diff.normalize();
|
|
|
|
float dirScale = (-relVel.x*diff.x-relVel.y*diff.y) + 1.0f;
|
|
float distScale = (range - distance)/range;
|
|
|
|
|
|
correction = -diff;
|
|
|
|
|
|
// selfVel.normalize();
|
|
// float crossZ = (relVel.x*diff.y - relVel.y*diff.x);
|
|
float crossZ = (selfVel.x*diff.y - selfVel.y*diff.x);
|
|
if( crossZ<0 )
|
|
{
|
|
correction = Vec3d(-selfVel.y, selfVel.x, 0);
|
|
}
|
|
else
|
|
{
|
|
correction = Vec3d(selfVel.y, -selfVel.x, 0);
|
|
}
|
|
|
|
correction *= velScale*dirScale*distScale;
|
|
*/
|
|
}
|
|
|
|
return correction;
|
|
|
|
}
|
|
|
|
void CXVehicleProxy::Load(CStream &stm)
|
|
{
|
|
int nPresent=0;
|
|
|
|
//check curr behaviour
|
|
stm.Read(nPresent);
|
|
if (nPresent)
|
|
{
|
|
char str[255];
|
|
stm.Read(str,255);
|
|
m_AIHandler.SetBehaviour(str);
|
|
}
|
|
|
|
// check prev
|
|
stm.Read(nPresent);
|
|
if (nPresent)
|
|
{
|
|
char str[255];
|
|
stm.Read(str,255);
|
|
}
|
|
}
|
|
|
|
void CXVehicleProxy::Save(CStream &stm)
|
|
{
|
|
// save the current & previous behaviours
|
|
const char *szString;
|
|
if (m_AIHandler.m_pBehavior)
|
|
{
|
|
stm.Write((int)1); // we have a current behaviour
|
|
m_AIHandler.m_pBehavior->GetValue("Name",szString);
|
|
stm.Write(szString);
|
|
}
|
|
else
|
|
stm.Write((int)0);
|
|
|
|
if (m_AIHandler.m_pPreviousBehavior)
|
|
{
|
|
stm.Write((int)1);
|
|
m_AIHandler.m_pPreviousBehavior->GetValue("Name",szString);
|
|
stm.Write(szString);
|
|
}
|
|
else
|
|
stm.Write((int)0);
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|