summaryrefslogtreecommitdiffstats
path: root/src/vehicles
diff options
context:
space:
mode:
Diffstat (limited to 'src/vehicles')
-rw-r--r--src/vehicles/Automobile.cpp419
-rw-r--r--src/vehicles/Automobile.h19
-rw-r--r--src/vehicles/DamageManager.h3
-rw-r--r--src/vehicles/HandlingMgr.cpp36
-rw-r--r--src/vehicles/HandlingMgr.h2
-rw-r--r--src/vehicles/Transmission.cpp15
-rw-r--r--src/vehicles/Transmission.h3
-rw-r--r--src/vehicles/Vehicle.cpp49
-rw-r--r--src/vehicles/Vehicle.h14
9 files changed, 486 insertions, 74 deletions
diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp
index 1f64228b..6e31414f 100644
--- a/src/vehicles/Automobile.cpp
+++ b/src/vehicles/Automobile.cpp
@@ -12,7 +12,12 @@
#include "World.h"
#include "SurfaceTable.h"
#include "HandlingMgr.h"
+#include "Record.h"
+#include "Remote.h"
+#include "Population.h"
#include "CarCtrl.h"
+#include "CarAI.h"
+#include "Garages.h"
#include "PathFind.h"
#include "Ped.h"
#include "PlayerPed.h"
@@ -38,7 +43,370 @@ CAutomobile::SetModelIndex(uint32 id)
SetupModelNodes();
}
-WRAPPER void CAutomobile::ProcessControl(void) { EAXJMP(0x531470); }
+//WRAPPER void CAutomobile::ProcessControl(void) { EAXJMP(0x531470); }
+void
+CAutomobile::ProcessControl(void)
+{
+ int i;
+ CColModel *colModel;
+
+ if(m_veh_flagC80)
+ colModel = &CWorld::Players[CWorld::PlayerInFocus].m_ColModel;
+ else
+ colModel = GetColModel();
+ bWarnedPeds = false;
+
+ // skip if the collision isn't for the current level
+ if(colModel->level > LEVEL_NONE && colModel->level != CCollision::ms_collisionInMemory)
+ return;
+
+ // Improve grip of vehicles in certain cases
+ bool strongGrip1 = false;
+ bool strongGrip2 = false;
+ if(FindPlayerVehicle() && this != FindPlayerVehicle()){
+ switch(AutoPilot.m_nCarMission){
+ case MISSION_RAMPLAYER_FARAWAY:
+ case MISSION_RAMPLAYER_CLOSE:
+ case MISSION_BLOCKPLAYER_FARAWAY:
+ case MISSION_BLOCKPLAYER_CLOSE:
+ if(FindPlayerSpeed().Magnitude() > 0.3f){
+ strongGrip1 = true;
+ if(FindPlayerSpeed().Magnitude() > 0.4f){
+ if(m_vecMoveSpeed.Magnitude() < 0.3f)
+ strongGrip2 = true;
+ }else{
+ if((GetPosition() - FindPlayerCoors()).Magnitude() > 50.0f)
+ strongGrip2 = true;
+ }
+ }
+ }
+ }
+
+ if(bIsBus)
+ ProcessAutoBusDoors();
+
+ ProcessCarAlarm();
+
+ // Scan if this car is committing a crime that the police can see
+ if(m_status != STATUS_ABANDONED && m_status != STATUS_WRECKED &&
+ m_status != STATUS_PLAYER && m_status != STATUS_PLAYER_REMOTE && m_status != STATUS_PLAYER_DISABLED){
+ switch(GetModelIndex())
+ case MI_FBICAR:
+ case MI_POLICE:
+ case MI_ENFORCER:
+ case MI_SECURICA:
+ case MI_RHINO:
+ case MI_BARRACKS:
+ ScanForCrimes();
+ }
+
+ // Process driver
+ if(pDriver){
+ if(!bHadDriver && m_bombType == 5){
+ // If someone enters the car and there is a bomb, detonate
+ m_nBombTimer = 1000;
+ m_pBlowUpEntity = field_4DC;
+ if(m_pBlowUpEntity)
+ m_pBlowUpEntity->RegisterReference((CEntity**)&m_pBlowUpEntity);
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_BOMB_TICK, 1.0f);
+ }
+ bHadDriver = true;
+
+ if(IsUpsideDown() && CanPedEnterCar()){
+ if(!pDriver->IsPlayer() &&
+ !(pDriver->m_leader && pDriver->m_leader->bInVehicle) &&
+ pDriver->CharCreatedBy != MISSION_CHAR)
+ pDriver->SetObjective(OBJECTIVE_LEAVE_VEHICLE, this);
+ }
+ }else
+ bHadDriver = false;
+
+ // Process passengers
+ if(m_nNumPassengers != 0 && IsUpsideDown() && CanPedEnterCar()){
+ for(i = 0; i < m_nNumMaxPassengers; i++)
+ if(pPassengers[i])
+ if(!pPassengers[i]->IsPlayer() &&
+ !(pPassengers[i]->m_leader && pPassengers[i]->m_leader->bInVehicle) &&
+ pPassengers[i]->CharCreatedBy != MISSION_CHAR)
+ pPassengers[i]->SetObjective(OBJECTIVE_LEAVE_VEHICLE, this);
+ }
+
+ // CRubbish::StirUp
+
+ // 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);
+
+ AutoPilot.m_flag1 = false;
+ AutoPilot.m_flag2 = false;
+
+ // Set Center of Mass to make car more stable
+ if(strongGrip1 || bCheat3)
+ m_vecCentreOfMass.z = 0.3f*m_aSuspensionSpringLength[0] + -1.0*m_fHeightAboveRoad;
+ else if(pHandling->Flags & HANDLING_NONPLAYER_STABILISER && m_status == STATUS_PHYSICS)
+ m_vecCentreOfMass.z = pHandling->CentreOfMass.z - 0.2f*pHandling->Dimension.z;
+ else
+ m_vecCentreOfMass.z = pHandling->CentreOfMass.z;
+
+ // Process depending on status
+
+ bool playerRemote = false;
+ switch(m_status){
+ case STATUS_PLAYER_REMOTE:
+ if(CPad::GetPad(0)->WeaponJustDown()){
+ BlowUpCar(FindPlayerPed());
+ CRemote::TakeRemoteControlledCarFromPlayer();
+ }
+
+ if(GetModelIndex() == MI_RCBANDIT){
+ CVector pos = GetPosition();
+ // FindPlayerCoors unused
+ if(RcbanditCheckHitWheels() || bIsInWater || CPopulation::IsPointInSafeZone(&pos)){
+ if(CPopulation::IsPointInSafeZone(&pos))
+ CGarages::TriggerMessage("HM2_5", -1, 5000, -1);
+ CRemote::TakeRemoteControlledCarFromPlayer();
+ BlowUpCar(FindPlayerPed());
+ }
+ }
+
+ if(CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle == this)
+ playerRemote = true;
+ // fall through
+ case STATUS_PLAYER:
+ if(playerRemote ||
+ pDriver && pDriver->GetPedState() != PED_EXIT_CAR && pDriver->GetPedState() != PED_DRAG_FROM_CAR){
+ // process control input if controlled by player
+ if(playerRemote || pDriver->m_nPedType == PEDTYPE_PLAYER1)
+ ProcessControlInputs(0);
+
+ PruneReferences();
+
+ if(m_status == STATUS_PLAYER && CRecordDataForChase::Status != RECORDSTATE_1)
+ DoDriveByShootings();
+ }
+ break;
+
+ case STATUS_SIMPLE:
+ CCarAI::UpdateCarAI(this);
+ CPhysical::ProcessControl();
+ CCarCtrl::UpdateCarOnRails(this);
+
+ m_nWheelsOnGround_2 = 4;
+ m_nWheelsOnGroundPrev = m_nWheelsOnGround;
+ m_nWheelsOnGround = 4;
+
+ pHandling->Transmission.CalculateGearForSimpleCar(AutoPilot.m_fMaxTrafficSpeed/50.0f, m_nCurrentGear);
+
+ {
+ float wheelRot = ProcessWheelRotation(WHEEL_STATE_0, GetForward(), m_vecMoveSpeed, 0.35f);
+ for(i = 0; i < 4; i++)
+ m_aWheelRotation[i] += wheelRot;
+ }
+
+ PlayHornIfNecessary();
+ ReduceHornCounter();
+ bVehicleColProcessed = false;
+ // that's all we do for simple vehicles
+ return;
+
+ case STATUS_PHYSICS:
+ CCarAI::UpdateCarAI(this);
+ CCarCtrl::SteerAICarWithPhysics(this);
+ PlayHornIfNecessary();
+ break;
+
+ case STATUS_ABANDONED:
+ m_fBrakePedal = 0.2f;
+ bIsHandbrakeOn = false;
+
+ m_fSteerAngle = 0.0f;
+ m_fGasPedal = 0.0f;
+ m_nCarHornTimer = 0;
+ break;
+
+ case STATUS_WRECKED:
+ m_fBrakePedal = 0.05f;
+ bIsHandbrakeOn = true;
+
+ m_fSteerAngle = 0.0f;
+ m_fGasPedal = 0.0f;
+ m_nCarHornTimer = 0;
+ break;
+
+ case STATUS_PLAYER_DISABLED:
+ m_fBrakePedal = 1.0f;
+ bIsHandbrakeOn = true;
+
+ m_fSteerAngle = 0.0f;
+ m_fGasPedal = 0.0f;
+ m_nCarHornTimer = 0;
+ break;
+ }
+
+ if(GetPosition().z < -0.6f){
+ assert(0);
+ }
+
+ bool skipPhysics = false;
+ if(!bIsStuck){
+ assert(0);
+ }
+
+ // Postpone
+ for(i = 0; i < 4; i++)
+ if(m_aGroundPhysical[i] && !CWorld::bForceProcessControl && m_aGroundPhysical[i]->bIsInSafePosition){
+ bWasPostponed = true;
+ return;
+ }
+
+ // VehicleDamage
+
+ // special control
+ switch(GetModelIndex()){
+ case MI_FIRETRUCK:
+ case MI_RHINO:
+ case MI_YARDIE:
+ default:
+ assert(0);
+ }
+
+ if(skipPhysics){
+ bHasContacted = false;
+ bIsInSafePosition = false;
+ bWasPostponed = false;
+ bHasHitWall = false;
+ m_nCollisionRecords = 0;
+ bHasCollided = false;
+ bVehicleColProcessed = 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);
+ }else{
+
+ // This has to be done if ProcessEntityCollision wasn't called
+ if(!bVehicleColProcessed){
+ CMatrix mat(GetMatrix());
+ bIsStuck = false;
+ bHasContacted = false;
+ bIsInSafePosition = false;
+ bWasPostponed = false;
+ bHasHitWall = false;
+ m_fDistanceTravelled = 0.0f;
+ field_EF = false;
+ m_phy_flagA80 = false;
+ ApplyMoveSpeed();
+ ApplyTurnSpeed();
+ for(i = 0; CheckCollision() && i < 5; i++){
+ GetMatrix() = mat;
+ ApplyMoveSpeed();
+ ApplyTurnSpeed();
+ }
+ bIsInSafePosition = true;
+ bIsStuck = false;
+ }
+
+ CPhysical::ProcessControl();
+
+ ProcessBuoyancy();
+
+ // Rescale spring ratios, i.e. subtract wheel radius
+ for(i = 0; i < 4; i++){
+ // wheel radius in relation to suspension line
+ float wheelRadius = 1.0f - m_aSuspensionSpringLength[i]/m_aSuspensionLineLength[i];
+ // rescale such that 0.0 is fully compressed and 1.0 is fully extended
+ m_aSuspensionSpringRatio[i] = (m_aSuspensionSpringRatio[i]-wheelRadius)/(1.0f-wheelRadius);
+ }
+
+ float fwdSpeed = DotProduct(m_vecMoveSpeed, GetForward());
+ CVector contactPoints[4]; // relative to model
+ CVector contactSpeeds[4]; // speed at contact points
+ CVector springDirections[4]; // normalized, in model space
+
+ for(i = 0; i < 4; i++){
+ // Set spring under certain circumstances
+ if(Damage.GetWheelStatus(i) == WHEEL_STATUS_MISSING)
+ m_aSuspensionSpringRatio[i] = 1.0f;
+ else if(Damage.GetWheelStatus(i) == WHEEL_STATUS_BURST){
+ // wheel more bumpy the faster we are
+ if(CGeneral::GetRandomNumberInRange(0, (uint16)(40*fwdSpeed) + 98) < 100){
+ m_aSuspensionSpringRatio[i] += 0.3f*(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
+ if(m_aSuspensionSpringRatio[i] < 1.0f){
+ contactPoints[i] = m_aWheelColPoints[i].point - GetPosition();
+ springDirections[i] = Multiply3x3(GetMatrix(), colModel->lines[i].p1 - colModel->lines[i].p0);
+ springDirections[i].Normalise();
+ }
+ }
+
+ // Make springs push up vehicle
+ for(i = 0; i < 4; i++){
+ if(m_aSuspensionSpringRatio[i] < 1.0f){
+ float bias = pHandling->fSuspensionBias;
+ if(i == 1 || i == 3) // rear
+ bias = 1.0f - bias;
+
+ ApplySpringCollision(pHandling->fSuspensionForceLevel,
+ springDirections[i], contactPoints[i],
+ m_aSuspensionSpringRatio[i], bias);
+ m_aWheelSkidmarkMuddy[i] =
+ m_aWheelColPoints[i].surfaceB == SURFACE_GRASS ||
+ m_aWheelColPoints[i].surfaceB == SURFACE_DIRTTRACK ||
+ m_aWheelColPoints[i].surfaceB == SURFACE_SAND;
+ }else{
+ contactPoints[i] = Multiply3x3(GetMatrix(), colModel->lines[i].p1);
+ }
+ }
+
+ // Get speed at contact points
+ for(i = 0; i < 4; i++){
+ contactSpeeds[i] = GetSpeed(contactPoints[i]);
+ if(m_aGroundPhysical[i]){
+ // subtract movement of physical we're standing on
+ contactSpeeds[i] -= m_aGroundPhysical[i]->GetSpeed(m_aGroundOffset[i]);
+#ifndef FIX_BUGS
+ // this shouldn't be reset because we still need it below
+ m_aGroundPhysical[i] = nil;
+#endif
+ }
+ }
+
+ // dampen springs
+ for(i = 0; i < 4; i++)
+ if(m_aSuspensionSpringRatio[i] < 1.0f)
+ ApplySpringDampening(pHandling->fSuspensionDampingLevel,
+ springDirections[i], contactPoints[i], contactSpeeds[i]);
+
+ // Get speed at contact points again
+ for(i = 0; i < 4; i++){
+ contactSpeeds[i] = GetSpeed(contactPoints[i]);
+ if(m_aGroundPhysical[i]){
+ // subtract movement of physical we're standing on
+ contactSpeeds[i] -= m_aGroundPhysical[i]->GetSpeed(m_aGroundOffset[i]);
+ m_aGroundPhysical[i] = nil;
+ }
+ }
+
+ assert(0);
+ }
+
+ assert(0 && "misc stuff");
+}
void
CAutomobile::Teleport(CVector pos)
@@ -230,7 +598,7 @@ CAutomobile::ProcessControlInputs(uint8 pad)
fValue = -sq(m_fSteerRatio);
else
fValue = sq(m_fSteerRatio);
- m_fSteerAngle = DEGTORAD(m_handling->fSteeringLock) * fValue;
+ m_fSteerAngle = DEGTORAD(pHandling->fSteeringLock) * fValue;
if(bComedyControls){
int rnd = CGeneral::GetRandomNumber() % 10;
@@ -271,6 +639,21 @@ CAutomobile::ProcessControlInputs(uint8 pad)
}
}
+WRAPPER void
+CAutomobile::ProcessBuoyancy(void)
+{ EAXJMP(0x5308D0);
+}
+
+WRAPPER void
+CAutomobile::DoDriveByShootings(void)
+{ EAXJMP(0x564000);
+}
+
+WRAPPER int32
+CAutomobile::RcbanditCheckHitWheels(void)
+{ EAXJMP(0x53C990);
+}
+
void
CAutomobile::GetComponentWorldPosition(int32 component, CVector &pos)
{
@@ -524,7 +907,7 @@ CAutomobile::BlowUpCar(CEntity *culprit)
m_fHealth = 0.0f;
m_nBombTimer = 0;
- m_auto_flagA7 = 0;
+ m_bombType = 0;
TheCamera.CamShake(0.7f, GetPosition().x, GetPosition().y, GetPosition().z);
@@ -660,8 +1043,8 @@ CAutomobile::PlayCarHorn(void)
void
CAutomobile::PlayHornIfNecessary(void)
{
- if(m_autoPilot.m_flag2 ||
- m_autoPilot.m_flag1)
+ if(AutoPilot.m_flag2 ||
+ AutoPilot.m_flag1)
if(!HasCarStoppedBecauseOfLight())
PlayCarHorn();
}
@@ -694,23 +1077,23 @@ CAutomobile::SetupSuspensionLines(void)
m_aWheelPosition[i] = posn.z;
// uppermost wheel position
- posn.z += m_handling->fSuspensionUpperLimit;
+ posn.z += pHandling->fSuspensionUpperLimit;
colModel->lines[i].p0 = posn;
// lowermost wheel position
- posn.z += m_handling->fSuspensionLowerLimit - m_handling->fSuspensionUpperLimit;
+ posn.z += pHandling->fSuspensionLowerLimit - pHandling->fSuspensionUpperLimit;
// lowest point on tyre
posn.z -= mi->m_wheelScale*0.5f;
colModel->lines[i].p1 = posn;
// this is length of the spring at rest
- m_aSuspensionSpringLength[i] = m_handling->fSuspensionUpperLimit - m_handling->fSuspensionLowerLimit;
+ m_aSuspensionSpringLength[i] = pHandling->fSuspensionUpperLimit - pHandling->fSuspensionLowerLimit;
m_aSuspensionLineLength[i] = colModel->lines[i].p0.z - colModel->lines[i].p1.z;
}
// 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*m_handling->fSuspensionForceLevel)));
+ (1.0f - 1.0f/(8.0f*pHandling->fSuspensionForceLevel)));
for(i = 0; i < 4; i++)
m_aWheelPosition[i] = mi->m_wheelScale*0.5f - m_fHeightAboveRoad;
@@ -761,20 +1144,20 @@ CAutomobile::HasCarStoppedBecauseOfLight(void)
if(m_status != STATUS_SIMPLE && m_status != STATUS_PHYSICS)
return false;
- if(m_autoPilot.m_nCurrentRouteNode && m_autoPilot.m_nNextRouteNode){
- CPathNode *curnode = &ThePaths.m_pathNodes[m_autoPilot.m_nCurrentRouteNode];
+ if(AutoPilot.m_nCurrentRouteNode && AutoPilot.m_nNextRouteNode){
+ CPathNode *curnode = &ThePaths.m_pathNodes[AutoPilot.m_nCurrentRouteNode];
for(i = 0; i < curnode->numLinks; i++)
- if(ThePaths.m_connections[curnode->firstLink + i] == m_autoPilot.m_nNextRouteNode)
+ if(ThePaths.m_connections[curnode->firstLink + i] == AutoPilot.m_nNextRouteNode)
break;
if(i < curnode->numLinks &&
ThePaths.m_carPathLinks[ThePaths.m_carPathConnections[curnode->firstLink + i]].trafficLightType & 3) // TODO
return true;
}
- if(m_autoPilot.m_nCurrentRouteNode && m_autoPilot.m_nPrevRouteNode){
- CPathNode *curnode = &ThePaths.m_pathNodes[m_autoPilot.m_nCurrentRouteNode];
+ if(AutoPilot.m_nCurrentRouteNode && AutoPilot.m_nPrevRouteNode){
+ CPathNode *curnode = &ThePaths.m_pathNodes[AutoPilot.m_nCurrentRouteNode];
for(i = 0; i < curnode->numLinks; i++)
- if(ThePaths.m_connections[curnode->firstLink + i] == m_autoPilot.m_nPrevRouteNode)
+ if(ThePaths.m_connections[curnode->firstLink + i] == AutoPilot.m_nPrevRouteNode)
break;
if(i < curnode->numLinks &&
ThePaths.m_carPathLinks[ThePaths.m_carPathConnections[curnode->firstLink + i]].trafficLightType & 3) // TODO
@@ -861,7 +1244,7 @@ CAutomobile::Fix(void)
Damage.ResetDamageStatus();
- if(m_handling->Flags & HANDLING_NO_DOORS){
+ if(pHandling->Flags & HANDLING_NO_DOORS){
Damage.SetDoorStatus(DOOR_FRONT_LEFT, DOOR_STATUS_MISSING);
Damage.SetDoorStatus(DOOR_FRONT_RIGHT, DOOR_STATUS_MISSING);
Damage.SetDoorStatus(DOOR_REAR_LEFT, DOOR_STATUS_MISSING);
@@ -987,7 +1370,7 @@ CAutomobile::SpawnFlyingComponent(int32 component, uint32 type)
obj->m_fElasticity = 0.1f;
obj->m_fBuoyancy = obj->m_fMass*GRAVITY/0.75f;
obj->ObjectCreatedBy = TEMP_OBJECT;
- obj->bIsStatic = true;
+ obj->bIsStatic = false;
obj->bIsPickup = false;
obj->bUseVehicleColours = true;
obj->m_colour1 = m_currentColour1;
@@ -1114,7 +1497,7 @@ CAutomobile::SetDoorDamage(int32 component, eDoors door, bool noFlyingComponents
return;
}
- if(door == DOOR_BOOT && status == DOOR_STATUS_SWINGING && m_handling->Flags & HANDLING_NOSWING_BOOT){
+ if(door == DOOR_BOOT && status == DOOR_STATUS_SWINGING && pHandling->Flags & HANDLING_NOSWING_BOOT){
Damage.SetDoorStatus(DOOR_BOOT, DOOR_STATUS_MISSING);
status = DOOR_STATUS_MISSING;
}
diff --git a/src/vehicles/Automobile.h b/src/vehicles/Automobile.h
index 60e08d0a..6ed5e154 100644
--- a/src/vehicles/Automobile.h
+++ b/src/vehicles/Automobile.h
@@ -6,6 +6,12 @@
class CObject;
+// Wheels are in order:
+// FRONT LEFT
+// REAR LEFT
+// FRONT RIGHT
+// REAR RIGHT
+
class CAutomobile : public CVehicle
{
public:
@@ -24,13 +30,15 @@ public:
float m_aWheelPosition[4];
float m_aWheelSpeed[4];
uint8 field_4D8;
- uint8 m_auto_flagA7 : 1;
+ uint8 m_bombType : 3;
uint8 bTaxiLight : 1;
- uint8 m_auto_flagA10 : 1;
+ uint8 bHadDriver : 1; // for bombs
uint8 m_auto_flagA20 : 1;
uint8 m_auto_flagA40 : 1;
uint8 m_auto_flagA80 : 1;
- uint8 field_4DA[10];
+ uint8 field_4DA[2];
+ CEntity *field_4DC; // blow up entity
+ uint8 field_4E0[4];
uint32 m_nBusDoorTimerEnd;
uint32 m_nBusDoorTimerStart;
float m_aSuspensionSpringLength[4];
@@ -41,7 +49,7 @@ public:
float field_530;
CPhysical *m_aGroundPhysical[4]; // physicals touching wheels
CVector m_aGroundOffset[4]; // from ground object to colpoint
- CEntity *m_pBlowUpEntity;
+ CEntity *m_pSetOnFireEntity;
float m_weaponThingA; // TODO
float m_weaponThingB; // TODO
float m_fCarGunLR;
@@ -87,6 +95,9 @@ public:
float GetHeightAboveRoad(void);
void PlayCarHorn(void);
+ void ProcessBuoyancy(void);
+ void DoDriveByShootings(void);
+ int32 RcbanditCheckHitWheels(void);
void PlayHornIfNecessary(void);
void ResetSuspension(void);
void SetupSuspensionLines(void);
diff --git a/src/vehicles/DamageManager.h b/src/vehicles/DamageManager.h
index b815f724..f2044ec2 100644
--- a/src/vehicles/DamageManager.h
+++ b/src/vehicles/DamageManager.h
@@ -23,7 +23,8 @@ enum ePanelStatus
enum eWheelStatus
{
WHEEL_STATUS_OK,
- WHEEL_STATUS_BURST
+ WHEEL_STATUS_BURST,
+ WHEEL_STATUS_MISSING
};
enum tComponent
diff --git a/src/vehicles/HandlingMgr.cpp b/src/vehicles/HandlingMgr.cpp
index 47d0564c..9bcaaf81 100644
--- a/src/vehicles/HandlingMgr.cpp
+++ b/src/vehicles/HandlingMgr.cpp
@@ -140,11 +140,11 @@ cHandlingDataMgr::LoadHandlingData(void)
case 9: handling->fTractionMultiplier = strtod(word, nil); break;
case 10: handling->fTractionLoss = strtod(word, nil); break;
case 11: handling->fTractionBias = strtod(word, nil); break;
- case 12: handling->TransmissionData.nNumberOfGears = atoi(word); break;
- case 13: handling->TransmissionData.fMaxVelocity = strtod(word, nil); break;
- case 14: handling->TransmissionData.fEngineAcceleration = strtod(word, nil) * 0.4f; break;
- case 15: handling->TransmissionData.nDriveType = word[0]; break;
- case 16: handling->TransmissionData.nEngineType = word[0]; break;
+ case 12: handling->Transmission.nNumberOfGears = atoi(word); break;
+ case 13: handling->Transmission.fMaxVelocity = strtod(word, nil); break;
+ case 14: handling->Transmission.fEngineAcceleration = strtod(word, nil) * 0.4f; break;
+ case 15: handling->Transmission.nDriveType = word[0]; break;
+ case 16: handling->Transmission.nEngineType = word[0]; break;
case 17: handling->fBrakeDeceleration = strtod(word, nil); break;
case 18: handling->fBrakeBias = strtod(word, nil); break;
case 19: handling->bABS = !!atoi(word); break;
@@ -159,7 +159,7 @@ cHandlingDataMgr::LoadHandlingData(void)
case 28: handling->fSuspensionBias = strtod(word, nil); break;
case 29:
sscanf(word, "%x", &handling->Flags);
- handling->TransmissionData.Flags = handling->Flags;
+ handling->Transmission.Flags = handling->Flags;
break;
case 30: handling->FrontLights = atoi(word); break;
case 31: handling->RearLights = atoi(word); break;
@@ -192,8 +192,8 @@ cHandlingDataMgr::ConvertDataToGameUnits(tHandlingData *handling)
// TODO: figure out what exactly is being converted here
float velocity, a, b, specificVolume;
- handling->TransmissionData.fEngineAcceleration /= 2500.0f;
- handling->TransmissionData.fMaxVelocity /= 180.0f;
+ handling->Transmission.fEngineAcceleration /= 2500.0f;
+ handling->Transmission.fMaxVelocity /= 180.0f;
handling->fBrakeDeceleration /= 2500.0f;
handling->fTurnMass = (sq(handling->Dimension.x) + sq(handling->Dimension.y)) * handling->fMass / 12.0f;
if(handling->fTurnMass < 10.0f)
@@ -205,27 +205,27 @@ cHandlingDataMgr::ConvertDataToGameUnits(tHandlingData *handling)
specificVolume = handling->Dimension.x*handling->Dimension.z*0.5f / handling->fMass; // ?
a = 0.0f;
b = 100.0f;
- velocity = handling->TransmissionData.fMaxVelocity;
+ velocity = handling->Transmission.fMaxVelocity;
while(a < b && velocity > 0.0f){
velocity -= 0.01;
- a = handling->TransmissionData.fEngineAcceleration/6.0f;
+ a = handling->Transmission.fEngineAcceleration/6.0f;
b = -velocity * (1.0f/(specificVolume * sq(velocity) + 1.0f) - 1.0f);
}
if(handling->nIdentifier == HANDLING_RCBANDIT){
- handling->TransmissionData.fUnkMaxVelocity = handling->TransmissionData.fMaxVelocity;
+ handling->Transmission.fUnkMaxVelocity = handling->Transmission.fMaxVelocity;
}else{
- handling->TransmissionData.fUnkMaxVelocity = velocity;
- handling->TransmissionData.fMaxVelocity = velocity * 1.2f;
+ handling->Transmission.fUnkMaxVelocity = velocity;
+ handling->Transmission.fMaxVelocity = velocity * 1.2f;
}
- handling->TransmissionData.fMaxReverseVelocity = -0.2f;
+ handling->Transmission.fMaxReverseVelocity = -0.2f;
- if(handling->TransmissionData.nDriveType == '4')
- handling->TransmissionData.fEngineAcceleration /= 4.0f;
+ if(handling->Transmission.nDriveType == '4')
+ handling->Transmission.fEngineAcceleration /= 4.0f;
else
- handling->TransmissionData.fEngineAcceleration /= 2.0f;
+ handling->Transmission.fEngineAcceleration /= 2.0f;
- handling->TransmissionData.InitGearRatios();
+ handling->Transmission.InitGearRatios();
}
int32
diff --git a/src/vehicles/HandlingMgr.h b/src/vehicles/HandlingMgr.h
index 2627fbae..7d8613da 100644
--- a/src/vehicles/HandlingMgr.h
+++ b/src/vehicles/HandlingMgr.h
@@ -94,7 +94,7 @@ struct tHandlingData
int8 nPercentSubmerged;
float fBuoyancy;
float fTractionMultiplier;
- cTransmission TransmissionData;
+ cTransmission Transmission;
float fBrakeDeceleration;
float fBrakeBias;
int8 bABS;
diff --git a/src/vehicles/Transmission.cpp b/src/vehicles/Transmission.cpp
index 2be25cbb..f8c345f1 100644
--- a/src/vehicles/Transmission.cpp
+++ b/src/vehicles/Transmission.cpp
@@ -35,3 +35,18 @@ cTransmission::InitGearRatios(void)
Gears[1].fShiftDownVelocity = -0.01f;
}
+
+void
+cTransmission::CalculateGearForSimpleCar(float speed, uint8 &gear)
+{
+ static tGear *pGearRatio = &Gears[gear];
+ fCurVelocity = speed;
+ if(speed > pGearRatio->fShiftUpVelocity)
+ gear++;
+ else if(speed < pGearRatio->fShiftDownVelocity){
+ if(gear - 1 < 0)
+ gear = 0;
+ else
+ gear--;
+ }
+}
diff --git a/src/vehicles/Transmission.h b/src/vehicles/Transmission.h
index 686e0aca..ea67b62c 100644
--- a/src/vehicles/Transmission.h
+++ b/src/vehicles/Transmission.h
@@ -20,7 +20,8 @@ public:
float fMaxVelocity;
float fUnkMaxVelocity;
float fMaxReverseVelocity;
- float field_5C;
+ float fCurVelocity;
void InitGearRatios(void);
+ void CalculateGearForSimpleCar(float speed, uint8 &gear);
};
diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp
index b21c859a..f3a8f785 100644
--- a/src/vehicles/Vehicle.cpp
+++ b/src/vehicles/Vehicle.cpp
@@ -56,16 +56,16 @@ CVehicle::CVehicle(uint8 CreatedBy)
for(i = 0; i < m_nNumMaxPassengers; i++)
pPassengers[i] = nil;
m_nBombTimer = 0;
- m_pWhoSetMeOnFire = nil;
+ m_pBlowUpEntity = nil;
field_1FB = 0;
bComedyControls = false;
m_veh_flagB40 = false;
m_veh_flagB80 = false;
m_veh_flagC1 = false;
bIsDamaged = false;
- m_veh_flagC8 = false;
+ bFadeOut = false;
m_veh_flagC10 = false;
- m_veh_flagC4 = false;
+ bHasBeenOwnedByPlayer = false;
m_veh_flagC20 = false;
bCanBeDamaged = true;
m_veh_flagC80 = false;
@@ -96,11 +96,11 @@ CVehicle::CVehicle(uint8 CreatedBy)
m_comedyControlState = 0;
m_aCollPolys[0].valid = false;
m_aCollPolys[1].valid = false;
- m_autoPilot.m_nCarMission = MISSION_NONE;
- m_autoPilot.m_nAnimationId = TEMPACT_NONE;
- m_autoPilot.m_nTimeToStartMission = CTimer::GetTimeInMilliseconds();
- m_autoPilot.m_flag4 = false;
- m_autoPilot.m_flag10 = false;
+ AutoPilot.m_nCarMission = MISSION_NONE;
+ AutoPilot.m_nAnimationId = TEMPACT_NONE;
+ AutoPilot.m_nTimeToStartMission = CTimer::GetTimeInMilliseconds();
+ AutoPilot.m_flag4 = false;
+ AutoPilot.m_flag10 = false;
}
CVehicle::~CVehicle()
@@ -259,7 +259,7 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon
adhesion *= CTimer::GetTimeStep();
if(bAlreadySkidding)
- adhesion *= m_handling->fTractionLoss;
+ adhesion *= pHandling->fTractionLoss;
// moving sideways
if(contactSpeedRight != 0.0f){
@@ -318,7 +318,7 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon
}
float l = Sqrt(sq(right) + sq(fwd));
- float tractionLoss = bAlreadySkidding ? 1.0f : m_handling->fTractionLoss;
+ float tractionLoss = bAlreadySkidding ? 1.0f : pHandling->fTractionLoss;
right *= adhesion * tractionLoss / l;
fwd *= adhesion * tractionLoss / l;
}
@@ -374,20 +374,21 @@ CVehicle::ProcessDelayedExplosion(void)
if(m_nBombTimer == 0)
return;
- if(m_nBombTimer == 0){
- int tick = CTimer::GetTimeStep()/60.0f*1000.0f;
- if(tick > m_nBombTimer)
- m_nBombTimer = 0;
- else
- m_nBombTimer -= tick;
+ int tick = CTimer::GetTimeStep()/60.0f*1000.0f;
+ if(tick > m_nBombTimer)
+ m_nBombTimer = 0;
+ else
+ m_nBombTimer -= tick;
- if(IsCar() && ((CAutomobile*)this)->m_auto_flagA7 == 4 && (m_nBombTimer & 0xFE00) != 0xFE00)
- DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_BOMB_TICK, 0.0f);
+ if(IsCar() && ((CAutomobile*)this)->m_bombType == 4 && (m_nBombTimer & 0xFE00) != 0xFE00)
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_BOMB_TICK, 0.0f);
- if(FindPlayerVehicle() != this && m_pWhoSetMeOnFire == FindPlayerPed())
- CWorld::Players[CWorld::PlayerInFocus].AwardMoneyForExplosion(this);
- BlowUpCar(m_pWhoSetMeOnFire);
- }
+ if (m_nBombTimer != 0)
+ return;
+
+ if(FindPlayerVehicle() != this && m_pBlowUpEntity == FindPlayerPed())
+ CWorld::Players[CWorld::PlayerInFocus].AwardMoneyForExplosion(this);
+ BlowUpCar(m_pBlowUpEntity);
}
bool
@@ -449,7 +450,7 @@ CVehicle::IsVehicleNormal(void)
bool
CVehicle::CarHasRoof(void)
{
- if((m_handling->Flags & HANDLING_HAS_NO_ROOF) == 0)
+ if((pHandling->Flags & HANDLING_HAS_NO_ROOF) == 0)
return true;
if(m_aExtras[0] && m_aExtras[1])
return false;
@@ -519,7 +520,7 @@ bool
CVehicle::CanPedOpenLocks(CPed *ped)
{
if(m_nDoorLock == CARLOCK_LOCKED ||
- m_nDoorLock == CARLOCK_COP_CAR ||
+ m_nDoorLock == CARLOCK_LOCKED_INITIALLY ||
m_nDoorLock == CARLOCK_LOCKED_PLAYER_INSIDE)
return false;
if(ped->IsPlayer() && m_nDoorLock == CARLOCK_LOCKOUT_PLAYER_ONLY)
diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h
index 55805e9d..b37ea84d 100644
--- a/src/vehicles/Vehicle.h
+++ b/src/vehicles/Vehicle.h
@@ -20,7 +20,7 @@ enum eCarLock {
CARLOCK_LOCKED,
CARLOCK_LOCKOUT_PLAYER_ONLY,
CARLOCK_LOCKED_PLAYER_INSIDE,
- CARLOCK_COP_CAR,
+ CARLOCK_LOCKED_INITIALLY,
CARLOCK_FORCE_SHUT_DOORS,
CARLOCK_SKIP_SHUT_DOORS
};
@@ -125,8 +125,8 @@ class CVehicle : public CPhysical
{
public:
// 0x128
- tHandlingData *m_handling;
- CAutoPilot m_autoPilot;
+ tHandlingData *pHandling;
+ CAutoPilot AutoPilot;
uint8 m_currentColour1;
uint8 m_currentColour2;
uint8 m_aExtras[2];
@@ -162,14 +162,14 @@ public:
uint8 bIsBig: 1; // Is this vehicle a bus
uint8 bLowVehicle: 1; // Need this for sporty type cars to use low getting-in/out anims
uint8 bComedyControls : 1; // Will make the car hard to control (hopefully in a funny way)
- uint8 m_veh_flagB20 : 1;
+ uint8 bWarnedPeds : 1; // Has scan and warn peds of danger been processed?
uint8 m_veh_flagB40 : 1;
uint8 m_veh_flagB80 : 1;
uint8 m_veh_flagC1 : 1;
uint8 bIsDamaged : 1; // This vehicle has been damaged and is displaying all its components
- uint8 m_veh_flagC4 : 1;
- uint8 m_veh_flagC8 : 1;
+ uint8 bHasBeenOwnedByPlayer : 1;// To work out whether stealing it is a crime
+ uint8 bFadeOut : 1; // Fade vehicle out
uint8 m_veh_flagC10 : 1;
uint8 m_veh_flagC20 : 1;
uint8 bCanBeDamaged : 1; // Set to FALSE during cut scenes to avoid explosions
@@ -196,7 +196,7 @@ public:
uint32 m_nTimeOfDeath;
int16 field_214;
int16 m_nBombTimer; // goes down with each frame
- CPed *m_pWhoSetMeOnFire;
+ CEntity *m_pBlowUpEntity;
float field_21C;
float field_220;
eCarLock m_nDoorLock;