////////////////////////////////////////////////////////////////////// // // Game Source Code // // File: XVehicleProxy.cpp // Description: AI vehicles proxy // // History: // - Oct, 17, 2002: Created by Kirill Bulatsev // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "xvehicleproxy.h" #include "XVehicle.h" #include CXVehicleProxy::CXVehicleProxy(IEntity *pEntity,IScriptSystem *pScriptSystem, CXGame *pGame): pSignalTable(pScriptSystem), m_MinAltitude(0.0f), m_bTargetInWater(true) { m_pScriptSystem = pScriptSystem; m_pEntity = pEntity; m_fThrust = 0; m_fTilt = 0; m_fAngle = 0; m_VertThrust = 0.0f; m_DeviationTime = 0.0f; m_Movement(0,0,0); // m_Direction(0,0,0); m_Direction = pEntity->GetAngles(); m_NotMovingTime = 0.0f; m_ReverseTime = 0.0f; if (m_pEntity->GetContainer()) { if (!m_pEntity->GetContainer()->QueryContainerInterface(CIT_IVEHICLE,(void**) &m_pVehicle)) m_pVehicle = 0; } else m_pVehicle = 0; // m_bDead = false; m_fBackwardSpeed = 0; m_fForwardSpeed = 0; // m_vHeadDir = pEntity->GetAngles(); // m_vHeadDir.ConvertToRadAngles(); m_pGame = pGame; m_AIHandler.Init( m_pGame, m_pEntity, m_pGame->GetSystem()->GetILog() ); } CXVehicleProxy::~CXVehicleProxy(void) { } int CXVehicleProxy::Update(SOBJECTSTATE *state) { // fixme - this should be done some other way - not to check for AI driver every time if(m_Type==AIOBJECT_HELICOPTER) // no driver in hely MoveLikeAHelicopter( state ); else { IEntity *driverEnt =0; if (m_pVehicle && m_Type) driverEnt = m_pGame->GetSystem()->GetIEntitySystem()->GetEntity(m_pVehicle->m_DriverID); if(driverEnt) { IAIObject * driveAI = driverEnt->GetAI(); if(driveAI && driveAI->GetType() != AIOBJECT_PLAYER) { // fixme over switch(m_Type) { case AIOBJECT_HELICOPTER: MoveLikeAHelicopter( state ); break; case AIOBJECT_CAR: MoveLikeACar( state ); break; case AIOBJECT_BOAT: MoveLikeABoat( state ); break; } } } } //------------------------------------------- if (state->bReevaluate) UpdateMind(state); if (!(m_LastObjectState == *state)) { m_LastObjectState = *state; UpdateMotor(state); } while (!state->vSignals.empty()) { AISIGNAL sstruct = state->vSignals.back(); state->vSignals.pop_back(); int signal = sstruct.nSignal; const char *szText = sstruct.strText; IEntity* pSender= (IEntity*) sstruct.pSender; SendSignal(signal,szText,pSender); } if (state->nAuxSignal) { SendAuxSignal(state->nAuxSignal,state->szAuxSignalText.c_str()); state->nAuxSignal = 0; } return 0; } // //-------------------------------------------------------------------------------------------------- void CXVehicleProxy::UpdateMind(SOBJECTSTATE *state) { m_AIHandler.AIMind( state ); state->bReevaluate = false; return; } // //-------------------------------------------------------------------------------------------------- int CXVehicleProxy::UpdateMotor(SOBJECTSTATE *state) { return 0; } // //-------------------------------------------------------------------------------------------------- void CXVehicleProxy::SendSignal(int signalID, const char * szText, IEntity *pSender) { m_pEntity->SetNeedUpdate( true ); m_AIHandler.AISignal( signalID, szText, pSender ); return; } // //-------------------------------------------------------------------------------------------------- void CXVehicleProxy::SendAuxSignal(int signalID, const char * szText) { // clear normal stuff pSignalTable->SetValue("nSignal",0); pSignalTable->SetToNull("SignalText"); pSignalTable->SetValue("nAuxSignal",signalID); pSignalTable->SetValue("AuxSignalText",szText); // m_pScriptSystem->BeginCall(m_pEntity->GetEntityClassName(),m_strSignalFuncName.c_str()); m_pScriptSystem->BeginCall(m_hSignalFunc); m_pScriptSystem->PushFuncParam(m_pEntity->GetScriptObject()); m_pScriptSystem->PushFuncParam(*pSignalTable); m_pScriptSystem->EndCall(); } // //-------------------------------------------------------------------------------------------------- void CXVehicleProxy::SetSignalFunc(HSCRIPTFUNCTION pFunc) { m_hSignalFunc.Init(m_pScriptSystem,pFunc); } void CXVehicleProxy::SetBehaviourFunc(HSCRIPTFUNCTION pFunc) { m_hBehaviourFunc.Init(m_pScriptSystem,pFunc); } void CXVehicleProxy::SetMotorFunc(HSCRIPTFUNCTION pFunc) { m_hMotorFunc.Init(m_pScriptSystem,pFunc); } // //-------------------------------------------------------------------------------------------------- bool CXVehicleProxy::QueryProxy(unsigned char type, void **pProxy) { if (type == AIPROXY_VEHICLE) { *pProxy = (void *) this; return true; } else return false; } // //-------------------------------------------------------------------------------------------------- // //-------------------------------------------------------------------------------------------------- // isn't it obvious void CXVehicleProxy::MoveLikeAnAirplane(SOBJECTSTATE * state) { /* //m_fForwardSpeed = 16; Vec3d angles = m_pEntity->GetAngles(); Vec3d dir = angles; dir.ConvertToRadAngles(); float tScale = m_pGame->GetSystem()->GetITimer()->GetFrameTime(); pe_action_move motion; // Vec3d pos; // Vec3d dir; if (state->vTargetPos.Length()) { Vec3d tDir = state->vTargetPos - m_pEntity->GetPos(); Vec3d correction = tDir - m_curMoveDir; m_curMoveDir = m_curMoveDir + correction*m_pGame->GetSystem()->GetITimer()->GetFrameTime()*0.05f; m_curMoveDir.Normalize(); if (state->turnleft || state->turnright) { angles.z+=state->fValue; } } else m_curMoveDir = Vec3d(0,0,0); if (m_curMoveDir.Length()) { Vec3d vMoveNorm = m_curMoveDir; vMoveNorm.Normalize(); Vec3d vMoveNorm2 = dir; vMoveNorm2.Normalize(); float zcross = vMoveNorm2.x * vMoveNorm.y - vMoveNorm2.y * vMoveNorm.x; zcross *=-40.3f; // if ((m_fTilt < 50.f) && (m_fTilt > -50.f)) // m_fTilt += (zcross-m_fTilt)*1.7f; if (fabs(m_fTilt) < 50) m_fTilt -= (zcross); } if (fabs(m_fTilt) > 0) { if(m_fTilt<0) { m_fTilt+=m_pGame->GetSystem()->GetITimer()->GetFrameTime()*23.2f; if(m_fTilt>0.0f) m_fTilt=0.0f; } else { m_fTilt-=m_pGame->GetSystem()->GetITimer()->GetFrameTime()*23.2f; if(m_fTilt<0.0f) m_fTilt=0.0f; } } angles.y = m_fTilt; Vec3d xyDir = m_curMoveDir; xyDir.ConvertVectorToCameraAngles(); angles.x = xyDir.x; angles.z = xyDir.z; m_pEntity->SetAngles(angles,false); // motion.dir.set(0,0,0); motion.dir = m_curMoveDir*m_fForwardSpeed; if(m_pEntity->GetPhysics()) m_pEntity->GetPhysics()->Action(&motion); */ } // //-------------------------------------------------------------------------------------------------- // isn't it obvious void CXVehicleProxy::MoveLikeACar(SOBJECTSTATE * state) { Vec3d angles = m_pEntity->GetAngles(); Vec3d anglesMovement; CXEntityProcessingCmd tempCommand; float frameTime = m_pGame->GetSystem()->GetITimer()->GetFrameTime(); bool doBreak = false; bool doGoBack = false; bool bChasing = (state->bodystate==1); if(frameTime<=0.0f) frameTime = 0.01f; if(frameTime > .1f) frameTime = .1f; state->pathUsage = SOBJECTSTATE::PU_PathOK; if( bChasing ) // update path always { //* Vec3 vClosestPoint; bool intersectsForbidden = true; // if(state->fDistanceFromTarget<100.0f) if((state->vTargetPos.x+state->vTargetPos.y)!=0.0f) intersectsForbidden = m_pGame->GetSystem()->GetAISystem()->IntersectsForbidden(m_pEntity->GetPos(), state->vTargetPos, vClosestPoint); if(intersectsForbidden) // state->pathUsage = SOBJECTSTATE::PU_NoPathfind; m_pEntity->GetAI()->NeedsPathOutdoor(true, true); else m_pEntity->GetAI()->NeedsPathOutdoor(false, true); state->pathUsage = SOBJECTSTATE::PU_NewPathWanted; } Vec3d vCurVel; float curVel; // Create a new status object. The fields are initialized for us pe_status_dynamics status; // Get a pointer to the physics engine IPhysicalEntity *physEnt = m_pEntity->GetPhysics(); // Get new player status from physics engine if (physEnt && physEnt->GetStatus(&status)) { // Get our current velocity, default will be (0,0,0) vCurVel = (Vec3d)status.v; anglesMovement = -status.v.normalized(); } curVel = vCurVel.len(); Vec3d desired = state->vMoveDir;//(Vec3d)motion.dir; // desired += BoatAvoidCollision( 6.0f )*10.0f; float avoidRadius = curVel*.73f; if(avoidRadius > 0) { if(avoidRadius<8) avoidRadius = 8; if(avoidRadius>15) avoidRadius = 15; desired += CarAvoidCollision( avoidRadius )*7.0f; desired.Normalize(); } //----------------------------------------- // avoid sticking if (GetLengthSquared(state->vMoveDir)) { if( m_ReverseTime > 0 ) { if( m_ReverseTime > .12 ) doGoBack = true; // back up else doBreak = true; // now stop m_ReverseTime -= frameTime; m_NotMovingTime = -0.3f; } else { if( curVel < .3 )// && m_ReverseTime<=0 ) { m_NotMovingTime += frameTime; if( m_NotMovingTime>1.0 ) { m_ReverseTime = 1.9f; m_NotMovingTime = 0.0f; } } else m_NotMovingTime = 0.0f; } } else m_NotMovingTime = 0.0f; m_LastPos = m_pEntity->GetPos(); // if( state->fDistanceFromTarget<5 && state->bodystate==1 ) // { // m_ReverseTime = .1f; // doBreak = true; // now stop // } //if ( state->dodge ) // { // tempCommand.AddAction(ACTION_JUMP); // } // else //if (state->left || state->right || doBreak || desired.len2()==0.0f) // brake!!! //if (state->left || state->right || doBreak) //filippo: if there is no active target to go hold down the brake. //GetISystem()->GetILog()->Log("distance from target for %s : %.3f (%s) %i",m_pEntity->GetName(),state->fDistanceFromTarget,state->bTargetEnabled?"enable":"not enable",state->nTargetType); if (state->left || state->right || doBreak || (!state->bTargetEnabled /*&& state->fDistanceFromTarget<=0.0f*/)) { tempCommand.AddAction(ACTION_WALK); } else // drive!!! { float crossz = desired.x * anglesMovement.y - desired.y * anglesMovement.x; float dotz = desired.x * anglesMovement.x + desired.y * anglesMovement.y; if (state->back || doGoBack) { tempCommand.AddAction(ACTION_MOVE_BACKWARD); if( fabs(crossz) <= 0.1f ) { if( rand()%100<50 ) crossz = -1.0f; else crossz = 1.0f; } } else if (GetLengthSquared(state->vMoveDir)) { float newSlowDwn=1.0f; float fMaxSpeed = 25.5f; // Create a new status object. The fields are initialized for us pe_status_vehicle_abilities status_va; // Get new player status from physics engine if (physEnt && physEnt->GetStatus(&status_va)) fMaxSpeed = status_va.maxVelocity*.4f; // physics returns not real value fMaxSpeed *= m_fForwardSpeed; float scaleSlowDown = 1; if(state->fDistanceFromTarget < 25) scaleSlowDown = 1.0f-( Ffabs(crossz) * 2.0f * (25.0f-state->fDistanceFromTarget)/25.0f); // If chasing and close to target - don't speed up if( state->fDistanceFromTarget<20 && bChasing ) { newSlowDwn = state->fDistanceFromTarget/10.0f; if( scaleSlowDown > newSlowDwn ) scaleSlowDown = newSlowDwn; } if(fabsf(status.w.z)>1.0f) // too much of angular velosity - don't speed up { newSlowDwn = 1.0f - fabsf(status.w.z)/5.0f; if( newSlowDwn<0.0f ) newSlowDwn = 0.0f; if(scaleSlowDown > newSlowDwn) scaleSlowDown = newSlowDwn; } if( scaleSlowDown < .7f ) state->pathUsage = SOBJECTSTATE::PU_NewPathWanted; if( scaleSlowDown < .2f ) scaleSlowDown = .2f; if( state->fDesiredSpeed > scaleSlowDown ) state->fDesiredSpeed = scaleSlowDown; // if(curVel.len2()fDistanceFromTarget) if(fMaxSpeed==1.0f || curVel < fMaxSpeed*state->fDesiredSpeed) { // If chasing and close to target - don't speed up // if( !(state->fDistanceFromTarget<2 && state->bodystate==1) ) tempCommand.AddAction(ACTION_MOVE_FORWARD); // speed up } else if(state->fDesiredSpeed<.5f && curVel>1.0f) tempCommand.AddAction(ACTION_WALK); // break } if( curVel < 3 || fabsf(status.w.z)*curVel<30.0f ) // don't steer if too fast anh have angulaar momentum already { float omegaScale = state->fDistanceFromTarget/50.0f; if(omegaScale>1.0f) omegaScale = 1.0f; else if(omegaScale<0.1f) omegaScale = 0.1f; omegaScale = 0.05f; float delta = 0.0f; if(dotz<0) delta = .0051f; float curWZ = status.w.z; if (crossz < -delta) { if((crossz < curWZ*omegaScale || curWZ>0) ) { tempCommand.AddAction(ACTION_MOVE_RIGHT); state->DEBUG_controlDirection = 1; } } else if (crossz > delta) { if((crossz > curWZ*omegaScale || curWZ<0)) { tempCommand.AddAction(ACTION_MOVE_LEFT); state->DEBUG_controlDirection = 2; } } } else int amv=2; } if( curVel>0 && state->fDistanceFromTarget/curVel<3.0f ) state->pathUsage = SOBJECTSTATE::PU_PathOK; // don't regenirate path if too close to navTarget // cuz can take too long to make new path pe_status_vehicle vStatus; physEnt->GetStatus(&vStatus); if(vStatus.bWheelContact == 0) // no wheels on ground - don't turn { tempCommand.RemoveAction(ACTION_MOVE_LEFT); tempCommand.RemoveAction(ACTION_MOVE_RIGHT); } m_pVehicle->ProcessMovement(tempCommand); } // //-------------------------------------------------------------------------------------------------- // isn't it obvious void CXVehicleProxy::MoveLikeABoat(SOBJECTSTATE * state) { bool bApproachingDropPoint=state->left||state->right; // if strafing - means we are dropping people bool bAttacking = (state->fStickDist>0.0f); bool bTargetOnLand = (state->bodystate==1); Vec3d desired = state->vMoveDir;//(Vec3d)motion.dir; bool bWantToMove = (desired.len2()!=0); desired += BoatAvoidCollision( 25.0f )*60.0f; desired.Normalize(); bool bWantToAvoidCollision = (desired.len2()!=0); Vec3d angles = m_pEntity->GetAngles(); Vec3d vFwd; CXEntityProcessingCmd tempCommand; float frameTime = m_pGame->GetSystem()->GetITimer()->GetFrameTime(); if(frameTime > .1f) frameTime = 0.1f; Vec3d vCurVel=Vec3d(0,0,0); float fCurVel=0.0f; float curWZ=0.0f; // Create a new status object. The fields are initialized for us pe_status_dynamics status; // Get a pointer to the physics engine IPhysicalEntity *physEnt = m_pEntity->GetPhysics(); // Get new player status from physics engine if (physEnt && physEnt->GetStatus(&status)) { // Get our current velocity, default will be (0,0,0) vCurVel = (Vec3d)status.v; fCurVel = vCurVel.len(); curWZ = status.w.z; } Matrix44 m; m.SetIdentity(); //m.RotateMatrix_fix(angles); m=Matrix44::CreateRotationZYX(-angles*gf_DEGTORAD)*m; //NOTE: angles in radians and negated angles = m.TransformPointOLD(Vec3d(0,-1,0)); angles.z=0; vFwd = angles; state->pathUsage = SOBJECTSTATE::PU_NewPathWanted; // send a signal if target (player) goes from water to land if( !BoatPointInWater(state->vTargetPos) ) { if(m_bTargetInWater) { m_bTargetInWater = false; SendSignal(0, "TARGET_ON_LAND", m_pEntity); } } else m_bTargetInWater = true; // drive!!! { bool doGoBack = false; bool doBreak = false; //----------------------------------------- // avoid stucking if (bWantToMove) { if( m_ReverseTime > 0 ) { doGoBack = true; // back up m_ReverseTime -= frameTime; m_NotMovingTime = -0.5f; } else { if( fCurVel < .03 && !bAttacking) { m_NotMovingTime += frameTime; if( m_NotMovingTime>.31 ) { m_ReverseTime = 1.62f; m_NotMovingTime = 0.0f; } } else m_NotMovingTime = 0.0f; } } else m_NotMovingTime = 0.0f; m_LastPos = m_pEntity->GetPos(); Vec3d actualDir = -vCurVel; actualDir.z=0; actualDir.normalize(); angles = angles+actualDir*.5f; angles.normalize(); float crossz = desired.x * angles.y - desired.y * angles.x; float dotz = desired.x * angles.x + desired.y * angles.y; if (state->back || doGoBack ) { tempCommand.AddAction(ACTION_MOVE_BACKWARD); if( crossz == 0.1f ) { if( rand()%100<50 ) crossz = -1.0f; else crossz = 1.0f; } else { if( crossz < 0.0f ) crossz = 1.0f; else crossz = -1.0f; } } else if (bWantToMove||bWantToAvoidCollision) tempCommand.AddAction(ACTION_MOVE_FORWARD); float targetCone = state->fDistanceFromTarget*0.32f/15.0f; if(targetCone>0.20f) targetCone = 0.20f; if(targetCone<0.05f) targetCone = 0.05f; float omegaScale = state->fDistanceFromTarget/50.0f; if(omegaScale>1.0f) omegaScale = 1.0f; else if(omegaScale<0.1f) omegaScale = 0.1f; if(dotz>0.0f) { targetCone = 0.0f; omegaScale = 0.0f; } if(!bWantToMove) // not moving - just turn to look at target { if(state->fValue<-.35f && (state->fValue < curWZ || curWZ>0) ) { tempCommand.AddAction(ACTION_MOVE_RIGHT); state->DEBUG_controlDirection = 1; tempCommand.AddAction(ACTION_MOVEMODE); // to enable turning without any speed } else if(state->fValue>.35f && (state->fValue > curWZ || curWZ<0) ) { tempCommand.AddAction(ACTION_MOVE_LEFT); state->DEBUG_controlDirection = 2; tempCommand.AddAction(ACTION_MOVEMODE); // to enable turning without any speed } } else // normal turning when moving { if (crossz < -targetCone ) { if((crossz < curWZ*omegaScale || curWZ>0) ) { tempCommand.AddAction(ACTION_MOVE_RIGHT); state->DEBUG_controlDirection = 1; } } else if (crossz > targetCone ) { if((crossz > curWZ*omegaScale || curWZ<0)) { tempCommand.AddAction(ACTION_MOVE_LEFT); state->DEBUG_controlDirection = 2; } } } float needToSlow = fCurVel*(float)(fabs(crossz)/state->fDistanceFromTarget); if ( bAttacking ) // sticking - don't go too close to target { { if(state->fDistanceFromTargetfStickDist && !bWantToAvoidCollision) { float spidDistCoeff = state->fDistanceFromTarget/state->fStickDist; tempCommand.RemoveAction( ACTION_MOVE_FORWARD ); if(spidDistCoeff>.6 && fCurVel>spidDistCoeff*5.1 ) { tempCommand.AddAction( ACTION_WALK ); // break } } //slow down if diff dir float allowedSpeed=50; if(dotz>0) { allowedSpeed = 5.2f - (1-fabsf(crossz))*3; if( curWZ > 1.1f) // don't add turn if angular speed is big already { tempCommand.RemoveAction(ACTION_MOVE_LEFT); tempCommand.RemoveAction(ACTION_MOVE_RIGHT); } else if( curWZ < -1.1f ) { tempCommand.RemoveAction(ACTION_MOVE_LEFT); tempCommand.RemoveAction(ACTION_MOVE_RIGHT); } } else if( fabsf(crossz)>.5f ) allowedSpeed = 10.2f - (fabsf(crossz))*2; if( fCurVel>allowedSpeed ) { tempCommand.RemoveAction( ACTION_MOVE_FORWARD ); tempCommand.RemoveAction( ACTION_MOVE_BACKWARD ); if(allowedSpeed<5) tempCommand.AddAction( ACTION_WALK ); // break tempCommand.AddAction( ACTION_MOVEMODE ); // allow turning without movement } if( curWZ > 2 && fCurVel>.5f) // don't add turn if angular speed is big already { tempCommand.RemoveAction(ACTION_MOVE_LEFT); tempCommand.RemoveAction(ACTION_MOVE_RIGHT); } else if( curWZ < -3 ) { tempCommand.RemoveAction(ACTION_MOVE_LEFT); tempCommand.RemoveAction(ACTION_MOVE_RIGHT); } } } else if (bApproachingDropPoint && (fCurVel>7.5f || fCurVel*.70f > state->fDistanceFromTarget) ) // slow down!!! coz have to stop at target { if(dotz<0.0f) // if moving towards target // if( curVel.len2()*3.0f > state->fDistanceFromTarget) { tempCommand.RemoveAction( ACTION_MOVE_FORWARD ); if( fCurVel*0.5f > state->fDistanceFromTarget) tempCommand.AddAction(ACTION_MOVE_BACKWARD); } } else if(fabs(crossz)>.3f && fCurVel>7 && needToSlow>.2f ) // slow down!!! coz too close to target and going to miss it { tempCommand.RemoveAction( ACTION_MOVE_FORWARD ); if( fCurVel*1.0f > state->fDistanceFromTarget) tempCommand.AddAction(ACTION_MOVE_BACKWARD); } //* // avoid going into land, except when is too slow or dropping people if(!bApproachingDropPoint) { Vec3d fwdPoint; if(fCurVel>.05f) { float scale = fCurVel*0.3f + 5.0f; if( scale>13 ) scale = 13; fwdPoint = m_pEntity->GetPos() - actualDir*scale; } else { vFwd.normalize(); fwdPoint = m_pEntity->GetPos() - vFwd*5; } Vec3d vClosestPoint; bool intersectsForbidden = m_pGame->GetSystem()->GetAISystem()->IntersectsForbidden(m_pEntity->GetPos(), fwdPoint, vClosestPoint) && m_pEntity->GetAI()->IfNeedsPathOutdoor(); // check for runnin in land and crossing forbidden area for some forwardPoint // in direction of movement, depending on cur velocity if( !BoatPointInWater(fwdPoint) || intersectsForbidden ) { if(bAttacking) { if(dotz<0) // target in front m_ReverseTime = 1 + (1+dotz); // back off more if niids to turn for target else m_ReverseTime = 1; // back off more if needs to turn for target m_ReverseTime = 0; } // can hit ground/forbidden area // enable turning without moving tempCommand.AddAction(ACTION_MOVEMODE2); tempCommand.AddAction(ACTION_MOVEMODE); } } } if(bTargetOnLand) m_pVehicle->ProcessMovementBoat2(tempCommand, m_fForwardSpeed*.3f); else m_pVehicle->ProcessMovementBoat2(tempCommand, m_fForwardSpeed); // disable pathfind with // AI:PushGoal(".....","strafe",0,-1); if(state->right) state->pathUsage = SOBJECTSTATE::PU_NoPathfind; } // //-------------------------------------------------------------------------------------------------- void CXVehicleProxy::SetSpeeds(float fwd, float bkw) { if( fwd >= 0 ) m_fForwardSpeed = fwd; if( bkw >= 0 ) m_fBackwardSpeed = bkw; } // //-------------------------------------------------------------------------------------------------- // avoiding rockets Vec3d CXVehicleProxy::UpdateThreat( void* threat ) { switch(m_Type) { case AIOBJECT_HELICOPTER: return UpdateThreatHeli( threat ); case AIOBJECT_CAR: return UpdateThreatCar( threat ); } return Vec3d(0,0,0); } // //-------------------------------------------------------------------------------------------------- // avoiding rockets car Vec3d CXVehicleProxy::UpdateThreatCar( void* threat ) { IEntity* theThreatingEntity = (IEntity*)threat; if(!theThreatingEntity) return Vec3d(0,0,0); Vec3d dir = m_pEntity->GetPos() - theThreatingEntity->GetPos(); float dist = GetLengthSquared(dir); Vec3d threatVel = 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) threatVel = (Vec3d)status.v; float tDot = dir.Dot( threatVel ); /* if( tDot<0.7f ) // threat moves from me { if( dist>500 ) return Vec3d(0,0,0); } else //threat moves towards me { if( dist>2000 ) return Vec3d(0,0,0); } */ dir.Normalize(); return dir; } // //-------------------------------------------------------------------------------------------------- void CXVehicleProxy::DebugDraw(struct IRenderer * pRenderer) { } // //-------------------------------------------------------------------------------------------------- bool CXVehicleProxy::BoatPointInWater( const Vec3d& pos ) { float diff = m_pGame->m_p3DEngine->GetWaterLevel( &pos ) - m_pGame->m_p3DEngine->GetTerrainElevation( pos.x, pos.y ); // see if target is on land or in water if( m_pGame->m_p3DEngine->GetWaterLevel( &pos ) - m_pGame->m_p3DEngine->GetTerrainElevation( pos.x, pos.y ) > .3f ) return true; // point in water return false; // point on land or not deep } // //-------------------------------------------------------------------------------------------------- Vec3d CXVehicleProxy::BoatFindAttackPoint( const Vec3d& targetPos ) { Vec3d groundPos=targetPos; Vec3d waterPos=m_pEntity->GetPos(); return waterPos; for( int cntr=0; cntr<2; cntr++ ) { Vec3d nextPos = (groundPos+waterPos)*.5; if( BoatPointInWater(nextPos) ) waterPos = nextPos; else groundPos = nextPos; } return waterPos; }