summaryrefslogtreecommitdiffstats
path: root/src/vehicles/Automobile.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/vehicles/Automobile.cpp')
-rw-r--r--src/vehicles/Automobile.cpp2320
1 files changed, 1692 insertions, 628 deletions
diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp
index d2fedbd5..b0dc98ad 100644
--- a/src/vehicles/Automobile.cpp
+++ b/src/vehicles/Automobile.cpp
@@ -17,8 +17,10 @@
#include "Explosion.h"
#include "Particle.h"
#include "ParticleObject.h"
+#include "Glass.h"
#include "Antennas.h"
#include "Skidmarks.h"
+#include "WindModifiers.h"
#include "Shadows.h"
#include "PointLights.h"
#include "Coronas.h"
@@ -35,8 +37,10 @@
#include "Population.h"
#include "CarCtrl.h"
#include "CarAI.h"
+#include "Stats.h"
#include "Garages.h"
#include "PathFind.h"
+#include "Replay.h"
#include "AnimManager.h"
#include "RpAnimBlend.h"
#include "AnimBlendAssociation.h"
@@ -45,7 +49,9 @@
#include "Object.h"
#include "Automobile.h"
-bool bAllCarCheat; // unused
+//--MIAMI: file done except TODOs
+
+bool bAllCarCheat;
RwObject *GetCurrentAtomicObjectCB(RwObject *object, void *data);
@@ -67,7 +73,7 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(id);
m_fFireBlowUpTimer = 0.0f;
- m_auto_unk1 = 0;
+ m_doingBurnout = 0;
bTaxiLight = m_sAllTaxiLights;
bFixedColour = false;
bBigWheels = false;
@@ -75,7 +81,26 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
SetModelIndex(id);
+ // Already done in CVehicle...
+ switch(GetModelIndex()){
+ case MI_HUNTER:
+ case MI_ANGEL:
+ case MI_FREEWAY:
+ m_nRadioStation = V_ROCK;
+ break;
+ case MI_RCBARON:
+ case MI_RCBANDIT:
+ case MI_RCRAIDER:
+ case MI_RCGOBLIN:
+ case MI_TOPFUN:
+ case MI_CADDY:
+ case MI_BAGGAGE:
+ m_nRadioStation = RADIO_OFF;
+ break;
+ }
+
pHandling = mod_HandlingManager.GetHandlingData((eHandlingId)mi->m_handlingId);
+ pFlyingHandling = mod_HandlingManager.GetFlyingPointer((eHandlingId)mi->m_handlingId);
m_auto_unused1 = 20.0f;
m_auto_unused2 = 0;
@@ -129,6 +154,8 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
m_fElasticity = 0.05f;
m_fBuoyancy = pHandling->fBuoyancy;
+ m_fOrientation = m_auto_unk4 = 0.0f;
+
m_nBusDoorTimerEnd = 0;
m_nBusDoorTimerStart = 0;
@@ -139,6 +166,9 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
m_fGasPedalAudio = 0.0f;
bNotDamagedUpsideDown = false;
bMoreResistantToDamage = false;
+ bTankDetonateCars = true;
+ bStuckInSand = false;
+ bHeliDestroyed = false;
m_fVelocityChangeForAudio = 0.0f;
m_hydraulicState = 0;
@@ -150,7 +180,7 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
m_aWheelRotation[i] = 0.0f;
m_aWheelSpeed[i] = 0.0f;
m_aWheelState[i] = WHEEL_STATE_NORMAL;
- m_aWheelSkidmarkMuddy[i] = false;
+ m_aWheelSkidmarkType[i] = SKIDMARK_NORMAL;
m_aWheelSkidmarkBloody[i] = false;
}
@@ -159,6 +189,7 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
m_nDriveWheelsOnGroundPrev = 0;
m_fHeightAboveRoad = 0.0f;
m_fTraction = 1.0f;
+ m_fTireTemperature = 1.0f;
CColModel *colModel = mi->GetColModel();
if(colModel->lines == nil){
@@ -173,10 +204,6 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
m_nNumPassengers = 0;
- m_bombType = CARBOMB_NONE;
- bDriverLastFrame = false;
- m_pBombRigger = nil;
-
if(m_nDoorLock == CARLOCK_UNLOCKED &&
(id == MI_POLICE || id == MI_ENFORCER || id == MI_RHINO))
m_nDoorLock = CARLOCK_LOCKED_INITIALLY;
@@ -184,6 +211,7 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
m_fCarGunLR = 0.0f;
m_fCarGunUD = 0.05f;
m_fPropellerRotation = 0.0f;
+ m_fHeliOrientation = -1.0f;
m_weaponDoorTimerLeft = 0.0f;
m_weaponDoorTimerRight = m_weaponDoorTimerLeft;
@@ -194,7 +222,10 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
CMatrix mat2(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_LF]));
mat1.GetPosition() += CVector(mat2.GetPosition().x + 0.1f, 0.0f, mat2.GetPosition().z);
mat1.UpdateRW();
- }else if(GetModelIndex() == MI_MIAMI_SPARROW || GetModelIndex() == MI_MIAMI_RCRAIDER){
+ }else if(GetModelIndex() == MI_HUNTER){
+ RpAtomicSetFlags((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LB]), 0);
+ RpAtomicSetFlags((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RB]), 0);
+ }else if(IsRealHeli()){
RpAtomicSetFlags((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LF]), 0);
RpAtomicSetFlags((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RF]), 0);
RpAtomicSetFlags((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LB]), 0);
@@ -205,7 +236,6 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
}
}
-
void
CAutomobile::SetModelIndex(uint32 id)
{
@@ -213,6 +243,11 @@ CAutomobile::SetModelIndex(uint32 id)
SetupModelNodes();
}
+#define SAND_SLOWDOWN (0.01f)
+float CAR_BALANCE_MULT = 0.3f;
+CVector vecSeaSparrowGunPos(-0.5f, 2.4f, -0.785f);
+CVector vecHunterGunPos(0.0f, 4.8f, -1.3f);
+CVector vecHunterRocketPos(2.5f, 1.0f, -0.5f);
CVector vecDAMAGE_ENGINE_POS_SMALL(-0.1f, -0.1f, 0.0f);
CVector vecDAMAGE_ENGINE_POS_BIG(-0.5f, -0.3f, 0.0f);
@@ -227,12 +262,25 @@ CAutomobile::ProcessControl(void)
colModel = &CWorld::Players[CWorld::PlayerInFocus].m_ColModel;
else
colModel = GetColModel();
+ bool drivingInSand = false;
bWarnedPeds = false;
+ m_doingBurnout = 0;
+ bStuckInSand = false;
+ bRestingOnPhysical = false;
+
+ bool carHasNitro = bAllTaxisHaveNitro && GetStatus() == STATUS_PLAYER && IsTaxi();
- // skip if the collision isn't for the current level
- if(colModel->level > LEVEL_GENERIC && colModel->level != CCollision::ms_collisionInMemory)
+ if(CReplay::IsPlayingBack())
return;
+ // Heli wind
+ if(IsRealHeli())
+ if((GetStatus() == STATUS_PLAYER || GetStatus() == STATUS_PHYSICS) && m_aWheelSpeed[1] > 0.075f ||
+ GetStatus() == STATUS_SIMPLE)
+ CWindModifiers::RegisterOne(GetPosition(), 1);
+
+ UpdatePassengerList();
+
// Improve grip of vehicles in certain cases
bool strongGrip1 = false;
bool strongGrip2 = false;
@@ -247,7 +295,8 @@ CAutomobile::ProcessControl(void)
else if((GetPosition() - FindPlayerCoors()).Magnitude() > 50.0f)
strongGrip2 = true;
}
- }
+ }else if(GetModelIndex() == MI_RCBANDIT && GetStatus() != STATUS_PLAYER_REMOTE)
+ strongGrip1 = true;
if(bIsBus)
ProcessAutoBusDoors();
@@ -258,7 +307,7 @@ CAutomobile::ProcessControl(void)
if(GetStatus() != STATUS_ABANDONED && GetStatus() != STATUS_WRECKED &&
GetStatus() != STATUS_PLAYER && GetStatus() != STATUS_PLAYER_REMOTE && GetStatus() != STATUS_PLAYER_DISABLED){
switch(GetModelIndex())
- case MI_FBICAR:
+ case MI_FBIRANCH:
case MI_POLICE:
case MI_ENFORCER:
case MI_SECURICA:
@@ -268,25 +317,15 @@ CAutomobile::ProcessControl(void)
}
// Process driver
- if(pDriver){
- if(!bDriverLastFrame && m_bombType == CARBOMB_ONIGNITIONACTIVE){
- // If someone enters the car and there is a bomb, detonate
- m_nBombTimer = 1000;
- m_pBlowUpEntity = m_pBombRigger;
- if(m_pBlowUpEntity)
- m_pBlowUpEntity->RegisterReference((CEntity**)&m_pBlowUpEntity);
- DMAudio.PlayOneShot(m_audioEntityId, SOUND_BOMB_TICK, 1.0f);
- }
- bDriverLastFrame = true;
-
+ if(pDriver)
if(IsUpsideDown() && CanPedEnterCar()){
if(!pDriver->IsPlayer() &&
!(pDriver->m_leader && pDriver->m_leader->bInVehicle) &&
pDriver->CharCreatedBy != MISSION_CHAR)
pDriver->SetObjective(OBJECTIVE_LEAVE_CAR, this);
}
- }else
- bDriverLastFrame = false;
+
+ ActivateBombWhenEntered();
// Process passengers
if(m_nNumPassengers != 0 && IsUpsideDown() && CanPedEnterCar()){
@@ -300,18 +339,7 @@ CAutomobile::ProcessControl(void)
CRubbish::StirUp(this);
- // blend in clump
- int clumpAlpha = CVisibilityPlugins::GetClumpAlpha((RpClump*)m_rwObject);
- if(bFadeOut){
- clumpAlpha -= 8;
- if(clumpAlpha < 0)
- clumpAlpha = 0;
- }else if(clumpAlpha < 255){
- clumpAlpha += 16;
- if(clumpAlpha > 255)
- clumpAlpha = 255;
- }
- CVisibilityPlugins::SetClumpAlpha((RpClump*)m_rwObject, clumpAlpha);
+ UpdateClumpAlpha();
AutoPilot.m_bSlowedDownBecauseOfCars = false;
AutoPilot.m_bSlowedDownBecauseOfPeds = false;
@@ -322,24 +350,33 @@ CAutomobile::ProcessControl(void)
else if(pHandling->Flags & HANDLING_NONPLAYER_STABILISER && GetStatus() == STATUS_PHYSICS)
m_vecCentreOfMass.z = pHandling->CentreOfMass.z - 0.2f*pHandling->Dimension.z;
else
- m_vecCentreOfMass.z = pHandling->CentreOfMass.z;
+ m_vecCentreOfMass = pHandling->CentreOfMass;
+
+ // Park car
+ if(bCanPark && !bParking && VehicleCreatedBy != MISSION_VEHICLE && AutoPilot.m_nCarMission == MISSION_CRUISE &&
+ ((CTimer::GetFrameCounter() + m_randomSeed)&0xF) == 0 && !IsTaxi()){
+ CVector parkPosition = GetPosition() + 3.0f*GetRight() + 10.0f*GetForward();
+ CEntity *ent = nil;
+ CColPoint colpoint;
+ if(!CWorld::ProcessLineOfSight(GetPosition(), parkPosition, colpoint, ent, true, true, true, false, false, false) ||
+ ent == this)
+ CCarAI::GetCarToParkAtCoors(this, &parkPosition);
+ }
// Process depending on status
bool playerRemote = false;
switch(GetStatus()){
case STATUS_PLAYER_REMOTE:
- if(CPad::GetPad(0)->WeaponJustDown()){
+ if(CPad::GetPad(0)->WeaponJustDown() && !bDisableRemoteDetonation){
BlowUpCar(FindPlayerPed());
CRemote::TakeRemoteControlledCarFromPlayer();
}
- if(GetModelIndex() == MI_RCBANDIT){
- CVector pos = GetPosition();
+ if(GetModelIndex() == MI_RCBANDIT && !bDisableRemoteDetonationOnContact){
+ //CVector pos = GetPosition();
// FindPlayerCoors unused
- if(RcbanditCheckHitWheels() || bIsInWater || CPopulation::IsPointInSafeZone(&pos)){
- if(CPopulation::IsPointInSafeZone(&pos))
- CGarages::TriggerMessage("HM2_5", -1, 5000, -1);
+ if(RcbanditCheckHitWheels() || bIsInWater){
CRemote::TakeRemoteControlledCarFromPlayer();
BlowUpCar(FindPlayerPed());
}
@@ -350,7 +387,7 @@ CAutomobile::ProcessControl(void)
// fall through
case STATUS_PLAYER:
if(playerRemote ||
- pDriver && pDriver->GetPedState() != PED_EXIT_CAR && pDriver->GetPedState() != PED_DRAG_FROM_CAR){
+ pDriver && pDriver->GetPedState() != PED_EXIT_CAR && pDriver->GetPedState() != PED_DRAG_FROM_CAR && pDriver->GetPedState() != PED_ARRESTED){
// process control input if controlled by player
if(playerRemote || pDriver->m_nPedType == PEDTYPE_PLAYER1)
ProcessControlInputs(0);
@@ -359,7 +396,59 @@ CAutomobile::ProcessControl(void)
if(GetStatus() == STATUS_PLAYER && !CRecordDataForChase::IsRecording())
DoDriveByShootings();
+
+ // Tweak center on mass when driving on two wheels
+ int twoWheelTime = CWorld::Players[CWorld::PlayerInFocus].m_nTimeNotFullyOnGround;
+ if(twoWheelTime > 500 && !IsRealHeli() && !IsRealPlane()){
+ float tweak = Min(twoWheelTime-500, 1000)/500.0f;
+ if(GetUp().z > 0.0f){
+ // positive when on left wheels, negative on right wheels
+ if(GetRight().z <= 0.0f)
+ tweak *= -1.0f;
+ m_vecCentreOfMass.z = pHandling->CentreOfMass.z +
+ CPad::GetPad(0)->GetSteeringLeftRight()/128.0f *
+ CAR_BALANCE_MULT * tweak * colModel->boundingBox.max.z;
+ }
+ }else
+ m_vecCentreOfMass.z = pHandling->CentreOfMass.z;
+
+ if(bHoverCheat)
+ DoHoverSuspensionRatios();
+
+ if(m_aSuspensionSpringRatio[0] < 1.0f && CSurfaceTable::GetAdhesionGroup(m_aWheelColPoints[0].surfaceB) == ADHESIVE_SAND ||
+ m_aSuspensionSpringRatio[1] < 1.0f && CSurfaceTable::GetAdhesionGroup(m_aWheelColPoints[1].surfaceB) == ADHESIVE_SAND ||
+ m_aSuspensionSpringRatio[2] < 1.0f && CSurfaceTable::GetAdhesionGroup(m_aWheelColPoints[2].surfaceB) == ADHESIVE_SAND ||
+ m_aSuspensionSpringRatio[3] < 1.0f && CSurfaceTable::GetAdhesionGroup(m_aWheelColPoints[3].surfaceB) == ADHESIVE_SAND){
+ if(GetModelIndex() != MI_RCBANDIT && GetModelIndex() != MI_RHINO){
+ float slowdown;
+ CVector parallelSpeed = m_vecMoveSpeed - DotProduct(m_vecMoveSpeed, GetUp())*GetUp();
+ float fSpeed = parallelSpeed.MagnitudeSqr();
+ if(fSpeed > SQR(0.3f)){
+ fSpeed = Sqrt(fSpeed);
+ parallelSpeed *= 0.3f / fSpeed;
+ slowdown = SAND_SLOWDOWN * Max(1.0f - 2.0f*fSpeed, 0.2f);
+ }else{
+ bStuckInSand = true;
+ slowdown = SAND_SLOWDOWN;
+ }
+ if(pHandling->Flags & HANDLING_GOOD_INSAND)
+ slowdown *= 0.5f;
+ if(CWeather::WetRoads > 0.2f)
+ slowdown *= (1.2f - CWeather::WetRoads);
+ ApplyMoveForce(parallelSpeed * -CTimer::GetTimeStep()*slowdown*m_fMass);
+ drivingInSand = true;
+ }
+ }
+ }else if(pDriver && pDriver->IsPlayer() &&
+ (pDriver->GetPedState() == PED_ARRESTED ||
+ pDriver->GetPedState() == PED_DRAG_FROM_CAR ||
+ (pDriver->GetPedState() == PED_EXIT_CAR || pDriver->m_objective == OBJECTIVE_LEAVE_CAR) && !CanPedJumpOutCar())){
+ bIsHandbrakeOn = true;
+ m_fBrakePedal = 1.0f;
+ m_fGasPedal = 0.0f;
}
+ if(CPad::GetPad(0)->WeaponJustDown())
+ ActivateBomb();
break;
case STATUS_SIMPLE:
@@ -380,6 +469,7 @@ CAutomobile::ProcessControl(void)
PlayHornIfNecessary();
ReduceHornCounter();
bVehicleColProcessed = false;
+ bAudioChangingGear = false;
// that's all we do for simple vehicles
return;
@@ -387,15 +477,44 @@ CAutomobile::ProcessControl(void)
CCarAI::UpdateCarAI(this);
CCarCtrl::SteerAICarWithPhysics(this);
PlayHornIfNecessary();
+
+ if(bIsBeingCarJacked){
+ m_fGasPedal = 0.0f;
+ m_fBrakePedal = 1.0f;
+ bIsHandbrakeOn = true;
+ }
+
+ if(m_aSuspensionSpringRatio[0] < 1.0f && CSurfaceTable::GetAdhesionGroup(m_aWheelColPoints[0].surfaceB) == ADHESIVE_SAND ||
+ m_aSuspensionSpringRatio[1] < 1.0f && CSurfaceTable::GetAdhesionGroup(m_aWheelColPoints[1].surfaceB) == ADHESIVE_SAND ||
+ m_aSuspensionSpringRatio[2] < 1.0f && CSurfaceTable::GetAdhesionGroup(m_aWheelColPoints[2].surfaceB) == ADHESIVE_SAND ||
+ m_aSuspensionSpringRatio[3] < 1.0f && CSurfaceTable::GetAdhesionGroup(m_aWheelColPoints[3].surfaceB) == ADHESIVE_SAND){
+ if(GetModelIndex() != MI_RCBANDIT && GetModelIndex() != MI_SANDKING && GetModelIndex() != MI_BFINJECT){
+ bStuckInSand = true;
+ if(CWeather::WetRoads > 0.0f)
+ ApplyMoveForce(m_vecMoveSpeed * -CTimer::GetTimeStep()*SAND_SLOWDOWN*m_fMass * (1.0f-CWeather::WetRoads));
+ else
+ ApplyMoveForce(m_vecMoveSpeed * -CTimer::GetTimeStep()*SAND_SLOWDOWN*m_fMass);
+ }
+ }
break;
case STATUS_ABANDONED:
- m_fBrakePedal = 0.2f;
+ if(m_vecMoveSpeed.MagnitudeSqr() < SQR(0.1f))
+ m_fBrakePedal = 0.2f;
+ else
+ m_fBrakePedal = 0.0f;
bIsHandbrakeOn = false;
m_fSteerAngle = 0.0f;
m_fGasPedal = 0.0f;
- m_nCarHornTimer = 0;
+ if(!IsAlarmOn())
+ m_nCarHornTimer = 0;
+
+ if(bIsBeingCarJacked){
+ m_fGasPedal = 0.0f;
+ m_fBrakePedal = 1.0f;
+ bIsHandbrakeOn = true;
+ }
break;
case STATUS_WRECKED:
@@ -404,26 +523,32 @@ CAutomobile::ProcessControl(void)
m_fSteerAngle = 0.0f;
m_fGasPedal = 0.0f;
- m_nCarHornTimer = 0;
+ if(!IsAlarmOn())
+ m_nCarHornTimer = 0;
break;
case STATUS_PLAYER_DISABLED:
- m_fBrakePedal = 1.0f;
- bIsHandbrakeOn = true;
+ if(m_vecMoveSpeed.MagnitudeSqr() < SQR(0.1f) ||
+ (pDriver && pDriver->IsPlayer() &&
+ (pDriver->GetPedState() == PED_ARRESTED ||
+ pDriver->GetPedState() == PED_DRAG_FROM_CAR ||
+ (pDriver->GetPedState() == PED_EXIT_CAR || pDriver->m_objective == OBJECTIVE_LEAVE_CAR) && !CanPedJumpOutCar()))){
+ bIsHandbrakeOn = true;
+ m_fBrakePedal = 1.0f;
+ m_fGasPedal = 0.0f;
+ }else{
+ m_fBrakePedal = 0.0f;
+ bIsHandbrakeOn = false;
+ }
m_fSteerAngle = 0.0f;
m_fGasPedal = 0.0f;
- m_nCarHornTimer = 0;
+ if(!IsAlarmOn())
+ m_nCarHornTimer = 0;
break;
default: break;
}
- // what's going on here?
- if(GetPosition().z < -0.6f &&
- Abs(m_vecMoveSpeed.x) < 0.05f &&
- Abs(m_vecMoveSpeed.y) < 0.05f)
- m_vecTurnSpeed *= Pow(0.95f, CTimer::GetTimeStep());
-
// Skip physics if object is found to have been static recently
bool skipPhysics = false;
if(!bIsStuck && (GetStatus() == STATUS_ABANDONED || GetStatus() == STATUS_WRECKED)){
@@ -451,7 +576,8 @@ CAutomobile::ProcessControl(void)
if(m_vecMoveSpeedAvg.MagnitudeSqr() <= sq(moveSpeedLimit*CTimer::GetTimeStep()) &&
m_vecTurnSpeedAvg.MagnitudeSqr() <= sq(turnSpeedLimit*CTimer::GetTimeStep()) &&
- m_fDistanceTravelled < distanceLimit ||
+ m_fDistanceTravelled < distanceLimit &&
+ !(m_fDamageImpulse > 0.0f && m_pDamageEntity && m_pDamageEntity->IsPed()) ||
makeStatic){
m_nStaticFrames++;
@@ -467,15 +593,27 @@ CAutomobile::ProcessControl(void)
}
}else
m_nStaticFrames = 0;
+ if(IsRealHeli() && m_aWheelSpeed[1] > 0.0f){
+ skipPhysics = false;
+ m_nStaticFrames = 0;
+ }
}
// Postpone
for(i = 0; i < 4; i++)
- if(m_aGroundPhysical[i] && !CWorld::bForceProcessControl && m_aGroundPhysical[i]->bIsInSafePosition){
- bWasPostponed = true;
- return;
+ if(m_aGroundPhysical[i]){
+ bRestingOnPhysical = true;
+ if(!CWorld::bForceProcessControl && m_aGroundPhysical[i]->bIsInSafePosition){
+ bWasPostponed = true;
+ return;
+ }
}
+ if(bRestingOnPhysical){
+ skipPhysics = false;
+ m_nStaticFrames = 0;
+ }
+
VehicleDamage(0.0f, 0);
// special control
@@ -487,12 +625,11 @@ CAutomobile::ProcessControl(void)
TankControl();
BlowUpCarsInPath();
break;
- case MI_YARDIE:
- // beta also had esperanto here it seems
+ case MI_VOODOO:
HydraulicControl();
break;
default:
- if(CVehicle::bCheat3){
+ if(CVehicle::bCheat3 || carHasNitro){
// Make vehicle jump when horn is sounded
if(GetStatus() == STATUS_PLAYER && m_vecMoveSpeed.MagnitudeSqr() > sq(0.2f) &&
// BUG: game checks [0] four times, instead of all wheels
@@ -531,12 +668,17 @@ CAutomobile::ProcessControl(void)
1.2f*m_vecMoveSpeed, nil, 2.0f);
ApplyMoveForce(CVector(0.0f, 0.0f, 1.0f)*m_fMass*0.4f);
- ApplyTurnForce(GetUp()*m_fMass*0.035f, GetForward()*1.0f);
+ ApplyTurnForce(GetUp()*m_fTurnMass*0.01f, GetForward()*1.0f);
}
}
break;
}
+ if(GetStatus() == STATUS_PHYSICS || GetStatus() == STATUS_SIMPLE)
+ if(AutoPilot.m_nCarMission == MISSION_HELI_FLYTOCOORS ||
+ AutoPilot.m_nCarMission == MISSION_PLANE_FLYTOCOORS)
+ skipPhysics = true;
+
float brake;
if(skipPhysics){
bHasContacted = false;
@@ -546,11 +688,13 @@ CAutomobile::ProcessControl(void)
m_nCollisionRecords = 0;
bHasCollided = false;
bVehicleColProcessed = false;
+ bAudioChangingGear = false;
m_nDamagePieceType = 0;
m_fDamageImpulse = 0.0f;
m_pDamageEntity = nil;
m_vecTurnFriction = CVector(0.0f, 0.0f, 0.0f);
m_vecMoveFriction = CVector(0.0f, 0.0f, 0.0f);
+ m_fTireTemperature = 1.0f;
}else{
// This has to be done if ProcessEntityCollision wasn't called
@@ -603,6 +747,14 @@ CAutomobile::ProcessControl(void)
if(m_aSuspensionSpringRatio[i] > 1.0f)
m_aSuspensionSpringRatio[i] = 1.0f;
}
+ }else if(CSurfaceTable::GetAdhesionGroup(m_aWheelColPoints[i].surfaceB) == ADHESIVE_SAND &&
+ GetModelIndex() != MI_RHINO){
+ fwdSpeed *= 0.7f;
+ float f = 1.0f - fwdSpeed/0.3f - 0.7f*CWeather::WetRoads;
+ f = Max(f, 0.4f);
+ m_aSuspensionSpringRatio[i] += 0.35f*f*(m_aSuspensionLineLength[i]-m_aSuspensionSpringLength[i])/m_aSuspensionSpringLength[i];
+ if(m_aSuspensionSpringRatio[i] > 1.0f)
+ m_aSuspensionSpringRatio[i] = 1.0f;
}
// get points and directions if spring is compressed
@@ -620,13 +772,20 @@ CAutomobile::ProcessControl(void)
if(i == CARWHEEL_REAR_LEFT || i == CARWHEEL_REAR_RIGHT)
bias = 1.0f - bias;
- ApplySpringCollision(pHandling->fSuspensionForceLevel,
+ ApplySpringCollisionAlt(pHandling->fSuspensionForceLevel,
springDirections[i], contactPoints[i],
- m_aSuspensionSpringRatio[i], bias);
- m_aWheelSkidmarkMuddy[i] =
- m_aWheelColPoints[i].surfaceB == SURFACE_GRASS ||
- m_aWheelColPoints[i].surfaceB == SURFACE_MUD_DRY ||
- m_aWheelColPoints[i].surfaceB == SURFACE_SAND;
+ m_aSuspensionSpringRatio[i], bias, m_aWheelColPoints[i].normal);
+
+ m_aWheelSkidmarkUnk[i] = false;
+ if(m_aWheelColPoints[i].surfaceB == SURFACE_GRASS ||
+ m_aWheelColPoints[i].surfaceB == SURFACE_MUD_DRY)
+ m_aWheelSkidmarkType[i] = SKIDMARK_MUDDY;
+ else if(m_aWheelColPoints[i].surfaceB == SURFACE_SAND ||
+ m_aWheelColPoints[i].surfaceB == SURFACE_SAND_BEACH){
+ m_aWheelSkidmarkType[i] = SKIDMARK_SANDY;
+ m_aWheelSkidmarkUnk[i] = true;
+ }else
+ m_aWheelSkidmarkType[i] = SKIDMARK_NORMAL;
}else{
contactPoints[i] = Multiply3x3(GetMatrix(), colModel->lines[i].p1);
}
@@ -643,6 +802,8 @@ CAutomobile::ProcessControl(void)
m_aGroundPhysical[i] = nil;
#endif
}
+ if(m_aSuspensionSpringRatio[i] < 1.0f && m_aWheelColPoints[i].normal.z > 0.35f)
+ springDirections[i] = -m_aWheelColPoints[i].normal;
}
// dampen springs
@@ -661,7 +822,6 @@ CAutomobile::ProcessControl(void)
}
}
-
bool gripCheat = true;
fwdSpeed = DotProduct(m_vecMoveSpeed, GetForward());
if(!strongGrip1 && !CVehicle::bCheat3)
@@ -669,14 +829,25 @@ CAutomobile::ProcessControl(void)
float acceleration = pHandling->Transmission.CalculateDriveAcceleration(m_fGasPedal, m_nCurrentGear, m_fChangeGearTime, fwdSpeed, gripCheat);
acceleration /= m_fForceMultiplier;
- // unused
- if(GetModelIndex() == MI_MIAMI_RCBARON ||
- GetModelIndex() == MI_MIAMI_RCRAIDER ||
- GetModelIndex() == MI_MIAMI_SPARROW)
+ if(IsRealHeli() || IsRealPlane())
acceleration = 0.0f;
+ if(bAudioChangingGear && m_fGasPedal > 0.4f && m_fBrakePedal < 0.1f && fwdSpeed > 0.15f &&
+ this == FindPlayerVehicle() && TheCamera.Cams[TheCamera.ActiveCam].Mode != CCam::MODE_1STPERSON){
+ if(GetStatus() == STATUS_PLAYER && pHandling->Flags & HANDLING_IS_BUS){
+ if(m_nBusDoorTimerEnd == 0)
+ m_nBusDoorTimerEnd = 1000;
+ else if(m_nBusDoorTimerEnd > CTimer::GetTimeStepInMilliseconds())
+ m_nBusDoorTimerEnd -= CTimer::GetTimeStepInMilliseconds();
+ }
+
+ if(m_aSuspensionSpringRatio[0] < 1.0f || m_aSuspensionSpringRatio[1] < 1.0f ||
+ m_aSuspensionSpringRatio[2] < 1.0f || m_aSuspensionSpringRatio[3] < 1.0f)
+ ApplyTurnForce(-GRAVITY*Min(m_fTurnMass, 2500.0f)*GetUp(), -1.0f*GetForward());
+ }
+
brake = m_fBrakePedal * pHandling->fBrakeDeceleration * CTimer::GetTimeStep();
- bool neutralHandling = !!(pHandling->Flags & HANDLING_NEUTRALHANDLING);
+ bool neutralHandling = GetStatus() != STATUS_PLAYER && GetStatus() != STATUS_PLAYER_REMOTE && (pHandling->Flags & HANDLING_NEUTRALHANDLING);
float brakeBiasFront = neutralHandling ? 1.0f : 2.0f*pHandling->fBrakeBias;
float brakeBiasRear = neutralHandling ? 1.0f : 2.0f*(1.0f-pHandling->fBrakeBias);
float tractionBiasFront = neutralHandling ? 1.0f : 2.0f*pHandling->fTractionBias;
@@ -722,21 +893,7 @@ CAutomobile::ProcessControl(void)
if(CVehicle::bCheat3)
traction *= 4.0f;
- if(FindPlayerVehicle() && FindPlayerVehicle() == this){
- if(CPad::GetPad(0)->WeaponJustDown()){
- if(m_bombType == CARBOMB_TIMED){
- m_bombType = CARBOMB_TIMEDACTIVE;
- m_nBombTimer = 7000;
- m_pBlowUpEntity = FindPlayerPed();
- CGarages::TriggerMessage("GA_12", -1, 3000, -1);
- DMAudio.PlayOneShot(m_audioEntityId, SOUND_BOMB_TIMED_ACTIVATED, 1.0f);
- }else if(m_bombType == CARBOMB_ONIGNITION){
- m_bombType = CARBOMB_ONIGNITIONACTIVE;
- CGarages::TriggerMessage("GA_12", -1, 3000, -1);
- DMAudio.PlayOneShot(m_audioEntityId, SOUND_BOMB_ONIGNITION_ACTIVATED, 1.0f);
- }
- }
- }else if(strongGrip1 || CVehicle::bCheat3){
+ if(FindPlayerVehicle() != this && (strongGrip1 || CVehicle::bCheat3)){
traction *= 1.2f;
acceleration *= 1.4f;
if(strongGrip2 || CVehicle::bCheat3){
@@ -748,13 +905,16 @@ CAutomobile::ProcessControl(void)
static float fThrust;
static tWheelState WheelState[4];
- // Process front wheels on ground
+ bool rearWheelsFirst = !!(pHandling->Flags & HANDLING_REARWHEEL_1ST);
+ // Process front wheels on ground - first try
+
+ if(!rearWheelsFirst){
if(m_aWheelTimer[CARWHEEL_FRONT_LEFT] > 0.0f || m_aWheelTimer[CARWHEEL_FRONT_RIGHT] > 0.0f){
float s = Sin(m_fSteerAngle);
float c = Cos(m_fSteerAngle);
- CVector wheelFwd = Multiply3x3(GetMatrix(), CVector(-s, c, 0.0f));
- CVector wheelRight = Multiply3x3(GetMatrix(), CVector(c, s, 0.0f));
+
+ CVector wheelFwd, wheelRight, tmp;
if(m_aWheelTimer[CARWHEEL_FRONT_LEFT] > 0.0f){
if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier))
@@ -762,6 +922,15 @@ CAutomobile::ProcessControl(void)
else
fThrust = acceleration;
+ wheelFwd = GetForward();
+ wheelFwd -= DotProduct(wheelFwd, m_aWheelColPoints[CARWHEEL_FRONT_LEFT].normal)*m_aWheelColPoints[CARWHEEL_FRONT_LEFT].normal;
+ wheelFwd.Normalise();
+ wheelRight = CrossProduct(wheelFwd, m_aWheelColPoints[CARWHEEL_FRONT_LEFT].normal);
+ wheelRight.Normalise();
+ tmp = c*wheelFwd - s*wheelRight;
+ wheelRight = s*wheelFwd + c*wheelRight;
+ wheelFwd = tmp;
+
m_aWheelColPoints[CARWHEEL_FRONT_LEFT].surfaceA = SURFACE_WHEELBASE;
float adhesion = CSurfaceTable::GetAdhesiveLimit(m_aWheelColPoints[CARWHEEL_FRONT_LEFT])*traction;
if(GetStatus() == STATUS_PLAYER)
@@ -796,6 +965,15 @@ CAutomobile::ProcessControl(void)
else
fThrust = acceleration;
+ wheelFwd = GetForward();
+ wheelFwd -= DotProduct(wheelFwd, m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].normal)*m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].normal;
+ wheelFwd.Normalise();
+ wheelRight = CrossProduct(wheelFwd, m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].normal);
+ wheelRight.Normalise();
+ tmp = c*wheelFwd - s*wheelRight;
+ wheelRight = s*wheelFwd + c*wheelRight;
+ wheelFwd = tmp;
+
m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].surfaceA = SURFACE_WHEELBASE;
float adhesion = CSurfaceTable::GetAdhesiveLimit(m_aWheelColPoints[CARWHEEL_FRONT_RIGHT])*traction;
if(GetStatus() == STATUS_PLAYER)
@@ -827,33 +1005,36 @@ CAutomobile::ProcessControl(void)
// Process front wheels off ground
- if(m_aWheelTimer[CARWHEEL_FRONT_LEFT] <= 0.0f){
- if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f)
- m_aWheelSpeed[CARWHEEL_FRONT_LEFT] *= 0.95f;
- else{
- if(acceleration > 0.0f){
- if(m_aWheelSpeed[CARWHEEL_FRONT_LEFT] < 2.0f)
- m_aWheelSpeed[CARWHEEL_FRONT_LEFT] -= 0.2f;
- }else{
- if(m_aWheelSpeed[CARWHEEL_FRONT_LEFT] > -2.0f)
- m_aWheelSpeed[CARWHEEL_FRONT_LEFT] += 0.1f;
+ if(!IsRealHeli()){
+ if(m_aWheelTimer[CARWHEEL_FRONT_LEFT] <= 0.0f){
+ if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f)
+ m_aWheelSpeed[CARWHEEL_FRONT_LEFT] *= 0.95f;
+ else{
+ if(acceleration > 0.0f){
+ if(m_aWheelSpeed[CARWHEEL_FRONT_LEFT] < 2.0f)
+ m_aWheelSpeed[CARWHEEL_FRONT_LEFT] -= 0.2f;
+ }else{
+ if(m_aWheelSpeed[CARWHEEL_FRONT_LEFT] > -2.0f)
+ m_aWheelSpeed[CARWHEEL_FRONT_LEFT] += 0.1f;
+ }
}
+ m_aWheelRotation[CARWHEEL_FRONT_LEFT] += m_aWheelSpeed[CARWHEEL_FRONT_LEFT];
}
- m_aWheelRotation[CARWHEEL_FRONT_LEFT] += m_aWheelSpeed[CARWHEEL_FRONT_LEFT];
- }
- if(m_aWheelTimer[CARWHEEL_FRONT_RIGHT] <= 0.0f){
- if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f)
- m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] *= 0.95f;
- else{
- if(acceleration > 0.0f){
- if(m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] < 2.0f)
- m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] -= 0.2f;
- }else{
- if(m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] > -2.0f)
- m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] += 0.1f;
+ if(m_aWheelTimer[CARWHEEL_FRONT_RIGHT] <= 0.0f){
+ if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f)
+ m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] *= 0.95f;
+ else{
+ if(acceleration > 0.0f){
+ if(m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] < 2.0f)
+ m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] -= 0.2f;
+ }else{
+ if(m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] > -2.0f)
+ m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] += 0.1f;
+ }
}
+ m_aWheelRotation[CARWHEEL_FRONT_RIGHT] += m_aWheelSpeed[CARWHEEL_FRONT_RIGHT];
}
- m_aWheelRotation[CARWHEEL_FRONT_RIGHT] += m_aWheelSpeed[CARWHEEL_FRONT_RIGHT];
+ }
}
// Process rear wheels
@@ -862,14 +1043,28 @@ CAutomobile::ProcessControl(void)
CVector wheelFwd = GetForward();
CVector wheelRight = GetRight();
+ float rearBrake = brake;
+ float rearTraction = traction;
+ if(bIsHandbrakeOn){
#ifdef FIX_BUGS
- // Not sure if this is needed, but brake usually has timestep as a factor
- if(bIsHandbrakeOn)
- brake = 20000.0f * CTimer::GetTimeStepFix();
+ // Not sure if this is needed, but brake usually has timestep as a factor
+ rearBrake = 20000.0f * CTimer::GetTimeStepFix();
#else
- if(bIsHandbrakeOn)
- brake = 20000.0f;
+ rearBrake = 20000.0f;
#endif
+ if(fwdSpeed > 0.1f && pHandling->Flags & HANDLING_HANDBRAKE_TYRE){
+ m_fTireTemperature += 0.005*CTimer::GetTimeStep();
+ if(m_fTireTemperature > 2.0f)
+ m_fTireTemperature = 2.0f;
+ }
+ }else if(m_doingBurnout && !mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier)){
+ rearBrake = 0.0f;
+ rearTraction = 0.0f;
+ // BUG: missing timestep
+ ApplyTurnForce(contactPoints[CARWHEEL_REAR_LEFT], -0.001f*m_fTurnMass*m_fSteerAngle*GetRight());
+ }else if(m_fTireTemperature > 1.0f){
+ rearTraction *= m_fTireTemperature;
+ }
if(m_aWheelTimer[CARWHEEL_REAR_LEFT] > 0.0f){
if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier))
@@ -877,8 +1072,14 @@ CAutomobile::ProcessControl(void)
else
fThrust = acceleration;
+ wheelFwd = GetForward();
+ wheelFwd -= DotProduct(wheelFwd, m_aWheelColPoints[CARWHEEL_REAR_LEFT].normal)*m_aWheelColPoints[CARWHEEL_REAR_LEFT].normal;
+ wheelFwd.Normalise();
+ wheelRight = CrossProduct(wheelFwd, m_aWheelColPoints[CARWHEEL_REAR_LEFT].normal);
+ wheelRight.Normalise();
+
m_aWheelColPoints[CARWHEEL_REAR_LEFT].surfaceA = SURFACE_WHEELBASE;
- float adhesion = CSurfaceTable::GetAdhesiveLimit(m_aWheelColPoints[CARWHEEL_REAR_LEFT])*traction;
+ float adhesion = CSurfaceTable::GetAdhesiveLimit(m_aWheelColPoints[CARWHEEL_REAR_LEFT])*rearTraction;
if(GetStatus() == STATUS_PLAYER)
adhesion *= CSurfaceTable::GetWetMultiplier(m_aWheelColPoints[CARWHEEL_REAR_LEFT].surfaceB);
WheelState[CARWHEEL_REAR_LEFT] = m_aWheelState[CARWHEEL_REAR_LEFT];
@@ -887,7 +1088,7 @@ CAutomobile::ProcessControl(void)
ProcessWheel(wheelFwd, wheelRight,
contactSpeeds[CARWHEEL_REAR_LEFT], contactPoints[CARWHEEL_REAR_LEFT],
m_nWheelsOnGround, fThrust,
- brake*brakeBiasRear,
+ rearBrake*brakeBiasRear,
adhesion*tractionBiasRear*Damage.m_fWheelDamageEffect,
CARWHEEL_REAR_LEFT,
&m_aWheelSpeed[CARWHEEL_REAR_LEFT],
@@ -897,7 +1098,7 @@ CAutomobile::ProcessControl(void)
ProcessWheel(wheelFwd, wheelRight,
contactSpeeds[CARWHEEL_REAR_LEFT], contactPoints[CARWHEEL_REAR_LEFT],
m_nWheelsOnGround, fThrust,
- brake*brakeBiasRear,
+ rearBrake*brakeBiasRear,
adhesion*tractionBiasRear,
CARWHEEL_REAR_LEFT,
&m_aWheelSpeed[CARWHEEL_REAR_LEFT],
@@ -905,14 +1106,26 @@ CAutomobile::ProcessControl(void)
WHEEL_STATUS_OK);
}
+#ifdef FIX_BUGS
+ // Shouldn't we reset these after the left wheel?
+ wheelFwd = GetForward();
+ wheelRight = GetRight();
+#endif
+
if(m_aWheelTimer[CARWHEEL_REAR_RIGHT] > 0.0f){
if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier))
fThrust = 0.0f;
else
fThrust = acceleration;
+ wheelFwd = GetForward();
+ wheelFwd -= DotProduct(wheelFwd, m_aWheelColPoints[CARWHEEL_REAR_RIGHT].normal)*m_aWheelColPoints[CARWHEEL_REAR_RIGHT].normal;
+ wheelFwd.Normalise();
+ wheelRight = CrossProduct(wheelFwd, m_aWheelColPoints[CARWHEEL_REAR_RIGHT].normal);
+ wheelRight.Normalise();
+
m_aWheelColPoints[CARWHEEL_REAR_RIGHT].surfaceA = SURFACE_WHEELBASE;
- float adhesion = CSurfaceTable::GetAdhesiveLimit(m_aWheelColPoints[CARWHEEL_REAR_RIGHT])*traction;
+ float adhesion = CSurfaceTable::GetAdhesiveLimit(m_aWheelColPoints[CARWHEEL_REAR_RIGHT])*rearTraction;
if(GetStatus() == STATUS_PLAYER)
adhesion *= CSurfaceTable::GetWetMultiplier(m_aWheelColPoints[CARWHEEL_REAR_RIGHT].surfaceB);
WheelState[CARWHEEL_REAR_RIGHT] = m_aWheelState[CARWHEEL_REAR_RIGHT];
@@ -921,7 +1134,7 @@ CAutomobile::ProcessControl(void)
ProcessWheel(wheelFwd, wheelRight,
contactSpeeds[CARWHEEL_REAR_RIGHT], contactPoints[CARWHEEL_REAR_RIGHT],
m_nWheelsOnGround, fThrust,
- brake*brakeBiasRear,
+ rearBrake*brakeBiasRear,
adhesion*tractionBiasRear*Damage.m_fWheelDamageEffect,
CARWHEEL_REAR_RIGHT,
&m_aWheelSpeed[CARWHEEL_REAR_RIGHT],
@@ -931,7 +1144,7 @@ CAutomobile::ProcessControl(void)
ProcessWheel(wheelFwd, wheelRight,
contactSpeeds[CARWHEEL_REAR_RIGHT], contactPoints[CARWHEEL_REAR_RIGHT],
m_nWheelsOnGround, fThrust,
- brake*brakeBiasRear,
+ rearBrake*brakeBiasRear,
adhesion*tractionBiasRear,
CARWHEEL_REAR_RIGHT,
&m_aWheelSpeed[CARWHEEL_REAR_RIGHT],
@@ -940,58 +1153,203 @@ CAutomobile::ProcessControl(void)
}
}
+ if(m_doingBurnout && !mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier) &&
+ (m_aWheelState[CARWHEEL_REAR_LEFT] == WHEEL_STATE_SPINNING || m_aWheelState[CARWHEEL_REAR_RIGHT] == WHEEL_STATE_SPINNING)){
+ m_fTireTemperature += 0.001f*CTimer::GetTimeStep();
+ if(m_fTireTemperature > 3.0f)
+ m_fTireTemperature = 3.0f;
+ }else if(m_fTireTemperature > 1.0f){
+ m_fTireTemperature = (m_fTireTemperature - 1.0f)*Pow(0.995f, CTimer::GetTimeStep()) + 1.0f;
+ }
+
// Process rear wheels off ground
- if(m_aWheelTimer[CARWHEEL_REAR_LEFT] <= 0.0f){
- if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f)
- m_aWheelSpeed[CARWHEEL_REAR_LEFT] *= 0.95f;
- else{
- if(acceleration > 0.0f){
- if(m_aWheelSpeed[CARWHEEL_REAR_LEFT] < 2.0f)
- m_aWheelSpeed[CARWHEEL_REAR_LEFT] -= 0.2f;
- }else{
- if(m_aWheelSpeed[CARWHEEL_REAR_LEFT] > -2.0f)
- m_aWheelSpeed[CARWHEEL_REAR_LEFT] += 0.1f;
+ if(!IsRealHeli()){
+ if(m_aWheelTimer[CARWHEEL_REAR_LEFT] <= 0.0f){
+ if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f)
+ m_aWheelSpeed[CARWHEEL_REAR_LEFT] *= 0.95f;
+ else{
+ if(acceleration > 0.0f){
+ if(m_aWheelSpeed[CARWHEEL_REAR_LEFT] < 2.0f)
+ m_aWheelSpeed[CARWHEEL_REAR_LEFT] -= 0.2f;
+ }else{
+ if(m_aWheelSpeed[CARWHEEL_REAR_LEFT] > -2.0f)
+ m_aWheelSpeed[CARWHEEL_REAR_LEFT] += 0.1f;
+ }
}
+ m_aWheelRotation[CARWHEEL_REAR_LEFT] += m_aWheelSpeed[CARWHEEL_REAR_LEFT];
}
- m_aWheelRotation[CARWHEEL_REAR_LEFT] += m_aWheelSpeed[CARWHEEL_REAR_LEFT];
- }
- if(m_aWheelTimer[CARWHEEL_REAR_RIGHT] <= 0.0f){
- if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f)
- m_aWheelSpeed[CARWHEEL_REAR_RIGHT] *= 0.95f;
- else{
- if(acceleration > 0.0f){
- if(m_aWheelSpeed[CARWHEEL_REAR_RIGHT] < 2.0f)
- m_aWheelSpeed[CARWHEEL_REAR_RIGHT] -= 0.2f;
- }else{
- if(m_aWheelSpeed[CARWHEEL_REAR_RIGHT] > -2.0f)
- m_aWheelSpeed[CARWHEEL_REAR_RIGHT] += 0.1f;
+ if(m_aWheelTimer[CARWHEEL_REAR_RIGHT] <= 0.0f){
+ if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f)
+ m_aWheelSpeed[CARWHEEL_REAR_RIGHT] *= 0.95f;
+ else{
+ if(acceleration > 0.0f){
+ if(m_aWheelSpeed[CARWHEEL_REAR_RIGHT] < 2.0f)
+ m_aWheelSpeed[CARWHEEL_REAR_RIGHT] -= 0.2f;
+ }else{
+ if(m_aWheelSpeed[CARWHEEL_REAR_RIGHT] > -2.0f)
+ m_aWheelSpeed[CARWHEEL_REAR_RIGHT] += 0.1f;
+ }
+ }
+ m_aWheelRotation[CARWHEEL_REAR_RIGHT] += m_aWheelSpeed[CARWHEEL_REAR_RIGHT];
+ }
+ }
+
+ // Process front wheels on ground - second try
+
+ if(rearWheelsFirst){
+ if(m_aWheelTimer[CARWHEEL_FRONT_LEFT] > 0.0f || m_aWheelTimer[CARWHEEL_FRONT_RIGHT] > 0.0f){
+ float s = Sin(m_fSteerAngle);
+ float c = Cos(m_fSteerAngle);
+
+ CVector wheelFwd, wheelRight, tmp;
+
+ if(m_aWheelTimer[CARWHEEL_FRONT_LEFT] > 0.0f){
+ if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier))
+ fThrust = 0.0f;
+ else
+ fThrust = acceleration;
+
+ wheelFwd = GetForward();
+ wheelFwd -= DotProduct(wheelFwd, m_aWheelColPoints[CARWHEEL_FRONT_LEFT].normal)*m_aWheelColPoints[CARWHEEL_FRONT_LEFT].normal;
+ wheelFwd.Normalise();
+ wheelRight = CrossProduct(wheelFwd, m_aWheelColPoints[CARWHEEL_FRONT_LEFT].normal);
+ wheelRight.Normalise();
+ tmp = c*wheelFwd - s*wheelRight;
+ wheelRight = s*wheelFwd + c*wheelRight;
+ wheelFwd = tmp;
+
+ m_aWheelColPoints[CARWHEEL_FRONT_LEFT].surfaceA = SURFACE_WHEELBASE;
+ float adhesion = CSurfaceTable::GetAdhesiveLimit(m_aWheelColPoints[CARWHEEL_FRONT_LEFT])*traction;
+ if(GetStatus() == STATUS_PLAYER)
+ adhesion *= CSurfaceTable::GetWetMultiplier(m_aWheelColPoints[CARWHEEL_FRONT_LEFT].surfaceB);
+ WheelState[CARWHEEL_FRONT_LEFT] = m_aWheelState[CARWHEEL_FRONT_LEFT];
+
+ if(Damage.GetWheelStatus(VEHWHEEL_FRONT_LEFT) == WHEEL_STATUS_BURST)
+ ProcessWheel(wheelFwd, wheelRight,
+ contactSpeeds[CARWHEEL_FRONT_LEFT], contactPoints[CARWHEEL_FRONT_LEFT],
+ m_nWheelsOnGround, fThrust,
+ brake*brakeBiasFront,
+ adhesion*tractionBiasFront*Damage.m_fWheelDamageEffect,
+ CARWHEEL_FRONT_LEFT,
+ &m_aWheelSpeed[CARWHEEL_FRONT_LEFT],
+ &WheelState[CARWHEEL_FRONT_LEFT],
+ WHEEL_STATUS_BURST);
+ else
+ ProcessWheel(wheelFwd, wheelRight,
+ contactSpeeds[CARWHEEL_FRONT_LEFT], contactPoints[CARWHEEL_FRONT_LEFT],
+ m_nWheelsOnGround, fThrust,
+ brake*brakeBiasFront,
+ adhesion*tractionBiasFront,
+ CARWHEEL_FRONT_LEFT,
+ &m_aWheelSpeed[CARWHEEL_FRONT_LEFT],
+ &WheelState[CARWHEEL_FRONT_LEFT],
+ WHEEL_STATUS_OK);
+ }
+
+ if(m_aWheelTimer[CARWHEEL_FRONT_RIGHT] > 0.0f){
+ if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier))
+ fThrust = 0.0f;
+ else
+ fThrust = acceleration;
+
+ wheelFwd = GetForward();
+ wheelFwd -= DotProduct(wheelFwd, m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].normal)*m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].normal;
+ wheelFwd.Normalise();
+ wheelRight = CrossProduct(wheelFwd, m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].normal);
+ wheelRight.Normalise();
+ tmp = c*wheelFwd - s*wheelRight;
+ wheelRight = s*wheelFwd + c*wheelRight;
+ wheelFwd = tmp;
+
+ m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].surfaceA = SURFACE_WHEELBASE;
+ float adhesion = CSurfaceTable::GetAdhesiveLimit(m_aWheelColPoints[CARWHEEL_FRONT_RIGHT])*traction;
+ if(GetStatus() == STATUS_PLAYER)
+ adhesion *= CSurfaceTable::GetWetMultiplier(m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].surfaceB);
+ WheelState[CARWHEEL_FRONT_RIGHT] = m_aWheelState[CARWHEEL_FRONT_RIGHT];
+
+ if(Damage.GetWheelStatus(VEHWHEEL_FRONT_RIGHT) == WHEEL_STATUS_BURST)
+ ProcessWheel(wheelFwd, wheelRight,
+ contactSpeeds[CARWHEEL_FRONT_RIGHT], contactPoints[CARWHEEL_FRONT_RIGHT],
+ m_nWheelsOnGround, fThrust,
+ brake*brakeBiasFront,
+ adhesion*tractionBiasFront*Damage.m_fWheelDamageEffect,
+ CARWHEEL_FRONT_RIGHT,
+ &m_aWheelSpeed[CARWHEEL_FRONT_RIGHT],
+ &WheelState[CARWHEEL_FRONT_RIGHT],
+ WHEEL_STATUS_BURST);
+ else
+ ProcessWheel(wheelFwd, wheelRight,
+ contactSpeeds[CARWHEEL_FRONT_RIGHT], contactPoints[CARWHEEL_FRONT_RIGHT],
+ m_nWheelsOnGround, fThrust,
+ brake*brakeBiasFront,
+ adhesion*tractionBiasFront,
+ CARWHEEL_FRONT_RIGHT,
+ &m_aWheelSpeed[CARWHEEL_FRONT_RIGHT],
+ &WheelState[CARWHEEL_FRONT_RIGHT],
+ WHEEL_STATUS_OK);
+ }
+ }
+
+ // Process front wheels off ground
+
+ if(!IsRealHeli()){
+ if(m_aWheelTimer[CARWHEEL_FRONT_LEFT] <= 0.0f){
+ if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f)
+ m_aWheelSpeed[CARWHEEL_FRONT_LEFT] *= 0.95f;
+ else{
+ if(acceleration > 0.0f){
+ if(m_aWheelSpeed[CARWHEEL_FRONT_LEFT] < 2.0f)
+ m_aWheelSpeed[CARWHEEL_FRONT_LEFT] -= 0.2f;
+ }else{
+ if(m_aWheelSpeed[CARWHEEL_FRONT_LEFT] > -2.0f)
+ m_aWheelSpeed[CARWHEEL_FRONT_LEFT] += 0.1f;
+ }
}
+ m_aWheelRotation[CARWHEEL_FRONT_LEFT] += m_aWheelSpeed[CARWHEEL_FRONT_LEFT];
}
- m_aWheelRotation[CARWHEEL_REAR_RIGHT] += m_aWheelSpeed[CARWHEEL_REAR_RIGHT];
+ if(m_aWheelTimer[CARWHEEL_FRONT_RIGHT] <= 0.0f){
+ if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f)
+ m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] *= 0.95f;
+ else{
+ if(acceleration > 0.0f){
+ if(m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] < 2.0f)
+ m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] -= 0.2f;
+ }else{
+ if(m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] > -2.0f)
+ m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] += 0.1f;
+ }
+ }
+ m_aWheelRotation[CARWHEEL_FRONT_RIGHT] += m_aWheelSpeed[CARWHEEL_FRONT_RIGHT];
+ }
+ }
}
for(i = 0; i < 4; i++){
float wheelPos = colModel->lines[i].p0.z;
if(m_aSuspensionSpringRatio[i] > 0.0f)
wheelPos -= m_aSuspensionSpringRatio[i]*m_aSuspensionSpringLength[i];
- m_aWheelPosition[i] += (wheelPos - m_aWheelPosition[i])*0.75f;
+ if(GetModelIndex() == MI_VOODOO && bUsingSpecialColModel)
+ m_aWheelPosition[i] = wheelPos;
+ else
+ m_aWheelPosition[i] += (wheelPos - m_aWheelPosition[i])*0.75f;
}
for(i = 0; i < 4; i++)
m_aWheelState[i] = WheelState[i];
+ if(m_fGasPedal < 0.0f){
+ if(m_aWheelState[CARWHEEL_REAR_LEFT] == WHEEL_STATE_SPINNING)
+ m_aWheelState[CARWHEEL_REAR_LEFT] = WHEEL_STATE_NORMAL;
+ if(m_aWheelState[CARWHEEL_REAR_RIGHT] == WHEEL_STATE_SPINNING)
+ m_aWheelState[CARWHEEL_REAR_RIGHT] = WHEEL_STATE_NORMAL;
+ }
// Process horn
if(GetStatus() != STATUS_PLAYER){
- ReduceHornCounter();
+ if(!IsAlarmOn())
+ ReduceHornCounter();
}else{
- if(GetModelIndex() == MI_MRWHOOP){
- if(Pads[0].bHornHistory[Pads[0].iCurrHornHistory] &&
- !Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+4) % 5]){
- m_bSirenOrAlarm = !m_bSirenOrAlarm;
- printf("m_bSirenOrAlarm toggled to %d\n", m_bSirenOrAlarm);
- }
- }else if(UsesSiren(GetModelIndex())){
+ if(UsesSiren()){
if(Pads[0].bHornHistory[Pads[0].iCurrHornHistory]){
if(Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+4) % 5] &&
Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+3) % 5])
@@ -1004,43 +1362,137 @@ CAutomobile::ProcessControl(void)
m_bSirenOrAlarm = !m_bSirenOrAlarm;
}else
m_nCarHornTimer = 0;
- }else if(GetModelIndex() != MI_YARDIE && !CVehicle::bCheat3){
- if(Pads[0].GetHorn())
- m_nCarHornTimer = 1;
- else
- m_nCarHornTimer = 0;
+ }else if(GetModelIndex() != MI_VOODOO && !CVehicle::bCheat3 && !carHasNitro){
+ if(!IsAlarmOn()){
+ if(Pads[0].GetHorn())
+ m_nCarHornTimer = 1;
+ else
+ m_nCarHornTimer = 0;
+ }
}
}
// Flying
+ bool playRotorSound = false;
if(GetStatus() != STATUS_PLAYER && GetStatus() != STATUS_PLAYER_REMOTE && GetStatus() != STATUS_PHYSICS){
- if(GetModelIndex() == MI_MIAMI_RCRAIDER || GetModelIndex() == MI_MIAMI_SPARROW)
- m_aWheelSpeed[0] = Max(m_aWheelSpeed[0]-0.0005f, 0.0f);
+ if(IsRealHeli()){
+ bEngineOn = false;
+ m_aWheelSpeed[1] = Max(m_aWheelSpeed[1]-0.0005f, 0.0f);
+ if(GetModelIndex() != MI_RCRAIDER && GetModelIndex() != MI_RCGOBLIN)
+ if(m_aWheelSpeed[1] < 0.154f && m_aWheelSpeed[1] > 0.0044f)
+ playRotorSound = true;
+ }
}else if((GetModelIndex() == MI_DODO || CVehicle::bAllDodosCheat) &&
m_vecMoveSpeed.Magnitude() > 0.0f && CTimer::GetTimeStep() > 0.0f){
#ifdef ALT_DODO_CHEAT
if (bAltDodoCheat)
- FlyingControl(FLIGHT_MODEL_SEAPLANE);
+ FlyingControl(FLIGHT_MODEL_PLANE);
else
#endif
+ if(GetModelIndex() == MI_DODO)
FlyingControl(FLIGHT_MODEL_DODO);
- }else if(GetModelIndex() == MI_MIAMI_RCBARON){
- FlyingControl(FLIGHT_MODEL_RCPLANE);
- }else if(GetModelIndex() == MI_MIAMI_RCRAIDER || GetModelIndex() == MI_MIAMI_SPARROW || bAllCarCheat){
-#ifdef ALLCARSHELI_CHEAT
- if (bAllCarCheat)
- FlyingControl(FLIGHT_MODEL_HELI);
else
-#endif
- {
- if (CPad::GetPad(0)->GetCircleJustDown())
- m_aWheelSpeed[0] = Max(m_aWheelSpeed[0] - 0.03f, 0.0f);
- if (m_aWheelSpeed[0] < 0.22f)
- m_aWheelSpeed[0] += 0.0001f;
- if (m_aWheelSpeed[0] > 0.15f)
+ FlyingControl(FLIGHT_MODEL_PLANE);
+ }else if(GetModelIndex() == MI_RCBARON){
+ FlyingControl(FLIGHT_MODEL_RCPLANE);
+ }else if(IsRealHeli() || bAllCarCheat){
+ // Speed up rotor
+ if(m_aWheelSpeed[1] < 0.22f && !bIsInWater){
+ if(GetModelIndex() == MI_RCRAIDER || GetModelIndex() == MI_RCGOBLIN)
+ m_aWheelSpeed[1] += 0.003f;
+ else
+ m_aWheelSpeed[1] += 0.001f;
+ }
+
+ // Fly
+ if(m_aWheelSpeed[1] > 0.15f){
+ if(GetModelIndex() == MI_RCRAIDER || GetModelIndex() == MI_RCGOBLIN)
+ FlyingControl(FLIGHT_MODEL_RCHELI);
+ else if(m_nWheelsOnGround < 4 && !(GetModelIndex() == MI_SEASPAR && bTouchingWater) ||
+ CPad::GetPad(0)->GetAccelerate() != 0 || CPad::GetPad(0)->GetCarGunUpDown() > 1.0f ||
+ Abs(m_vecMoveSpeed.x) > 0.02f ||
+ Abs(m_vecMoveSpeed.y) > 0.02f ||
+ Abs(m_vecMoveSpeed.z) > 0.02f)
FlyingControl(FLIGHT_MODEL_HELI);
}
+
+ // Blade collision
+ if(m_aWheelSpeed[1] > 0.015f && m_aCarNodes[CAR_BONNET]){
+ CMatrix mat;
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_BONNET]));
+ if(GetModelIndex() == MI_RCRAIDER || GetModelIndex() == MI_RCGOBLIN)
+ DoBladeCollision(mat.GetPosition(), GetMatrix(), ROTOR_TOP, 0.72f, 0.9f);
+ else if(GetModelIndex() == MI_SPARROW || GetModelIndex() == MI_SEASPAR)
+ DoBladeCollision(mat.GetPosition(), GetMatrix(), ROTOR_TOP, 5.15f, 0.8f);
+ else if(GetModelIndex() == MI_HUNTER)
+ DoBladeCollision(mat.GetPosition(), GetMatrix(), ROTOR_TOP, 6.15f, 0.5f);
+ else
+ DoBladeCollision(mat.GetPosition(), GetMatrix(), ROTOR_TOP, 6.15f, 1.0f);
+ }
+
+ // Heli weapons
+ if(GetModelIndex() == MI_HUNTER && GetStatus() == STATUS_PLAYER){
+ // Hunter rockets
+ if(CPad::GetPad(0)->CarGunJustDown() && CTimer::GetTimeInMilliseconds() > m_nGunFiringTime+350){
+ CWeapon gun(WEAPONTYPE_ROCKETLAUNCHER, 100);
+ CVector source = vecHunterRocketPos;
+ source = GetMatrix()*source + Max(DotProduct(m_vecMoveSpeed, GetForward()), 0.0f)*GetForward()*CTimer::GetTimeStep();
+ gun.FireProjectile(this, &source, 0.0f);
+
+ source = vecHunterRocketPos;
+ source.x = -source.x;
+ source = GetMatrix()*source + Max(DotProduct(m_vecMoveSpeed, GetForward()), 0.0f)*GetForward()*CTimer::GetTimeStep();
+ gun.FireProjectile(this, &source, 0.0f);
+
+ CStats::RoundsFiredByPlayer++;
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_SHOT_FIRED, 0.0f);
+ m_nGunFiringTime = CTimer::GetTimeInMilliseconds();
+ // Hunter gun
+ }else if(CPad::GetPad(0)->GetHandBrake() && CTimer::GetTimeInMilliseconds() > m_nGunFiringTime+60){
+ CWeapon gun(WEAPONTYPE_HELICANNON, 5000);
+ CVector source = vecHunterGunPos;
+ source = GetMatrix()*source + m_vecMoveSpeed*CTimer::GetTimeStep();
+ gun.FireInstantHit(this, &source);
+ gun.AddGunshell(this, source, CVector2D(0.0f, 0.1f), 0.025f);
+ CStats::RoundsFiredByPlayer++;
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_SHOT_FIRED, 0.0f);
+ m_nGunFiringTime = CTimer::GetTimeInMilliseconds();
+ }
+ }else if(GetModelIndex() == MI_SEASPAR && GetStatus() == STATUS_PLAYER){
+ // Sea sparrow gun
+ if(CPad::GetPad(0)->GetHandBrake() && CTimer::GetTimeInMilliseconds() > m_nGunFiringTime+40){
+ CWeapon gun(WEAPONTYPE_M4, 5000);
+ CVector source = vecSeaSparrowGunPos;
+ source = GetMatrix()*source + m_vecMoveSpeed*CTimer::GetTimeStep();
+ gun.FireInstantHit(this, &source);
+ gun.AddGunshell(this, source, CVector2D(0.0f, 0.1f), 0.025f);
+ CStats::RoundsFiredByPlayer++;
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_SHOT_FIRED, 0.0f);
+ m_nGunFiringTime = CTimer::GetTimeInMilliseconds();
+ }
+ }
+
+ if(GetModelIndex() != MI_RCRAIDER && GetModelIndex() != MI_RCGOBLIN)
+ if(m_aWheelSpeed[1] < 0.154f && m_aWheelSpeed[1] > 0.0044f)
+ playRotorSound = true;
+ }
+
+ // Play rotor sound
+ if(playRotorSound && m_aCarNodes[CAR_BONNET]){
+ CVector camDist = TheCamera.GetPosition() - GetPosition();
+ float distSq = camDist.MagnitudeSqr();
+ if(distSq < SQR(20.0f) && Abs(m_fPropellerRotation - m_aWheelRotation[1]) > DEGTORAD(30.0f)){
+ CMatrix mat;
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_BONNET]));
+ CVector blade = mat.GetRight();
+ blade = GetMatrix() * blade;
+ camDist /= Max(Sqrt(distSq), 0.01f);
+ if(Abs(DotProduct(camDist, blade)) > 0.95f){
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_31, 0.0f);
+ m_fPropellerRotation = m_aWheelRotation[1];
+ }
+ }
}
}
@@ -1082,7 +1534,7 @@ CAutomobile::ProcessControl(void)
CParticle::AddParticle(PARTICLE_CARFLAME, damagePos,
CVector(0.0f, 0.0f, CGeneral::GetRandomNumberInRange(0.01125f, 0.09f)),
- nil, 0.9f);
+ nil, 0.63f);
CVector coors = damagePos;
coors.x += CGeneral::GetRandomNumberInRange(-0.5625f, 0.5625f),
@@ -1094,10 +1546,8 @@ CAutomobile::ProcessControl(void)
// Blow up car after 5 seconds
m_fFireBlowUpTimer += CTimer::GetTimeStepInMilliseconds();
- if(m_fFireBlowUpTimer > 5000.0f){
- CWorld::Players[CWorld::PlayerInFocus].AwardMoneyForExplosion(this);
+ if(m_fFireBlowUpTimer > 5000.0f)
BlowUpCar(m_pSetOnFireEntity);
- }
}else
m_fFireBlowUpTimer = 0.0f;
@@ -1109,7 +1559,7 @@ CAutomobile::ProcessControl(void)
if(m_bSirenOrAlarm && (CTimer::GetFrameCounter()&7) == 5 &&
- UsesSiren(GetModelIndex()) && GetModelIndex() != MI_MRWHOOP)
+ UsesSiren() && GetModelIndex() != MI_MRWHOOP)
CCarAI::MakeWayForCarWithSiren(this);
@@ -1117,10 +1567,14 @@ CAutomobile::ProcessControl(void)
float suspShake = 0.0f;
float surfShake = 0.0f;
+ float speedsq = m_vecMoveSpeed.MagnitudeSqr();
for(i = 0; i < 4; i++){
float suspChange = m_aSuspensionSpringRatioPrev[i] - m_aSuspensionSpringRatio[i];
- if(suspChange > 0.3f){
- DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_JUMP, suspChange);
+ if(suspChange > 0.3f && !drivingInSand && speedsq > 0.04f){
+ if(Damage.GetWheelStatus(i) == WHEEL_STATUS_BURST)
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_JUMP_2, suspChange);
+ else
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_JUMP, suspChange);
if(suspChange > suspShake)
suspShake = suspChange;
}
@@ -1129,7 +1583,7 @@ CAutomobile::ProcessControl(void)
if(surf == SURFACE_GRAVEL || surf == SURFACE_WATER || surf == SURFACE_HEDGE){
if(surfShake < 0.2f)
surfShake = 0.3f;
- }else if(surf == SURFACE_MUD_DRY || surf == SURFACE_SAND){
+ }else if(surf == SURFACE_MUD_DRY){
if(surfShake < 0.1f)
surfShake = 0.2f;
}else if(surf == SURFACE_GRASS){
@@ -1137,13 +1591,17 @@ CAutomobile::ProcessControl(void)
surfShake = 0.1f;
}
+ if(this == FindPlayerVehicle())
+// BUG: this only observes one of the wheels
+ TheCamera.m_bVehicleSuspenHigh = Abs(suspChange) > 0.05f;
+
m_aSuspensionSpringRatioPrev[i] = m_aSuspensionSpringRatio[i];
m_aSuspensionSpringRatio[i] = 1.0f;
}
// Shake pad
- if((suspShake > 0.0f || surfShake > 0.0f) && GetStatus() == STATUS_PLAYER){
+ if(!drivingInSand && (suspShake > 0.0f || surfShake > 0.0f) && GetStatus() == STATUS_PLAYER){
float speed = m_vecMoveSpeed.MagnitudeSqr();
if(speed > sq(0.1f)){
speed = Sqrt(speed);
@@ -1158,8 +1616,9 @@ CAutomobile::ProcessControl(void)
}
bVehicleColProcessed = false;
+ bAudioChangingGear = false;
- if(!bWarnedPeds)
+ if(!bWarnedPeds && GetVehicleAppearance() != VEHICLE_APPEARANCE_HELI && GetVehicleAppearance() != VEHICLE_APPEARANCE_PLANE)
CCarCtrl::ScanForPedDanger(this);
@@ -1167,20 +1626,20 @@ CAutomobile::ProcessControl(void)
// TODO: make the numbers defines
float heading;
- if(GetPosition().x > 1900.0f){
+ if(GetPosition().x > 1950.0f-400.0f){
if(m_vecMoveSpeed.x > 0.0f)
m_vecMoveSpeed.x *= -1.0f;
heading = GetForward().Heading();
if(heading > 0.0f) // going west
SetHeading(-heading);
- }else if(GetPosition().x < -1900.0f){
+ }else if(GetPosition().x < -1950.0f-400.0f){
if(m_vecMoveSpeed.x < 0.0f)
m_vecMoveSpeed.x *= -1.0f;
heading = GetForward().Heading();
if(heading < 0.0f) // going east
SetHeading(-heading);
}
- if(GetPosition().y > 1900.0f){
+ if(GetPosition().y > 1950.0f){
if(m_vecMoveSpeed.y > 0.0f)
m_vecMoveSpeed.y *= -1.0f;
heading = GetForward().Heading();
@@ -1188,7 +1647,7 @@ CAutomobile::ProcessControl(void)
SetHeading(PI-heading);
else if(heading > -HALFPI && heading < 0.0f)
SetHeading(-PI-heading);
- }else if(GetPosition().y < -1900.0f){
+ }else if(GetPosition().y < -1950.0f){
if(m_vecMoveSpeed.y < 0.0f)
m_vecMoveSpeed.y *= -1.0f;
heading = GetForward().Heading();
@@ -1207,11 +1666,31 @@ CAutomobile::ProcessControl(void)
(m_fGasPedal == 0.0f && brake == 0.0f || GetStatus() == STATUS_WRECKED)){
if(Abs(m_vecMoveSpeed.x) < 0.005f &&
Abs(m_vecMoveSpeed.y) < 0.005f &&
- Abs(m_vecMoveSpeed.z) < 0.005f){
+ Abs(m_vecMoveSpeed.z) < 0.005f &&
+ !(m_fDamageImpulse > 0.0f && m_pDamageEntity == FindPlayerPed()) &&
+ (m_aSuspensionSpringRatioPrev[0] < 1.0f && m_aSuspensionSpringRatioPrev[1] < 1.0f &&
+ m_aSuspensionSpringRatioPrev[2] < 1.0f && m_aSuspensionSpringRatioPrev[3] < 1.0f)){
m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f);
m_vecTurnSpeed.z = 0.0f;
}
}
+
+ if(IsRealHeli() && bHeliDestroyed && !bRenderScorched){
+ ApplyMoveForce(0.0f, 0.0f, -2.0f*CTimer::GetTimeStep());
+ m_vecTurnSpeed.z += -0.002f*CTimer::GetTimeStep();
+ m_vecTurnSpeed.x += -0.0002f*CTimer::GetTimeStep();
+
+ RwRGBA col = { 84, 84, 84, 255 };
+ CParticle::AddParticle(PARTICLE_ENGINE_SMOKE, GetMatrix()*CVector(0.0f, 0.0f, -10.0f),
+ CVector(0.0f, 0.0f, 0.0f), nil, 0.7f, col, 0, 0, 0, 3000);
+
+ if(CWorld::TestSphereAgainstWorld(GetPosition(), 10.0f, this, true, false, false, false, false, false) ||
+ GetPosition().z < 6.0f)
+ if(!bRenderScorched){ // we already know this is true...
+ CExplosion::AddExplosion(this, nil, EXPLOSION_CAR, GetPosition(), 0);
+ bRenderScorched = true;
+ }
+ }
}
void
@@ -1235,6 +1714,17 @@ CAutomobile::PreRender(void)
int i, j, n;
CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex());
+ if(GetModelIndex() == MI_RHINO && m_aCarNodes[CAR_BONNET]){
+ // Rotate Rhino turret
+ CMatrix m;
+ CVector p;
+ m.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_BONNET]));
+ p = m.GetPosition();
+ m.SetRotateZ(m_fCarGunLR);
+ m.Translate(p);
+ m.UpdateRW();
+ }
+
if(GetModelIndex() == MI_RCBANDIT){
CVector pos = GetMatrix() * CVector(0.218f, -0.444f, 0.391f);
CAntennas::RegisterOne((uintptr)this, GetUp(), pos, 1.0f);
@@ -1245,7 +1735,7 @@ CAutomobile::PreRender(void)
// Wheel particles
- if(GetModelIndex() == MI_DODO){
+ if(GetModelIndex() == MI_DODO || GetVehicleAppearance() != VEHICLE_APPEARANCE_CAR){
; // nothing
}else if(GetModelIndex() == MI_RCBANDIT){
for(i = 0; i < 4; i++){
@@ -1300,6 +1790,7 @@ CAutomobile::PreRender(void)
rearSkidding = true;
for(i = 0; i < 4; i++){
+ if(m_aSuspensionSpringRatioPrev[i] < 1.0f && m_aWheelColPoints[i].surfaceB != SURFACE_WATER)
switch(m_aWheelState[i]){
case WHEEL_STATE_SPINNING:
if(AddWheelDirtAndWater(&m_aWheelColPoints[i], drawParticles)){
@@ -1319,46 +1810,79 @@ CAutomobile::PreRender(void)
if(m_aWheelTimer[i] > 0.0f)
CSkidmarks::RegisterOne((uintptr)this + i, m_aWheelColPoints[i].point,
GetForward().x, GetForward().y,
- &m_aWheelSkidmarkMuddy[i], &m_aWheelSkidmarkBloody[i]);
+ m_aWheelSkidmarkType[i], &m_aWheelSkidmarkBloody[i]);
break;
case WHEEL_STATE_SKIDDING:
if(i == CARWHEEL_REAR_LEFT || i == CARWHEEL_REAR_RIGHT || rearSkidding){
// same as below
- AddWheelDirtAndWater(&m_aWheelColPoints[i], drawParticles);
+ if(Abs(fwdSpeed) > 5.0f){
+ AddWheelDirtAndWater(&m_aWheelColPoints[i], drawParticles);
- CParticle::AddParticle(PARTICLE_RUBBER_SMOKE,
- m_aWheelColPoints[i].point + CVector(0.0f, 0.0f, 0.25f),
- CVector(0.0f, 0.0f, 0.0f));
+ CParticle::AddParticle(PARTICLE_RUBBER_SMOKE,
+ m_aWheelColPoints[i].point + CVector(0.0f, 0.0f, 0.25f),
+ CVector(0.0f, 0.0f, 0.0f));
+ }
if(m_aWheelTimer[i] > 0.0f)
CSkidmarks::RegisterOne((uintptr)this + i, m_aWheelColPoints[i].point,
GetForward().x, GetForward().y,
- &m_aWheelSkidmarkMuddy[i], &m_aWheelSkidmarkBloody[i]);
+ m_aWheelSkidmarkType[i], &m_aWheelSkidmarkBloody[i]);
}
break;
case WHEEL_STATE_FIXED:
- AddWheelDirtAndWater(&m_aWheelColPoints[i], drawParticles);
+ if(Abs(fwdSpeed) > 5.0f){
+ AddWheelDirtAndWater(&m_aWheelColPoints[i], drawParticles);
- CParticle::AddParticle(PARTICLE_RUBBER_SMOKE,
- m_aWheelColPoints[i].point + CVector(0.0f, 0.0f, 0.25f),
- CVector(0.0f, 0.0f, 0.0f));
+ CParticle::AddParticle(PARTICLE_RUBBER_SMOKE,
+ m_aWheelColPoints[i].point + CVector(0.0f, 0.0f, 0.25f),
+ CVector(0.0f, 0.0f, 0.0f));
+ }
if(m_aWheelTimer[i] > 0.0f)
CSkidmarks::RegisterOne((uintptr)this + i, m_aWheelColPoints[i].point,
GetForward().x, GetForward().y,
- &m_aWheelSkidmarkMuddy[i], &m_aWheelSkidmarkBloody[i]);
+ m_aWheelSkidmarkType[i], &m_aWheelSkidmarkBloody[i]);
break;
default:
if(Abs(fwdSpeed) > 0.5f)
AddWheelDirtAndWater(&m_aWheelColPoints[i], drawParticles);
- if(m_aWheelSkidmarkBloody[i] && m_aWheelTimer[i] > 0.0f)
+ if((m_aWheelSkidmarkBloody[i] || m_aWheelSkidmarkUnk[i]) && m_aWheelTimer[i] > 0.0f)
CSkidmarks::RegisterOne((uintptr)this + i, m_aWheelColPoints[i].point,
GetForward().x, GetForward().y,
- &m_aWheelSkidmarkMuddy[i], &m_aWheelSkidmarkBloody[i]);
+ m_aWheelSkidmarkType[i], &m_aWheelSkidmarkBloody[i]);
+ }
+
+ // Sparks for friction of burst wheels
+ if(Damage.GetWheelStatus(i) == WHEEL_STATUS_BURST && m_aSuspensionSpringRatioPrev[i] < 1.0f){
+ static float speedSq;
+ speedSq = m_vecMoveSpeed.MagnitudeSqr();
+ if(speedSq > SQR(0.1f) &&
+ m_aWheelColPoints[i].surfaceB != SURFACE_GRASS &&
+ m_aWheelColPoints[i].surfaceB != SURFACE_MUD_DRY &&
+ m_aWheelColPoints[i].surfaceB != SURFACE_SAND &&
+ m_aWheelColPoints[i].surfaceB != SURFACE_SAND_BEACH &&
+ m_aWheelColPoints[i].surfaceB != SURFACE_WATER){
+ CVector normalSpeed = m_aWheelColPoints[i].normal * DotProduct(m_aWheelColPoints[i].normal, m_vecMoveSpeed);
+ CVector frictionSpeed = m_vecMoveSpeed - normalSpeed;
+ if(i == CARWHEEL_FRONT_LEFT || i == CARWHEEL_REAR_LEFT)
+ frictionSpeed -= 0.05f*GetRight();
+ else
+ frictionSpeed += 0.05f*GetRight();
+ CVector unusedRight = 0.15f*GetRight();
+ CVector sparkDir = 0.25f*frictionSpeed;
+ CParticle::AddParticle(PARTICLE_SPARK_SMALL, m_aWheelColPoints[i].point, sparkDir);
+
+ if(speedSq > 0.04f)
+ CParticle::AddParticle(PARTICLE_SPARK_SMALL, m_aWheelColPoints[i].point, sparkDir);
+ if(speedSq > 0.16f){
+ CParticle::AddParticle(PARTICLE_SPARK_SMALL, m_aWheelColPoints[i].point, sparkDir);
+ CParticle::AddParticle(PARTICLE_SPARK_SMALL, m_aWheelColPoints[i].point, sparkDir);
+ }
+ }
}
}
}
@@ -1381,7 +1905,7 @@ CAutomobile::PreRender(void)
CSkidmarks::RegisterOne((uintptr)this + CARWHEEL_REAR_LEFT,
m_aWheelColPoints[CARWHEEL_REAR_LEFT].point + offset,
GetForward().x, GetForward().y,
- &m_aWheelSkidmarkMuddy[CARWHEEL_REAR_LEFT], &m_aWheelSkidmarkBloody[CARWHEEL_REAR_LEFT]);
+ m_aWheelSkidmarkType[CARWHEEL_REAR_LEFT], &m_aWheelSkidmarkBloody[CARWHEEL_REAR_LEFT]);
break;
default: break;
}
@@ -1399,7 +1923,7 @@ CAutomobile::PreRender(void)
CSkidmarks::RegisterOne((uintptr)this + CARWHEEL_REAR_RIGHT,
m_aWheelColPoints[CARWHEEL_REAR_RIGHT].point + offset,
GetForward().x, GetForward().y,
- &m_aWheelSkidmarkMuddy[CARWHEEL_REAR_RIGHT], &m_aWheelSkidmarkBloody[CARWHEEL_REAR_RIGHT]);
+ m_aWheelSkidmarkType[CARWHEEL_REAR_RIGHT], &m_aWheelSkidmarkBloody[CARWHEEL_REAR_RIGHT]);
break;
default: break;
}
@@ -1434,21 +1958,22 @@ CAutomobile::PreRender(void)
AddDamagedVehicleParticles();
// Exhaust smoke
- if(bEngineOn && fwdSpeed < 90.0f){
+ if(bEngineOn && !(pHandling->Flags & HANDLING_NO_EXHAUST) && fwdSpeed < 130.0f){
CVector exhaustPos = mi->m_positions[CAR_POS_EXHAUST];
- CVector pos1, pos2, dir;
+ CVector pos1, pos2, dir1, dir2;
if(exhaustPos != CVector(0.0f, 0.0f, 0.0f)){
- dir.z = 0.0f;
+ dir1.z = 0.0f;
+ dir2.z = 0.0f;
if(fwdSpeed < 10.0f){
CVector steerFwd(-Sin(m_fSteerAngle), Cos(m_fSteerAngle), 0.0f);
steerFwd = Multiply3x3(GetMatrix(), steerFwd);
float r = CGeneral::GetRandomNumberInRange(-0.06f, -0.03f);
- dir.x = steerFwd.x * r;
- dir.y = steerFwd.y * r;
+ dir1.x = steerFwd.x * r;
+ dir1.y = steerFwd.y * r;
}else{
- dir.x = m_vecMoveSpeed.x;
- dir.y = m_vecMoveSpeed.y;
+ dir1.x = m_vecMoveSpeed.x;
+ dir1.y = m_vecMoveSpeed.y;
}
bool dblExhaust = false;
@@ -1458,17 +1983,62 @@ CAutomobile::PreRender(void)
pos2 = exhaustPos;
pos2.x = -pos2.x;
pos2 = GetMatrix() * pos2;
+ dir2 = dir1;
}
- n = 4.0f*m_fGasPedal;
- if(dblExhaust)
- for(i = 0; i <= n; i++){
- CParticle::AddParticle(PARTICLE_EXHAUST_FUMES, pos1, dir);
- CParticle::AddParticle(PARTICLE_EXHAUST_FUMES, pos2, dir);
+ static float fumesLimit = 2.0f;
+ if(CGeneral::GetRandomNumberInRange(1.0f, 3.0f)*(m_fGasPedal+1.1f) > fumesLimit)
+ for(i = 0; i < 4;){
+ CParticle::AddParticle(PARTICLE_EXHAUST_FUMES, pos1, dir1);
+ if(pHandling->Flags & HANDLING_DBL_EXHAUST)
+ CParticle::AddParticle(PARTICLE_EXHAUST_FUMES, pos2, dir2);
+
+ static float extraFumesLimit = 0.5f;
+ if(m_fGasPedal > extraFumesLimit && m_nCurrentGear < 3){
+ if(CGeneral::GetRandomNumber() & 1)
+ CParticle::AddParticle(PARTICLE_EXHAUST_FUMES, pos1, dir1);
+ else if(pHandling->Flags & HANDLING_DBL_EXHAUST)
+ CParticle::AddParticle(PARTICLE_EXHAUST_FUMES, pos2, dir2);
+ }
+
+ // Fire on Cuban hermes
+ if(GetModelIndex() == MI_CUBAN && i == 1 && m_fGasPedal > 0.9f){
+ if(m_nCurrentGear == 1 || m_nCurrentGear == 3 && (CTimer::GetTimeInMilliseconds()%1500) > 750){
+ if(CGeneral::GetRandomNumber() & 1){
+ CParticle::AddParticle(PARTICLE_FIREBALL, pos1, dir1, nil, 0.05f, 0, 0, 2, 200);
+ CParticle::AddParticle(PARTICLE_FIREBALL, pos1, dir1, nil, 0.05f, 0, 0, 2, 200);
+ }else{
+ CParticle::AddParticle(PARTICLE_FIREBALL, pos2, dir2, nil, 0.05f, 0, 0, 2, 200);
+ CParticle::AddParticle(PARTICLE_FIREBALL, pos2, dir2, nil, 0.05f, 0, 0, 2, 200);
+ }
+ }
+ }
+
+ if(GetStatus() == STATUS_PLAYER && (CTimer::GetFrameCounter()&3) == 0 &&
+ CWeather::Rain == 0.0f && i == 0){
+ CVector camDist = GetPosition() - TheCamera.GetPosition();
+ if(DotProduct(GetForward(), camDist) > 0.0f ||
+ TheCamera.GetLookDirection() == LOOKING_LEFT ||
+ TheCamera.GetLookDirection() == LOOKING_RIGHT){
+ CParticle::AddParticle(PARTICLE_HEATHAZE, pos1, CVector(0.0f, 0.0f, 0.0f));
+ if(pHandling->Flags & HANDLING_DBL_EXHAUST)
+ CParticle::AddParticle(PARTICLE_HEATHAZE, pos2, CVector(0.0f, 0.0f, 0.0f));
+
+ CParticle::AddParticle(PARTICLE_HEATHAZE, pos1, CVector(0.0f, 0.0f, 0.0f));
+ if(pHandling->Flags & HANDLING_DBL_EXHAUST)
+ CParticle::AddParticle(PARTICLE_HEATHAZE, pos2, CVector(0.0f, 0.0f, 0.0f));
+ }
+ }
+
+ if(GetModelIndex() == MI_CUBAN && i < 1){
+ i = 1;
+ pos1 = GetMatrix() * CVector(1.134f, -1.276f, -0.56f);
+ pos2 = GetMatrix() * CVector(-1.134f, -1.276f, -0.56f);
+ dir1 += 0.05f*GetRight();
+ dir2 -= 0.05f*GetRight();
+ }else
+ i = 99;
}
- else
- for(i = 0; i <= n; i++)
- CParticle::AddParticle(PARTICLE_EXHAUST_FUMES, pos1, dir);
}
}
@@ -1540,8 +2110,8 @@ CAutomobile::PreRender(void)
float angle = (CTimer::GetTimeInMilliseconds() & 0x3FF)*TWOPI/0x3FF;
float s = 8.0f*Sin(angle);
float c = 8.0f*Cos(angle);
- CShadows::StoreCarLightShadow(this, (uintptr)this + 21, gpShadowHeadLightsTex,
- &pos, c, s, s, -c, r, g, b, 8.0f);
+ //CShadows::StoreCarLightShadow(this, (uintptr)this + 21, gpShadowHeadLightsTex,
+ // &pos, c, s, s, -c, r, g, b, 8.0f);
CPointLights::AddLight(CPointLights::LIGHT_POINT,
pos + GetUp()*2.0f, CVector(0.0f, 0.0f, 0.0f), 12.0f,
@@ -1579,17 +2149,26 @@ CAutomobile::PreRender(void)
}
break;
- case MI_FBICAR:
+ case MI_FBIRANCH:
+ case MI_VICECHEE:
if(m_bSirenOrAlarm){
CVector pos = GetMatrix() * CVector(0.4f, 0.6f, 0.3f);
if(CTimer::GetTimeInMilliseconds() & 0x100 &&
DotProduct(GetForward(), GetPosition() - TheCamera.GetPosition()) < 0.0f)
- CCoronas::RegisterCorona((uintptr)this + 21,
- 0, 0, 255, 255,
- pos, 0.4f, 50.0f,
- CCoronas::TYPE_STAR,
- CCoronas::FLARE_NONE,
- CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+ if(GetModelIndex() == MI_VICECHEE)
+ CCoronas::RegisterCorona((uintptr)this + 21,
+ 255, 70, 70, 255,
+ pos, 0.4f, 50.0f,
+ CCoronas::TYPE_STAR,
+ CCoronas::FLARE_NONE,
+ CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+ else
+ CCoronas::RegisterCorona((uintptr)this + 21,
+ 0, 0, 255, 255,
+ pos, 0.4f, 50.0f,
+ CCoronas::TYPE_STAR,
+ CCoronas::FLARE_NONE,
+ CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
else
CCoronas::UpdateCoronaCoors((uintptr)this + 21, pos, 50.0f, 0.0f);
}
@@ -1597,7 +2176,8 @@ CAutomobile::PreRender(void)
case MI_TAXI:
case MI_CABBIE:
- case MI_BORGNINE:
+ case MI_ZEBRA:
+ case MI_KAUFMAN:
if(bTaxiLight){
CVector pos = GetPosition() + GetUp()*0.95f;
CCoronas::RegisterCorona((uintptr)this + 21,
@@ -1614,7 +2194,8 @@ CAutomobile::PreRender(void)
}
if(GetModelIndex() != MI_RCBANDIT && GetModelIndex() != MI_DODO &&
- GetModelIndex() != MI_RHINO) {
+ GetModelIndex() != MI_RHINO && GetModelIndex() != MI_RCBARON &&
+ GetVehicleAppearance() != VEHICLE_APPEARANCE_HELI) {
// Process lights
// Turn lights on/off
@@ -1653,7 +2234,6 @@ CAutomobile::PreRender(void)
lookVector = CVector(1.0f, 0.0f, 0.0f);
// 1.0 if directly behind car, -1.0 if in front
- // BUG on PC: Abs of DotProduct is taken
float behindness = DotProduct(lookVector, GetForward());
behindness = clamp(behindness, -1.0f, 1.0f); // shouldn't be necessary
// 0.0 if behind car, PI if in front
@@ -1668,7 +2248,8 @@ CAutomobile::PreRender(void)
lightL -= GetRight()*2.0f*headLightPos.x;
// Headlight coronas
- if(behindness < 0.0f){
+ if(DotProduct(lightR-TheCamera.GetPosition(), GetForward()) < 0.0f &&
+ (TheCamera.Cams[TheCamera.ActiveCam].Mode != CCam::MODE_1STPERSON || this != FindPlayerVehicle())){
// In front of car
float intensity = -0.5f*behindness + 0.3f;
float size = 1.0f - behindness;
@@ -1758,7 +2339,7 @@ CAutomobile::PreRender(void)
lightL -= GetRight()*2.0f*tailLightPos.x;
// Taillight coronas
- if(behindness > 0.0f){
+ if(DotProduct(lightR-TheCamera.GetPosition(), GetForward()) > 0.0f){
// Behind car
float intensity = 0.4f*behindness + 0.4f;
float size = (behindness + 1.0f)/2.0f;
@@ -1832,7 +2413,7 @@ CAutomobile::PreRender(void)
if(Damage.GetLightStatus(VEHLIGHT_FRONT_LEFT) == LIGHT_STATUS_OK ||
Damage.GetLightStatus(VEHLIGHT_FRONT_RIGHT) == LIGHT_STATUS_OK)
CShadows::StoreCarLightShadow(this, (uintptr)this + 22, gpShadowHeadLightsTex, &pos,
- 7.0f*fwd.x, 7.0f*fwd.y, 7.0f*fwd.y, -7.0f*fwd.x, 45, 45, 45, 7.0f);
+ 7.0f*fwd.x, 7.0f*fwd.y, 5.5f*fwd.y, -5.5f*fwd.x, 45, 45, 45, 7.0f);
f = (tailLightPos.y - 2.5f) - (headLightPos.y + 6.0f);
pos += CVector(f*fwd.x, f*fwd.y, 0.0f);
@@ -1924,26 +2505,39 @@ CAutomobile::PreRender(void)
// end of lights
}
+//TODO(MIAMI): StoreShadowForVehicle once we have it
CShadows::StoreShadowForCar(this);
-}
-void
-CAutomobile::Render(void)
-{
- int i;
+ DoSunGlare();
+
+ // Heli dust
+ if(IsRealHeli() && m_aWheelSpeed[1] > 0.1125f && GetPosition().z < 30.0f){
+ bool foundGround = false;
+ float waterZ = -1000.0f;
+ float groundZ = CWorld::FindGroundZFor3DCoord(GetPosition().x, GetPosition().y, GetPosition().z, &foundGround);
+ if(!CWaterLevel::GetWaterLevel(GetPosition(), &waterZ, false))
+ waterZ = 0.0f;
+ groundZ = Max(groundZ, waterZ);
+ float rnd = (m_aWheelSpeed[1]-0.1125f)*((int)Max(16.0f-4.0f*CTimer::GetTimeStep(),2.0f))*400.0f/43.0f;
+ float radius = 10.0f;
+ if(GetModelIndex() == MI_RCGOBLIN || GetModelIndex() == MI_RCRAIDER)
+ radius = 3.0f;
+ if(GetPosition().z - groundZ < radius)
+ HeliDustGenerate(this, radius-(GetPosition().z - groundZ), groundZ, Ceil(rnd));
+ }
+
CMatrix mat;
CVector pos;
- CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex());
- if(GetModelIndex() == MI_RHINO && m_aCarNodes[CAR_BONNET]){
- // Rotate Rhino turret
- CMatrix m;
- CVector p;
- m.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_BONNET]));
- p = m.GetPosition();
- m.SetRotateZ(m_fCarGunLR);
- m.Translate(p);
- m.UpdateRW();
+ bool onlyFrontWheels = false;
+ if(IsRealHeli()){
+ // top rotor
+ m_aWheelRotation[1] += m_aWheelSpeed[1]*CTimer::GetTimeStep();
+ if(m_aWheelRotation[1] > TWOPI) m_aWheelRotation[1] -= TWOPI;
+ // rear rotor
+ m_aWheelRotation[3] += m_aWheelSpeed[1]*CTimer::GetTimeStep();
+ if(m_aWheelRotation[3] > TWOPI) m_aWheelRotation[3] -= TWOPI;
+ onlyFrontWheels = true;
}
CVector contactPoints[4]; // relative to model
@@ -1951,7 +2545,7 @@ CAutomobile::Render(void)
CVector frontWheelFwd = Multiply3x3(GetMatrix(), CVector(-Sin(m_fSteerAngle), Cos(m_fSteerAngle), 0.0f));
CVector rearWheelFwd = GetForward();
for(i = 0; i < 4; i++){
- if (m_aWheelTimer[i] > 0.0f) {
+ if (m_aWheelTimer[i] > 0.0f && (!onlyFrontWheels || i == CARWHEEL_FRONT_LEFT || i == CARWHEEL_FRONT_RIGHT)) {
contactPoints[i] = m_aWheelColPoints[i].point - GetPosition();
contactSpeeds[i] = GetSpeed(contactPoints[i]);
if (i == CARWHEEL_FRONT_LEFT || i == CARWHEEL_FRONT_RIGHT)
@@ -1962,75 +2556,146 @@ CAutomobile::Render(void)
}
}
+ RwRGBA hoverParticleCol = { 255, 255, 255, 32 };
+
// Rear right wheel
mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RB]));
- pos.x = mat.GetPosition().x;
- pos.y = mat.GetPosition().y;
+ pos = mat.GetPosition();
pos.z = m_aWheelPosition[CARWHEEL_REAR_RIGHT];
if(Damage.GetWheelStatus(CARWHEEL_REAR_RIGHT) == WHEEL_STATUS_BURST)
mat.SetRotate(m_aWheelRotation[CARWHEEL_REAR_RIGHT], 0.0f, 0.3f*Sin(m_aWheelRotation[CARWHEEL_REAR_RIGHT]));
else
mat.SetRotateX(m_aWheelRotation[CARWHEEL_REAR_RIGHT]);
- mat.Scale(mi->m_wheelScale);
+ if(GetStatus() == STATUS_PLAYER){
+ if(bHoverCheat && m_aSuspensionSpringRatioPrev[CARWHEEL_REAR_RIGHT] < 1.0f &&
+ m_aWheelColPoints[CARWHEEL_REAR_RIGHT].surfaceB == SURFACE_WATER){
+ // hovering on water
+ mat.RotateY(-HALFPI);
+ if((CTimer::GetFrameCounter()+CARWHEEL_REAR_RIGHT) & 1){
+ CParticle::AddParticle(PARTICLE_STEAM_NY_SLOWMOTION, m_aWheelColPoints[CARWHEEL_REAR_RIGHT].point,
+ 0.5f*m_vecMoveSpeed+0.1f*GetRight(), nil, 0.4f, hoverParticleCol);
+ }else{
+ CParticle::AddParticle(PARTICLE_CAR_SPLASH, m_aWheelColPoints[CARWHEEL_REAR_RIGHT].point,
+ 0.3f*m_vecMoveSpeed+0.15f*GetRight()+CVector(0.0f, 0.0f, 0.1f), nil, 0.15f, hoverParticleCol,
+ CGeneral::GetRandomNumberInRange(0.0f, 90.0f),
+ CGeneral::GetRandomNumberInRange(0.0f, 10.0f), 1);
+ }
+ }else{
+ // tilt wheel depending oh how much it presses on ground
+ float groundOffset = pos.z + m_fHeightAboveRoad - 0.5f*mi->m_wheelScale;
+ if(GetModelIndex() == MI_VOODOO)
+ groundOffset *= 0.6f;
+ mat.RotateY(Asin(clamp(-groundOffset, -1.0f, 1.0f)));
+ }
+ }
+ if(pHandling->Flags & HANDLING_FAT_REARW)
+ mat.Scale(1.15f*mi->m_wheelScale, mi->m_wheelScale, mi->m_wheelScale);
+ else
+ mat.Scale(mi->m_wheelScale);
mat.Translate(pos);
mat.UpdateRW();
- if(CVehicle::bWheelsOnlyCheat)
- RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RB]));
// Rear left wheel
mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_LB]));
- pos.x = mat.GetPosition().x;
- pos.y = mat.GetPosition().y;
+ pos = mat.GetPosition();
pos.z = m_aWheelPosition[CARWHEEL_REAR_LEFT];
if(Damage.GetWheelStatus(CARWHEEL_REAR_LEFT) == WHEEL_STATUS_BURST)
- mat.SetRotate(-m_aWheelRotation[CARWHEEL_REAR_LEFT], 0.0f, PI+0.3f*Sin(-m_aWheelRotation[CARWHEEL_REAR_LEFT]));
+ mat.SetRotate(-m_aWheelRotation[CARWHEEL_REAR_LEFT], 0.0f, PI+0.3f*Sin(m_aWheelRotation[CARWHEEL_REAR_LEFT]));
else
mat.SetRotate(-m_aWheelRotation[CARWHEEL_REAR_LEFT], 0.0f, PI);
- mat.Scale(mi->m_wheelScale);
+ if(GetStatus() == STATUS_PLAYER){
+ if(bHoverCheat && m_aSuspensionSpringRatioPrev[CARWHEEL_REAR_LEFT] < 1.0f &&
+ m_aWheelColPoints[CARWHEEL_REAR_LEFT].surfaceB == SURFACE_WATER){
+ // hovering on water
+ mat.RotateY(HALFPI);
+ if((CTimer::GetFrameCounter()+CARWHEEL_REAR_LEFT) & 1){
+ CParticle::AddParticle(PARTICLE_STEAM_NY_SLOWMOTION, m_aWheelColPoints[CARWHEEL_REAR_LEFT].point,
+ 0.5f*m_vecMoveSpeed-0.1f*GetRight(), nil, 0.4f, hoverParticleCol);
+ }else{
+ CParticle::AddParticle(PARTICLE_CAR_SPLASH, m_aWheelColPoints[CARWHEEL_REAR_LEFT].point,
+ 0.3f*m_vecMoveSpeed-0.15f*GetRight()+CVector(0.0f, 0.0f, 0.1f), nil, 0.15f, hoverParticleCol,
+ CGeneral::GetRandomNumberInRange(0.0f, 90.0f),
+ CGeneral::GetRandomNumberInRange(0.0f, 10.0f), 1);
+ }
+ }else{
+ // tilt wheel depending oh how much it presses on ground
+ float groundOffset = pos.z + m_fHeightAboveRoad - 0.5f*mi->m_wheelScale;
+ if(GetModelIndex() == MI_VOODOO)
+ groundOffset *= 0.6f;
+ mat.RotateY(Asin(clamp(groundOffset, -1.0f, 1.0f)));
+ }
+ }
+ if(pHandling->Flags & HANDLING_FAT_REARW)
+ mat.Scale(1.15f*mi->m_wheelScale, mi->m_wheelScale, mi->m_wheelScale);
+ else
+ mat.Scale(mi->m_wheelScale);
mat.Translate(pos);
mat.UpdateRW();
- if(CVehicle::bWheelsOnlyCheat)
- RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LB]));
// Mid right wheel
if(m_aCarNodes[CAR_WHEEL_RM]){
mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RM]));
- pos.x = mat.GetPosition().x;
- pos.y = mat.GetPosition().y;
+ pos = mat.GetPosition();
pos.z = m_aWheelPosition[CARWHEEL_REAR_RIGHT];
if(Damage.GetWheelStatus(CARWHEEL_REAR_RIGHT) == WHEEL_STATUS_BURST)
mat.SetRotate(m_aWheelRotation[CARWHEEL_REAR_RIGHT], 0.0f, 0.3f*Sin(m_aWheelRotation[CARWHEEL_REAR_RIGHT]));
else
mat.SetRotateX(m_aWheelRotation[CARWHEEL_REAR_RIGHT]);
- mat.Scale(mi->m_wheelScale);
+ if(GetStatus() == STATUS_PLAYER){
+ if(bHoverCheat && m_aSuspensionSpringRatioPrev[CARWHEEL_REAR_RIGHT] < 1.0f &&
+ m_aWheelColPoints[CARWHEEL_REAR_RIGHT].surfaceB == SURFACE_WATER){
+ // hovering on water
+ mat.RotateY(-HALFPI);
+ }else{
+ // tilt wheel depending oh how much it presses on ground
+ float groundOffset = pos.z + m_fHeightAboveRoad - 0.5f*mi->m_wheelScale;
+ if(GetModelIndex() == MI_VOODOO)
+ groundOffset *= 0.6f;
+ mat.RotateY(Asin(clamp(-groundOffset, -1.0f, 1.0f)));
+ }
+ }
+ if(pHandling->Flags & HANDLING_FAT_REARW)
+ mat.Scale(1.15f*mi->m_wheelScale, mi->m_wheelScale, mi->m_wheelScale);
+ else
+ mat.Scale(mi->m_wheelScale);
mat.Translate(pos);
mat.UpdateRW();
- if(CVehicle::bWheelsOnlyCheat)
- RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RM]));
}
// Mid left wheel
if(m_aCarNodes[CAR_WHEEL_LM]){
mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_LM]));
- pos.x = mat.GetPosition().x;
- pos.y = mat.GetPosition().y;
+ pos = mat.GetPosition();
pos.z = m_aWheelPosition[CARWHEEL_REAR_LEFT];
if(Damage.GetWheelStatus(CARWHEEL_REAR_LEFT) == WHEEL_STATUS_BURST)
- mat.SetRotate(-m_aWheelRotation[CARWHEEL_REAR_LEFT], 0.0f, PI+0.3f*Sin(-m_aWheelRotation[CARWHEEL_REAR_LEFT]));
+ mat.SetRotate(-m_aWheelRotation[CARWHEEL_REAR_LEFT], 0.0f, PI+0.3f*Sin(m_aWheelRotation[CARWHEEL_REAR_LEFT]));
else
mat.SetRotate(-m_aWheelRotation[CARWHEEL_REAR_LEFT], 0.0f, PI);
- mat.Scale(mi->m_wheelScale);
+ if(GetStatus() == STATUS_PLAYER){
+ if(bHoverCheat && m_aSuspensionSpringRatioPrev[CARWHEEL_REAR_LEFT] < 1.0f &&
+ m_aWheelColPoints[CARWHEEL_REAR_LEFT].surfaceB == SURFACE_WATER){
+ // hovering on water
+ mat.RotateY(HALFPI);
+ }else{
+ // tilt wheel depending oh how much it presses on ground
+ float groundOffset = pos.z + m_fHeightAboveRoad - 0.5f*mi->m_wheelScale;
+ if(GetModelIndex() == MI_VOODOO)
+ groundOffset *= 0.6f;
+ mat.RotateY(Asin(clamp(groundOffset, -1.0f, 1.0f)));
+ }
+ }
+ if(pHandling->Flags & HANDLING_FAT_REARW)
+ mat.Scale(1.15f*mi->m_wheelScale, mi->m_wheelScale, mi->m_wheelScale);
+ else
+ mat.Scale(mi->m_wheelScale);
mat.Translate(pos);
mat.UpdateRW();
- if(CVehicle::bWheelsOnlyCheat)
- RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LM]));
}
if(GetModelIndex() == MI_DODO){
// Front wheel
mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RF]));
- pos.x = mat.GetPosition().x;
- pos.y = mat.GetPosition().y;
+ pos = mat.GetPosition();
pos.z = m_aWheelPosition[CARWHEEL_FRONT_RIGHT];
if(Damage.GetWheelStatus(CARWHEEL_FRONT_RIGHT) == WHEEL_STATUS_BURST)
mat.SetRotate(m_aWheelRotation[CARWHEEL_FRONT_RIGHT], 0.0f, m_fSteerAngle+0.3f*Sin(m_aWheelRotation[CARWHEEL_FRONT_RIGHT]));
@@ -2039,8 +2704,6 @@ CAutomobile::Render(void)
mat.Scale(mi->m_wheelScale);
mat.Translate(pos);
mat.UpdateRW();
- if(CVehicle::bWheelsOnlyCheat)
- RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RF]));
// Rotate propeller
if(m_aCarNodes[CAR_WINDSCREEN]){
@@ -2070,59 +2733,130 @@ CAutomobile::Render(void)
}else if(GetModelIndex() == MI_RHINO){
// Front right wheel
mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RF]));
- pos.x = mat.GetPosition().x;
- pos.y = mat.GetPosition().y;
+ pos = mat.GetPosition();
pos.z = m_aWheelPosition[CARWHEEL_FRONT_RIGHT];
// no damaged wheels or steering
mat.SetRotate(m_aWheelRotation[CARWHEEL_FRONT_RIGHT], 0.0f, 0.0f);
mat.Scale(mi->m_wheelScale);
mat.Translate(pos);
mat.UpdateRW();
- if(CVehicle::bWheelsOnlyCheat)
- RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RF]));
// Front left wheel
mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_LF]));
- pos.x = mat.GetPosition().x;
- pos.y = mat.GetPosition().y;
+ pos = mat.GetPosition();
pos.z = m_aWheelPosition[CARWHEEL_FRONT_LEFT];
// no damaged wheels or steering
mat.SetRotate(-m_aWheelRotation[CARWHEEL_FRONT_LEFT], 0.0f, PI);
mat.Scale(mi->m_wheelScale);
mat.Translate(pos);
mat.UpdateRW();
- if(CVehicle::bWheelsOnlyCheat)
- RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LF]));
+ }else if(IsRealHeli()){
+ // Top rotor
+ if(m_aCarNodes[CAR_BONNET]){
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_BONNET]));
+ pos = mat.GetPosition();
+ mat.SetRotateZ(m_aWheelRotation[1]);
+ mat.Translate(pos);
+ mat.UpdateRW();
+ }
+ // Blurred top rotor
+ if(m_aCarNodes[CAR_WINDSCREEN]){
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WINDSCREEN]));
+ pos = mat.GetPosition();
+ mat.SetRotateZ(-m_aWheelRotation[1]);
+ mat.Translate(pos);
+ mat.UpdateRW();
+ }
+ // Rear rotor
+ if(m_aCarNodes[CAR_BOOT]){
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_BOOT]));
+ pos = mat.GetPosition();
+ mat.SetRotateX(m_aWheelRotation[3]);
+ mat.Translate(pos);
+ mat.UpdateRW();
+ }
+ // Blurred rear rotor
+ if(m_aCarNodes[CAR_BUMP_REAR]){
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_BUMP_REAR]));
+ pos = mat.GetPosition();
+ mat.SetRotateX(-m_aWheelRotation[3]);
+ mat.Translate(pos);
+ mat.UpdateRW();
+ }
}else{
// Front right wheel
mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RF]));
- pos.x = mat.GetPosition().x;
- pos.y = mat.GetPosition().y;
+ pos = mat.GetPosition();
pos.z = m_aWheelPosition[CARWHEEL_FRONT_RIGHT];
if(Damage.GetWheelStatus(CARWHEEL_FRONT_RIGHT) == WHEEL_STATUS_BURST)
mat.SetRotate(m_aWheelRotation[CARWHEEL_FRONT_RIGHT], 0.0f, m_fSteerAngle+0.3f*Sin(m_aWheelRotation[CARWHEEL_FRONT_RIGHT]));
else
mat.SetRotate(m_aWheelRotation[CARWHEEL_FRONT_RIGHT], 0.0f, m_fSteerAngle);
- mat.Scale(mi->m_wheelScale);
+ if(GetStatus() == STATUS_PLAYER){
+ if(bHoverCheat && m_aSuspensionSpringRatioPrev[CARWHEEL_FRONT_RIGHT] < 1.0f &&
+ m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].surfaceB == SURFACE_WATER){
+ // hovering on water
+ mat.RotateY(-HALFPI);
+ if((CTimer::GetFrameCounter()+CARWHEEL_FRONT_RIGHT) & 1){
+ CParticle::AddParticle(PARTICLE_STEAM_NY_SLOWMOTION, m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].point,
+ 0.5f*m_vecMoveSpeed+0.1f*GetRight(), nil, 0.4f, hoverParticleCol);
+ }else{
+ CParticle::AddParticle(PARTICLE_CAR_SPLASH, m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].point,
+ 0.3f*m_vecMoveSpeed+0.15f*GetRight()+CVector(0.0f, 0.0f, 0.1f), nil, 0.15f, hoverParticleCol,
+ CGeneral::GetRandomNumberInRange(0.0f, 90.0f),
+ CGeneral::GetRandomNumberInRange(0.0f, 10.0f), 1);
+ }
+ }else{
+ // tilt wheel depending oh how much it presses on ground
+ float groundOffset = pos.z + m_fHeightAboveRoad - 0.5f*mi->m_wheelScale;
+ if(GetModelIndex() == MI_VOODOO)
+ groundOffset *= 0.6f;
+ mat.RotateY(Asin(clamp(-groundOffset, -1.0f, 1.0f)));
+ }
+ }
+ if(pHandling->Flags & HANDLING_NARROW_FRONTW)
+ mat.Scale(0.7f*mi->m_wheelScale, mi->m_wheelScale, mi->m_wheelScale);
+ else
+ mat.Scale(mi->m_wheelScale);
mat.Translate(pos);
mat.UpdateRW();
- if(CVehicle::bWheelsOnlyCheat)
- RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RF]));
// Front left wheel
mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_LF]));
- pos.x = mat.GetPosition().x;
- pos.y = mat.GetPosition().y;
+ pos = mat.GetPosition();
pos.z = m_aWheelPosition[CARWHEEL_FRONT_LEFT];
if(Damage.GetWheelStatus(CARWHEEL_FRONT_LEFT) == WHEEL_STATUS_BURST)
- mat.SetRotate(-m_aWheelRotation[CARWHEEL_FRONT_LEFT], 0.0f, PI+m_fSteerAngle+0.3f*Sin(-m_aWheelRotation[CARWHEEL_FRONT_LEFT]));
+ mat.SetRotate(-m_aWheelRotation[CARWHEEL_FRONT_LEFT], 0.0f, PI+m_fSteerAngle+0.3f*Sin(m_aWheelRotation[CARWHEEL_FRONT_LEFT]));
else
mat.SetRotate(-m_aWheelRotation[CARWHEEL_FRONT_LEFT], 0.0f, PI+m_fSteerAngle);
- mat.Scale(mi->m_wheelScale);
+ if(GetStatus() == STATUS_PLAYER){
+ if(bHoverCheat && m_aSuspensionSpringRatioPrev[CARWHEEL_FRONT_LEFT] < 1.0f &&
+ m_aWheelColPoints[CARWHEEL_FRONT_LEFT].surfaceB == SURFACE_WATER){
+ // hovering on water
+ mat.RotateY(HALFPI);
+ if((CTimer::GetFrameCounter()+CARWHEEL_FRONT_LEFT) & 1){
+ CParticle::AddParticle(PARTICLE_STEAM_NY_SLOWMOTION, m_aWheelColPoints[CARWHEEL_FRONT_LEFT].point,
+ 0.5f*m_vecMoveSpeed-0.1f*GetRight(), nil, 0.4f, hoverParticleCol);
+ }else{
+ CParticle::AddParticle(PARTICLE_CAR_SPLASH, m_aWheelColPoints[CARWHEEL_FRONT_LEFT].point,
+ 0.3f*m_vecMoveSpeed-0.15f*GetRight()+CVector(0.0f, 0.0f, 0.1f), nil, 0.15f, hoverParticleCol,
+ CGeneral::GetRandomNumberInRange(0.0f, 90.0f),
+ CGeneral::GetRandomNumberInRange(0.0f, 10.0f), 1);
+ }
+ }else{
+ // tilt wheel depending oh how much it presses on ground
+ float groundOffset = pos.z + m_fHeightAboveRoad - 0.5f*mi->m_wheelScale;
+ if(GetModelIndex() == MI_VOODOO)
+ groundOffset *= 0.6f;
+ mat.RotateY(Asin(clamp(groundOffset, -1.0f, 1.0f)));
+ }
+ }
+ if(pHandling->Flags & HANDLING_NARROW_FRONTW)
+ mat.Scale(0.7f*mi->m_wheelScale, mi->m_wheelScale, mi->m_wheelScale);
+ else
+ mat.Scale(mi->m_wheelScale);
mat.Translate(pos);
mat.UpdateRW();
- if(CVehicle::bWheelsOnlyCheat)
- RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LF]));
ProcessSwingingDoor(CAR_DOOR_LF, DOOR_FRONT_LEFT);
ProcessSwingingDoor(CAR_DOOR_RF, DOOR_FRONT_RIGHT);
@@ -2130,11 +2864,104 @@ CAutomobile::Render(void)
ProcessSwingingDoor(CAR_DOOR_RR, DOOR_REAR_RIGHT);
ProcessSwingingDoor(CAR_BONNET, DOOR_BONNET);
ProcessSwingingDoor(CAR_BOOT, DOOR_BOOT);
+ }
+
+ if((GetModelIndex() == MI_PHEONIX || GetModelIndex() == MI_BFINJECT) &&
+ GetStatus() == STATUS_PLAYER && m_aCarNodes[CAR_WING_LR]){
+ float rotation = 0.0f;
+
+ if(GetModelIndex() == MI_BFINJECT)
+ if(m_fPropellerRotation > TWOPI) m_fPropellerRotation -= TWOPI;
+
+ if(Abs(m_fGasPedal) > 0.0f){
+ if(GetModelIndex() == MI_BFINJECT){
+ m_fPropellerRotation += 0.2f*CTimer::GetTimeStep();
+ rotation = m_fPropellerRotation;
+ }else{
+ if(m_fPropellerRotation < 1.3f){
+ m_fPropellerRotation = Min(m_fPropellerRotation+0.1f*CTimer::GetTimeStep(), 1.3f);
+ rotation = m_fPropellerRotation;
+ }else{
+ float wave = Sin((CTimer::GetTimeInMilliseconds()%10000)/70.0f);
+ rotation = m_fPropellerRotation + 0.13*wave;
+ }
+ }
+ }else{
+ if(GetModelIndex() == MI_BFINJECT){
+ m_fPropellerRotation += 0.1f*CTimer::GetTimeStep();
+ rotation = m_fPropellerRotation;
+ }else{
+ if(m_fPropellerRotation > 0.0f){
+ m_fPropellerRotation = Max(m_fPropellerRotation-0.05f*CTimer::GetTimeStep(), 0.0f);
+ rotation = m_fPropellerRotation;
+ }
+ }
+ }
+
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WING_LR]));
+ pos = mat.GetPosition();
+ if(GetModelIndex() == MI_BFINJECT)
+ mat.SetRotateY(rotation);
+ else
+ mat.SetRotateX(rotation);
+ mat.Translate(pos);
+ mat.UpdateRW();
+ }
+}
- mi->SetVehicleColour(m_currentColour1, m_currentColour2);
+void
+CAutomobile::Render(void)
+{
+ CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex());
+
+ mi->SetVehicleColour(m_currentColour1, m_currentColour2);
+
+ if(IsRealHeli()){
+ RpAtomic *atomic = nil;
+ int rotorAlpha = (1.5f - Min(1.7f*Max(m_aWheelSpeed[1],0.0f)/0.22f, 1.5f))*255.0f;
+ rotorAlpha = Min(rotorAlpha, 255);
+ int blurAlpha = Max(1.5f*m_aWheelSpeed[1]/0.22f - 0.4f, 0.0f)*150.0f;
+ blurAlpha = Min(blurAlpha, 150);
+
+ // Top rotor
+ if(m_aCarNodes[CAR_BONNET]){
+ RwFrameForAllObjects(m_aCarNodes[CAR_BONNET], GetCurrentAtomicObjectCB, &atomic);
+ if(atomic)
+ SetComponentAtomicAlpha(atomic, rotorAlpha);
+ }
+ atomic = nil;
+ // Rear rotor
+ if(m_aCarNodes[CAR_BOOT]){
+ RwFrameForAllObjects(m_aCarNodes[CAR_BOOT], GetCurrentAtomicObjectCB, &atomic);
+ if(atomic)
+ SetComponentAtomicAlpha(atomic, rotorAlpha);
+ }
+ atomic = nil;
+ // Blurred top rotor
+ if(m_aCarNodes[CAR_WINDSCREEN]){
+ RwFrameForAllObjects(m_aCarNodes[CAR_WINDSCREEN], GetCurrentAtomicObjectCB, &atomic);
+ if(atomic)
+ SetComponentAtomicAlpha(atomic, blurAlpha);
+ }
+ atomic = nil;
+ // Blurred rear rotor
+ if(m_aCarNodes[CAR_BUMP_REAR]){
+ RwFrameForAllObjects(m_aCarNodes[CAR_BUMP_REAR], GetCurrentAtomicObjectCB, &atomic);
+ if(atomic)
+ SetComponentAtomicAlpha(atomic, blurAlpha);
+ }
}
- if(!CVehicle::bWheelsOnlyCheat)
+ if(CVehicle::bWheelsOnlyCheat){
+ RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RB]));
+ RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LB]));
+ RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RF]));
+ RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LF]));
+ if(m_aCarNodes[CAR_WHEEL_RM])
+ RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RM]));
+ if(m_aCarNodes[CAR_WHEEL_LM])
+ RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LM]));
+ }else
CEntity::Render();
}
@@ -2157,6 +2984,10 @@ CAutomobile::ProcessEntityCollision(CEntity *ent, CColPoint *colpoints)
for(i = 0; i < 4; i++)
prevRatios[i] = m_aSuspensionSpringRatio[i];
+ if(m_bIsVehicleBeingShifted || bSkipLineCol || ent->IsPed() ||
+ GetModelIndex() == MI_DODO && ent->IsVehicle())
+ colModel->numLines = 0;
+
int numCollisions = CCollision::ProcessColModels(GetMatrix(), *colModel,
ent->GetMatrix(), *ent->GetColModel(),
colpoints,
@@ -2165,12 +2996,7 @@ CAutomobile::ProcessEntityCollision(CEntity *ent, CColPoint *colpoints)
// m_aSuspensionSpringRatio are now set to the point where the tyre touches ground.
// In ProcessControl these will be re-normalized to ignore the tyre radius.
- if(m_bIsVehicleBeingShifted || bSkipLineCol ||
- GetModelIndex() == MI_DODO && (ent->IsPed() || ent->IsVehicle())){
- // don't do line collision
- for(i = 0; i < 4; i++)
- m_aSuspensionSpringRatio[i] = prevRatios[i];
- }else{
+ if(colModel->numLines){
for(i = 0; i < 4; i++)
if(m_aSuspensionSpringRatio[i] < 1.0f && m_aSuspensionSpringRatio[i] < prevRatios[i]){
numWheelCollisions++;
@@ -2182,30 +3008,14 @@ CAutomobile::ProcessEntityCollision(CEntity *ent, CColPoint *colpoints)
m_aGroundPhysical[i] = phys;
phys->RegisterReference((CEntity**)&m_aGroundPhysical[i]);
m_aGroundOffset[i] = m_aWheelColPoints[i].point - phys->GetPosition();
-
- if(phys->GetModelIndex() == MI_BODYCAST && GetStatus() == STATUS_PLAYER){
- // damage body cast
- float speed = m_vecMoveSpeed.MagnitudeSqr();
- if(speed > 0.1f){
- CObject::nBodyCastHealth -= 0.1f*m_fMass*speed;
- DMAudio.PlayOneShot(m_audioEntityId, SOUND_PED_BODYCAST_HIT, 0.0f);
- }
-
- // move body cast
- if(phys->IsStatic()){
- phys->bIsStatic = false;
- phys->m_nStaticFrames = 0;
- phys->ApplyMoveForce(m_vecMoveSpeed / Sqrt(speed));
- phys->AddToMovingList();
- }
- }
}
m_nSurfaceTouched = m_aWheelColPoints[i].surfaceB;
if(ent->IsBuilding())
m_pCurGroundEntity = ent;
}
- }
+ }else
+ colModel->numLines = 4;
if(numCollisions > 0 || numWheelCollisions > 0){
AddCollisionRecord(ent);
@@ -2231,10 +3041,12 @@ CAutomobile::ProcessControlInputs(uint8 pad)
{
float speed = DotProduct(m_vecMoveSpeed, GetForward());
- if(CPad::GetPad(pad)->GetExitVehicle())
- bIsHandbrakeOn = true;
- else
+ if(!CPad::GetPad(pad)->GetExitVehicle() ||
+ pDriver && pDriver->m_pVehicleAnim && (pDriver->m_pVehicleAnim->animId == ANIM_CAR_ROLLOUT_LHS ||
+ pDriver->m_pVehicleAnim->animId == ANIM_CAR_ROLLOUT_RHS))
bIsHandbrakeOn = !!CPad::GetPad(pad)->GetHandBrake();
+ else
+ bIsHandbrakeOn = true;
// Steer left/right
if(CCamera::m_bUseMouse3rdPerson && !CVehicle::m_bDisableMouseSteering){
@@ -2262,8 +3074,14 @@ CAutomobile::ProcessControlInputs(uint8 pad)
acceleration *= 0.3f;
if(Abs(speed) < 0.01f){
// standing still, go into direction we want
- m_fGasPedal = acceleration;
- m_fBrakePedal = 0.0f;
+ if(CPad::GetPad(pad)->GetAccelerate() > 150.0f && CPad::GetPad(pad)->GetBrake() > 150.0f){
+ m_fGasPedal = CPad::GetPad(pad)->GetAccelerate()/255.0f;
+ m_fBrakePedal = CPad::GetPad(pad)->GetBrake()/255.0f;
+ m_doingBurnout = 1;
+ }else{
+ m_fGasPedal = acceleration;
+ m_fBrakePedal = 0.0f;
+ }
}else{
#if 1
// simpler than the code below
@@ -2312,17 +3130,6 @@ CAutomobile::ProcessControlInputs(uint8 pad)
m_fSteerAngle = DEGTORAD(pHandling->fSteeringLock) * fValue;
if(bComedyControls){
-#if 0 // old comedy controls from PS2 - same as bike's
- if(((CTimer::GetTimeInMilliseconds() >> 10) & 0xF) < 12)
- m_fGasPedal = 1.0f;
- if((((CTimer::GetTimeInMilliseconds() >> 10)+6) & 0xF) < 12)
- m_fBrakePedal = 0.0f;
- bIsHandbrakeOn = false;
- if(CTimer::GetTimeInMilliseconds() & 0x800)
- m_fSteerAngle += 0.08f;
- else
- m_fSteerAngle -= 0.03f;
-#else
int rnd = CGeneral::GetRandomNumber() % 10;
switch(m_comedyControlState){
case 0:
@@ -2342,10 +3149,8 @@ CAutomobile::ProcessControlInputs(uint8 pad)
m_comedyControlState = 0;
break;
}
- }else{
+ }else
m_comedyControlState = 0;
-#endif
- }
// Brake if player isn't in control
// BUG: game always uses pad 0 here
@@ -2524,22 +3329,10 @@ CAutomobile::TankControl(void)
flashPos += 0.1f*shotDir;
CParticle::AddParticle(PARTICLE_GUNFLASH, flashPos, nullDir, nil, 0.15f, black, 0, 0, 0, lifeSpan);
}
-
- // Actually update turret node
- if(m_aCarNodes[CAR_WINDSCREEN]){
- CMatrix mat;
- CVector pos;
-
- mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WINDSCREEN]));
- pos = mat.GetPosition();
- mat.SetRotateZ(m_fCarGunLR);
- mat.Translate(pos);
- mat.UpdateRW();
- }
}
-#define HYDRAULIC_UPPER_EXT (-0.12f)
-#define HYDRAULIC_LOWER_EXT (0.14f)
+#define HYDRAULIC_UPPER_EXT (-0.16f)
+#define HYDRAULIC_LOWER_EXT (0.16f)
void
CAutomobile::HydraulicControl(void)
@@ -2647,8 +3440,6 @@ CAutomobile::HydraulicControl(void)
if(m_hydraulicState < 20 && m_fVelocityChangeForAudio > 0.2f){
if(m_hydraulicState == 0){
m_hydraulicState = 20;
- for(i = 0; i < 4; i++)
- m_aWheelPosition[i] -= 0.06f;
DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_1, 0.0f);
setPrevRatio = true;
}else{
@@ -2722,7 +3513,6 @@ CAutomobile::HydraulicControl(void)
}
setPrevRatio = true;
- m_aWheelPosition[i] -= 0.05f;
}
DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_2, 0.0f);
}
@@ -2753,7 +3543,6 @@ CAutomobile::HydraulicControl(void)
if(suspChange[i] > 1.0f)
suspChange[i] = 1.0f;
- float oldZ = specialColModel->lines[i].p1.z;
float upperLimit = suspChange[i]*(extendedUpperLimit-normalUpperLimit) + normalUpperLimit;
float springLength = suspChange[i]*(extendedSpringLength-normalSpringLength) + normalSpringLength;
float lineLength = springLength + wheelRadius;
@@ -2773,15 +3562,11 @@ CAutomobile::HydraulicControl(void)
m_aSuspensionSpringRatio[i] = (specialColModel->lines[i].p0.z - wheelPositions[i])/m_aSuspensionLineLength[i];
if(m_aSuspensionSpringRatio[i] > 1.0f)
m_aSuspensionSpringRatio[i] = 1.0f;
- m_aWheelPosition[i] -= (oldZ - specialColModel->lines[i].p1.z)*0.3f;
}
}
}else{
- if(m_hydraulicState < 104){
+ if(m_hydraulicState < 104)
m_hydraulicState++;
- for(i = 0; i < 4; i++)
- m_aWheelPosition[i] -= 0.1f;
- }
if(m_fVelocityChangeForAudio < 0.1f){
normalUpperLimit += HYDRAULIC_UPPER_EXT;
@@ -2847,19 +3632,47 @@ CAutomobile::ProcessBuoyancy(void)
CVector impulse, point;
if(mod_Buoyancy.ProcessBuoyancy(this, m_fBuoyancy, &point, &impulse)){
- bTouchingWater = true;
- ApplyMoveForce(impulse);
- ApplyTurnForce(impulse, point);
-
- CVector initialSpeed = m_vecMoveSpeed;
float timeStep = Max(CTimer::GetTimeStep(), 0.01f);
float impulseRatio = impulse.z / (GRAVITY * m_fMass * timeStep);
float waterResistance = Pow(1.0f - 0.05f*impulseRatio, CTimer::GetTimeStep());
m_vecMoveSpeed *= waterResistance;
m_vecTurnSpeed *= waterResistance;
- if(impulseRatio > 0.5f){
+ bool heliHitWaterHard = false;
+ if(IsRealHeli() && m_aWheelSpeed[1] > 0.15f){
+ if(GetModelIndex() == MI_SEASPAR){
+ if(impulseRatio > 3.0f){
+ m_aWheelSpeed[1] = 0.0f;
+ heliHitWaterHard = true;
+ }
+ }else{
+ float strength = 1.0f/Max(8.0f*impulseRatio, 1.0f);
+ ApplyMoveForce(-2.0f*impulse/strength);
+ ApplyTurnForce(-impulse/strength, point);
+ if(impulseRatio > 0.9f){
+ m_aWheelSpeed[1] = 0.0f;
+ heliHitWaterHard = true;
+ }else
+ return;
+ }
+ }
+
+ bTouchingWater = true;
+ ApplyMoveForce(impulse);
+ ApplyTurnForce(impulse, point);
+ CVector initialSpeed = m_vecMoveSpeed;
+
+ if(m_modelIndex == MI_SEASPAR && impulseRatio < 3.0f && (GetUp().z > -0.5f || impulseRatio < 0.6f) ||
+ CVehicle::bHoverCheat && GetStatus() == STATUS_PLAYER && GetUp().z > 0.1f){
+ bIsInWater = false;
+ bIsDrowning = false;
+ }else if(heliHitWaterHard || impulseRatio > 1.0f ||
+ impulseRatio > 0.6f && (m_aSuspensionSpringRatio[0] == 1.0f ||
+ m_aSuspensionSpringRatio[1] == 1.0f ||
+ m_aSuspensionSpringRatio[2] == 1.0f ||
+ m_aSuspensionSpringRatio[3] == 1.0f)){
bIsInWater = true;
+ bIsDrowning = true;
if(m_vecMoveSpeed.z < -0.1f)
m_vecMoveSpeed.z = -0.1f;
@@ -2874,49 +3687,35 @@ CAutomobile::ProcessBuoyancy(void)
if(pPassengers[i]->IsPlayer() || !bWaterTight)
pPassengers[i]->InflictDamage(nil, WEAPONTYPE_DROWNING, CTimer::GetTimeStep(), PEDPIECE_TORSO, 0);
}
- }else
+ }else{
bIsInWater = false;
+ bIsDrowning = false;
+ }
static uint32 nGenerateRaindrops = 0;
static uint32 nGenerateWaterCircles = 0;
- if(initialSpeed.z < -0.3f && impulse.z > 0.3f){
-#if defined(PC_PARTICLE) || defined (PS2_ALTERNATIVE_CARSPLASH)
+ if(initialSpeed.z < -0.1f && impulse.z > 0.3f || heliHitWaterHard){
RwRGBA color;
- color.red = (0.5f * CTimeCycle::GetDirectionalRed() + CTimeCycle::GetAmbientRed())*0.45f*255;
- color.green = (0.5f * CTimeCycle::GetDirectionalGreen() + CTimeCycle::GetAmbientGreen())*0.45f*255;
- color.blue = (0.5f * CTimeCycle::GetDirectionalBlue() + CTimeCycle::GetAmbientBlue())*0.45f*255;
+ color.red = (0.5f * CTimeCycle::GetDirectionalRed() + CTimeCycle::GetAmbientRed_Obj())*0.45f*255;
+ color.green = (0.5f * CTimeCycle::GetDirectionalGreen() + CTimeCycle::GetAmbientGreen_Obj())*0.45f*255;
+ color.blue = (0.5f * CTimeCycle::GetDirectionalBlue() + CTimeCycle::GetAmbientBlue_Obj())*0.45f*255;
color.alpha = CGeneral::GetRandomNumberInRange(0, 32) + 128;
+ CVector target = CVector(0.0f, 0.0f, CGeneral::GetRandomNumberInRange(0.15f, 0.45f));
CParticleObject::AddObject(POBJECT_CAR_WATER_SPLASH, GetPosition(),
- CVector(0.0f, 0.0f, CGeneral::GetRandomNumberInRange(0.15f, 0.3f)),
- 0.0f, 75, color, true);
-#else
- CVector pos = (initialSpeed * 2.0f) + (GetPosition() + point);
-
- for ( int32 i = 0; i < 360; i += 4 )
- {
- float fSin = Sin(float(i));
- float fCos = Cos(float(i));
-
- CVector dir(fSin*0.01f, fCos*0.01f, CGeneral::GetRandomNumberInRange(0.25f, 0.45f));
-
- CParticle::AddParticle(PARTICLE_CAR_SPLASH,
- pos + CVector(fSin*4.5f, fCos*4.5f, 0.0f),
- dir, NULL, 0.0f, CRGBA(225, 225, 255, 180));
-
- for ( int32 j = 0; j < 3; j++ )
- {
- float fMul = 1.5f * float(j + 1);
-
- CParticle::AddParticle(PARTICLE_CAR_SPLASH,
- pos + CVector(fSin * fMul, fCos * fMul, 0.0f),
- dir, NULL, 0.0f, CRGBA(225, 225, 255, 180));
- }
- }
-#endif
+ target, 0.0f, 75, color, true);
nGenerateRaindrops = CTimer::GetTimeInMilliseconds() + 300;
nGenerateWaterCircles = CTimer::GetTimeInMilliseconds() + 60;
+
+ if(heliHitWaterHard){
+ CVector right = CrossProduct(GetForward(), CVector(0.0f, 0.0f, 1.0f));
+ CParticleObject::AddObject(POBJECT_CAR_WATER_SPLASH, GetPosition() + right,
+ target, 0.0f, 75, color, true);
+ CParticleObject::AddObject(POBJECT_CAR_WATER_SPLASH, GetPosition() - right,
+ target, 0.0f, 75, color, true);
+ }
+
if(m_vecMoveSpeed.z < -0.2f)
m_vecMoveSpeed.z = -0.2f;
DMAudio.PlayOneShot(m_audioEntityId, SOUND_WATER_FALL, 0.0f);
@@ -2957,6 +3756,7 @@ CAutomobile::ProcessBuoyancy(void)
}
}else{
bIsInWater = false;
+ bIsDrowning = false;
bTouchingWater = false;
static RwRGBA splashCol = {155, 155, 185, 196};
@@ -2967,13 +3767,7 @@ CAutomobile::ProcessBuoyancy(void)
CVector pos = m_aWheelColPoints[i].point + 0.3f*GetUp() - GetPosition();
CVector vSpeed = GetSpeed(pos);
vSpeed.z = 0.0f;
-#ifdef GTA_PS2_STUFF
- // ps2 puddle physics
- CVector moveForce = CTimer::GetTimeStep() * (m_fMass * (vSpeed * -0.003f));
- ApplyMoveForce(moveForce.x, moveForce.y, moveForce.z);
-#endif
float fSpeed = vSpeed.MagnitudeSqr();
-#ifdef PC_PARTICLE
if(fSpeed > sq(0.05f)){
fSpeed = Sqrt(fSpeed);
@@ -2993,35 +3787,6 @@ CAutomobile::ProcessBuoyancy(void)
if((CTimer::GetFrameCounter() & 0xF) == 0)
DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_SPLASH, 2000.0f*fSpeed);
}
-#else
- if ( ( (CTimer::GetFrameCounter() + i) & 3 ) == 0 )
- {
- if(fSpeed > sq(0.05f))
- {
- fSpeed = Sqrt(fSpeed);
- CRGBA color(155, 185, 155, 255);
- float boxY = GetColModel()->boundingBox.max.y;
- CVector right = 0.5f * GetRight();
-
- if ( i == 2 )
- {
- CParticle::AddParticle(PARTICLE_PED_SPLASH,
- GetPosition() + (boxY * GetForward()) + right,
- 0.75f*m_vecMoveSpeed, NULL, 0.0f, color);
-
- }
- else if ( i == 0 )
- {
- CParticle::AddParticle(PARTICLE_PED_SPLASH,
- GetPosition() + (boxY * GetForward()) - right,
- 0.75f*m_vecMoveSpeed, NULL, 0.0f, color);
- }
-
- if((CTimer::GetFrameCounter() & 0xF) == 0)
- DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_SPLASH, 2000.0f*fSpeed);
- }
- }
-#endif
}
}
}
@@ -3030,16 +3795,21 @@ CAutomobile::ProcessBuoyancy(void)
void
CAutomobile::DoDriveByShootings(void)
{
- CAnimBlendAssociation *anim;
+ CAnimBlendAssociation *anim = nil;
+ CPlayerInfo* playerInfo = ((CPlayerPed*)pDriver)->GetPlayerInfoForThisPlayerPed();
+ if (playerInfo && !playerInfo->m_bDriveByAllowed)
+ return;
+
CWeapon *weapon = pDriver->GetWeapon();
- if(weapon->m_eWeaponType != WEAPONTYPE_UZI)
+ if(CWeaponInfo::GetWeaponInfo(weapon->m_eWeaponType)->m_nWeaponSlot != 5)
return;
- weapon->Update(pDriver->m_audioEntityId);
+ weapon->Update(pDriver->m_audioEntityId, nil);
bool lookingLeft = false;
bool lookingRight = false;
- if(TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN){
+ if(TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN ||
+ TheCamera.m_bObbeCinematicCarCamOn){
if(CPad::GetPad(0)->GetLookLeft())
lookingLeft = true;
if(CPad::GetPad(0)->GetLookRight())
@@ -3051,37 +3821,42 @@ CAutomobile::DoDriveByShootings(void)
lookingRight = true;
}
+ AnimationId rightAnim = ANIM_DRIVEBY_R;
+ AnimationId leftAnim = ANIM_DRIVEBY_L;
+ if (pDriver->m_pMyVehicle->bLowVehicle) {
+ rightAnim = ANIM_DRIVEBY_LOW_R;
+ leftAnim = ANIM_DRIVEBY_LOW_L;
+ }
+
if(lookingLeft || lookingRight){
if(lookingLeft){
- anim = RpAnimBlendClumpGetAssociation(pDriver->GetClump(), ANIM_DRIVEBY_R);
+ anim = RpAnimBlendClumpGetAssociation(pDriver->GetClump(), rightAnim);
if(anim)
anim->blendDelta = -1000.0f;
- anim = RpAnimBlendClumpGetAssociation(pDriver->GetClump(), ANIM_DRIVEBY_L);
+ anim = RpAnimBlendClumpGetAssociation(pDriver->GetClump(), leftAnim);
if(anim == nil || anim->blendDelta < 0.0f)
- CAnimManager::AddAnimation(pDriver->GetClump(), ASSOCGRP_STD, ANIM_DRIVEBY_L);
- else
- anim->SetRun();
+ anim = CAnimManager::AddAnimation(pDriver->GetClump(), ASSOCGRP_STD, leftAnim);
}else if(pDriver->m_pMyVehicle->pPassengers[0] == nil || TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_1STPERSON){
- anim = RpAnimBlendClumpGetAssociation(pDriver->GetClump(), ANIM_DRIVEBY_L);
+ anim = RpAnimBlendClumpGetAssociation(pDriver->GetClump(), leftAnim);
if(anim)
anim->blendDelta = -1000.0f;
- anim = RpAnimBlendClumpGetAssociation(pDriver->GetClump(), ANIM_DRIVEBY_R);
+ anim = RpAnimBlendClumpGetAssociation(pDriver->GetClump(), rightAnim);
if(anim == nil || anim->blendDelta < 0.0f)
- CAnimManager::AddAnimation(pDriver->GetClump(), ASSOCGRP_STD, ANIM_DRIVEBY_R);
- else
- anim->SetRun();
+ anim = CAnimManager::AddAnimation(pDriver->GetClump(), ASSOCGRP_STD, rightAnim);
}
- if(CPad::GetPad(0)->GetCarGunFired() && CTimer::GetTimeInMilliseconds() > weapon->m_nTimer){
- weapon->FireFromCar(this, lookingLeft);
- weapon->m_nTimer = CTimer::GetTimeInMilliseconds() + 70;
+ if (!anim || !anim->IsRunning()) {
+ if (CPad::GetPad(0)->GetCarGunFired() && CTimer::GetTimeInMilliseconds() > weapon->m_nTimer) {
+ weapon->FireFromCar(this, lookingLeft, true);
+ weapon->m_nTimer = CTimer::GetTimeInMilliseconds() + 70;
+ }
}
}else{
weapon->Reload();
- anim = RpAnimBlendClumpGetAssociation(pDriver->GetClump(), ANIM_DRIVEBY_L);
+ anim = RpAnimBlendClumpGetAssociation(pDriver->GetClump(), leftAnim);
if(anim)
anim->blendDelta = -1000.0f;
- anim = RpAnimBlendClumpGetAssociation(pDriver->GetClump(), ANIM_DRIVEBY_R);
+ anim = RpAnimBlendClumpGetAssociation(pDriver->GetClump(), rightAnim);
if(anim)
anim->blendDelta = -1000.0f;
}
@@ -3089,11 +3864,49 @@ CAutomobile::DoDriveByShootings(void)
// TODO: what is this?
if(!lookingLeft && m_weaponDoorTimerLeft > 0.0f){
m_weaponDoorTimerLeft = Max(m_weaponDoorTimerLeft - CTimer::GetTimeStep()*0.1f, 0.0f);
- ProcessOpenDoor(CAR_DOOR_LF, NUM_ANIMS, m_weaponDoorTimerLeft);
+ ProcessOpenDoor(CAR_DOOR_LF, NUM_STD_ANIMS, m_weaponDoorTimerLeft);
}
if(!lookingRight && m_weaponDoorTimerRight > 0.0f){
m_weaponDoorTimerRight = Max(m_weaponDoorTimerRight - CTimer::GetTimeStep()*0.1f, 0.0f);
- ProcessOpenDoor(CAR_DOOR_RF, NUM_ANIMS, m_weaponDoorTimerRight);
+ ProcessOpenDoor(CAR_DOOR_RF, NUM_STD_ANIMS, m_weaponDoorTimerRight);
+ }
+}
+
+void
+CAutomobile::DoHoverSuspensionRatios(void)
+{
+ int i;
+
+ if(GetUp().z < 0.1f)
+ return;
+
+ CColModel *colmodel = GetColModel();
+ for(i = 0; i < 4; i++){
+ float z, waterZ;
+ CVector upper = GetMatrix() * colmodel->lines[i].p0;
+ CVector lower = GetMatrix() * colmodel->lines[i].p1;
+ if(m_aSuspensionSpringRatio[i] < 1.0f)
+ z = m_aWheelColPoints[i].point.z;
+ else
+ z = -100.0f;
+ // see if touching water
+ if(CWaterLevel::GetWaterLevel(lower, &waterZ, false) &&
+ waterZ > z && lower.z-1.0f < waterZ){
+ // compress spring
+ if(lower.z < waterZ){
+ if(upper.z < waterZ)
+ m_aSuspensionSpringRatio[i] = 0.0f;
+ else
+ m_aSuspensionSpringRatio[i] = (upper.z - waterZ)/(upper.z - lower.z);
+ }else
+ m_aSuspensionSpringRatio[i] = 0.99999f;
+
+ m_aWheelColPoints[i].point.x = (lower.x - upper.x)*m_aSuspensionSpringRatio[i] + upper.x;
+ m_aWheelColPoints[i].point.y = (lower.y - upper.y)*m_aSuspensionSpringRatio[i] + upper.y;
+ m_aWheelColPoints[i].point.z = waterZ;
+ m_aWheelColPoints[i].normal = CVector(0.01f, 0.0f, 1.0f);
+ m_aWheelColPoints[i].surfaceB = SURFACE_WATER;
+ }
}
}
@@ -3136,7 +3949,8 @@ CAutomobile::RcbanditCheck1CarWheels(CPtrList &list)
for(node = list.first; node; node = node->next){
car = (CAutomobile*)node->item;
- if(this != car && car->IsCar() && car->m_scanCode != CWorld::GetCurrentScanCode()){
+ if(this != car && car->IsCar() && car->GetModelIndex() != MI_RCBANDIT &&
+ car->m_scanCode != CWorld::GetCurrentScanCode()){
car->m_scanCode = CWorld::GetCurrentScanCode();
if(Abs(this->GetPosition().x - car->GetPosition().x) < 10.0f &&
@@ -3210,8 +4024,7 @@ void
CAutomobile::VehicleDamage(float impulse, uint16 damagedPiece)
{
int i;
- float damageMultiplier = 0.2f;
- bool doubleMoney = false;
+ float damageMultiplier = 0.333f;
if(impulse == 0.0f){
impulse = m_fDamageImpulse;
@@ -3219,19 +4032,30 @@ CAutomobile::VehicleDamage(float impulse, uint16 damagedPiece)
damageMultiplier = 1.0f;
}
+ if(GetStatus() == STATUS_PLAYER && CStats::GetPercentageProgress() >= 100.0f)
+ impulse *= 0.5f;
+
CVector pos(0.0f, 0.0f, 0.0f);
if(!bCanBeDamaged)
return;
+ if(m_pDamageEntity && m_pDamageEntity->IsPed() && ((CPed*)m_pDamageEntity)->bIsStanding){
+ float speed = ((CPed*)m_pDamageEntity)->m_vecAnimMoveDelta.y * DotProduct(GetForward(), m_vecDamageNormal);
+ if(speed < 0.0f)
+ impulse = Max(impulse + ((CPed*)m_pDamageEntity)->m_fMass * speed, 0.0f);
+ }
+
// damage flipped over car
if(GetUp().z < 0.0f && this != FindPlayerVehicle()){
if(bNotDamagedUpsideDown || GetStatus() == STATUS_PLAYER_REMOTE || bIsInWater)
return;
- m_fHealth -= 4.0f*CTimer::GetTimeStep();
+ if(GetStatus() != STATUS_WRECKED)
+ m_fHealth = Max(m_fHealth - 4.0f*CTimer::GetTimeStep(), 0.0f);
}
- if(impulse > 25.0f && GetStatus() != STATUS_WRECKED){
+ float minImpulse = GetModelIndex() == MI_RCRAIDER || GetModelIndex() == MI_RCGOBLIN ? 1.0f : 25.0f;
+ if(impulse > minImpulse && GetStatus() != STATUS_WRECKED){
if(bIsLawEnforcer &&
FindPlayerVehicle() && FindPlayerVehicle() == m_pDamageEntity &&
GetStatus() != STATUS_ABANDONED &&
@@ -3244,12 +4068,17 @@ CAutomobile::VehicleDamage(float impulse, uint16 damagedPiece)
CPad::GetPad(0)->StartShake(40000/freq, freq);
}
- if(bOnlyDamagedByPlayer){
+ if(GetStatus() != STATUS_PLAYER && bOnlyDamagedByPlayer){
if(m_pDamageEntity != FindPlayerPed() &&
m_pDamageEntity != FindPlayerVehicle())
return;
}
+ if(m_pDamageEntity && m_pDamageEntity->IsVehicle()){
+ m_nLastWeaponDamage = WEAPONTYPE_RAMMEDBYCAR;
+ m_pLastDamageEntity = m_pDamageEntity;
+ }
+
if(bCollisionProof)
return;
@@ -3269,109 +4098,81 @@ CAutomobile::VehicleDamage(float impulse, uint16 damagedPiece)
switch(damagedPiece){
case CAR_PIECE_BUMP_FRONT:
GetComponentWorldPosition(CAR_BUMP_FRONT, pos);
- dmgDrawCarCollidingParticles(pos, impulse);
- if(Damage.ApplyDamage(COMPONENT_BUMPER_FRONT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
+ if(Damage.ApplyDamage(COMPONENT_BUMPER_FRONT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
SetBumperDamage(CAR_BUMP_FRONT, VEHBUMPER_FRONT);
- doubleMoney = true;
- }
if(m_aCarNodes[CAR_BONNET] && Damage.GetPanelStatus(VEHBUMPER_FRONT) == PANEL_STATUS_MISSING){
case CAR_PIECE_BONNET:
GetComponentWorldPosition(CAR_BONNET, pos);
- dmgDrawCarCollidingParticles(pos, impulse);
+ dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
if(GetModelIndex() != MI_DODO)
- if(Damage.ApplyDamage(COMPONENT_DOOR_BONNET, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ if(Damage.ApplyDamage(COMPONENT_DOOR_BONNET, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
SetDoorDamage(CAR_BONNET, DOOR_BONNET);
- doubleMoney = true;
- }
}
break;
case CAR_PIECE_BUMP_REAR:
GetComponentWorldPosition(CAR_BUMP_REAR, pos);
- dmgDrawCarCollidingParticles(pos, impulse);
- if(Damage.ApplyDamage(COMPONENT_BUMPER_REAR, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
+ if(Damage.ApplyDamage(COMPONENT_BUMPER_REAR, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
SetBumperDamage(CAR_BUMP_REAR, VEHBUMPER_REAR);
- doubleMoney = true;
- }
if(m_aCarNodes[CAR_BOOT] && Damage.GetPanelStatus(VEHBUMPER_REAR) == PANEL_STATUS_MISSING){
case CAR_PIECE_BOOT:
GetComponentWorldPosition(CAR_BOOT, pos);
- dmgDrawCarCollidingParticles(pos, impulse);
- if(Damage.ApplyDamage(COMPONENT_DOOR_BOOT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
+ if(Damage.ApplyDamage(COMPONENT_DOOR_BOOT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
SetDoorDamage(CAR_BOOT, DOOR_BOOT);
- doubleMoney = true;
- }
}
break;
case CAR_PIECE_DOOR_LF:
GetComponentWorldPosition(CAR_DOOR_LF, pos);
- dmgDrawCarCollidingParticles(pos, impulse);
- if((m_nDoorLock == CARLOCK_NOT_USED || m_nDoorLock == CARLOCK_UNLOCKED) &&
- Damage.ApplyDamage(COMPONENT_DOOR_FRONT_LEFT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
+ if(Damage.ApplyDamage(COMPONENT_DOOR_FRONT_LEFT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
SetDoorDamage(CAR_DOOR_LF, DOOR_FRONT_LEFT);
- doubleMoney = true;
- }
break;
case CAR_PIECE_DOOR_RF:
GetComponentWorldPosition(CAR_DOOR_RF, pos);
- dmgDrawCarCollidingParticles(pos, impulse);
- if((m_nDoorLock == CARLOCK_NOT_USED || m_nDoorLock == CARLOCK_UNLOCKED) &&
- Damage.ApplyDamage(COMPONENT_DOOR_FRONT_RIGHT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
+ if(Damage.ApplyDamage(COMPONENT_DOOR_FRONT_RIGHT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
SetDoorDamage(CAR_DOOR_RF, DOOR_FRONT_RIGHT);
- doubleMoney = true;
- }
break;
case CAR_PIECE_DOOR_LR:
GetComponentWorldPosition(CAR_DOOR_LR, pos);
- dmgDrawCarCollidingParticles(pos, impulse);
- if((m_nDoorLock == CARLOCK_NOT_USED || m_nDoorLock == CARLOCK_UNLOCKED) &&
- Damage.ApplyDamage(COMPONENT_DOOR_REAR_LEFT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
+ if(Damage.ApplyDamage(COMPONENT_DOOR_REAR_LEFT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
SetDoorDamage(CAR_DOOR_LR, DOOR_REAR_LEFT);
- doubleMoney = true;
- }
break;
case CAR_PIECE_DOOR_RR:
GetComponentWorldPosition(CAR_DOOR_RR, pos);
- dmgDrawCarCollidingParticles(pos, impulse);
- if((m_nDoorLock == CARLOCK_NOT_USED || m_nDoorLock == CARLOCK_UNLOCKED) &&
- Damage.ApplyDamage(COMPONENT_DOOR_REAR_RIGHT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
+ if(Damage.ApplyDamage(COMPONENT_DOOR_REAR_RIGHT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
SetDoorDamage(CAR_DOOR_RR, DOOR_REAR_RIGHT);
- doubleMoney = true;
- }
break;
case CAR_PIECE_WING_LF:
GetComponentWorldPosition(CAR_WING_LF, pos);
- dmgDrawCarCollidingParticles(pos, impulse);
- if(Damage.ApplyDamage(COMPONENT_PANEL_FRONT_LEFT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
+ if(Damage.ApplyDamage(COMPONENT_PANEL_FRONT_LEFT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
SetPanelDamage(CAR_WING_LF, VEHPANEL_FRONT_LEFT);
- doubleMoney = true;
- }
break;
case CAR_PIECE_WING_RF:
GetComponentWorldPosition(CAR_WING_RF, pos);
- dmgDrawCarCollidingParticles(pos, impulse);
- if(Damage.ApplyDamage(COMPONENT_PANEL_FRONT_RIGHT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
+ if(Damage.ApplyDamage(COMPONENT_PANEL_FRONT_RIGHT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
SetPanelDamage(CAR_WING_RF, VEHPANEL_FRONT_RIGHT);
- doubleMoney = true;
- }
break;
case CAR_PIECE_WING_LR:
GetComponentWorldPosition(CAR_WING_LR, pos);
- dmgDrawCarCollidingParticles(pos, impulse);
- if(Damage.ApplyDamage(COMPONENT_PANEL_REAR_LEFT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
+ if(Damage.ApplyDamage(COMPONENT_PANEL_REAR_LEFT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
SetPanelDamage(CAR_WING_LR, VEHPANEL_REAR_LEFT);
- doubleMoney = true;
- }
break;
case CAR_PIECE_WING_RR:
GetComponentWorldPosition(CAR_WING_RR, pos);
- dmgDrawCarCollidingParticles(pos, impulse);
- if(Damage.ApplyDamage(COMPONENT_PANEL_REAR_RIGHT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
+ if(Damage.ApplyDamage(COMPONENT_PANEL_REAR_RIGHT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
SetPanelDamage(CAR_WING_RR, VEHPANEL_REAR_RIGHT);
- doubleMoney = true;
- }
break;
case CAR_PIECE_WHEEL_LF:
@@ -3385,37 +4186,43 @@ CAutomobile::VehicleDamage(float impulse, uint16 damagedPiece)
uint8 oldStatus = Damage.GetPanelStatus(VEHPANEL_WINDSCREEN);
SetPanelDamage(CAR_WINDSCREEN, VEHPANEL_WINDSCREEN);
if(oldStatus != Damage.GetPanelStatus(VEHPANEL_WINDSCREEN)){
- DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_WINDSHIELD_CRACK, 0.0f);
- doubleMoney = true;
+ // DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_WINDSHIELD_CRACK, 0.0f);
}
}
break;
}
-
- if(m_pDamageEntity && m_pDamageEntity == FindPlayerVehicle() && impulse > 10.0f){
- int money = (doubleMoney ? 2 : 1) * impulse*pHandling->nMonetaryValue/1000000.0f;
- money = Min(money, 40);
- if(money > 2){
- sprintf(gString, "$%d", money);
- CWorld::Players[CWorld::PlayerInFocus].m_nMoney += money;
- }
- }
}
- float damage = (impulse-25.0f)*pHandling->fCollisionDamageMultiplier*0.6f*damageMultiplier;
+ float damage = (impulse-minImpulse)*pHandling->fCollisionDamageMultiplier*0.6f*damageMultiplier;
if(GetModelIndex() == MI_SECURICA && m_pDamageEntity && m_pDamageEntity->GetStatus() == STATUS_PLAYER)
damage *= 7.0f;
+ if(GetModelIndex() == MI_RCGOBLIN || GetModelIndex() == MI_RCRAIDER)
+ damage *= 30.0f;
+
if(damage > 0.0f){
+ if(damage > 5.0f &&
+ pDriver &&
+ m_pDamageEntity && m_pDamageEntity->IsVehicle() &&
+ (this != FindPlayerVehicle() || ((CVehicle*)m_pDamageEntity)->VehicleCreatedBy == MISSION_VEHICLE) &&
+// TODO(MIAMI): enum
+ ((CVehicle*)m_pDamageEntity)->pDriver){
+ if(GetVehicleAppearance() == VEHICLE_APPEARANCE_CAR)
+ pDriver->Say(145);
+ else
+ pDriver->Say(144);
+ }
+
int oldHealth = m_fHealth;
- if(this == FindPlayerVehicle()){
+ if(this == FindPlayerVehicle())
m_fHealth -= bTakeLessDamage ? damage/6.0f : damage/2.0f;
- }else{
- if(damage > 35.0f && pDriver)
- pDriver->Say(SOUND_PED_CAR_COLLISION);
- m_fHealth -= bTakeLessDamage ? damage/12.0f : damage/4.0f;
- }
+ else if(bTakeLessDamage)
+ m_fHealth -= damage/12.0f;
+ else if(m_pDamageEntity && m_pDamageEntity == FindPlayerVehicle())
+ m_fHealth -= damage/1.5f;
+ else
+ m_fHealth -= damage/4.0f;
if(m_fHealth <= 0.0f && oldHealth > 0)
m_fHealth = 1.0f;
}
@@ -3490,15 +4297,16 @@ CAutomobile::dmgDrawCarCollidingParticles(const CVector &pos, float amount)
void
CAutomobile::AddDamagedVehicleParticles(void)
{
+ int i, n;
+
if(this == FindPlayerVehicle() && TheCamera.GetLookingForwardFirstPerson())
return;
-
- uint8 engineStatus = Damage.GetEngineStatus();
- if(engineStatus < ENGINE_STATUS_STEAM1)
+ if(this != FindPlayerVehicle() && (CTimer::GetFrameCounter() + m_randomSeed) & 1)
+ return;
+ if(m_fHealth >= 650.0f)
return;
- float fwdSpeed = DotProduct(m_vecMoveSpeed, GetForward()) * 180.0f;
- CVector direction = 0.5f*m_vecMoveSpeed;
+ CVector direction = 0.85f*m_vecMoveSpeed;
CVector damagePos = ((CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex()))->m_positions[CAR_POS_HEADLIGHTS];
switch(Damage.GetDoorStatus(DOOR_BONNET)){
@@ -3516,26 +4324,72 @@ CAutomobile::AddDamagedVehicleParticles(void)
if(GetModelIndex() == MI_BFINJECT)
damagePos = CVector(0.3f, -1.5f, -0.1f);
-
+ else if(GetModelIndex() == MI_CADDY)
+ damagePos = CVector(0.6f, -1.0f, -0.25f);
+ else if(IsRealHeli()){
+ damagePos.x = 0.4f*GetColModel()->boundingBox.max.x;
+ damagePos.y = 0.2f*GetColModel()->boundingBox.min.y;
+ damagePos.z = 0.3f*GetColModel()->boundingBox.max.z;
+ }else
+ damagePos.z += 0.4f*(GetColModel()->boundingBox.max.z-damagePos.z) * DotProduct(GetForward(), m_vecMoveSpeed);
damagePos = GetMatrix()*damagePos;
damagePos.z += 0.15f;
- if(engineStatus < ENGINE_STATUS_STEAM2){
- if(fwdSpeed < 90.0f){
- direction.z += 0.05f;
- CParticle::AddParticle(PARTICLE_ENGINE_STEAM, damagePos, direction, nil, 0.1f);
- }
- }else if(engineStatus < ENGINE_STATUS_SMOKE){
- if(fwdSpeed < 90.0f)
- CParticle::AddParticle(PARTICLE_ENGINE_STEAM, damagePos, direction, nil, 0.0f);
- }else if(engineStatus < ENGINE_STATUS_ON_FIRE){
- if(fwdSpeed < 90.0f){
- CParticle::AddParticle(PARTICLE_ENGINE_STEAM, damagePos, direction, nil, 0.0f);
- CParticle::AddParticle(PARTICLE_ENGINE_SMOKE, damagePos, 0.3f*direction, nil, 0.0f);
- }
- }else if(m_fHealth > 250.0f){
- if(fwdSpeed < 90.0f)
- CParticle::AddParticle(PARTICLE_ENGINE_SMOKE2, damagePos, 0.2f*direction, nil, 0.0f);
+ bool electric = pHandling->Transmission.nEngineType == 'E';
+
+ if(electric && m_fHealth < 320.0f && m_fHealth > 1.0f){
+ direction = 0.85f*m_vecMoveSpeed;
+ direction += GetRight() * CGeneral::GetRandomNumberInRange(0.0f, 0.04f) * (1.0f - 2.0f*m_vecMoveSpeed.Magnitude());
+ direction.z += 0.001f;
+ n = (CGeneral::GetRandomNumber() & 7) + 2;
+ for(i = 0; i < n; i++)
+ CParticle::AddParticle(PARTICLE_SPARK_SMALL, damagePos, direction);
+ if(((CTimer::GetFrameCounter() + m_randomSeed) & 7) == 0)
+ CParticle::AddParticle(PARTICLE_ENGINE_SMOKE2, damagePos, 0.8f*m_vecMoveSpeed, nil, 0.1f, 0, 0, 0, 1000);
+ }else if(electric && m_fHealth < 460.0f){
+ direction = 0.85f*m_vecMoveSpeed;
+ direction += GetRight() * CGeneral::GetRandomNumberInRange(0.0f, 0.04f) * (1.0f - 2.0f*m_vecMoveSpeed.Magnitude());
+ direction.z += 0.001f;
+ n = (CGeneral::GetRandomNumber() & 3) + 2;
+ for(i = 0; i < n; i++)
+ CParticle::AddParticle(PARTICLE_SPARK_SMALL, damagePos, direction);
+ if(((CTimer::GetFrameCounter() + m_randomSeed) & 0xF) == 0)
+ CParticle::AddParticle(PARTICLE_ENGINE_SMOKE, damagePos, 0.8f*m_vecMoveSpeed, nil, 0.1f, 0, 0, 0, 1000);
+ }else if(m_fHealth < 250.0f){
+ // nothing
+ }else if(m_fHealth < 320.0f){
+ CParticle::AddParticle(PARTICLE_ENGINE_SMOKE2, damagePos, 0.8f*direction);
+ }else if(m_fHealth < 390.0f){
+ CParticle::AddParticle(PARTICLE_ENGINE_STEAM, damagePos, 0.75f*direction);
+ CParticle::AddParticle(PARTICLE_ENGINE_SMOKE, damagePos, 0.85f*direction);
+ }else if(m_fHealth < 460.0f){
+ int rnd = CTimer::GetFrameCounter() + m_randomSeed;
+ if(rnd < 10 ||
+ rnd < 70 && rnd > 25 ||
+ rnd < 160 && rnd > 100 ||
+ rnd < 200 && rnd > 175 ||
+ rnd > 235)
+ return;
+ direction.z += 0.05f*Max(1.0f - 1.6f*m_vecMoveSpeed.Magnitude(), 0.0f);
+ if(electric){
+ // BUG. we had that case already
+ direction = 0.85f*m_vecMoveSpeed;
+ direction += GetRight() * CGeneral::GetRandomNumberInRange(0.0f, 0.04f) * (1.0f - 2.0f*m_vecMoveSpeed.Magnitude());
+ direction.z += 0.001f;
+ n = (CGeneral::GetRandomNumber() & 2) + 2;
+ for(i = 0; i < n; i++)
+ CParticle::AddParticle(PARTICLE_SPARK_SMALL, damagePos, direction);
+ if(((CTimer::GetFrameCounter() + m_randomSeed) & 0xF) == 0)
+ CParticle::AddParticle(PARTICLE_ENGINE_SMOKE, damagePos, 0.8f*m_vecMoveSpeed, nil, 0.1f, 0, 0, 0, 1000);
+ }else{
+ if(TheCamera.GetLookDirection() != LOOKING_FORWARD)
+ CParticle::AddParticle(PARTICLE_ENGINE_STEAM, damagePos, 0.75f*direction);
+ else if(((CTimer::GetFrameCounter() + m_randomSeed) & 1) == 0)
+ CParticle::AddParticle(PARTICLE_ENGINE_STEAM, damagePos, 0.85f*m_vecMoveSpeed);
+ }
+ }else if(((CTimer::GetFrameCounter() + m_randomSeed) & 3) == 0 ||
+ ((CTimer::GetFrameCounter() + m_randomSeed) & 3) == 2){
+ CParticle::AddParticle(PARTICLE_ENGINE_STEAM, damagePos, 0.9f*direction);
}
}
@@ -3547,9 +4401,11 @@ CAutomobile::AddWheelDirtAndWater(CColPoint *colpoint, uint32 belowEffectSpeed)
static RwRGBA grassCol = { 8, 24, 8, 255 };
static RwRGBA gravelCol = { 64, 64, 64, 255 };
static RwRGBA mudCol = { 64, 32, 16, 255 };
+ static RwRGBA sandCol = { 170, 165, 140, 255 };
static RwRGBA waterCol = { 48, 48, 64, 0 };
- if(!belowEffectSpeed)
+ if(!belowEffectSpeed &&
+ colpoint->surfaceB != SURFACE_SAND && colpoint->surfaceB != SURFACE_SAND_BEACH)
return 0;
switch(colpoint->surfaceB){
@@ -3568,7 +4424,7 @@ CAutomobile::AddWheelDirtAndWater(CColPoint *colpoint, uint32 belowEffectSpeed)
for(i = 0; i < 4; i++){
dir.z = CGeneral::GetRandomNumberInRange(0.03f, 0.06f);
CParticle::AddParticle(PARTICLE_WHEEL_DIRT, colpoint->point, dir, nil,
- CGeneral::GetRandomNumberInRange(0.02f, 0.06f), gravelCol);
+ CGeneral::GetRandomNumberInRange(0.05f, 0.09f), gravelCol);
}
return 1;
case SURFACE_MUD_DRY:
@@ -3580,30 +4436,30 @@ CAutomobile::AddWheelDirtAndWater(CColPoint *colpoint, uint32 belowEffectSpeed)
CGeneral::GetRandomNumberInRange(0.02f, 0.06f), mudCol);
}
return 0;
+ case SURFACE_SAND:
+ case SURFACE_SAND_BEACH:
+ if(CTimer::GetFrameCounter() & 2 ||
+ CGeneral::GetRandomNumberInRange(CWeather::WetRoads, 1.01f) > 0.5f)
+ return 0;
+ dir.x = 0.5f*m_vecMoveSpeed.x;
+ dir.y = 0.5f*m_vecMoveSpeed.y;
+ for(i = 0; i < 1; i++){
+ dir.z = CGeneral::GetRandomNumberInRange(0.02f, 0.055f);
+ CParticle::AddParticle(PARTICLE_SAND, colpoint->point, dir, nil,
+ 2.0f*m_vecMoveSpeed.Magnitude(), sandCol);
+ }
+ return 0;
default:
- if ( CWeather::WetRoads > 0.01f
-#ifdef PC_PARTICLE
- && CTimer::GetFrameCounter() & 1
-#endif
- )
- {
- CParticle::AddParticle(
-#if defined(FIX_BUGS) && !defined(PC_PARTICLE) // looks wrong on PC particles
- PARTICLE_WHEEL_WATER,
-#else
- PARTICLE_WATERSPRAY,
-#endif
- colpoint->point + CVector(0.0f, 0.0f, 0.25f+0.25f),
-#ifdef PC_PARTICLE
- CVector(0.0f, 0.0f, 1.0f),
-#else
- CVector(0.0f, 0.0f, CGeneral::GetRandomNumberInRange(0.005f, 0.04f)),
-#endif
- nil,
- CGeneral::GetRandomNumberInRange(0.1f, 0.5f), waterCol);
+ if(CWeather::WetRoads > 0.01f){
+ if(CTimer::GetFrameCounter() & 1)
+ CParticle::AddParticle(
+ PARTICLE_WATERSPRAY,
+ colpoint->point + CVector(0.0f, 0.0f, 0.25f+0.25f),
+ CVector(0.0f, 0.0f, CGeneral::GetRandomNumberInRange(0.005f, 0.04f)),
+ nil,
+ CGeneral::GetRandomNumberInRange(0.1f, 0.5f), waterCol);
return 0;
}
-
return 1;
}
}
@@ -3714,6 +4570,7 @@ inline void ProcessDoorOpenCloseAnimation(CAutomobile *car, uint32 component, eD
car->OpenDoor(component, door, 0.0f);
}
}
+
void
CAutomobile::ProcessOpenDoor(uint32 component, uint32 anim, float time)
{
@@ -3734,13 +4591,13 @@ CAutomobile::ProcessOpenDoor(uint32 component, uint32 anim, float time)
case ANIM_CAR_QJACK:
case ANIM_CAR_OPEN_LHS:
case ANIM_CAR_OPEN_RHS:
- ProcessDoorOpenAnimation(this, component, door, time, 0.66f, 0.8f);
+ ProcessDoorOpenAnimation(this, component, door, time, 0.41f, 0.89f);
break;
case ANIM_CAR_CLOSEDOOR_LHS:
case ANIM_CAR_CLOSEDOOR_LOW_LHS:
case ANIM_CAR_CLOSEDOOR_RHS:
case ANIM_CAR_CLOSEDOOR_LOW_RHS:
- ProcessDoorCloseAnimation(this, component, door, time, 0.2f, 0.63f);
+ ProcessDoorCloseAnimation(this, component, door, time, 0.2f, 0.45f);
break;
case ANIM_CAR_ROLLDOOR:
case ANIM_CAR_ROLLDOOR_LOW:
@@ -3779,7 +4636,7 @@ CAutomobile::ProcessOpenDoor(uint32 component, uint32 anim, float time)
case ANIM_VAN_GETOUT:
ProcessDoorOpenAnimation(this, component, door, time, 0.5f, 0.6f);
break;
- case NUM_ANIMS:
+ case NUM_STD_ANIMS:
OpenDoor(component, door, time);
break;
}
@@ -3819,6 +4676,41 @@ CAutomobile::IsDoorMissing(eDoors door)
return Damage.GetDoorStatus(door) == DOOR_STATUS_MISSING;
}
+bool
+CAutomobile::IsDoorReady(uint32 door)
+{
+ switch(door){
+ case CAR_DOOR_RF: return IsDoorReady(DOOR_FRONT_RIGHT);
+ case CAR_DOOR_RR: return IsDoorReady(DOOR_REAR_RIGHT);
+ case CAR_DOOR_LF: return IsDoorReady(DOOR_FRONT_LEFT);
+ case CAR_DOOR_LR: return IsDoorReady(DOOR_REAR_LEFT);
+ default:
+ return false;
+ }
+}
+
+bool
+CAutomobile::IsDoorMissing(uint32 door)
+{
+ switch(door){
+ case CAR_DOOR_RF: return IsDoorMissing(DOOR_FRONT_RIGHT);
+ case CAR_DOOR_RR: return IsDoorMissing(DOOR_REAR_RIGHT);
+ case CAR_DOOR_LF: return IsDoorMissing(DOOR_FRONT_LEFT);
+ case CAR_DOOR_LR: return IsDoorMissing(DOOR_REAR_LEFT);
+ default:
+ return false;
+ }
+}
+
+bool
+CAutomobile::IsOpenTopCar(void)
+{
+ return GetModelIndex() == MI_STINGER ||
+ // component 0 is assumed to be a roof
+ GetModelIndex() == MI_COMET && m_aExtras[0] != 0 && m_aExtras[1] != 0 ||
+ GetModelIndex() == MI_STALLION && m_aExtras[0] != 0 && m_aExtras[1] != 0;
+}
+
void
CAutomobile::RemoveRefsToVehicle(CEntity *ent)
{
@@ -3831,12 +4723,17 @@ CAutomobile::RemoveRefsToVehicle(CEntity *ent)
void
CAutomobile::BlowUpCar(CEntity *culprit)
{
- int i;
RpAtomic *atomic;
if(!bCanBeDamaged)
return;
+ if(culprit == FindPlayerPed() || culprit == FindPlayerVehicle()){
+ CWorld::Players[CWorld::PlayerInFocus].m_nHavocLevel += 20;
+ CWorld::Players[CWorld::PlayerInFocus].m_fMediaAttention += 10.0f;
+ CStats::PropertyDestroyed += CGeneral::GetRandomNumber()%6000 + 4000;
+ }
+
// explosion pushes vehicle up
m_vecMoveSpeed.z += 0.13f;
SetStatus(STATUS_WRECKED);
@@ -3866,27 +4763,7 @@ CAutomobile::BlowUpCar(CEntity *culprit)
TheCamera.CamShake(0.7f, GetPosition().x, GetPosition().y, GetPosition().z);
- // kill driver and passengers
- if(pDriver){
- CDarkel::RegisterKillByPlayer(pDriver, WEAPONTYPE_EXPLOSION);
- if(pDriver->GetPedState() == PED_DRIVING){
- pDriver->SetDead();
- if(!pDriver->IsPlayer())
- pDriver->FlagToDestroyWhenNextProcessed();
- }else
- pDriver->SetDie(ANIM_KO_SHOT_FRONT1, 4.0f, 0.0f);
- }
- for(i = 0; i < m_nNumMaxPassengers; i++){
- if(pPassengers[i]){
- CDarkel::RegisterKillByPlayer(pPassengers[i], WEAPONTYPE_EXPLOSION);
- if(pPassengers[i]->GetPedState() == PED_DRIVING){
- pPassengers[i]->SetDead();
- if(!pPassengers[i]->IsPlayer())
- pPassengers[i]->FlagToDestroyWhenNextProcessed();
- }else
- pPassengers[i]->SetDie(ANIM_KO_SHOT_FRONT1, 4.0f, 0.0f);
- }
- }
+ KillPedsInVehicle();
bEngineOn = false;
bLightsOn = false;
@@ -3916,6 +4793,10 @@ CAutomobile::SetUpWheelColModel(CColModel *colModel)
CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex());
CColModel *vehColModel = mi->GetColModel();
+ if(GetVehicleAppearance() == VEHICLE_APPEARANCE_HELI ||
+ GetVehicleAppearance() == VEHICLE_APPEARANCE_PLANE)
+ return false;
+
colModel->boundingSphere = vehColModel->boundingSphere;
colModel->boundingBox = vehColModel->boundingBox;
@@ -3941,10 +4822,12 @@ CAutomobile::SetUpWheelColModel(CColModel *colModel)
return true;
}
-// this probably isn't used in III yet
void
-CAutomobile::BurstTyre(uint8 wheel)
+CAutomobile::BurstTyre(uint8 wheel, bool applyForces)
{
+ if(GetModelIndex() == MI_RHINO || bTyresDontBurst)
+ return;
+
switch(wheel){
case CAR_PIECE_WHEEL_LF: wheel = VEHWHEEL_FRONT_LEFT; break;
case CAR_PIECE_WHEEL_LR: wheel = VEHWHEEL_REAR_LEFT; break;
@@ -3955,14 +4838,18 @@ CAutomobile::BurstTyre(uint8 wheel)
int status = Damage.GetWheelStatus(wheel);
if(status == WHEEL_STATUS_OK){
Damage.SetWheelStatus(wheel, WHEEL_STATUS_BURST);
+ CStats::TyresPopped++;
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_TYRE_POP, 0.0f);
if(GetStatus() == STATUS_SIMPLE){
SetStatus(STATUS_PHYSICS);
CCarCtrl::SwitchVehicleToRealPhysics(this);
}
- ApplyMoveForce(GetRight() * m_fMass * CGeneral::GetRandomNumberInRange(-0.03f, 0.03f));
- ApplyTurnForce(GetRight() * m_fTurnMass * CGeneral::GetRandomNumberInRange(-0.03f, 0.03f), GetForward());
+ if(applyForces){
+ ApplyMoveForce(GetRight() * m_fMass * CGeneral::GetRandomNumberInRange(-0.03f, 0.03f));
+ ApplyTurnForce(GetRight() * m_fTurnMass * CGeneral::GetRandomNumberInRange(-0.03f, 0.03f), GetForward());
+ }
}
}
@@ -4008,7 +4895,7 @@ CAutomobile::IsRoomForPedToLeaveCar(uint32 component, CVector *doorOffset)
CVector dist = doorPos - seatPos;
- // Removing that makes this func. return false for van doors.
+ // Removing that makes thiProcessEntityCollisions func. return false for van doors.
doorPos.z += 0.5f;
float length = dist.Magnitude();
CVector pedPos = seatPos + dist*((length+0.6f)/length);
@@ -4039,10 +4926,16 @@ CAutomobile::PlayCarHorn(void)
{
int r;
- if(m_nCarHornTimer != 0)
+ if (IsAlarmOn() || m_nCarHornTimer != 0)
+ return;
+
+ if (m_nCarHornDelay) {
+ m_nCarHornDelay--;
return;
+ }
- r = CGeneral::GetRandomNumber() & 7;
+ m_nCarHornDelay = (CGeneral::GetRandomNumber() & 0x7F) + 150;
+ r = m_nCarHornDelay & 7;
if(r < 2){
m_nCarHornTimer = 45;
}else if(r < 4){
@@ -4064,7 +4957,6 @@ CAutomobile::PlayHornIfNecessary(void)
PlayCarHorn();
}
-
void
CAutomobile::ResetSuspension(void)
{
@@ -4107,8 +4999,8 @@ CAutomobile::SetupSuspensionLines(void)
}
// Compress spring somewhat to get normal height on road
- m_fHeightAboveRoad = -(colModel->lines[0].p0.z + (colModel->lines[0].p1.z - colModel->lines[0].p0.z)*
- (1.0f - 1.0f/(8.0f*pHandling->fSuspensionForceLevel)));
+ m_fHeightAboveRoad = m_aSuspensionSpringLength[0]*(1.0f - 1.0f/(4.0f*pHandling->fSuspensionForceLevel))
+ - colModel->lines[0].p0.z + mi->m_wheelScale*0.5f;
for(i = 0; i < 4; i++)
m_aWheelPosition[i] = mi->m_wheelScale*0.5f - m_fHeightAboveRoad;
@@ -4142,13 +5034,16 @@ CAutomobile::BlowUpCarsInPath(void)
{
int i;
- if(m_vecMoveSpeed.Magnitude() > 0.1f)
+ if(m_vecMoveSpeed.Magnitude() > 0.1f && bTankDetonateCars)
for(i = 0; i < m_nCollisionRecords; i++)
if(m_aCollisionRecords[i] &&
m_aCollisionRecords[i]->IsVehicle() &&
m_aCollisionRecords[i]->GetModelIndex() != MI_RHINO &&
- !m_aCollisionRecords[i]->bRenderScorched)
+ !m_aCollisionRecords[i]->bRenderScorched){
+ if(this == FindPlayerVehicle())
+ CEventList::RegisterEvent(EVENT_EXPLOSION, EVENT_ENTITY_VEHICLE, this, FindPlayerPed(), 2000);
((CVehicle*)m_aCollisionRecords[i])->BlowUpCar(this);
+ }
}
bool
@@ -4241,6 +5136,9 @@ CAutomobile::ProcessSwingingDoor(int32 component, eDoors door)
if(Damage.GetDoorStatus(door) != DOOR_STATUS_SWINGING)
return;
+ if (m_aCarNodes[component] == nil)
+ return;
+
CMatrix mat(RwFrameGetMatrix(m_aCarNodes[component]));
CVector pos = mat.GetPosition();
float axes[3] = { 0.0f, 0.0f, 0.0f };
@@ -4250,6 +5148,27 @@ CAutomobile::ProcessSwingingDoor(int32 component, eDoors door)
mat.SetRotate(axes[0], axes[1], axes[2]);
mat.Translate(pos);
mat.UpdateRW();
+
+ // make wind rip off bonnet
+ if(door == DOOR_BONNET && Doors[door].m_nDoorState == DOORST_OPEN &&
+ DotProduct(m_vecMoveSpeed, GetForward()) > 0.4f){
+#ifdef FIX_BUGS
+ CObject *comp = SpawnFlyingComponent(CAR_BONNET, COMPGROUP_BONNET);
+#else
+ CObject *comp = SpawnFlyingComponent(CAR_BONNET, COMPGROUP_DOOR);
+#endif
+ // make both doors invisible on car
+ SetComponentVisibility(m_aCarNodes[CAR_BONNET], ATOMIC_FLAG_NONE);
+ Damage.SetDoorStatus(DOOR_BONNET, DOOR_STATUS_MISSING);
+
+ if(comp){
+ if(CGeneral::GetRandomNumber() & 1)
+ comp->m_vecMoveSpeed = 0.4f*m_vecMoveSpeed + 0.1f*GetRight() + 0.5f*GetUp();
+ else
+ comp->m_vecMoveSpeed = 0.4f*m_vecMoveSpeed - 0.1f*GetRight() + 0.5f*GetUp();
+ comp->ApplyTurnForce(10.0f*GetUp(), GetForward());
+ }
+ }
}
void
@@ -4276,6 +5195,19 @@ CAutomobile::Fix(void)
mat.UpdateRW();
}
}
+
+ for(component = 0; component < 4; component++)
+ Damage.SetWheelStatus(component, WHEEL_STATUS_OK);
+
+ if(GetModelIndex() == MI_HUNTER){
+ RpAtomicSetFlags((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LB]), 0);
+ RpAtomicSetFlags((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RB]), 0);
+ }else if(IsRealHeli()){
+ RpAtomicSetFlags((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LF]), 0);
+ RpAtomicSetFlags((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RF]), 0);
+ RpAtomicSetFlags((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LB]), 0);
+ RpAtomicSetFlags((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RB]), 0);
+ }
}
void
@@ -4317,8 +5249,6 @@ GetCurrentAtomicObjectCB(RwObject *object, void *data)
return object;
}
-static CColPoint aTempPedColPts[MAX_COLLISION_POINTS];
-
CObject*
CAutomobile::SpawnFlyingComponent(int32 component, uint32 type)
{
@@ -4351,6 +5281,7 @@ CAutomobile::SpawnFlyingComponent(int32 component, uint32 type)
case COMPGROUP_DOOR:
obj->SetModelIndexNoCreate(MI_CAR_DOOR);
obj->SetCenterOfMass(0.0f, -0.5f, 0.0f);
+ obj->bDrawLast = true;
break;
case COMPGROUP_BONNET:
obj->SetModelIndexNoCreate(MI_CAR_BONNET);
@@ -4377,6 +5308,7 @@ CAutomobile::SpawnFlyingComponent(int32 component, uint32 type)
RpAtomicSetFrame(atomic, frame);
CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil);
obj->AttachToRwObject((RwObject*)atomic);
+ obj->bDontStream = true;
// init object
obj->m_fMass = 10.0f;
@@ -4435,9 +5367,16 @@ CAutomobile::SpawnFlyingComponent(int32 component, uint32 type)
obj->m_fAirResistance = 0.99f;
}
+ if(GetStatus() == STATUS_WRECKED && IsVisible() && DotProduct(dist, TheCamera.GetPosition() - GetPosition()) > -0.5f){
+ dist = TheCamera.GetPosition() - GetPosition();
+ dist.Normalise();
+ dist.z += 0.3f;
+ ApplyMoveForce(5.0f*dist);
+ }
+
if(CCollision::ProcessColModels(obj->GetMatrix(), *obj->GetColModel(),
this->GetMatrix(), *this->GetColModel(),
- aTempPedColPts, nil, nil) > 0)
+ CWorld::m_aTempColPts, nil, nil) > 0)
obj->m_pCollidingEntity = this;
if(bRenderScorched)
@@ -4475,11 +5414,14 @@ CAutomobile::SetPanelDamage(int32 component, ePanels panel, bool noFlyingCompone
if(m_aCarNodes[component] == nil)
return;
if(status == PANEL_STATUS_SMASHED1){
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_WINDSHIELD_CRACK, 0.0f);
// show damaged part
SetComponentVisibility(m_aCarNodes[component], ATOMIC_FLAG_DAM);
}else if(status == PANEL_STATUS_MISSING){
if(!noFlyingComponents)
SpawnFlyingComponent(component, COMPGROUP_PANEL);
+ else
+ CGlass::CarWindscreenShatters(this, false);
// hide both
SetComponentVisibility(m_aCarNodes[component], ATOMIC_FLAG_NONE);
}
@@ -4515,6 +5457,11 @@ CAutomobile::SetDoorDamage(int32 component, eDoors door, bool noFlyingComponents
return;
}
+ if(!CanDoorsBeDamaged() && status > DOOR_STATUS_SMASHED && door != DOOR_BONNET && door != DOOR_BOOT){
+ Damage.SetDoorStatus(door, DOOR_STATUS_SMASHED);
+ status = DOOR_STATUS_SMASHED;
+ }
+
if(door == DOOR_BOOT && status == DOOR_STATUS_SWINGING && pHandling->Flags & HANDLING_NOSWING_BOOT){
Damage.SetDoorStatus(DOOR_BOOT, DOOR_STATUS_MISSING);
status = DOOR_STATUS_MISSING;
@@ -4611,6 +5558,123 @@ CAutomobile::SetAllTaxiLights(bool set)
m_sAllTaxiLights = set;
}
+void
+CAutomobile::TellHeliToGoToCoors(float x, float y, float z, uint8 speed)
+{
+ AutoPilot.m_nCarMission = MISSION_HELI_FLYTOCOORS;
+ AutoPilot.m_vecDestinationCoors.x = x;
+ AutoPilot.m_vecDestinationCoors.y = y;
+ AutoPilot.m_vecDestinationCoors.z = z;
+ AutoPilot.m_nCruiseSpeed = speed;
+ SetStatus(STATUS_PHYSICS);
+
+ if(m_fOrientation == 0.0f){
+ m_fOrientation = CGeneral::GetATanOfXY(GetForward().x, GetForward().y) + PI;
+ while(m_fOrientation > TWOPI) m_fOrientation -= TWOPI;
+ }
+}
+
+void
+CAutomobile::TellPlaneToGoToCoors(float x, float y, float z, uint8 speed)
+{
+ AutoPilot.m_nCarMission = MISSION_HELI_FLYTOCOORS;
+ AutoPilot.m_vecDestinationCoors.x = x;
+ AutoPilot.m_vecDestinationCoors.y = y;
+ AutoPilot.m_vecDestinationCoors.z = z;
+ AutoPilot.m_nCruiseSpeed = speed;
+ SetStatus(STATUS_PHYSICS);
+
+ if(m_fOrientation == 0.0f)
+ m_fOrientation = CGeneral::GetATanOfXY(GetForward().x, GetForward().y);
+}
+
+void
+CAutomobile::PopBoot(void)
+{
+ switch(Damage.GetDoorStatus(DOOR_BOOT)){
+ case DOOR_STATUS_OK:
+ case DOOR_STATUS_SMASHED:
+ Doors[DOOR_BOOT].m_fAngle = Doors[DOOR_BOOT].m_fMinAngle;
+ CMatrix mat(RwFrameGetMatrix(m_aCarNodes[DOOR_BOOT]));
+ CVector pos = mat.GetPosition();
+ float axes[3] = { 0.0f, 0.0f, 0.0f };
+ axes[Doors[DOOR_BOOT].m_nAxis] = Doors[DOOR_BOOT].m_fAngle;
+ mat.SetRotate(axes[0], axes[1], axes[2]);
+ mat.Translate(pos);
+ mat.UpdateRW();
+ }
+}
+
+void
+CAutomobile::PopBootUsingPhysics(void)
+{
+ switch(Damage.GetDoorStatus(DOOR_BOOT))
+ case DOOR_STATUS_OK:
+ case DOOR_STATUS_SMASHED:
+ Damage.SetDoorStatus(DOOR_BOOT, DOOR_STATUS_SWINGING);
+ Doors[DOOR_BOOT].m_fAngle = -2.0f;
+}
+
+void
+CAutomobile::CloseAllDoors(void)
+{
+ CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex());
+ if(!IsDoorMissing(DOOR_FRONT_LEFT))
+ OpenDoor(CAR_DOOR_LF, DOOR_FRONT_LEFT, 0.0f);
+ if(mi->m_numDoors > 1){
+ if(!IsDoorMissing(DOOR_FRONT_RIGHT))
+ OpenDoor(CAR_DOOR_RF, DOOR_FRONT_RIGHT, 0.0f);
+ if(mi->m_numDoors > 2){
+ if(!IsDoorMissing(DOOR_REAR_LEFT))
+ OpenDoor(CAR_DOOR_LR, DOOR_REAR_LEFT, 0.0f);
+ if(!IsDoorMissing(DOOR_REAR_RIGHT))
+ OpenDoor(CAR_DOOR_RR, DOOR_REAR_RIGHT, 0.0f);
+ }
+ }
+}
+
+void
+CAutomobile::KnockPedOutCar(eWeaponType weapon, uint16 door, CPed *ped)
+{
+ AnimationId anim = ANIM_KO_SHOT_FRONT1;
+ if(ped == nil)
+ return;
+
+ ped->m_vehEnterType = door;
+ ped->SetPedState(PED_IDLE);
+ CAnimManager::BlendAnimation(ped->GetClump(), ped->m_animGroup, ANIM_IDLE_STANCE, 100.0f);
+ CPed::PedSetOutCarCB(nil, ped);
+ ped->SetMoveState(PEDMOVE_STILL);
+ if(GetUp().z < 0.0f)
+ ped->SetHeading(CGeneral::LimitRadianAngle(GetForward().Heading() + PI));
+ else
+ ped->SetHeading(GetForward().Heading());
+
+ switch(weapon){
+ case WEAPONTYPE_UNARMED:
+ case WEAPONTYPE_UNIDENTIFIED:
+ ped->m_vecMoveSpeed = m_vecMoveSpeed;
+ ped->m_pCollidingEntity = this;
+ anim = NUM_STD_ANIMS;
+ break;
+
+ case WEAPONTYPE_BASEBALLBAT:
+ case WEAPONTYPE_RAMMEDBYCAR:
+ case WEAPONTYPE_FALL:
+ ped->m_vecMoveSpeed = m_vecMoveSpeed;
+ anim = ANIM_KD_LEFT;
+ ApplyMoveForce(4.0f*GetUp() + 8.0f*GetRight());
+ break;
+ }
+
+ if(weapon != WEAPONTYPE_UNARMED){
+ ped->SetFall(1000, anim, 0);
+ ped->bIsStanding = false;
+ ped->m_headingRate = 0.0f;
+ }
+ ped->m_pMyVehicle = nil;
+}
+
#ifdef COMPATIBLE_SAVES
void
CAutomobile::Save(uint8*& buf)