1980 lines
54 KiB
C++
1980 lines
54 KiB
C++
#include "stdafx.h"
|
|
#include "XVehicle.h"
|
|
#include <IAgent.h>
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
#define SGN(a) ((a < 0) ? -1 : 1)
|
|
|
|
string CVehicle::m_sNoWeaponName("NoWeapon");
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
CVehicle::CVehicle(CXGame *pGame):
|
|
m_fPedalSpeed(0.0f),
|
|
m_DriverID(0),
|
|
m_fPrevFwvSpeedLen(0.0f),
|
|
m_pHeadLight(NULL),
|
|
m_pHeadLightLeft(NULL),
|
|
m_pHeadLightRight(NULL),
|
|
m_pBreakLightLeft(NULL),
|
|
m_pBreakLightRight(NULL),
|
|
m_bHeadLightsOn(false),
|
|
m_bBreakLightsOn(false),
|
|
m_bAutoLights(false),
|
|
m_bPhysAwaike(false),
|
|
m_bBrakeOnNodriver(true),
|
|
m_fNoDriverTime(0.0f),
|
|
m_AngleLimitVFlag(false),
|
|
m_AngleLimitHFlag(false),
|
|
m_vWpnAng(0,0,180),
|
|
m_vWpnAngDelta(0,0,0),
|
|
m_bCrossOnScreen(false),
|
|
m_WeaponUser(0),
|
|
m_bForceHandBreak(false)
|
|
{
|
|
m_pGame = pGame;
|
|
m_pScriptObject=NULL;
|
|
m_fPedalSpeed = 10.0f;
|
|
m_fSteerSpeed = 25.0f; m_fv0MaxSteer = 40.0f; m_fkvMaxSteer = 0.0f;
|
|
m_fv0SteerRelaxation = 0.0f; m_fkvSteerRelaxation = 5.0f;
|
|
m_fMaxSteeringPedal = 0.015f; m_fPedalLimitSpeed = 10.0f;
|
|
m_ScriptStream.Create(m_pGame->GetScriptSystem());
|
|
m_Type = VHT_CAR;
|
|
|
|
SwitchLights(0);
|
|
|
|
m_btVelocity = 0;
|
|
m_vEnginePos(0,0,0);
|
|
|
|
//make unit so that at least it will move
|
|
// m_fBoatTurnSpeed=1.0f;
|
|
// m_fBoatSpeed=1.0f;
|
|
|
|
m_fEngineHealth=100.0f;
|
|
m_fDeathTimer=-1;
|
|
|
|
m_pGliderGravity=m_pGame->GetSystem()->GetIConsole()->GetCVar("game_GliderGravity");
|
|
m_pGliderBackImpulse=m_pGame->GetSystem()->GetIConsole()->GetCVar("game_GliderBackImpulse");
|
|
m_pGliderDamping=m_pGame->GetSystem()->GetIConsole()->GetCVar("game_GliderDamping");
|
|
m_pGliderStartGravity=m_pGame->GetSystem()->GetIConsole()->GetCVar("game_GliderStartGravity");
|
|
|
|
m_sAutoWeaponName.clear();
|
|
m_sMountedWeaponName.clear();
|
|
// m_sNoWeaponName = "NoWEapon";
|
|
|
|
//m_sWeaponName = "VehicleMountedMG";
|
|
|
|
m_AngleLimitVFlag = true;
|
|
m_AngleLimitHFlag = true;
|
|
//m_MinVAngle = -20;
|
|
m_MaxVAngle = 20;
|
|
m_MinHAngle = -95;
|
|
m_MaxHAngle = 95;
|
|
|
|
|
|
m_bUpdateCamera = false;
|
|
m_vCamStiffness[0](0,0,0); m_vCamStiffness[1](0,0,0);
|
|
m_vCamLimits[0](1,1,1); m_vCamLimits[1](1,1,1);
|
|
m_fCamDamping=0.8f; m_fMaxCamTimestep=0.01f; m_fCamSnapDist=0.001f; m_fCamSnapVel=0.01f;
|
|
|
|
m_fhandbraking_value = 0;
|
|
m_fhandbraking_value_nodriver = 0;
|
|
|
|
m_fMaxBrakingFriction = 1.0;
|
|
m_fMaxBrakingFrictionNoDriver = 1.0;
|
|
|
|
m_bUsingNoDriverFriction = false;
|
|
|
|
m_DirVelDotProduct = 0.0f;
|
|
|
|
m_fstabilizejump = 0.0f;
|
|
|
|
m_flastwheelrotation = 0.0f;
|
|
|
|
m_fWaterlevelLimit = 0.0f;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
CVehicle::~CVehicle()
|
|
{
|
|
SAFE_DELETE( m_pHeadLight );
|
|
SAFE_DELETE( m_pHeadLightLeft );
|
|
SAFE_DELETE( m_pHeadLightRight );
|
|
SAFE_DELETE( m_pBreakLightLeft );
|
|
SAFE_DELETE( m_pBreakLightRight );
|
|
|
|
if(m_pScriptObject)
|
|
m_pScriptObject->Release();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CVehicle::Init()
|
|
{
|
|
m_bAcceleratedLastUpdate = false;
|
|
m_bAcceleratedFlagSetLastFrame = false;
|
|
m_bIsBreaking = false;
|
|
m_iPrevMoveTime = 0;
|
|
m_fSimTime = 0;
|
|
|
|
GetEntity()->GetScriptObject()->SetValue("type", "Vehicle");
|
|
// [kirill] need this to use character(weapon on vehicle) and m_objects (vehicle's geometry)
|
|
// when calculating BBox
|
|
GetEntity()->SetFlags( ETY_FLAG_CALCBBOX_USEALL );
|
|
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CVehicle::Update()
|
|
{
|
|
// [marco] remove the vehicle after 30 seconds it
|
|
// exploded - not in multiplayer
|
|
float fTimeStep = m_pGame->GetSystem()->GetITimer()->GetFrameTime();
|
|
if (m_fEngineHealth<=0)
|
|
m_bHeadLightsOn=false;
|
|
if (!m_pGame->IsMultiplayer())
|
|
{
|
|
if (m_fEngineHealth<=0)
|
|
{
|
|
// first time set the death timer
|
|
if (m_fDeathTimer<-0.5f) // epsilon
|
|
{
|
|
float deathTimer=m_pGame->p_deathtime->GetFVal();
|
|
m_fDeathTimer = deathTimer;
|
|
}
|
|
else
|
|
m_fDeathTimer-=fTimeStep;
|
|
|
|
if (m_fDeathTimer<=0.0f)
|
|
{
|
|
m_fDeathTimer = 0.0f;
|
|
int nRendererFrameID = m_pGame->GetSystem()->GetIRenderer()->GetFrameID();
|
|
if (nRendererFrameID-m_pEntity->GetDrawFrame()>150)
|
|
{
|
|
m_pEntity->Remove();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
UpdateLights();
|
|
UpdateWeaponPosAngl();
|
|
|
|
if(GetEntity()->GetPhysics())
|
|
if(!GetEntity()->GetPhysics()->GetStatus(&pe_status_awake()))
|
|
UpdateCamera(fTimeStep, m_pGame->IsSynchronizing());
|
|
|
|
if ((m_Type == VHT_BOAT) )
|
|
WakeupPhys();
|
|
|
|
if (GetEntity()->GetPhysics())
|
|
{
|
|
pe_params_flags pf;
|
|
pf.flagsOR = pef_custom_poststep | pef_fixed_damping;
|
|
GetEntity()->GetPhysics()->SetParams(&pf);
|
|
}
|
|
}
|
|
|
|
void CVehicle::UpdatePhysics(float fTimeStep)
|
|
{
|
|
if(!HasDriver())
|
|
m_fNoDriverTime += fTimeStep;
|
|
|
|
UpdateMovementStatus();
|
|
|
|
if ((m_Type == VHT_BOAT))
|
|
UpdateBoat(fTimeStep);
|
|
else if ( m_Type == VHT_PARAGLIDER )
|
|
UpdateParaglider(fTimeStep);
|
|
//[filippo]
|
|
/*else if ((m_Type == VHT_CAR) && !HasDriver() && (m_bBrakeOnNodriver || m_fNoDriverTime>3.0f))
|
|
{
|
|
// there is no driver
|
|
// brake the car
|
|
IPhysicalEntity *icar = GetEntity()->GetPhysics();
|
|
if(!icar) // not phisycalized
|
|
{
|
|
m_pGame->GetSystem()->GetILog()->Log("\002 WARNING car is NOT phisycalized [ %s ]", m_pEntity->GetName());
|
|
return;
|
|
}
|
|
|
|
pe_action_drive drive;
|
|
drive.bHandBrake = 1;
|
|
icar->Action(&drive);
|
|
}*/
|
|
else if (m_Type == VHT_CAR)
|
|
{
|
|
// there is no driver
|
|
// brake the car
|
|
IPhysicalEntity *icar = GetEntity()->GetPhysics();
|
|
if(!icar) // not phisycalized
|
|
{
|
|
m_pGame->GetSystem()->GetILog()->Log("\002 WARNING car is NOT phisycalized [ %s ]", m_pEntity->GetName());
|
|
return;
|
|
}
|
|
|
|
if ((!HasDriver() && (m_bBrakeOnNodriver || m_fNoDriverTime>3.0f)) || m_bForceHandBreak)
|
|
{
|
|
//filippo:when vehicles are without driver use a fake friction and save the right friction value.
|
|
if (!m_bUsingNoDriverFriction)
|
|
{
|
|
pe_params_car pc;
|
|
pc.maxBrakingFriction = m_fMaxBrakingFrictionNoDriver;
|
|
|
|
//GetISystem()->GetILog()->Log("change friction to %f",pc.maxBrakingFriction);
|
|
|
|
icar->SetParams(&pc);
|
|
|
|
m_bUsingNoDriverFriction = true;
|
|
}
|
|
|
|
pe_action_drive drive;
|
|
drive.bHandBrake = 1;
|
|
icar->Action(&drive);
|
|
|
|
AdditionalPhysics(icar,fTimeStep,true);
|
|
}
|
|
else
|
|
{
|
|
//if there is no driver and we still dont handbrake automatically , release the pedal
|
|
if (!HasDriver())
|
|
{
|
|
pe_action_drive drive;
|
|
drive.pedal = 0;
|
|
icar->Action(&drive);
|
|
}
|
|
//filippo:when vehicles have driver use restore the right friction value.
|
|
if (m_bUsingNoDriverFriction)
|
|
{
|
|
pe_params_car pc;
|
|
pc.maxBrakingFriction = m_fMaxBrakingFriction;
|
|
|
|
//GetISystem()->GetILog()->Log("change friction to %f",pc.maxBrakingFriction);
|
|
|
|
icar->SetParams(&pc);
|
|
|
|
m_bUsingNoDriverFriction = false;
|
|
}
|
|
|
|
AdditionalPhysics(icar,fTimeStep,false);
|
|
}
|
|
}
|
|
//
|
|
|
|
m_pGame->ConstrainToSandbox(GetEntity());
|
|
UpdateCamera(fTimeStep, m_pGame->IsSynchronizing());
|
|
|
|
if (m_pGame->m_pClient && !m_pGame->m_pServer && m_pGame->m_pClient->GetPlayerId()==m_DriverID && !m_bAIDriver)
|
|
ProcessMovement(m_cmdLastMove);
|
|
}
|
|
|
|
// 0 - normal
|
|
// 1 - moving back
|
|
// 2 - turnLeft
|
|
// 3 - turnRight
|
|
// 4 - break
|
|
// 5 - break beckwards
|
|
// sets current movement type to be used to play animations for users (turning/breaking/movingBack)
|
|
void CVehicle::UpdateMovementStatus()
|
|
{
|
|
// if nobody inside - no need to update usersMovamaneStates
|
|
if(m_UsersList.empty())
|
|
return;
|
|
|
|
IPhysicalEntity *pEnt=m_pEntity->GetPhysics();
|
|
pe_status_dynamics dyn;
|
|
pEnt->GetStatus(&dyn);
|
|
|
|
m_TurnState = 0;
|
|
if(dyn.w.z > .1f)
|
|
m_TurnState = 2;
|
|
else if(dyn.w.z < -.1f)
|
|
m_TurnState = 3;
|
|
|
|
Vec3 vFwdDir = m_pEntity->GetAngles();
|
|
|
|
Matrix44 tm;
|
|
tm.SetIdentity();
|
|
tm=Matrix44::CreateRotationZYX(-vFwdDir*gf_DEGTORAD)*tm; //NOTE: angles in radians and negated
|
|
vFwdDir = GetTransposed44(tm)*(Vec3d(0,-1,0));
|
|
|
|
float dot2d = vFwdDir.x*dyn.v.x + vFwdDir.y*dyn.v.y;
|
|
float velLen2 = dyn.v.len2();
|
|
if( dot2d>0 && velLen2>1.0f)
|
|
m_TurnState = 1;
|
|
|
|
//GetISystem()->GetILog()->Log("dot2d: %f",dot2d);
|
|
|
|
if(m_bIsBreaking && velLen2>3.0f)
|
|
{
|
|
if(m_TurnState == 1)
|
|
m_TurnState = 5;
|
|
else
|
|
m_TurnState = 4;
|
|
}
|
|
|
|
m_btVelocity = velLen2;
|
|
|
|
m_DirVelDotProduct = dot2d;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//this is specific fake-physics code for the boat only
|
|
//
|
|
void CVehicle::UpdateBoat(float fTimeStep)
|
|
{
|
|
float dTime = fTimeStep;//m_pGame->GetSystem()->GetITimer()->GetFrameTime();
|
|
m_fSimTime += fTimeStep;
|
|
if( dTime > 0.1f )
|
|
dTime = 0.1f ;
|
|
|
|
pe_action_awake aa;
|
|
aa.bAwake=0;
|
|
|
|
//dTime = .02f;
|
|
|
|
// if(m_fTimeDelay > -10)
|
|
// m_fTimeDelay -= dTime;
|
|
|
|
if (!m_pEntity->GetPhysics())
|
|
return; // not physicalized
|
|
IPhysicalEntity *pEnt=m_pEntity->GetPhysics();
|
|
|
|
float cTime = m_fSimTime;//m_pGame->GetSystem()->GetITimer()->GetCurrTime();
|
|
// float coef = m_BoatParams.m_fBtStand*dTime;
|
|
Vec3 pos;
|
|
pe_action_impulse am;
|
|
am.iSource = 3; // this will mark impulse as non-scheduleable in fixed timestep multiplayer
|
|
Matrix33 m;
|
|
Vec3 boatUp=Vec3(0.0f,0.0f,1.0f);
|
|
Vec3 boatFwd=Vec3(0.0f,-1.0f,0.0f);
|
|
Vec3 vert=Vec3(0.0f,0.0f,1.0f);
|
|
Vec3 dv;
|
|
Vec3 waterLine;
|
|
pe_status_dynamics dyn;
|
|
pe_status_pos spos;
|
|
spos.pMtx3x3 = m.data;
|
|
pEnt->GetStatus(&spos);
|
|
pos = spos.pos;
|
|
|
|
//get the engine pos, from where to apply the impulse
|
|
GetEntity()->GetHelperPosition("waterlevel",waterLine,true);
|
|
waterLine = m*waterLine+pos;
|
|
// if( m_Type == VHT_BOATDEAD )
|
|
// waterLine.z += .4f;
|
|
|
|
pEnt->GetStatus( &dyn );
|
|
m_btVelocity = dyn.v.len();
|
|
|
|
//if(m_btVelocity>10)
|
|
//m_pGame->GetSystem()->GetILog()->Log("\001 boat VEL [ %.2f ]", m_btVelocity);
|
|
|
|
am.momentum.Set(0,0,0);
|
|
// transform into entity space
|
|
boatUp = m*boatUp;
|
|
boatFwd = m*boatFwd;
|
|
dv = vert^boatUp;
|
|
|
|
// waves
|
|
float waveWScale = m_pGame->b_wscalew->GetFVal();
|
|
float waveScale = m_pGame->b_wscale->GetFVal();
|
|
float waveMomentum = m_BoatParams.m_fBtWave;//m_pGame->b_wmomentum->GetFVal();
|
|
Vec3 wave;
|
|
wave.x = cry_cosf((pos.x+pos.y)*waveScale + cTime*waveWScale);
|
|
wave.y = cry_sinf((pos.x+pos.y)*waveScale + cTime*waveWScale*1.21f);
|
|
wave.z = 0.0f;
|
|
|
|
//get the engine pos, from where to apply the impulse
|
|
GetEntity()->GetHelperPosition("engine",m_vEnginePos,true);
|
|
m_vEnginePos = m*m_vEnginePos+pos;
|
|
|
|
float waterLevel = (m_pGame->GetSystem()->GetI3DEngine()->GetWaterLevel( m_pEntity) - waterLine.z );//+ .6f - pos.z);
|
|
|
|
//m_btInWater = (m_pGame->m_p3DEngine->GetWaterLevel(m_pEntity) > m_vEnginePos.z);
|
|
|
|
bool inwatersave = m_btInWater;
|
|
m_btInWater = (waterLevel>m_fWaterlevelLimit);
|
|
|
|
//this is because we dont want the inwater state to switch between inwater/onground every 0.01 sec
|
|
if (m_btInWater && !inwatersave)
|
|
m_fWaterlevelLimit = -0.25f;
|
|
else if (!m_btInWater && inwatersave)
|
|
m_fWaterlevelLimit = 0.0f;
|
|
|
|
//m_pGame->GetSystem()->GetILog()->Log("waterLevel:%.3f,limit:%.3f",waterLevel,m_fWaterlevelLimit);
|
|
|
|
bool bFloating = true;
|
|
// float coef = (1.0f + dv.len2()*5.0f)*m_BoatParams.m_fBtStand*dTime;
|
|
float coef;
|
|
|
|
// if(coef>(3.0f)*m_BoatParams.m_fBtStand*dTime)
|
|
// coef = (3.0f)*m_BoatParams.m_fBtStand*dTime;
|
|
|
|
// waterLevel += m_btVelocity*.02f;
|
|
|
|
//if(waterLevel>0.0f) // is in water
|
|
if(m_btInWater) // is in water
|
|
{
|
|
// m_btInWater = true;
|
|
// go stright
|
|
// am.momentum.x = -dv.x*coef;
|
|
// am.momentum.y = -dv.y*coef;
|
|
coef = (1.0f + dv.len2()*5.0f)*m_BoatParams.m_fBtStand*dTime;
|
|
|
|
am.momentum.x = -(dv.x+dyn.w.x*m_BoatParams.m_fBtDumpW)*coef;
|
|
am.momentum.y = -(dv.y+dyn.w.y*m_BoatParams.m_fBtDumpW)*coef;
|
|
|
|
//am.momentum.set(0,0,0);
|
|
//*
|
|
// add waves
|
|
wave = vert^wave;
|
|
am.momentum.x += wave.x*waveMomentum*dTime;
|
|
am.momentum.y += wave.y*waveMomentum*dTime;
|
|
//*/
|
|
// do water friction
|
|
// Vec3 waveDump=dyn.w*m_BoatParams.m_fBtDumpW*dTime;
|
|
// am.momentum = Vec3(am.momentum.x - waveDump.x, am.momentum.y - waveDump.y, am.momentum.z - dyn.w.z*m_BoatParams.m_fBtDumpRot*dTime);
|
|
am.momentum.z -= dyn.w.z*m_BoatParams.m_fBtDumpRot*dTime;
|
|
///*
|
|
// here goes speed damping - separate fwd/back and sideways
|
|
// get forvard and side component of velocity
|
|
Vec3 projVel(dyn.v.x, dyn.v.y, 0.0f);
|
|
Vec3 projDir(boatFwd.x, boatFwd.y, 0.0f);
|
|
float projVelLen = projVel.len();
|
|
projVel.normalize();
|
|
projDir.normalize();
|
|
Vec3 projSide(projDir.y, -projDir.x, 0.0f);
|
|
float velCos = projVel.x*projDir.x + projVel.y*projDir.y;
|
|
float fwdVelLen = projVelLen*velCos;
|
|
Vec3 fwdV = projDir*fwdVelLen;
|
|
velCos = projVel.x*projSide.x + projVel.y*projSide.y;
|
|
Vec3 sideV = projSide*projVelLen*velCos;
|
|
am.impulse.x = -(fwdV.x*m_BoatParams.m_fBtDumpV + sideV.x*m_BoatParams.m_fBtDumpVSide)*dTime;
|
|
am.impulse.y = -(fwdV.y*m_BoatParams.m_fBtDumpV + sideV.y*m_BoatParams.m_fBtDumpVSide)*dTime;
|
|
//am.impulse.Set(0,0,0);
|
|
am.impulse.z = -dyn.v.z*m_BoatParams.m_fBtDumpVH*dTime;
|
|
//*
|
|
//
|
|
// do tilt on speedup
|
|
fwdVelLen = -fwdVelLen;
|
|
float velDiff = fwdVelLen - m_fPrevFwvSpeedLen;
|
|
if( fwdVelLen>0.0f )
|
|
{
|
|
Vec3 momentum = (-boatFwd)^Vec3(0.0f, 0.0f, m_BoatParams.m_fBtTitlSpd);
|
|
// if(velDiff>0 && velDiff/fwdVelLen*dTime>0.0007F)
|
|
if(velDiff>0 && velDiff/fwdVelLen>m_BoatParams.m_fBtTitlSpdA)
|
|
{
|
|
if(velDiff>dTime*20.0f)
|
|
velDiff=dTime*20.0f;
|
|
am.momentum += vectorf(momentum*velDiff);
|
|
m_fPrevFwvTilt = velDiff;
|
|
}
|
|
else if( fwdVelLen>m_BoatParams.m_fBtTitlSpdMinV )
|
|
{
|
|
float tilt = fwdVelLen*dTime*m_BoatParams.m_fBtTitlSpdMinVTilt;
|
|
float diff = m_fPrevFwvTilt - tilt;
|
|
float tiltSpd=.1f;
|
|
if(diff/dTime>tiltSpd)
|
|
tilt = m_fPrevFwvTilt - tiltSpd*dTime;
|
|
// tilt += (m_fPrevFwvTilt - tilt)*.1f;
|
|
am.momentum += vectorf(momentum*tilt);
|
|
m_fPrevFwvTilt = tilt;
|
|
}
|
|
}
|
|
m_fPrevFwvSpeedLen = fwdVelLen;
|
|
//*/
|
|
}
|
|
else // not in water (jumping?)
|
|
{
|
|
coef = (1.0f + dv.len2()*5.0f)*m_BoatParams.m_fBtStandAir*dTime;
|
|
|
|
bFloating = false;
|
|
{
|
|
// go stright
|
|
am.momentum.x = -(dv.x+dyn.w.x*m_BoatParams.m_fBtDumpW)*coef;
|
|
am.momentum.y = -(dv.y+dyn.w.y*m_BoatParams.m_fBtDumpW)*coef;
|
|
/*
|
|
// do air friction
|
|
am.momentum = am.momentum - dyn.w*m_BoatParams.m_fBtDumpW*dTime*.3f;
|
|
// dyn.w*m_pGame->b_dump->GetFVal()*dTime*.3f;
|
|
*/
|
|
}
|
|
}
|
|
|
|
pEnt->Action(&am);
|
|
|
|
pe_simulation_params sp;
|
|
sp.gravity.zero();
|
|
sp.gravity.z = waterLevel*m_pGame->b_float->GetFVal();//*m_pGame->b_float->GetFVal();
|
|
// if(!m_btInWater)
|
|
if(!bFloating)
|
|
{
|
|
//filippo: if m_BoatParams.m_fBoatGravity is 0 use the old sys
|
|
sp.gravity.z = (m_BoatParams.m_fBoatGravity==0)?(sp.gravity.z*1.5f - 3):(m_BoatParams.m_fBoatGravity);
|
|
//sp.gravity.z = sp.gravity.z*1.5f - 3; // LUC modification for better jumps out of water
|
|
}
|
|
else
|
|
sp.gravity.z = sp.gravity.z*3.5f;
|
|
pEnt->SetParams(&sp);
|
|
|
|
// set water level
|
|
//
|
|
//don't use water/float with physics
|
|
pe_params_buoyancy pb;
|
|
pb.waterDensity = 0.0f;
|
|
pEnt->SetParams(&pb);
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CVehicle::UpdateParaglider(float fTimeStep)
|
|
{
|
|
float dTime = fTimeStep;//m_pGame->GetSystem()->GetITimer()->GetFrameTime();
|
|
if( dTime > 0.1f )
|
|
dTime = 0.1f ;
|
|
|
|
//dTime = .02f;
|
|
|
|
if(!HasDriver())
|
|
{
|
|
|
|
// do override gravity for the paraglider
|
|
IPhysicalEntity *pEnt=m_pEntity->GetPhysics();
|
|
pe_simulation_params sp;
|
|
sp.gravity.zero();
|
|
sp.gravity.z = -9.8f;
|
|
sp.gravityFreefall=vectorf(0,0,-9.8f);
|
|
sp.damping=m_pGliderDamping->GetFVal()*4.0f;
|
|
sp.dampingFreefall=m_pGliderDamping->GetFVal();
|
|
m_pEntity->GetPhysics()->SetParams(&sp);
|
|
return;
|
|
}
|
|
|
|
// if(m_fTimeDelay > -10)
|
|
// m_fTimeDelay -= dTime;
|
|
|
|
|
|
//
|
|
//this is specific fake-physics code for the boat only
|
|
//
|
|
if (!m_pEntity->GetPhysics())
|
|
return; // not physicalized
|
|
|
|
|
|
float cTime = m_pGame->GetSystem()->GetITimer()->GetCurrTime();
|
|
float coef = m_BoatParams.m_fBtStand*dTime;
|
|
Vec3 pos = m_pEntity->GetPos();
|
|
Vec3 angle = m_pEntity->GetAngles();
|
|
pe_action_impulse am;
|
|
Matrix44 m;
|
|
Vec3 boatUp=Vec3(0.0f,0.0f,1.0f);
|
|
Vec3 boatFwd=Vec3(0.0f,-1.0f,0.0f);
|
|
Vec3 vert=Vec3(0.0f,0.0f,1.0f);
|
|
Vec3 dv;
|
|
pe_status_dynamics dyn;
|
|
|
|
m_pEntity->GetPhysics()->GetStatus( &dyn );
|
|
m_btVelocity = dyn.v.len();
|
|
|
|
am.momentum.Set(0,0,0);
|
|
// transform into entity space
|
|
m.SetIdentity();
|
|
angle.x = -DEG2RAD(angle.x);
|
|
angle.y = -DEG2RAD(angle.y);
|
|
angle.z = -DEG2RAD(angle.z);
|
|
m.SetRotationZYX( angle );
|
|
boatUp = m.TransformVectorOLD(boatUp);
|
|
boatFwd = m.TransformVectorOLD(boatFwd);
|
|
dv = vert^boatUp;
|
|
|
|
//go stright
|
|
coef = (1.0f + dv.len2()*5.0f)*m_BoatParams.m_fBtStand*dTime;
|
|
am.momentum.x = -dv.x*coef;
|
|
am.momentum.y = -dv.y*coef;
|
|
|
|
|
|
// do water friction
|
|
// Vec3 waveDump=dyn.w*m_BoatParams.m_fBtDumpW*dTime;
|
|
// am.momentum = Vec3(am.momentum.x - waveDump.x, am.momentum.y - waveDump.y, am.momentum.z - dyn.w.z*m_BoatParams.m_fBtDumpRot*dTime);
|
|
am.momentum = am.momentum - dyn.w*m_BoatParams.m_fBtDumpRot*dTime;
|
|
|
|
//am.momentum.Set(0,0,0);
|
|
|
|
///*
|
|
// here goes speed damping - separate fwd/back and sideways
|
|
// get forvard and side component of velocity
|
|
Vec3 projVel(dyn.v.x, dyn.v.y, 0.0f);
|
|
Vec3 projDir(boatFwd.x, boatFwd.y, 0.0f);
|
|
float projVelLen = projVel.len();
|
|
projVel.normalize();
|
|
projDir.normalize();
|
|
Vec3 projSide(projDir.y, -projDir.x, 0.0f);
|
|
float velCos = projVel.x*projDir.x + projVel.y*projDir.y;
|
|
float fwdVelLen = projVelLen*velCos;
|
|
Vec3 fwdV = projDir*fwdVelLen;
|
|
velCos = projVel.x*projSide.x + projVel.y*projSide.y;
|
|
Vec3 sideV = projSide*projVelLen*velCos;
|
|
am.impulse.x = -(fwdV.x*m_BoatParams.m_fBtDumpV + sideV.x*m_BoatParams.m_fBtDumpVSide)*dTime;
|
|
am.impulse.y = -(fwdV.y*m_BoatParams.m_fBtDumpV + sideV.y*m_BoatParams.m_fBtDumpVSide)*dTime;
|
|
//am.impulse.Set(0,0,0);
|
|
am.impulse.z = -dyn.v.z*m_BoatParams.m_fBtDumpVH*dTime;
|
|
|
|
am.impulse.x += -(fwdV.x*m_BoatParams.m_fBtDumpV + sideV.x*m_BoatParams.m_fBtDumpVSide)*dTime;
|
|
am.impulse.y += -(fwdV.y*m_BoatParams.m_fBtDumpV + sideV.y*m_BoatParams.m_fBtDumpVSide)*dTime;
|
|
|
|
|
|
|
|
//m_pGame->GetSystem()->GetILog()->Log("\003 GLIDER [ %.2f ] >> %.2f ", m_btVelocity, m_pEntity->GetPos().z);
|
|
|
|
//*
|
|
if(fabs(boatFwd.z)<.07) // just go forward
|
|
{
|
|
am.impulse -= boatFwd*dTime*m_BoatParams.m_fBtSpeedV;
|
|
}
|
|
else if(boatFwd.z>0) // going down
|
|
{
|
|
//// am.impulse.z -= boatFwd.z*20.0f;
|
|
boatFwd *= 1.0f+boatFwd.z*6.0f;
|
|
am.impulse -= boatFwd*dTime*m_BoatParams.m_fBtSpeedV;
|
|
|
|
// projDir *= (1.0f+boatFwd.z*2.1f);
|
|
// am.impulse -= projDir*dTime*m_BoatParams.m_fBtSpeedV;
|
|
}
|
|
else // doing up
|
|
{
|
|
|
|
if(projVelLen>m_BoatParams.m_fPgUpSpeedThrhld) // go up if speed is high
|
|
{
|
|
float upscale = projVelLen;
|
|
if( upscale>m_BoatParams.m_fPgUpSpeedThrhld+5 )
|
|
upscale = m_BoatParams.m_fPgUpSpeedThrhld+5;
|
|
am.impulse.z -= boatFwd.z*m_BoatParams.m_fPgBackUpRate*upscale*dTime;
|
|
}
|
|
|
|
/*
|
|
if(m_btVelocity>m_BoatParams.m_fPgUpSpeedThrhld) // go up if speed is high
|
|
{
|
|
float upscale = m_btVelocity;
|
|
if( upscale>m_BoatParams.m_fPgUpSpeedThrhld+5 )
|
|
upscale = m_BoatParams.m_fPgUpSpeedThrhld+5;
|
|
am.impulse.z -= boatFwd.z*m_BoatParams.m_fPgBackUpRate*upscale*dTime;
|
|
}
|
|
// else if(m_btVelocity<7.0f) // too slow - fall
|
|
// am.impulse.z -= 520.0f*dTime;
|
|
//*/
|
|
if(m_btVelocity>5.0f) // slow down
|
|
{
|
|
// projDir *= (boatFwd.z*m_BoatParams.m_fPgBackUpSlowRate);
|
|
// am.impulse += projDir*dTime*m_BoatParams.m_fBtSpeedV;
|
|
am.impulse += boatFwd.z*dyn.v*m_BoatParams.m_fPgBackUpSlowRate*dTime;
|
|
}
|
|
else // keep going
|
|
{
|
|
am.impulse -= projDir*dTime*m_BoatParams.m_fBtSpeedV;
|
|
|
|
Vec3 momentum = (boatFwd)^Vec3(0.0f, 0.0f, m_BoatParams.m_fBtTitlSpd)*10.0f;
|
|
am.momentum = vectorf(momentum*dTime);
|
|
}
|
|
}
|
|
//*/
|
|
|
|
// go down
|
|
am.impulse.z -= m_BoatParams.m_fPgDownRate*dTime;
|
|
|
|
// am.impulse -= projDir*dTime*m_BoatParams.m_fBtSpeedV;
|
|
m_pEntity->GetPhysics()->Action(&am);
|
|
|
|
// do override gravity for the paraglider
|
|
IPhysicalEntity *pEnt=m_pEntity->GetPhysics();
|
|
pe_simulation_params sp;
|
|
sp.gravity.zero();
|
|
// sp.gravity.z = m_pGliderStartGravity->GetFVal();
|
|
// sp.gravityFreefall=vectorf(0,0,m_pGliderGravity->GetFVal());
|
|
sp.gravityFreefall.zero();
|
|
sp.damping=m_pGliderDamping->GetFVal()*4.0f;
|
|
sp.dampingFreefall=m_pGliderDamping->GetFVal();
|
|
m_pEntity->GetPhysics()->SetParams(&sp);
|
|
|
|
//don't use water/float with physics
|
|
pe_params_buoyancy pb;
|
|
pb.waterDensity = 0.0f;
|
|
m_pEntity->GetPhysics()->SetParams(&pb);
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// not-real-physics boat
|
|
void CVehicle::ProcessMovementBoat2(CXEntityProcessingCmd &cmd, float velScale )
|
|
{
|
|
bool bCanBreak = (velScale>=0);
|
|
|
|
if(velScale<0)
|
|
velScale = 1;
|
|
|
|
IPhysicalWorld *pWorld = m_pGame->GetSystem()->GetIPhysicalWorld();
|
|
int iCurTime = pWorld->GetiPhysicsTime();
|
|
float dt = (iCurTime - m_iPrevMoveTime)*pWorld->GetPhysVars()->timeGranularity;
|
|
// m_pGame->GetSystem()->GetITimer()->GetFrameTime();
|
|
m_iPrevMoveTime = iCurTime;
|
|
if( dt>.1f )
|
|
dt = .1f;
|
|
|
|
//return;
|
|
if(!m_pEntity->GetPhysics())
|
|
return;
|
|
IPhysicalEntity *iboat = GetEntity()->GetPhysics();
|
|
|
|
// to prevent undisered input
|
|
if(velScale>1.0f)
|
|
velScale = 1.0f;
|
|
if(velScale<.1f)
|
|
velScale = .1f;
|
|
|
|
bool bCanTurn = (m_btVelocity>m_BoatParams.m_fBtSpeedTurnMin);
|
|
float fMovementImpuls = m_BoatParams.m_fBtSpeedV*velScale;
|
|
//float fTurnImpuls = m_BoatParams.m_fBtTurn*m_btVelocity*.05f;
|
|
float fTurnImpuls = m_BoatParams.m_fBtTurn - m_btVelocity*m_BoatParams.m_fBtTurnSpeedScale;
|
|
|
|
if(fTurnImpuls < m_BoatParams.m_fBtTurnMin)
|
|
fTurnImpuls = m_BoatParams.m_fBtTurnMin;
|
|
|
|
if( (cmd.CheckAction(ACTION_MOVEMODE) || cmd.CheckAction(ACTION_MOVEMODE_TOGGLE)) && bCanBreak )
|
|
{
|
|
fTurnImpuls = m_BoatParams.m_fBtTurn*2;
|
|
bCanTurn = true;
|
|
}
|
|
|
|
//get the engine pos, from where to apply the impulse
|
|
// GetEntity()->GetHelperPosition("engine",m_vEnginePos);
|
|
|
|
Vec3 vWaterFlowSpeed(0,0,0);
|
|
//if (!m_btInWater && (m_Type!=VHT_PARAGLIDER))
|
|
// return;
|
|
|
|
// FIXME
|
|
if (!m_btInWater)
|
|
{
|
|
if (m_Type!=VHT_PARAGLIDER)
|
|
return;
|
|
}
|
|
else
|
|
if (m_Type==VHT_PARAGLIDER)
|
|
return;
|
|
|
|
//define impulse action
|
|
pe_status_pos spos;
|
|
iboat->GetStatus(&spos);
|
|
pe_action_impulse control;
|
|
control.iSource = 3; // this will mark impulse as non-scheduleable in fixed timestep multiplayer
|
|
Vec3 angles = Ang3::GetAnglesXYZ(matrix3x3f(spos.q))*gf_RADTODEG;
|
|
Vec3 turn = Vec3( 0.0f, 1.0f, 0.0f );
|
|
Vec3 momentum;
|
|
Vec3 tdir = angles;
|
|
Vec3 dir;
|
|
pe_status_dynamics dyn;
|
|
|
|
iboat->GetStatus( &dyn );
|
|
// velocity = dyn.v.len();
|
|
//tdir = ConvertToRadAngles(tdir);
|
|
Vec3 refdir(0,-1,0);
|
|
Matrix44 tm;
|
|
tm.SetIdentity();
|
|
//tm.RotateMatrix_fix( angles );
|
|
tm=Matrix44::CreateRotationZYX(-angles*gf_DEGTORAD)*tm; //NOTE: angles in radians and negated
|
|
tdir = GetTransposed44(tm)*(refdir);
|
|
|
|
dir = -tdir;
|
|
if (m_Type!=VHT_PARAGLIDER)
|
|
{
|
|
dir.z = 0;
|
|
dir.Normalize();
|
|
}
|
|
|
|
tdir = dir;
|
|
tdir *= 10.0f;
|
|
|
|
control.momentum = Vec3(0.0f, 0.0f, 0.0f);
|
|
control.impulse = Vec3(0.0f, 0.0f, 0.0f);
|
|
|
|
//*/
|
|
//drive the boat
|
|
//dt = .02f;
|
|
|
|
/*
|
|
if (cmd.CheckAction(ACTION_JUMP))
|
|
{
|
|
pe_action_reset rst;
|
|
iboat->Action(&rst);
|
|
|
|
Vec3 angle = Vec3(30,21,30);
|
|
// Vec3 angle = Vec3(40,31,30);
|
|
m_pEntity->SetAngles(angle);
|
|
}
|
|
*/
|
|
|
|
if (cmd.CheckAction(ACTION_MOVE_FORWARD))
|
|
{
|
|
control.impulse = dir*fMovementImpuls*dt;
|
|
}
|
|
else
|
|
if (cmd.CheckAction(ACTION_MOVE_BACKWARD))
|
|
{
|
|
if(bCanBreak)
|
|
control.impulse = -dir*fMovementImpuls*dt;
|
|
else
|
|
control.impulse = -dir*fMovementImpuls*.3f*dt;
|
|
}
|
|
|
|
if (cmd.CheckAction(ACTION_MOVE_RIGHT) && bCanTurn)
|
|
{
|
|
control.momentum = -Vec3( -dir.x*m_btVelocity*m_BoatParams.m_fBtTitlTurn*dt,
|
|
-dir.y*m_btVelocity*m_BoatParams.m_fBtTitlTurn*dt,
|
|
fTurnImpuls*dt);
|
|
}
|
|
else
|
|
if (cmd.CheckAction(ACTION_MOVE_LEFT) && bCanTurn)
|
|
{
|
|
control.momentum = Vec3( -dir.x*m_btVelocity*m_BoatParams.m_fBtTitlTurn*dt,
|
|
-dir.y*m_btVelocity*m_BoatParams.m_fBtTitlTurn*dt,
|
|
fTurnImpuls*dt);
|
|
}
|
|
if( dyn.v*dir<0.0f ) // moving backward - switch turning direction
|
|
{
|
|
control.momentum.z = -control.momentum.z;
|
|
}
|
|
|
|
if( cmd.CheckAction(ACTION_WALK) && bCanBreak) // do breaking
|
|
{
|
|
control.impulse = -dyn.v*m_BoatParams.m_fBtSpeedV*dt*.082f;
|
|
control.impulse.z = 0;
|
|
}
|
|
if( cmd.CheckAction(ACTION_MOVEMODE2) && bCanBreak) // do backoff
|
|
{
|
|
if(m_btVelocity>.1)
|
|
control.impulse = -dyn.v*m_BoatParams.m_fBtSpeedV*dt*.82f;
|
|
else
|
|
control.impulse = -dir*m_BoatParams.m_fBtSpeedV*dt*5.0f;
|
|
control.impulse.z = 0;
|
|
}
|
|
iboat->Action(&control);
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// not-real-physics boat
|
|
void CVehicle::ProcessMovementParaglider(CXEntityProcessingCmd &cmd )
|
|
{
|
|
|
|
//return;
|
|
|
|
IPhysicalWorld *pWorld = m_pGame->GetSystem()->GetIPhysicalWorld();
|
|
int iCurTime = pWorld->GetiPhysicsTime();
|
|
float dt = (iCurTime - m_iPrevMoveTime)*pWorld->GetPhysVars()->timeGranularity;
|
|
// m_pGame->GetSystem()->GetITimer()->GetFrameTime();
|
|
m_iPrevMoveTime = iCurTime;
|
|
if( dt>.1f )
|
|
dt = .1f;
|
|
if(!m_pEntity->GetPhysics())
|
|
return;
|
|
|
|
float fMovementImpuls = m_BoatParams.m_fBtSpeedV;
|
|
float fTurnImpuls = m_BoatParams.m_fBtTurn;//*m_btVelocity*.05f;
|
|
bool bCanTurn = (m_btVelocity>m_BoatParams.m_fBtSpeedTurnMin);
|
|
|
|
//get the engine pos, from where to apply the impulse
|
|
// GetEntity()->GetHelperPosition("engine",m_vEnginePos);
|
|
|
|
//define impulse action
|
|
pe_action_impulse control;
|
|
Vec3 angles = m_pEntity->GetAngles();
|
|
Vec3 turn = Vec3( 0.0f, 1.0f, 0.0f );
|
|
Vec3 momentum;
|
|
Vec3 tdir = angles;
|
|
Vec3 dir;
|
|
pe_status_dynamics dyn;
|
|
|
|
|
|
m_pEntity->GetPhysics()->GetStatus( &dyn );
|
|
// velocity = dyn.v.len();
|
|
|
|
//tdir = ConvertToRadAngles(tdir);
|
|
|
|
Vec3 refdir(0,-1,0);
|
|
|
|
Matrix44 tm;
|
|
tm.SetIdentity();
|
|
//tm.RotateMatrix_fix( angles );
|
|
tm=Matrix44::CreateRotationZYX(-angles*gf_DEGTORAD)*tm; //NOTE: angles in radians and negated
|
|
tdir = GetTransposed44(tm)*(refdir);
|
|
|
|
dir = -tdir;
|
|
tdir = dir;
|
|
tdir *= 10.0f;
|
|
|
|
control.momentum = Vec3(0.0f, 0.0f, 0.0f);
|
|
control.impulse = Vec3(0.0f, 0.0f, 0.0f);
|
|
|
|
//*/
|
|
//drive the glider
|
|
IPhysicalEntity *iboat = GetEntity()->GetPhysics();
|
|
|
|
if (cmd.CheckAction(ACTION_MOVE_FORWARD))
|
|
{
|
|
// go down when pressing forward
|
|
Vec3 momentum = (-tdir)^Vec3(0.0f, 0.0f, m_BoatParams.m_fBtTitlSpd);
|
|
control.momentum = vectorf(momentum*dt);
|
|
}
|
|
else
|
|
if (cmd.CheckAction(ACTION_MOVE_BACKWARD))
|
|
{
|
|
// can't fly back when using the paraglider, but rather
|
|
// go up
|
|
Vec3 momentum = (tdir)^Vec3(0.0f, 0.0f, m_BoatParams.m_fBtTitlSpd);
|
|
control.momentum = vectorf(momentum*dt);
|
|
}
|
|
|
|
// to prevent rolling over
|
|
bCanTurn = fabs(dyn.w.z)<.4f;
|
|
|
|
if (cmd.CheckAction(ACTION_MOVE_RIGHT) && bCanTurn)
|
|
{
|
|
|
|
control.momentum = -Vec3( -dir.x*m_btVelocity*m_BoatParams.m_fBtTitlTurn*dt,
|
|
-dir.y*m_btVelocity*m_BoatParams.m_fBtTitlTurn*dt,
|
|
fTurnImpuls*dt);
|
|
}
|
|
else
|
|
if (cmd.CheckAction(ACTION_MOVE_LEFT) && bCanTurn)
|
|
{
|
|
control.momentum = Vec3( -dir.x*m_btVelocity*m_BoatParams.m_fBtTitlTurn*dt,
|
|
-dir.y*m_btVelocity*m_BoatParams.m_fBtTitlTurn*dt,
|
|
fTurnImpuls*dt);
|
|
}
|
|
iboat->Action(&control);
|
|
|
|
/*
|
|
if( cmd.CheckAction(ACTION_WALK) ) // push it up - for debuggibg
|
|
{
|
|
m_pEntity->SetPos( m_pEntity->GetPos() + Vec3(0,0,10) );
|
|
}
|
|
*/
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CVehicle::ProcessMovement(CXEntityProcessingCmd &cmd)
|
|
{
|
|
|
|
// if(m_fTimeDelay > 0) // waite for startup delay
|
|
// return;
|
|
m_cmdLastMove = cmd;
|
|
|
|
if (m_Type == VHT_BOAT)
|
|
{
|
|
ProcessMovementBoat2( cmd );
|
|
return;
|
|
}
|
|
if (m_Type == VHT_PARAGLIDER)
|
|
{
|
|
ProcessMovementParaglider( cmd );
|
|
return;
|
|
}
|
|
|
|
|
|
// unsigned long nFlags = cmd.GetActionFlags();
|
|
|
|
//drive the car
|
|
IPhysicalEntity *icar = GetEntity()->GetPhysics();
|
|
if(!icar) // not phisycalized
|
|
{
|
|
m_pGame->GetSystem()->GetILog()->Log("\002 WARNING car is NOT phisycalized [ %s ]", m_pEntity->GetName());
|
|
return;
|
|
}
|
|
|
|
|
|
// brakes off - will switch on if breaking
|
|
m_bBreakLightsOn = false;
|
|
|
|
pe_action_drive drive;
|
|
pe_status_vehicle status;
|
|
float maxsteer;
|
|
|
|
icar->GetStatus(&status);
|
|
|
|
IPhysicalWorld *pWorld = m_pGame->GetSystem()->GetIPhysicalWorld();
|
|
int iCurTime = pWorld->GetiPhysicsTime();
|
|
float dt = (iCurTime - m_iPrevMoveTime)*pWorld->GetPhysVars()->timeGranularity;
|
|
// m_pGame->GetSystem()->GetITimer()->GetFrameTime();
|
|
m_iPrevMoveTime = iCurTime;
|
|
|
|
if (m_bAcceleratedLastUpdate)
|
|
m_bAcceleratedLastUpdate = false;
|
|
|
|
/*
|
|
no boost is used
|
|
if (cmd.CheckAction(ACTION_VEHICLE_BOOST))
|
|
{
|
|
drive.bHandBrake = 0;
|
|
drive.pedal = 1;
|
|
TRACE("BOOST!!!!\n");
|
|
if (!m_bAcceleratedFlagSetLastFrame)
|
|
{
|
|
m_bAcceleratedLastUpdate = true;
|
|
m_bAcceleratedFlagSetLastFrame = true;
|
|
}
|
|
}
|
|
else
|
|
*/
|
|
|
|
m_bIsBreaking = false; //cmd.CheckAction(ACTION_JUMP);
|
|
|
|
if (cmd.CheckAction(ACTION_MOVE_FORWARD))
|
|
{
|
|
if (m_DirVelDotProduct>1.0f)
|
|
{
|
|
m_bIsBreaking = true;
|
|
}
|
|
else
|
|
{
|
|
drive.bHandBrake = 0;
|
|
drive.dpedal = m_fPedalSpeed*dt*min(m_fEngineHealth/50.0f,1.0f); //use damage model here, filippo:begin to use damage model when vehicle have half the health.
|
|
}
|
|
|
|
if (!m_bAcceleratedFlagSetLastFrame)
|
|
{
|
|
m_bAcceleratedLastUpdate = true;
|
|
m_bAcceleratedFlagSetLastFrame = true;
|
|
}
|
|
}
|
|
else if (cmd.CheckAction(ACTION_MOVE_BACKWARD))
|
|
{
|
|
//if we are trying to brake with footbrake use in any case the handbrake
|
|
//TODO? make this a parameter of the vehicle?
|
|
if (m_DirVelDotProduct<-1.0f)
|
|
{
|
|
m_bIsBreaking = true;
|
|
}
|
|
else
|
|
{
|
|
drive.bHandBrake = 0;
|
|
drive.dpedal = -m_fPedalSpeed*dt*min(m_fEngineHealth/50.0f,1.0f); //use damage model here, filippo:begin to use damage model when vehicle have half the health.
|
|
m_bBreakLightsOn = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(drive.pedal!=1){
|
|
|
|
drive.bHandBrake = 0;
|
|
drive.pedal = 0;
|
|
|
|
m_bAcceleratedFlagSetLastFrame = false;
|
|
}
|
|
}
|
|
|
|
if (cmd.CheckAction( ACTION_WALK) || !HasDriver() || cmd.CheckAction(ACTION_JUMP))
|
|
m_bIsBreaking = true;
|
|
|
|
/*if (nFlags & ACTIONFLAG_JUMP)
|
|
{
|
|
m_bIsBreaking = !m_bIsBreaking;
|
|
cmd.RemoveActionFlags(ACTIONFLAG_JUMP);
|
|
}*/
|
|
|
|
|
|
drive.steer = status.steer;
|
|
float vel = status.vel.len();
|
|
maxsteer = m_fv0MaxSteer + m_fkvMaxSteer*vel;
|
|
//maxsteer = 40.0f;
|
|
//if (maxsteer<40) maxsteer=40;
|
|
maxsteer *= (float)(gf_PI)/180.0f;
|
|
float maxpedal = 1.0f;
|
|
if (status.vel.len2()>sqr(m_fPedalLimitSpeed))
|
|
maxpedal -= fabs_tpl(status.steer)/maxsteer*(1.0f-m_fMaxSteeringPedal);
|
|
if (status.pedal>maxpedal)
|
|
drive.pedal = maxpedal;
|
|
else if (status.pedal<-maxpedal)
|
|
drive.pedal = -maxpedal;
|
|
|
|
// rotate the steering wheel (if any)
|
|
int nSlot=m_pEntity->GetSteeringWheelSlot();
|
|
if (nSlot>=0)
|
|
{
|
|
// set the correct position
|
|
// since the steering wheel is at pos. 0,0,0
|
|
Vec3 vCurrAngles;
|
|
m_pEntity->GetObjectAngles(nSlot,vCurrAngles);
|
|
vCurrAngles.y=drive.steer*180;
|
|
|
|
float deltaa = vCurrAngles.y-m_flastwheelrotation;
|
|
|
|
//if the delta is above 180 deg snap it to the correct angles, otherwise could be a crazy rotating wheel in few cases.
|
|
if (fabs(deltaa)<180)
|
|
{
|
|
m_flastwheelrotation += deltaa*min(dt*5.0f,1.0f);//5 degree at sec
|
|
vCurrAngles.y = m_flastwheelrotation;
|
|
}
|
|
else
|
|
m_flastwheelrotation = vCurrAngles.y;
|
|
|
|
Vec3 vRotPointObjSpace;
|
|
m_pEntity->GetHelperPosition("steering_pivot",vRotPointObjSpace,true);
|
|
m_pEntity->SetObjectPos(nSlot,vRotPointObjSpace);
|
|
//m_pEntity->SetObjectAngles(nSlot,vCurrAngles);
|
|
m_pEntity->SetObjectAngles(nSlot,vCurrAngles);
|
|
}
|
|
|
|
/*float curSteerSpeed = m_fSteerSpeed*(1.0f+sqrt_tpl(fabs_tpl(status.steer)/maxsteer)*m_fSteerSpeedVelSCale);// - vel*m_fSteerSpeedVelSCale;
|
|
if(curSteerSpeed<m_fSteerSpeedMin)
|
|
curSteerSpeed = m_fSteerSpeedMin;*/
|
|
|
|
//get the normalized speed delta, between 0-30
|
|
float speeddelta = vel;
|
|
if (speeddelta > 30.0f) speeddelta = 30.0f;
|
|
speeddelta /= 30.0f;
|
|
|
|
//use a steerspeed between min and max velocity values
|
|
float steerdelta = m_fSteerSpeed - m_fSteerSpeedMin;
|
|
float curSteerSpeed = m_fSteerSpeedMin + steerdelta * speeddelta;
|
|
//the same per the steerscale
|
|
float steerscaledelta = m_fsteerspeed_scale - m_fsteerspeed_scale_min;
|
|
float sensitivitybyspeed = m_fsteerspeed_scale_min + steerscaledelta * speeddelta;
|
|
|
|
//GetISystem()->GetILog()->Log("steerSpeed:%f,steer:%f",curSteerSpeed*sensitivitybyspeed,drive.steer);
|
|
|
|
//the second condition because we want steering to go from left to right quickly, so in this case we use steerrelaxation.
|
|
if (cmd.CheckAction(ACTION_MOVE_RIGHT) && drive.steer>-0.1f)
|
|
{
|
|
drive.steer += curSteerSpeed*((float)(gf_PI)/180.0f)*dt*sensitivitybyspeed;
|
|
if (drive.steer > maxsteer)
|
|
drive.steer = maxsteer;
|
|
}
|
|
//the second condition because we want steering to go from left to right quickly, so in this case we use steerrelaxation.
|
|
else if (cmd.CheckAction(ACTION_MOVE_LEFT) && drive.steer<0.1f)
|
|
{
|
|
drive.steer -= curSteerSpeed*((float)(gf_PI)/180.0f)*dt*sensitivitybyspeed;
|
|
if (drive.steer < -maxsteer)
|
|
drive.steer = -maxsteer;
|
|
}
|
|
else //if (/*status.vel.len()*/vel>0.01f && status.steer!=0)
|
|
{
|
|
|
|
/*if (status.steer > 0)
|
|
{
|
|
//drive.steer -= curSteerSpeed*((float)(gf_PI)/180.0f)*dt*.5f;
|
|
//if(drive.steer<0)
|
|
// drive.steer = 0;
|
|
drive.dsteer = -dt*(m_fv0SteerRelaxation+m_fkvSteerRelaxation*vel)*((float)(gf_PI)/180.0f);
|
|
}
|
|
else
|
|
{
|
|
//drive.steer += curSteerSpeed*((float)(gf_PI)/180.0f)*dt*.5f;
|
|
//if(drive.steer>0)
|
|
// drive.steer = 0;
|
|
drive.dsteer = dt*(m_fv0SteerRelaxation+m_fkvSteerRelaxation*vel)*((float)(gf_PI)/180.0f);
|
|
}
|
|
|
|
if (status.steer*drive.dsteer<0 && fabs_tpl(status.steer)<fabs_tpl(drive.dsteer))
|
|
drive.steer = drive.dsteer = 0;*/
|
|
|
|
//get the delta necessary to put the steer in the center position, and change the steer in smooth way.
|
|
float deltaa = 0-drive.steer;
|
|
drive.steer += deltaa*min(dt*m_fv0SteerRelaxation*gf_PI/180.0f,1.0f);
|
|
}
|
|
|
|
pe_params_car pc;
|
|
pc.axleFriction = m_fAxleFriction;
|
|
icar->SetParams(&pc);
|
|
|
|
|
|
if (m_bIsBreaking)
|
|
{
|
|
drive.bHandBrake = 1; // handbrake brake always
|
|
m_bBreakLightsOn = true;
|
|
/*
|
|
if (vel<m_fBrakeVelThreshold)
|
|
drive.bHandBrake = 1;
|
|
else
|
|
{
|
|
pc.axleFriction = m_fBrakeAxleFriction;
|
|
icar->SetParams(&pc);
|
|
}
|
|
*/
|
|
}
|
|
|
|
//drive.bHandBrake = 1;
|
|
|
|
|
|
//GetGame()->GetSystem()->GetILog()->Log("\001 %.3f", drive.dpedal);
|
|
|
|
icar->Action(&drive);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CVehicle::GetWheelStatus(int nWheel, pe_status_wheel *pStatus)
|
|
{
|
|
if (!pStatus)
|
|
return;
|
|
IPhysicalEntity *icar = GetEntity()->GetPhysics();
|
|
if (!icar)
|
|
return;
|
|
pStatus->iWheel=nWheel;
|
|
icar->GetStatus(pStatus);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CVehicle::SetDrivingParams(float pedalspeed,float steerspeed,float v0maxsteer,float kvmaxsteer,float v0steerrelax,float kvsteerrelax,
|
|
float brake_vel_threshold,float brake_axle_friction,
|
|
float steerspeedVelScale, float steerspeedMin,
|
|
float maxSteeringPedal, float pedalLimitSpeed,
|
|
float fhandbrakingvalue,float fmaxbrakingfrictionnodriver,
|
|
float fhandbrakingvaluenodriver,float fstabilizejump,
|
|
float fsteerspeedscale, float fsteerspeedscalemin)
|
|
{
|
|
m_fPedalSpeed = pedalspeed; m_fSteerSpeed = steerspeed; m_fv0MaxSteer = v0maxsteer; m_fkvMaxSteer = kvmaxsteer;
|
|
m_fv0SteerRelaxation = v0steerrelax; m_fkvSteerRelaxation = kvsteerrelax;
|
|
m_fBrakeVelThreshold = brake_vel_threshold; m_fBrakeAxleFriction = brake_axle_friction;
|
|
m_fSteerSpeedVelSCale = steerspeedVelScale;
|
|
m_fSteerSpeedMin = steerspeedMin;
|
|
m_fMaxSteeringPedal = maxSteeringPedal;
|
|
m_fPedalLimitSpeed = pedalLimitSpeed;
|
|
m_fhandbraking_value = fhandbrakingvalue;
|
|
m_fhandbraking_value_nodriver = fhandbrakingvaluenodriver;
|
|
m_fstabilizejump = fstabilizejump;
|
|
m_fMaxBrakingFrictionNoDriver = 1.0;
|
|
m_fsteerspeed_scale = fsteerspeedscale;
|
|
m_fsteerspeed_scale_min = fsteerspeedscalemin;
|
|
|
|
IPhysicalEntity *icar = NULL;
|
|
|
|
if (GetEntity())
|
|
icar = GetEntity()->GetPhysics();
|
|
|
|
if (icar)
|
|
{
|
|
pe_params_car pc;
|
|
icar->GetParams(&pc);
|
|
m_fAxleFriction = pc.axleFriction;
|
|
|
|
//
|
|
m_fMaxBrakingFriction = pc.maxBrakingFriction;
|
|
|
|
if (fmaxbrakingfrictionnodriver<=0)// if there is no fmaxbrakingfrictionnodriver specified use the same friction in any case
|
|
m_fMaxBrakingFrictionNoDriver = m_fMaxBrakingFriction;
|
|
else
|
|
m_fMaxBrakingFrictionNoDriver = fmaxbrakingfrictionnodriver;
|
|
|
|
//and at first time set the car to nodriver friction.
|
|
pc.maxBrakingFriction = m_fMaxBrakingFrictionNoDriver;
|
|
//GetISystem()->GetILog()->Log("%s change friction to %f (first time)",m_pEntity->GetName(),pc.maxBrakingFriction);
|
|
icar->SetParams(&pc);
|
|
|
|
m_bUsingNoDriverFriction = true;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CVehicle::QueryContainerInterface(ContainerInterfaceType desired_interface, void **ppInterface )
|
|
{
|
|
if (desired_interface == CIT_IVEHICLE)
|
|
{
|
|
*ppInterface = (void *) this;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
*ppInterface = 0;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CVehicle::Write(CStream& stm,EntityCloneState *cs)
|
|
{
|
|
if(m_pEntity->IsHidden())
|
|
return true;
|
|
|
|
if (!cs || cs->m_bOffSync)
|
|
{
|
|
unsigned char ucHealth = (int)(m_fEngineHealth*2+0.5f);
|
|
stm.Write(ucHealth);
|
|
if (m_pGame->UseFixedStep() && (m_Type == VHT_BOAT))
|
|
{
|
|
stm.Write(true);
|
|
stm.Write(m_fPrevFwvTilt);
|
|
stm.Write(m_fPrevFwvSpeedLen);
|
|
stm.Write(m_fSimTime);
|
|
}
|
|
else
|
|
stm.Write(false);
|
|
|
|
if (cs && !cs->m_bLocalplayer)
|
|
{
|
|
stm.Write(true);
|
|
stm.Write(m_cmdLastMove.CheckAction(ACTION_MOVE_FORWARD));
|
|
stm.Write(m_cmdLastMove.CheckAction(ACTION_MOVE_BACKWARD));
|
|
stm.Write(m_cmdLastMove.CheckAction(ACTION_MOVE_LEFT));
|
|
stm.Write(m_cmdLastMove.CheckAction(ACTION_MOVE_RIGHT));
|
|
stm.Write(m_cmdLastMove.CheckAction(ACTION_WALK));
|
|
stm.Write(m_cmdLastMove.CheckAction(ACTION_JUMP));
|
|
}
|
|
else
|
|
stm.Write(false);
|
|
}
|
|
|
|
IScriptSystem *pScScriptSystem=m_pGame->GetScriptSystem();
|
|
//CScriptObjectStream stmObj;
|
|
//stmObj.Create(pScScriptSystem,&stm);
|
|
m_ScriptStream.Attach(&stm);
|
|
pScScriptSystem->BeginCall(GetEntity()->GetEntityClassName(),"OnWrite");
|
|
pScScriptSystem->PushFuncParam(GetEntity()->GetScriptObject());
|
|
pScScriptSystem->PushFuncParam(m_ScriptStream.GetScriptObject());
|
|
pScScriptSystem->EndCall();
|
|
|
|
stm.Write(m_bHeadLightsOn);
|
|
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CVehicle::Read(CStream& stm)
|
|
{
|
|
|
|
if(m_pEntity->IsHidden())
|
|
return true;
|
|
|
|
IPhysicalEntity *icar = GetEntity()->GetPhysics();
|
|
pe_params_flags pf;
|
|
icar->GetParams(&pf);
|
|
if (!(pf.flags & pef_checksum_received))
|
|
{
|
|
unsigned char ucHealth;
|
|
stm.Read(ucHealth);
|
|
m_fEngineHealth = ucHealth*0.5f;
|
|
bool bnz; stm.Read(bnz);
|
|
if (bnz)
|
|
{
|
|
stm.Read(m_fPrevFwvTilt);
|
|
stm.Read(m_fPrevFwvSpeedLen);
|
|
stm.Read(m_fSimTime);
|
|
}
|
|
if ((m_Type == VHT_BOAT))
|
|
{
|
|
pe_status_dynamics sd;
|
|
m_pEntity->GetPhysics()->GetStatus( &sd );
|
|
m_btVelocity = sd.v.len();
|
|
}
|
|
|
|
stm.Read(bnz);
|
|
if (bnz)
|
|
{
|
|
m_cmdLastMove.Reset();
|
|
stm.Read(bnz); if (bnz)
|
|
m_cmdLastMove.AddAction(ACTION_MOVE_FORWARD);
|
|
stm.Read(bnz); if (bnz)
|
|
m_cmdLastMove.AddAction(ACTION_MOVE_BACKWARD);
|
|
stm.Read(bnz); if (bnz)
|
|
m_cmdLastMove.AddAction(ACTION_MOVE_LEFT);
|
|
stm.Read(bnz); if (bnz)
|
|
m_cmdLastMove.AddAction(ACTION_MOVE_RIGHT);
|
|
stm.Read(bnz); if (bnz)
|
|
m_cmdLastMove.AddAction(ACTION_WALK);
|
|
stm.Read(bnz); if (bnz)
|
|
m_cmdLastMove.AddAction(ACTION_JUMP);
|
|
}
|
|
|
|
UpdateCamera(0,true);
|
|
}
|
|
|
|
IScriptSystem *pScScriptSystem=m_pGame->GetScriptSystem();
|
|
/*CScriptObjectStream stmObj;
|
|
stmObj.Create(pScScriptSystem,&stm);*/
|
|
m_ScriptStream.Attach(&stm);
|
|
pScScriptSystem->BeginCall(GetEntity()->GetEntityClassName(),"OnRead");
|
|
pScScriptSystem->PushFuncParam(GetEntity()->GetScriptObject());
|
|
pScScriptSystem->PushFuncParam(m_ScriptStream.GetScriptObject());
|
|
pScScriptSystem->EndCall();
|
|
|
|
if(icar && m_pGame && !m_pGame->IsMultiplayer()) // not phisycalized
|
|
{ // [Anton] - don't put vehicles on brake during network synchronization!
|
|
|
|
if ((m_Type == VHT_BOAT) || m_Type == VHT_PARAGLIDER)
|
|
{
|
|
pe_action_set_velocity control;
|
|
// pe_action_impulse control;
|
|
icar->Action(&control);
|
|
}
|
|
else
|
|
{
|
|
pe_action_drive drive;
|
|
drive.pedal = 0;
|
|
drive.bHandBrake = 1;
|
|
icar->Action(&drive);
|
|
}
|
|
}
|
|
|
|
stm.Read( m_bHeadLightsOn );
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void CVehicle::SetEngineHealth(float fEngineHealth, bool bScheduled)
|
|
{
|
|
if (m_pGame->IsMultiplayer() && m_pGame->UseFixedStep() && !bScheduled)
|
|
{
|
|
if (m_pGame->IsServer())
|
|
m_pGame->ScheduleEvent(-1, m_pEntity,fEngineHealth);
|
|
return;
|
|
}
|
|
m_fEngineHealth = fEngineHealth;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//void CVehicle::SetWaterVehicleParameters(float fBSpeed,float fBTurn)
|
|
void CVehicle::SetWaterVehicleParameters( WATER_VEHICLE_PARAMS &wvpar, bool bFlyingVehicle)
|
|
{
|
|
m_BoatParams = wvpar;
|
|
|
|
if (bFlyingVehicle)
|
|
m_Type = VHT_PARAGLIDER;
|
|
else
|
|
m_Type = VHT_BOAT;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CVehicle::HasDriver()
|
|
{
|
|
return (m_DriverID!=0);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CVehicle::WakeupPhys( )
|
|
{
|
|
// if (!m_bPhysAwaike && GetEntity()->GetPhysics())
|
|
// wake up always when visible or used - otherwise some wierd stuff happens - boats don't move
|
|
if (GetEntity()->GetPhysics())
|
|
{
|
|
pe_action_awake aa;
|
|
aa.bAwake = 1;
|
|
GetEntity()->GetPhysics()->Action(&aa);
|
|
m_bPhysAwaike = true;
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CVehicle::AddUser(int entId)
|
|
{
|
|
WakeupPhys( );
|
|
m_UsersList.push_back(entId);
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CVehicle::RemoveUser( int entId )
|
|
{
|
|
UsersList::iterator itr = std::find(m_UsersList.begin(), m_UsersList.end(), entId );
|
|
if( itr != m_UsersList.end() )
|
|
m_UsersList.erase( itr );
|
|
}
|
|
|
|
void CVehicle::PreloadInstanceResources(Vec3d vPrevPortalPos, float fPrevPortalDistance, float fTime)
|
|
{
|
|
#pragma message( "Warning: Preloading of render resources is not implemented in " __FUNCTION__ )
|
|
// for all objects what will be used for rendering call
|
|
// ICryCharInstance::PreloadResources or
|
|
// IStatObj::PreloadResources
|
|
// Ask Vlad for details
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------------------------
|
|
void CVehicle::InitHeadLight( const char* sImg, const char* sShader )
|
|
{
|
|
SAFE_DELETE( m_pHeadLight );
|
|
//ReleaseLight( m_pHeadLight );
|
|
//m_pHeadLight = 0;
|
|
|
|
if(sImg && sImg[0]) // no texture - no light!!!
|
|
{
|
|
m_pHeadLight = new CDLight();
|
|
m_pHeadLight->m_fAnimSpeed = 0;
|
|
int nFlags2 = FT2_FORCECUBEMAP;
|
|
// if (bUseAsCube)
|
|
// nFlags2 |= FT2_REPLICATETOALLSIDES;
|
|
// if (fAnimSpeed)
|
|
// nFlags2 |= FT2_CHECKFORALLSEQUENCES;
|
|
m_pHeadLight->m_pLightImage = m_pGame->GetSystem()->GetIRenderer()->EF_LoadTexture(sImg, 0, nFlags2, eTT_Cubemap);
|
|
m_pHeadLight->m_Flags = DLF_PROJECT | DLF_IGNORE_OWNER;
|
|
|
|
if(sShader && sShader[0])
|
|
m_pHeadLight->m_pShader = m_pGame->GetSystem()->GetIRenderer()->EF_LoadShader((char*)sShader, eSH_World);
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------------------------
|
|
void CVehicle::InitFakeLight( CDLight** pLight, const char* sShader )
|
|
{
|
|
if (*pLight)
|
|
delete *pLight;
|
|
|
|
if(sShader && sShader[0]) // no shader - no light!!!
|
|
{
|
|
*pLight = new CDLight();
|
|
(*pLight)->m_Flags = DLF_POINT|DLF_FAKE | DLF_IGNORE_OWNER;
|
|
(*pLight)->m_pShader = m_pGame->GetSystem()->GetIRenderer()->EF_LoadShader((char*)sShader, eSH_World);
|
|
}
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------------------------
|
|
void CVehicle::UpdateLights( )
|
|
{
|
|
if(m_fEngineHealth<1) // no lights when destroyed
|
|
return;
|
|
|
|
// float totalLightScale = 1.0f - m_pGame->GetSystem( )->GetI3DEngine()->GetAmbientLightAmountForEntity(m_pEntity)*2.0f;
|
|
|
|
if(m_bAutoLights && m_bAIDriver)
|
|
{
|
|
if(!HasDriver() )
|
|
return;
|
|
// float totalLightScale = m_pGame->GetSystem( )->GetI3DEngine()->GetAmbientLightAmountForEntity(m_pEntity);
|
|
// if( totalLightScale>.6f )
|
|
// return;
|
|
m_bHeadLightsOn = true;
|
|
}
|
|
//
|
|
// adding the light
|
|
// if(0)
|
|
if(m_bHeadLightsOn)
|
|
{
|
|
if(m_pHeadLight)
|
|
{
|
|
m_pHeadLight->m_fLightFrustumAngle = 45;
|
|
m_pHeadLight->m_fRadius = 50;
|
|
|
|
m_pEntity->GetHelperPosition(m_HeadLightHelper.c_str(), m_pHeadLight->m_Origin );
|
|
m_pHeadLight->m_ProjAngles = Vec3d(m_pEntity->GetAngles().y,m_pEntity->GetAngles().x,m_pEntity->GetAngles().z+90);
|
|
|
|
// m_pHeadLight->m_Color = CFColor(totalLightScale,totalLightScale,totalLightScale, 1.0f);
|
|
// m_pHeadLight->m_SpecColor = CFColor(totalLightScale,totalLightScale,totalLightScale);
|
|
|
|
m_pHeadLight->m_Color = CFColor(1.f,1.f,1.f, 1.0f);
|
|
m_pHeadLight->m_SpecColor = CFColor(1.f,1.f,1.f);
|
|
|
|
//m_pHeadLight->m_pShader = NULL;
|
|
|
|
m_pHeadLight->m_Flags = DLF_PROJECT | DLF_LIGHTSOURCE | DLF_IGNORE_OWNER;
|
|
m_pGame->GetSystem()->GetI3DEngine()->AddDynamicLightSource(*m_pHeadLight, GetEntity());
|
|
}
|
|
|
|
// flares
|
|
UpdateFakeLight(m_pHeadLightLeft, m_HeadLightHelperLeft.c_str());
|
|
UpdateFakeLight(m_pHeadLightRight, m_HeadLightHelperRight.c_str());
|
|
}
|
|
|
|
if( !HasDriver() )
|
|
return;
|
|
//
|
|
// adding flares on backlights if breaking
|
|
if(m_bBreakLightsOn)
|
|
{
|
|
UpdateFakeLight(m_pBreakLightLeft, m_BackLightHelperLeft.c_str());
|
|
UpdateFakeLight(m_pBreakLightRight, m_BackLightHelperRight.c_str());
|
|
}
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------------------------
|
|
void CVehicle::UpdateFakeLight( CDLight* light, const char* sHelper )
|
|
{
|
|
|
|
if( light == NULL ) return;
|
|
light->m_fLightFrustumAngle = 30;
|
|
light->m_fRadius = 5;
|
|
|
|
m_pEntity->GetHelperPosition(sHelper, light->m_Origin);
|
|
light->m_ProjAngles = Vec3d(m_pEntity->GetAngles().y,m_pEntity->GetAngles().x,m_pEntity->GetAngles().z+90);
|
|
|
|
// m_pHeadLight->m_Color = CFColor(totalLightScale,totalLightScale,totalLightScale, 1.0f);
|
|
// m_pHeadLight->m_SpecColor = CFColor(totalLightScale,totalLightScale,totalLightScale);
|
|
|
|
light->m_Color = CFColor(1.f,1.f,1.f, 1.0f);
|
|
light->m_SpecColor = CFColor(1.f,1.f,1.f);
|
|
|
|
light->m_Flags = DLF_FAKE | DLF_LIGHTSOURCE | DLF_PROJECT | DLF_IGNORE_OWNER;
|
|
|
|
// m_pHeadLight->m_Flags = DLF_PROJECT | DLF_LIGHTSOURCE;
|
|
m_pGame->GetSystem()->GetI3DEngine()->AddDynamicLightSource(*light, GetEntity(), light->m_nEntityLightId);
|
|
|
|
|
|
}
|
|
|
|
|
|
//
|
|
//--------------------------------------------------------------------------------------
|
|
void CVehicle::SwitchLights( int light )
|
|
{
|
|
if(light == 1)
|
|
m_bHeadLightsOn = true;
|
|
else if(light == 0)
|
|
m_bHeadLightsOn = false;
|
|
else
|
|
m_bHeadLightsOn = !m_bHeadLightsOn;
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------------------------
|
|
|
|
float CVehicle::GetLightRadius()
|
|
{
|
|
if(m_pHeadLight && m_bHeadLightsOn)
|
|
return m_pHeadLight->m_fRadius;
|
|
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------------------------
|
|
void CVehicle::GetFirePosAngles(Vec3d& firePos, Vec3d& fireAngles)
|
|
{
|
|
// if(m_sWeaponName.empty())
|
|
// return;
|
|
|
|
// firePos = GetEntity()->GetPos()+Vec3(0,0,3.5);
|
|
// GetEntity()->GetHelperPosition("turret",firePos);
|
|
|
|
firePos = m_vWpnPos;
|
|
fireAngles = m_vWpnAng;
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
//--------------------------------------------------------------------------------------
|
|
const string& CVehicle::GetWeaponName( CPlayer::eInVehiclestate state )
|
|
{
|
|
switch(state)
|
|
{
|
|
case CPlayer::PVS_DRIVER:
|
|
return m_sAutoWeaponName;
|
|
case CPlayer::PVS_GUNNER:
|
|
return m_sMountedWeaponName;
|
|
}
|
|
return m_sNoWeaponName;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
//--------------------------------------------------------------------------------------
|
|
|
|
void CVehicle::SetCameraParams(Vec3 vCamStiffness[2],Vec3 vCamLimits[2],float fCamDamping,float fMaxCamTimestep,
|
|
float fCamSnapDist,float fCamSnapVel)
|
|
{
|
|
m_vCamStiffness[0] = vCamStiffness[0];
|
|
m_vCamStiffness[1] = vCamStiffness[1];
|
|
m_vCamLimits[0] = vCamLimits[0];
|
|
m_vCamLimits[1] = vCamLimits[1];
|
|
m_fCamDamping = fCamDamping;
|
|
m_fMaxCamTimestep = fMaxCamTimestep;
|
|
m_fCamSnapDist = fCamSnapDist;
|
|
m_fCamSnapVel = fCamSnapVel;
|
|
}
|
|
|
|
|
|
void CVehicle::ResetCamera(bool bUpdateCamera,const char *pHelperName)
|
|
{
|
|
if (bUpdateCamera && GetEntity()->GetPhysics())
|
|
{
|
|
pe_status_pos sp;
|
|
pe_status_dynamics sd;
|
|
GetEntity()->GetPhysics()->GetStatus(&sp);
|
|
GetEntity()->GetPhysics()->GetStatus(&sd);
|
|
GetEntity()->GetHelperPosition(pHelperName,m_vCamHelperPos,true);
|
|
m_vPrevCamTarget = m_vCamPos = sp.pos + sp.q*m_vCamHelperPos;
|
|
m_vCamVel = sd.v + (sd.w^m_vCamPos-sd.centerOfMass);
|
|
m_bUpdateCamera = true;
|
|
}
|
|
else
|
|
m_bUpdateCamera = false;
|
|
}
|
|
|
|
|
|
void CVehicle::UpdateCamera(float fTimeStep, bool bSynchronizing)
|
|
{
|
|
if (m_bUpdateCamera)
|
|
{
|
|
pe_status_pos sp;
|
|
GetEntity()->GetPhysics()->GetStatus(&sp);
|
|
Vec3 posTarget,posTargetNew,posDelta,posDeltaLoc,posDeltaLocNorm,velTarget;
|
|
Matrix33 R = Matrix33(sp.q);
|
|
posTargetNew = sp.pos + R*m_vCamHelperPos;
|
|
|
|
if (!bSynchronizing)
|
|
{
|
|
if (fTimeStep==0 || (velTarget = (posTargetNew-m_vPrevCamTarget)/fTimeStep).len2()>sqr(200) ||
|
|
m_vCamStiffness[0].len2()+m_vCamStiffness[1].len2()==0)
|
|
{
|
|
m_vCamPos = posTargetNew;
|
|
pe_status_dynamics sd;
|
|
GetEntity()->GetPhysics()->GetStatus(&sd);
|
|
m_vCamVel = sd.v + (sd.w^m_vCamPos-sd.centerOfMass);
|
|
}
|
|
else
|
|
{
|
|
float ks,fStep;
|
|
int i,j;
|
|
|
|
posTarget = m_vPrevCamTarget;
|
|
do
|
|
{
|
|
fStep = min(fTimeStep,m_fMaxCamTimestep);
|
|
posTarget += velTarget*fStep;
|
|
m_vCamPos += m_vCamVel*fStep;
|
|
|
|
if ((posDelta = m_vCamPos-posTarget).len2()>sqr(m_fCamSnapDist))
|
|
{
|
|
posDeltaLocNorm = (posDeltaLoc=posDelta*R).GetNormalized();
|
|
for(i=0,ks=0; i<3; i++)
|
|
{
|
|
j = isneg(posDeltaLoc[i])^1;
|
|
if (m_vCamStiffness[j][i]==0)
|
|
m_vCamPos -= R.GetColumn(i)*posDeltaLoc[i];
|
|
else if (fabs_tpl(posDeltaLoc[i])>m_vCamLimits[j][i])
|
|
m_vCamPos -= R.GetColumn(i)*(posDeltaLoc[i]+m_vCamLimits[j][i]*(j*2-1));
|
|
ks += sqr(posDeltaLocNorm[i])*m_vCamStiffness[j][i];
|
|
}
|
|
//m_vCamVel -= posDelta*((ks + 2.0f*sqrt_tpl(ks)*m_fCamDamping*((posDelta*(m_vCamVel-velTarget))/posDelta.len2()))*fStep);
|
|
m_vCamVel -= posDelta*(ks*fStep);
|
|
m_vCamVel += (velTarget-m_vCamVel)*(m_fCamDamping*fStep);
|
|
}
|
|
else if ((m_vCamVel-velTarget).len2()<sqr(m_fCamSnapVel))
|
|
{
|
|
m_vCamPos = posTarget;
|
|
m_vCamVel = velTarget;
|
|
}
|
|
} while ((fTimeStep-=fStep)>0.0001f);
|
|
}
|
|
m_vPrevCamTarget = posTargetNew;
|
|
}
|
|
else
|
|
{
|
|
m_vCamPos += (posTargetNew-m_vPrevCamTarget);
|
|
m_vPrevCamTarget = posTargetNew;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------------------------
|
|
void CVehicle::WeaponState(int userId, bool shooting, int fireMode)
|
|
{
|
|
CPlayer* theShooter = GetUserInState( CPlayer::PVS_PASSENGER);
|
|
|
|
// it's a passenger - has it's own weapon, don't affect vehicle's weapon
|
|
if( theShooter )
|
|
return;
|
|
|
|
if(shooting)
|
|
{
|
|
// use appropriate fire animation, depending on fire mode (MG/rockets)
|
|
if(fireMode == 0)
|
|
m_pEntity->StartAnimation(0, "default" );
|
|
}
|
|
else
|
|
{
|
|
theShooter = GetUserInState( CPlayer::PVS_GUNNER );
|
|
if(theShooter)
|
|
if(theShooter->GetEntity()->GetId()!=userId)
|
|
// there is still gunner in - don't stop ani
|
|
return;
|
|
ICryCharInstance *pCharacter = m_pEntity->GetCharInterface()->GetCharacter(0);
|
|
if(pCharacter)
|
|
pCharacter->StopAnimation(0);
|
|
}
|
|
}
|
|
|
|
//[filippo]
|
|
void CVehicle::AdditionalPhysics(IPhysicalEntity *pcar,float fdelta,bool bforcebreaking)
|
|
{
|
|
if (pcar==NULL || m_fEngineHealth<=0)
|
|
return;
|
|
|
|
pe_status_vehicle vstatus;
|
|
pe_status_dynamics dstatus;
|
|
|
|
pcar->GetStatus(&vstatus);
|
|
pcar->GetStatus(&dstatus);
|
|
|
|
float fvelmod = dstatus.v.len();
|
|
|
|
if (vstatus.bWheelContact>1)
|
|
{
|
|
float handbrake;
|
|
pe_action_set_velocity action;
|
|
|
|
if (m_bUsingNoDriverFriction)
|
|
handbrake = m_fhandbraking_value_nodriver;
|
|
else
|
|
handbrake = m_fhandbraking_value;
|
|
|
|
if ((m_bIsBreaking||bforcebreaking||vstatus.bHandBrake) && fvelmod>0 && handbrake>0
|
|
&& vstatus.nActiveColliders==0) // [Anton] don't force unaccounted for excessive damping when contacting with other
|
|
// objects, for ex. platform in the boat puzzle
|
|
{
|
|
//GetISystem()->GetILog()->Log("braking");
|
|
|
|
action.v[0] = dstatus.v[0];
|
|
action.v[1] = dstatus.v[1];
|
|
action.v[2] = dstatus.v[2];
|
|
|
|
float fnewvel = fvelmod - handbrake*fdelta;
|
|
|
|
if (fnewvel<=0)
|
|
fnewvel = 0;
|
|
|
|
action.v = action.v / fvelmod * fnewvel;
|
|
|
|
pcar->Action(&action);
|
|
}
|
|
|
|
/*action.w[0] = dstatus.w[0]*0.01f;
|
|
action.w[1] = dstatus.w[1]*0.01f;
|
|
action.w[2] = dstatus.w[2];
|
|
|
|
pcar->Action(&action);*/
|
|
}
|
|
else if (m_fstabilizejump>0)//flying? try to stabilize the rolling
|
|
//if (m_fstabilizejump>0)//flying? try to stabilize the rolling
|
|
{
|
|
Matrix44 tm;
|
|
tm.SetIdentity();
|
|
tm = Matrix44::CreateRotationZYX(-m_pEntity->GetAngles()*gf_DEGTORAD)*tm; //NOTE: angles in radians and negated
|
|
|
|
Vec3 vUpDir = GetTransposed44(tm)*Vec3d(0,0,1);
|
|
Vec3 vFwdDir = GetTransposed44(tm)*Vec3d(0,-1,0);
|
|
|
|
//GetISystem()->GetILog()->Log("a:%.1f,%.1f,%.1f",m_pEntity->GetAngles().x,m_pEntity->GetAngles().y,m_pEntity->GetAngles().z);
|
|
|
|
if (vUpDir.z > 0.5f)
|
|
{
|
|
Vec3 vStabilizedangles = m_pEntity->GetAngles();
|
|
vStabilizedangles.y = 0;
|
|
|
|
tm.SetIdentity();
|
|
tm = Matrix44::CreateRotationZYX(-vStabilizedangles*gf_DEGTORAD)*tm; //NOTE: angles in radians and negated
|
|
Vec3 vert = GetTransposed44(tm)*Vec3d(0,0,1);
|
|
|
|
pe_action_impulse am;
|
|
|
|
//Vec3 vert(vFwdDir.x,vFwdDir.y,1.0f);
|
|
|
|
float coef = m_fstabilizejump*fdelta;
|
|
|
|
/*if (vstatus.bWheelContact>1)
|
|
{
|
|
coef *= 2.0f;
|
|
}*/
|
|
|
|
//vert.Normalize();
|
|
|
|
Vec3 dv = vert^vUpDir;
|
|
|
|
coef *= 1.0f + dv.len2();
|
|
|
|
am.momentum.x = -(dv.x+dstatus.w.x)*coef;
|
|
am.momentum.y = -(dv.y+dstatus.w.y)*coef;
|
|
am.momentum.z = 0;
|
|
|
|
//GetISystem()->GetILog()->Log("momentum: %.1f %.1f %.1f", am.momentum.x, am.momentum.y, am.momentum.z);
|
|
|
|
pcar->Action(&am);
|
|
}
|
|
|
|
//GetISystem()->GetILog()->Log("w:%.1f,%.1f,%.1f , fwd:%.1f,%.1f,%.1f",dstatus.w.x,dstatus.w.y,dstatus.w.z,vFwdDir.x,vFwdDir.y,vFwdDir.z);
|
|
}
|
|
}
|
|
|
|
|
|
void CVehicle::SaveAIState(CStream & stm, CScriptObjectStream & scriptStream)
|
|
{
|
|
|
|
IAIObject *pObject = m_pEntity->GetAI();
|
|
if (pObject)
|
|
pObject->Save(stm);
|
|
|
|
IScriptSystem *pScriptSystem = m_pGame->GetSystem()->GetIScriptSystem();
|
|
HSCRIPTFUNCTION saveOverallFunction=NULL;
|
|
if( m_pEntity->GetScriptObject() && m_pEntity->GetScriptObject()->GetValue("OnSaveOverall", saveOverallFunction) )
|
|
{
|
|
pScriptSystem->BeginCall(saveOverallFunction);
|
|
pScriptSystem->PushFuncParam(m_pEntity->GetScriptObject());
|
|
pScriptSystem->PushFuncParam(scriptStream.GetScriptObject());
|
|
pScriptSystem->EndCall();
|
|
}
|
|
|
|
}
|
|
|
|
void CVehicle::LoadAIState(CStream & stm, CScriptObjectStream & scriptStream)
|
|
{
|
|
|
|
IAIObject *pObject = m_pEntity->GetAI();
|
|
if (pObject)
|
|
pObject->Load(stm);
|
|
|
|
IScriptSystem *pScriptSystem = m_pGame->GetSystem()->GetIScriptSystem();
|
|
HSCRIPTFUNCTION saveOverallFunction=NULL;
|
|
if( m_pEntity->GetScriptObject() && m_pEntity->GetScriptObject()->GetValue("OnLoadOverall", saveOverallFunction) )
|
|
{
|
|
pScriptSystem->BeginCall(saveOverallFunction);
|
|
pScriptSystem->PushFuncParam(m_pEntity->GetScriptObject());
|
|
pScriptSystem->PushFuncParam(scriptStream.GetScriptObject());
|
|
pScriptSystem->EndCall();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CVehicle::OnEntityNetworkUpdate( const EntityId &idViewerEntity, const Vec3d &v3dViewer, uint32 &inoutPriority,
|
|
EntityCloneState &inoutCloneState) const
|
|
{
|
|
IEntity *pLocPlayerEnt = GetISystem()->GetIEntitySystem()->GetEntity(idViewerEntity);
|
|
|
|
if(pLocPlayerEnt) // if there is a local player
|
|
{
|
|
IEntityContainer *pCnt = pLocPlayerEnt->GetContainer();
|
|
|
|
if(pCnt)
|
|
{
|
|
CPlayer *pLocPlayer;
|
|
|
|
// if this vehicle has the player as passanger
|
|
if(pCnt->QueryContainerInterface(CIT_IPLAYER,(void **)&pLocPlayer)) // and it's a player
|
|
{
|
|
CVehicle *pVehiclepLocPlayer = pLocPlayer->GetVehicle();
|
|
|
|
if(pVehiclepLocPlayer && pVehiclepLocPlayer->GetEntity()->GetId()==m_pEntity->GetId()) // that is inside this vehicle
|
|
inoutPriority += 350000; // boost the vehicle the player rides in
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|