summaryrefslogtreecommitdiffstats
path: root/src/vehicles
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/vehicles/Automobile.cpp1488
-rw-r--r--src/vehicles/Automobile.h8
-rw-r--r--src/vehicles/Bike.cpp44
-rw-r--r--src/vehicles/Bike.h6
-rw-r--r--src/vehicles/Boat.cpp5
-rw-r--r--src/vehicles/Cranes.cpp10
-rw-r--r--src/vehicles/DamageManager.cpp5
-rw-r--r--src/vehicles/DamageManager.h1
-rw-r--r--src/vehicles/Door.cpp55
-rw-r--r--src/vehicles/Door.h19
-rw-r--r--src/vehicles/Ferry.cpp833
-rw-r--r--src/vehicles/Ferry.h143
-rw-r--r--src/vehicles/HandlingMgr.cpp160
-rw-r--r--src/vehicles/HandlingMgr.h93
-rw-r--r--src/vehicles/Heli.cpp2
-rw-r--r--src/vehicles/Plane.cpp6
-rw-r--r--src/vehicles/Plane.h1
-rw-r--r--src/vehicles/Train.cpp88
-rw-r--r--src/vehicles/Transmission.cpp118
-rw-r--r--src/vehicles/Transmission.h2
-rw-r--r--src/vehicles/Vehicle.cpp320
-rw-r--r--src/vehicles/Vehicle.h45
22 files changed, 2396 insertions, 1056 deletions
diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp
index 815b2534..b0f21af7 100644
--- a/src/vehicles/Automobile.cpp
+++ b/src/vehicles/Automobile.cpp
@@ -51,6 +51,8 @@
#include "Bike.h"
#include "Wanted.h"
#include "SaveBuf.h"
+#include "Streaming.h"
+#include "sampman.h"
bool bAllCarCheat;
@@ -86,6 +88,7 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
switch(GetModelIndex()){
case MI_HUNTER:
case MI_ANGEL:
+ case MI_ANGEL2:
case MI_FREEWAY:
m_nRadioStation = V_ROCK;
break;
@@ -103,6 +106,8 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
pHandling = mod_HandlingManager.GetHandlingData((tVehicleType)mi->m_handlingId);
pFlyingHandling = mod_HandlingManager.GetFlyingPointer((tVehicleType)mi->m_handlingId);
+ m_fEngineInertiaVar1 = 0.0f;
+ m_fEngineInertiaVar2 = 0.0f;
m_auto_unused1 = 20.0f;
m_auto_unused2 = 0;
@@ -148,10 +153,10 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
for(i = 0; i < 6; i++)
m_randomValues[i] = CGeneral::GetRandomNumberInRange(-0.15f, 0.15f);
- m_fMass = pHandling->fMass;
- m_fTurnMass = pHandling->fTurnMass;
+ m_fMass = pHandling->GetMass();
+ m_fTurnMass = pHandling->GetTurnMass();
m_vecCentreOfMass = pHandling->CentreOfMass;
- m_fAirResistance = pHandling->Dimension.x*pHandling->Dimension.z/m_fMass;
+ m_fAirResistance = pHandling->fDragMult > 0.01f ? pHandling->fDragMult*0.0005f : pHandling->fDragMult;
m_fElasticity = 0.05f;
m_fBuoyancy = pHandling->fBuoyancy;
@@ -192,12 +197,6 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
m_fTraction = 1.0f;
m_fTireTemperature = 1.0f;
- CColModel *colModel = mi->GetColModel();
- if(colModel->lines == nil){
- colModel->lines = (CColLine*)RwMalloc(4*sizeof(CColLine));
- colModel->numLines = 4;
- }
-
SetupSuspensionLines();
SetStatus(STATUS_SIMPLE);
@@ -205,6 +204,10 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
m_nNumPassengers = 0;
+ m_pBombRigger = nil;
+ m_bombType = CARBOMB_NONE;
+ bDriverLastFrame = false;
+
if(m_nDoorLock == CARLOCK_UNLOCKED &&
(id == MI_POLICE || id == MI_ENFORCER || id == MI_RHINO))
m_nDoorLock = CARLOCK_LOCKED_INITIALLY;
@@ -235,6 +238,7 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy)
bExplosionProof = true;
bBulletProof = true;
}
+ m_vehLCS_2A3 = -1;
}
void
@@ -246,6 +250,8 @@ CAutomobile::SetModelIndex(uint32 id)
#define SAND_SLOWDOWN (0.01f)
float CAR_BALANCE_MULT = 0.3f;
+float CAR_INAIR_ROTF = 0.0007f;
+float CAR_INAIR_ROTLIM = 0.02f;
float HELI_ROTOR_DOTPROD_LIMIT = 0.95f;
CVector vecSeaSparrowGunPos(-0.5f, 2.4f, -0.785f);
CVector vecHunterGunPos(0.0f, 4.8f, -1.3f);
@@ -263,6 +269,23 @@ CAutomobile::ProcessControl(void)
CColModel *colModel;
float brake = 0.0f;
+ if(TheCamera.WorldViewerBeingUsed){
+ if(bIsAmbulanceOnDuty){
+ bIsAmbulanceOnDuty = false;
+ CCarCtrl::NumAmbulancesOnDuty--;
+ }
+ if(bIsFireTruckOnDuty){
+ bIsFireTruckOnDuty = false;
+ CCarCtrl::NumFiretrucksOnDuty--;
+ }
+ }
+
+ if(m_vehLCS_2A3 >= 0){
+ m_vehLCS_2A4--;
+ if(m_vehLCS_2A4 == 0)
+ m_vehLCS_2A3 = -1;
+ }
+
if(bUsingSpecialColModel)
colModel = &CWorld::Players[CWorld::PlayerInFocus].m_ColModel;
else
@@ -312,7 +335,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_FBIRANCH:
+ case MI_FBICAR:
case MI_POLICE:
case MI_ENFORCER:
case MI_SECURICA:
@@ -321,16 +344,29 @@ CAutomobile::ProcessControl(void)
ScanForCrimes();
}
+ 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;
+ }
+ else
+ bDriverLastFrame = false;
+
// Process driver
- if(pDriver)
+ 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);
}
-
- ActivateBombWhenEntered();
+ }
// Process passengers
if(m_nNumPassengers != 0 && IsUpsideDown() && CanPedEnterCar()){
@@ -353,7 +389,7 @@ CAutomobile::ProcessControl(void)
if(strongGrip1 || bCheat3)
m_vecCentreOfMass.z = 0.3f*m_aSuspensionSpringLength[0] + -1.0f*m_fHeightAboveRoad;
else if(pHandling->Flags & HANDLING_NONPLAYER_STABILISER && GetStatus() == STATUS_PHYSICS)
- m_vecCentreOfMass.z = pHandling->CentreOfMass.z - 0.2f*pHandling->Dimension.z;
+ m_vecCentreOfMass.z = pHandling->CentreOfMass.z + (colModel->boundingBox.min.z - pHandling->CentreOfMass.z)*0.4f;
else
m_vecCentreOfMass = pHandling->CentreOfMass;
@@ -373,11 +409,7 @@ CAutomobile::ProcessControl(void)
bool playerRemote = false;
switch(GetStatus()){
case STATUS_PLAYER_REMOTE:
-#ifdef FIX_BUGS
if(CPad::GetPad(0)->CarGunJustDown() && !bDisableRemoteDetonation){
-#else
- if(CPad::GetPad(0)->WeaponJustDown() && !bDisableRemoteDetonation){
-#endif
BlowUpCar(FindPlayerPed());
CRemote::TakeRemoteControlledCarFromPlayer();
}
@@ -396,7 +428,8 @@ CAutomobile::ProcessControl(void)
// fall through
case STATUS_PLAYER:
if(playerRemote ||
- pDriver && pDriver->GetPedState() != PED_EXIT_CAR && pDriver->GetPedState() != PED_DRAG_FROM_CAR && pDriver->GetPedState() != PED_ARRESTED){
+ // TODO(LCS): ped state 64
+ pDriver && pDriver->GetPedState() != PED_EXIT_CAR && pDriver->GetPedState() != PED_DRAG_FROM_CAR && pDriver->GetPedState() != PED_ARRESTED && pDriver->GetPedState() != PED_STATE64){
// process control input if controlled by player
if(playerRemote || pDriver->m_nPedType == PEDTYPE_PLAYER1)
ProcessControlInputs(0);
@@ -421,6 +454,34 @@ CAutomobile::ProcessControl(void)
}else
m_vecCentreOfMass.z = pHandling->CentreOfMass.z;
+ // in air handling
+ if(m_nWheelsOnGround == 0 &&
+ GetVehicleAppearance() != VEHICLE_APPEARANCE_PLANE && GetVehicleAppearance() != VEHICLE_APPEARANCE_HELI){
+ float turnForce = m_fTurnMass * CAR_INAIR_ROTF;
+ turnForce *= Min(3000.0f/m_fTurnMass, 1.0f);
+ if(CPad::GetPad(0)->GetHandBrake()){
+ float upRot = DotProduct(m_vecTurnSpeed, GetUp());
+ if(upRot < CAR_INAIR_ROTLIM && CPad::GetPad(0)->GetSteeringLeftRight() < 0.0f ||
+ upRot > -CAR_INAIR_ROTLIM && CPad::GetPad(0)->GetSteeringLeftRight() > 0.0f)
+ ApplyTurnForce(GetRight() * turnForce * (CPad::GetPad(0)->GetSteeringLeftRight()/128.0f) * CTimer::GetTimeStep(),
+ m_vecCentreOfMass + GetForward());
+ }else if(!CPad::GetPad(0)->GetAccelerate()){
+ float fwdRot = DotProduct(m_vecTurnSpeed, GetForward());
+ if(fwdRot < CAR_INAIR_ROTLIM && CPad::GetPad(0)->GetSteeringLeftRight() < 0.0f ||
+ fwdRot > -CAR_INAIR_ROTLIM && CPad::GetPad(0)->GetSteeringLeftRight() > 0.0f)
+ ApplyTurnForce(GetRight() * turnForce * (CPad::GetPad(0)->GetSteeringLeftRight()/128.0f) * CTimer::GetTimeStep(),
+ m_vecCentreOfMass + GetUp());
+ }
+
+ if(!CPad::GetPad(0)->GetAccelerate()){
+ float rightRot = DotProduct(m_vecTurnSpeed, GetRight());
+ if(rightRot < CAR_INAIR_ROTLIM && CPad::GetPad(0)->GetSteeringUpDown() < 0.0f ||
+ rightRot > -CAR_INAIR_ROTLIM && CPad::GetPad(0)->GetSteeringUpDown() > 0.0f)
+ ApplyTurnForce(GetUp() * turnForce * (CPad::GetPad(0)->GetSteeringUpDown()/128.0f) * CTimer::GetTimeStep(),
+ m_vecCentreOfMass + GetForward());
+ }
+ }
+
if(bHoverCheat)
DoHoverSuspensionRatios();
@@ -456,8 +517,6 @@ CAutomobile::ProcessControl(void)
m_fBrakePedal = 1.0f;
m_fGasPedal = 0.0f;
}
- if(CPad::GetPad(0)->CarGunJustDown())
- ActivateBomb();
break;
case STATUS_SIMPLE:
@@ -532,8 +591,10 @@ CAutomobile::ProcessControl(void)
m_fSteerAngle = 0.0f;
m_fGasPedal = 0.0f;
- if(!IsAlarmOn())
- m_nCarHornTimer = 0;
+ m_nCarHornTimer = 0;
+ // TODO(LCS):
+ // CWeapon::::RemovePlayersRemoteDetonatorForThisVehicle
+ m_pBombRigger = nil;
break;
case STATUS_PLAYER_DISABLED:
@@ -627,9 +688,7 @@ CAutomobile::ProcessControl(void)
// special control
switch(GetModelIndex()){
- case MI_FIRETRUCK:
- FireTruckControl();
- break;
+ // FireTruckControl in PreRender now
case MI_RHINO:
TankControl();
BlowUpCarsInPath();
@@ -724,7 +783,7 @@ CAutomobile::ProcessControl(void)
ApplyTurnSpeed();
}
bIsInSafePosition = true;
- bIsStuck = false;
+ bIsStuck = false;
}
CPhysical::ProcessControl();
@@ -743,6 +802,7 @@ CAutomobile::ProcessControl(void)
CVector contactPoints[4]; // relative to model
CVector contactSpeeds[4]; // speed at contact points
CVector springDirections[4]; // normalized, in world space
+ float springForces[4];
for(i = 0; i < 4; i++){
// Set spring under certain circumstances
@@ -766,10 +826,13 @@ CAutomobile::ProcessControl(void)
}
// get points and directions if spring is compressed
+ springDirections[i] = -GetUp(); // springs are always pointing down anyway
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();
+// springDirections[i] = Multiply3x3(GetMatrix(), colModel->lines[i].p1 - colModel->lines[i].p0);
+// springDirections[i].Normalise();
+ }else{
+ contactPoints[i] = CVector(0.0f, 0.0f, 0.0f);
}
}
@@ -782,7 +845,7 @@ CAutomobile::ProcessControl(void)
ApplySpringCollisionAlt(pHandling->fSuspensionForceLevel,
springDirections[i], contactPoints[i],
- m_aSuspensionSpringRatio[i], bias, m_aWheelColPoints[i].normal);
+ m_aSuspensionSpringRatio[i], bias, m_aWheelColPoints[i].normal, springForces[i]);
m_aWheelSkidmarkUnk[i] = false;
if(m_aWheelColPoints[i].surfaceB == SURFACE_GRASS ||
@@ -794,8 +857,8 @@ CAutomobile::ProcessControl(void)
m_aWheelSkidmarkUnk[i] = true;
}else
m_aWheelSkidmarkType[i] = SKIDMARK_NORMAL;
- }else{
- contactPoints[i] = Multiply3x3(GetMatrix(), colModel->lines[i].p1);
+// }else{
+// contactPoints[i] = Multiply3x3(GetMatrix(), colModel->lines[i].p1);
}
}
@@ -817,7 +880,7 @@ CAutomobile::ProcessControl(void)
// dampen springs
for(i = 0; i < 4; i++)
if(m_aSuspensionSpringRatio[i] < 0.99999f)
- ApplySpringDampening(pHandling->fSuspensionDampingLevel,
+ ApplySpringDampening(pHandling->fSuspensionDampingLevel, springForces[i],
springDirections[i], contactPoints[i], contactSpeeds[i]);
// Get speed at contact points again
@@ -830,42 +893,6 @@ CAutomobile::ProcessControl(void)
}
}
- bool gripCheat = true;
- fwdSpeed = DotProduct(m_vecMoveSpeed, GetForward());
- if(!strongGrip1 && !CVehicle::bCheat3)
- gripCheat = false;
- float acceleration = pHandling->Transmission.CalculateDriveAcceleration(m_fGasPedal, m_nCurrentGear, m_fChangeGearTime, fwdSpeed, gripCheat);
- acceleration /= m_fForceMultiplier;
-
- 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 {
- uint32 timeStepInMs = CTimer::GetTimeStepInMilliseconds();
- if(m_nBusDoorTimerEnd > timeStepInMs)
- m_nBusDoorTimerEnd -= timeStepInMs;
- else
- m_nBusDoorTimerEnd = 0;
- }
- }
-
- if((m_aSuspensionSpringRatio[0] < 1.0f || m_aSuspensionSpringRatio[2] < 1.0f) &&
- (m_aSuspensionSpringRatio[1] < 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 = 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-pHandling->fBrakeBias; // looks like a bug, but it was correct in III...
- float tractionBiasFront = neutralHandling ? 1.0f : 2.0f*pHandling->fTractionBias;
- float tractionBiasRear = neutralHandling ? 1.0f : 2.0f-tractionBiasFront;
-
// Count how many wheels are touching the ground
m_nWheelsOnGround = 0;
@@ -896,16 +923,48 @@ CAutomobile::ProcessControl(void)
}
}
+ bool gripCheat = true;
+ fwdSpeed = DotProduct(m_vecMoveSpeed, GetForward());
+ if(!strongGrip1 && !CVehicle::bCheat3)
+ gripCheat = false;
+ float acceleration = pHandling->Transmission.CalculateDriveAcceleration(m_fGasPedal, m_nCurrentGear, m_fChangeGearTime, fwdSpeed,
+ &m_fEngineInertiaVar1, &m_fEngineInertiaVar2, m_nDriveWheelsOnGround, gripCheat);
+ acceleration /= m_fForceMultiplier;
+
+ if(IsRealHeli() || IsRealPlane())
+ acceleration = 0.0f;
+
+ if(Abs(acceleration) > 0.0f)
+ m_fEngineEnergy += Abs(acceleration);
+ else
+ m_fEngineEnergy = 0.0f;
+
float traction;
if(GetStatus() == STATUS_PHYSICS)
traction = 0.004f * m_fTraction;
else
traction = 0.004f;
- traction *= pHandling->fTractionMultiplier / 4.0f;
+ traction *= pHandling->GetTractionMultiplier() / 4.0f;
traction /= m_fForceMultiplier;
if(CVehicle::bCheat3)
traction *= 4.0f;
+ if(FindPlayerVehicle() && FindPlayerVehicle() == this)
+ if (CPad::GetPad(0)->CarGunJustDown()) {
+ 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);
+ }
+ }
+
if(FindPlayerVehicle() != this && (strongGrip1 || CVehicle::bCheat3)){
traction *= 1.2f;
acceleration *= 1.4f;
@@ -915,429 +974,67 @@ CAutomobile::ProcessControl(void)
}
}
- static float fThrust;
- static tWheelState WheelState[4];
-
- 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, wheelRight, tmp;
-
- if(m_aWheelTimer[CARWHEEL_FRONT_LEFT] > 0.0f){
- if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier))
- fThrust = acceleration;
- else
- fThrust = 0.0f;
-
- 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(CARWHEEL_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.HasFrontWheelDrive(pHandling->nIdentifier))
- fThrust = acceleration;
- else
- fThrust = 0.0f;
-
- 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(CARWHEEL_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.HasFrontWheelDrive(pHandling->nIdentifier) && acceleration != 0.0f){
- 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;
- }
- }else{
- m_aWheelSpeed[CARWHEEL_FRONT_LEFT] *= 0.95f;
- }
- m_aWheelRotation[CARWHEEL_FRONT_LEFT] += m_aWheelSpeed[CARWHEEL_FRONT_LEFT];
- }
- if(m_aWheelTimer[CARWHEEL_FRONT_RIGHT] <= 0.0f){
- if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier) && acceleration != 0.0f){
- 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;
- }
- }else{
- m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] *= 0.95f;
- }
- m_aWheelRotation[CARWHEEL_FRONT_RIGHT] += m_aWheelSpeed[CARWHEEL_FRONT_RIGHT];
- }
- }
- }
-
- // Process rear wheels
-
- if(m_aWheelTimer[CARWHEEL_REAR_LEFT] > 0.0f || m_aWheelTimer[CARWHEEL_REAR_RIGHT] > 0.0f){
- CVector wheelFwd = GetForward();
- CVector wheelRight = GetRight(); // overwritten for resp. wheel
-
- 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
- rearBrake = 20000.0f * CTimer::GetTimeStepFix();
-#else
- 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;
+ // TODO(LCS): where did this go?
+/*
+ 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 {
+ uint32 timeStepInMs = CTimer::GetTimeStepInMilliseconds();
+ if(m_nBusDoorTimerEnd > timeStepInMs)
+ m_nBusDoorTimerEnd -= timeStepInMs;
+ else
+ m_nBusDoorTimerEnd = 0;
}
- }else if(m_doingBurnout && mod_HandlingManager.HasRearWheelDrive(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.HasRearWheelDrive(pHandling->nIdentifier))
- fThrust = acceleration;
- else
- fThrust = 0.0f;
-
- 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])*rearTraction;
- if(GetStatus() == STATUS_PLAYER)
- adhesion *= CSurfaceTable::GetWetMultiplier(m_aWheelColPoints[CARWHEEL_REAR_LEFT].surfaceB);
- WheelState[CARWHEEL_REAR_LEFT] = m_aWheelState[CARWHEEL_REAR_LEFT];
-
- if(Damage.GetWheelStatus(CARWHEEL_REAR_LEFT) == WHEEL_STATUS_BURST)
- ProcessWheel(wheelFwd, wheelRight,
- contactSpeeds[CARWHEEL_REAR_LEFT], contactPoints[CARWHEEL_REAR_LEFT],
- m_nWheelsOnGround, fThrust,
- rearBrake*brakeBiasRear,
- adhesion*tractionBiasRear*Damage.m_fWheelDamageEffect,
- CARWHEEL_REAR_LEFT,
- &m_aWheelSpeed[CARWHEEL_REAR_LEFT],
- &WheelState[CARWHEEL_REAR_LEFT],
- WHEEL_STATUS_BURST);
- else
- ProcessWheel(wheelFwd, wheelRight,
- contactSpeeds[CARWHEEL_REAR_LEFT], contactPoints[CARWHEEL_REAR_LEFT],
- m_nWheelsOnGround, fThrust,
- rearBrake*brakeBiasRear,
- adhesion*tractionBiasRear,
- CARWHEEL_REAR_LEFT,
- &m_aWheelSpeed[CARWHEEL_REAR_LEFT],
- &WheelState[CARWHEEL_REAR_LEFT],
- WHEEL_STATUS_OK);
}
-#ifdef FIX_BUGS
- // Shouldn't we reset these after the left wheel?
- wheelFwd = GetForward();
- wheelRight = GetRight(); // actually useless
-#endif
-
- if(m_aWheelTimer[CARWHEEL_REAR_RIGHT] > 0.0f){
- if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier))
- fThrust = acceleration;
- else
- fThrust = 0.0f;
-
- 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])*rearTraction;
- if(GetStatus() == STATUS_PLAYER)
- adhesion *= CSurfaceTable::GetWetMultiplier(m_aWheelColPoints[CARWHEEL_REAR_RIGHT].surfaceB);
- WheelState[CARWHEEL_REAR_RIGHT] = m_aWheelState[CARWHEEL_REAR_RIGHT];
-
- if(Damage.GetWheelStatus(CARWHEEL_REAR_RIGHT) == WHEEL_STATUS_BURST)
- ProcessWheel(wheelFwd, wheelRight,
- contactSpeeds[CARWHEEL_REAR_RIGHT], contactPoints[CARWHEEL_REAR_RIGHT],
- m_nWheelsOnGround, fThrust,
- rearBrake*brakeBiasRear,
- adhesion*tractionBiasRear*Damage.m_fWheelDamageEffect,
- CARWHEEL_REAR_RIGHT,
- &m_aWheelSpeed[CARWHEEL_REAR_RIGHT],
- &WheelState[CARWHEEL_REAR_RIGHT],
- WHEEL_STATUS_BURST);
- else
- ProcessWheel(wheelFwd, wheelRight,
- contactSpeeds[CARWHEEL_REAR_RIGHT], contactPoints[CARWHEEL_REAR_RIGHT],
- m_nWheelsOnGround, fThrust,
- rearBrake*brakeBiasRear,
- adhesion*tractionBiasRear,
- CARWHEEL_REAR_RIGHT,
- &m_aWheelSpeed[CARWHEEL_REAR_RIGHT],
- &WheelState[CARWHEEL_REAR_RIGHT],
- WHEEL_STATUS_OK);
- }
- }
-
- if(m_doingBurnout && mod_HandlingManager.HasRearWheelDrive(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(!IsRealHeli()){
- if(m_aWheelTimer[CARWHEEL_REAR_LEFT] <= 0.0f){
- if(bIsHandbrakeOn)
- m_aWheelSpeed[CARWHEEL_REAR_LEFT] = 0.0f;
- else if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier) && acceleration != 0.0f){
- 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;
- }
- }else{
- m_aWheelSpeed[CARWHEEL_REAR_LEFT] *= 0.95f;
- }
- m_aWheelRotation[CARWHEEL_REAR_LEFT] += m_aWheelSpeed[CARWHEEL_REAR_LEFT];
- }
- if(m_aWheelTimer[CARWHEEL_REAR_RIGHT] <= 0.0f){
- if(bIsHandbrakeOn)
- m_aWheelSpeed[CARWHEEL_REAR_RIGHT] = 0.0f;
- else if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier) && acceleration != 0.0f){
- 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;
- }
- }else{
- m_aWheelSpeed[CARWHEEL_REAR_RIGHT] *= 0.95f;
- }
- m_aWheelRotation[CARWHEEL_REAR_RIGHT] += m_aWheelSpeed[CARWHEEL_REAR_RIGHT];
- }
+ if((m_aSuspensionSpringRatio[0] < 1.0f || m_aSuspensionSpringRatio[2] < 1.0f) &&
+ (m_aSuspensionSpringRatio[1] < 1.0f || m_aSuspensionSpringRatio[3] < 1.0f))
+ ApplyTurnForce(-GRAVITY*Min(m_fTurnMass, 2500.0f)*GetUp(), -1.0f*GetForward());
}
-
- // 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.HasFrontWheelDrive(pHandling->nIdentifier))
- fThrust = acceleration;
- else
- fThrust = 0.0f;
-
- 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(CARWHEEL_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.HasFrontWheelDrive(pHandling->nIdentifier))
- fThrust = acceleration;
+*/
+
+ static float magicValue = 4.0f;
+ if(magicValue > 0.0f){
+ float steerRange;
+ // looks like a bug with the wheel ids here, why only left wheels?
+ if(fwdSpeed > 0.01f && (m_aWheelTimer[CARWHEEL_FRONT_LEFT] > 0.0f || m_aWheelTimer[CARWHEEL_REAR_LEFT] > 0.0f) && GetStatus() == STATUS_PLAYER){
+ CColPoint point;
+ point.surfaceA = SURFACE_WHEELBASE;
+ point.surfaceB = SURFACE_TARMAC;
+ float rightSpeed = DotProduct(m_vecMoveSpeed, GetRight());
+ float adhesion = CSurfaceTable::GetAdhesiveLimit(point);
+ // i have no idea what's going on here
+ float magic = magicValue * traction * adhesion * 4.0f / SQR(fwdSpeed);
+ magic = Clamp(magic, -1.0f, 1.0f);
+ magic = Asin(magic);
+ if(m_fSteerAngle < 0.0f && rightSpeed > 0.05f ||
+ m_fSteerAngle > 0.0f && rightSpeed < -0.05f ||
+ bIsHandbrakeOn)
+ steerRange = 1.0f;
else
- fThrust = 0.0f;
-
- 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;
+ steerRange = Min(magic/DEGTORAD(pHandling->fSteeringLock), 1.0f);
+
+ }else
+ steerRange = 1.0f;
- 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(CARWHEEL_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);
- }
+ m_fSteerAngle *= steerRange;
}
- // Process front wheels off ground
+ brake = m_fBrakePedal * pHandling->fBrakeDeceleration * CTimer::GetTimeStep();
- if (!IsRealHeli()) {
- if(m_aWheelTimer[CARWHEEL_FRONT_LEFT] <= 0.0f){
- if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier) && acceleration != 0.0f){
- 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;
- }
- }else{
- m_aWheelSpeed[CARWHEEL_FRONT_LEFT] *= 0.95f;
- }
- m_aWheelRotation[CARWHEEL_FRONT_LEFT] += m_aWheelSpeed[CARWHEEL_FRONT_LEFT];
- }
- if(m_aWheelTimer[CARWHEEL_FRONT_RIGHT] <= 0.0f){
- if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier) && acceleration != 0.0f){
- 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;
- }
- }else{
- m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] *= 0.95f;
- }
- m_aWheelRotation[CARWHEEL_FRONT_RIGHT] += m_aWheelSpeed[CARWHEEL_FRONT_RIGHT];
- }
- }
+ if(pHandling->Flags & HANDLING_REARWHEEL_1ST){
+ ProcessCarWheelPair(CARWHEEL_REAR_LEFT, CARWHEEL_REAR_RIGHT, -999.0f, contactSpeeds, contactPoints,
+ traction, acceleration, brake, false);
+ ProcessCarWheelPair(CARWHEEL_FRONT_LEFT, CARWHEEL_FRONT_RIGHT, m_fSteerAngle, contactSpeeds, contactPoints,
+ traction, acceleration, brake, true);
+ }else{
+ ProcessCarWheelPair(CARWHEEL_FRONT_LEFT, CARWHEEL_FRONT_RIGHT, m_fSteerAngle, contactSpeeds, contactPoints,
+ traction, acceleration, brake, true);
+ ProcessCarWheelPair(CARWHEEL_REAR_LEFT, CARWHEEL_REAR_RIGHT, -999.0f, contactSpeeds, contactPoints,
+ traction, acceleration, brake, false);
}
for(i = 0; i < 4; i++){
@@ -1349,14 +1046,6 @@ CAutomobile::ProcessControl(void)
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
@@ -1367,7 +1056,7 @@ CAutomobile::ProcessControl(void)
if(UsesSiren()){
if(Pads[0].bHornHistory[Pads[0].iCurrHornHistory]){
if(Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+CPad::HORNHISTORY_SIZE-1) % CPad::HORNHISTORY_SIZE] &&
- Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+CPad::HORNHISTORY_SIZE-2) % CPad::HORNHISTORY_SIZE])
+ Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+1) % CPad::HORNHISTORY_SIZE])
m_nCarHornTimer = 1;
else
m_nCarHornTimer = 0;
@@ -1397,10 +1086,14 @@ CAutomobile::ProcessControl(void)
if(GetStatus() != STATUS_PLAYER && GetStatus() != STATUS_PLAYER_REMOTE && GetStatus() != STATUS_PHYSICS){
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;
+ if(GetStatus() == STATUS_WRECKED)
+ m_aWheelSpeed[1] = 0.0f;
+ else{
+ 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(isPlane && m_vecMoveSpeed.Magnitude() > 0.0f && CTimer::GetTimeStep() > 0.0f){
if(GetModelIndex() == MI_DODO)
@@ -1470,7 +1163,7 @@ CAutomobile::ProcessControl(void)
source = GetMatrix()*source + Max(DotProduct(m_vecMoveSpeed, GetForward()), 0.0f)*GetForward()*CTimer::GetTimeStep();
gun.FireProjectile(this, &source, 0.0f);
- CStats::RoundsFiredByPlayer++;
+// CStats::RoundsFiredByPlayer++;
DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_SHOT_FIRED, 0.0f);
m_nGunFiringTime = CTimer::GetTimeInMilliseconds();
// Hunter gun
@@ -1480,7 +1173,7 @@ CAutomobile::ProcessControl(void)
source = GetMatrix()*source + m_vecMoveSpeed*CTimer::GetTimeStep();
gun.FireInstantHit(this, &source);
gun.AddGunshell(this, source, CVector2D(0.0f, 0.1f), 0.025f);
- CStats::RoundsFiredByPlayer++;
+// CStats::RoundsFiredByPlayer++;
DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_SHOT_FIRED, 0.0f);
m_nGunFiringTime = CTimer::GetTimeInMilliseconds();
}
@@ -1492,7 +1185,7 @@ CAutomobile::ProcessControl(void)
source = GetMatrix()*source + m_vecMoveSpeed*CTimer::GetTimeStep();
gun.FireInstantHit(this, &source);
gun.AddGunshell(this, source, CVector2D(0.0f, 0.1f), 0.025f);
- CStats::RoundsFiredByPlayer++;
+// CStats::RoundsFiredByPlayer++;
DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_SHOT_FIRED, 0.0f);
m_nGunFiringTime = CTimer::GetTimeInMilliseconds();
}
@@ -1593,9 +1286,10 @@ CAutomobile::ProcessControl(void)
float suspShake = 0.0f;
float surfShake = 0.0f;
float speedsq = m_vecMoveSpeed.MagnitudeSqr();
+ float wheelSpin = 0.0f;
for(i = 0; i < 4; i++){
float suspChange = m_aSuspensionSpringRatioPrev[i] - m_aSuspensionSpringRatio[i];
- if(suspChange > 0.3f && !drivingInSand && speedsq > SQR(0.2f)){
+ if(suspChange > 0.1f && !drivingInSand && speedsq > SQR(0.2f)){
if(Damage.GetWheelStatus(i) == WHEEL_STATUS_BURST)
DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_JUMP_2, suspChange);
else
@@ -1620,10 +1314,27 @@ CAutomobile::ProcessControl(void)
// BUG: this only observes one of the wheels
TheCamera.m_bVehicleSuspenHigh = Abs(suspChange) > 0.05f;
+ if((i == CARWHEEL_FRONT_LEFT || i == CARWHEEL_FRONT_RIGHT) && mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier) ||
+ (i == CARWHEEL_REAR_LEFT || i == CARWHEEL_REAR_RIGHT) && mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier))
+ wheelSpin += WHEELSPIN_TARGET_RATE;
+ else if(m_aWheelState[i] == WHEEL_STATE_SPINNING)
+ wheelSpin += WHEELSPIN_INAIR_TARGET_RATE;
+
m_aSuspensionSpringRatioPrev[i] = m_aSuspensionSpringRatio[i];
m_aSuspensionSpringRatio[i] = 1.0f;
}
+ if(pHandling->Transmission.nDriveType == '4')
+ wheelSpin /= 4.0f;
+ else
+ wheelSpin /= 2.0f;
+ float spinChange;
+ if(wheelSpin < m_fWheelSpin)
+ spinChange = Pow(WHEELSPIN_FALL_RATE, CTimer::GetTimeStep());
+ else
+ spinChange = Pow(WHEELSPIN_RISE_RATE, CTimer::GetTimeStep());
+ m_fWheelSpin = m_fWheelSpin*spinChange + wheelSpin*(1.0f-spinChange);
+
// Shake pad
if(!drivingInSand && (suspShake > 0.0f || surfShake > 0.0f) && GetStatus() == STATUS_PLAYER){
@@ -1651,13 +1362,13 @@ CAutomobile::ProcessControl(void)
// TODO: make the numbers defines
float heading;
- if(GetPosition().x > 1950.0f-400.0f){
+ if(GetPosition().x > 1950.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 < -1950.0f-400.0f){
+ }else if(GetPosition().x < -1950.0f){
if(m_vecMoveSpeed.x < 0.0f)
m_vecMoveSpeed.x *= -1.0f;
heading = GetForward().Heading();
@@ -1710,17 +1421,262 @@ CAutomobile::ProcessControl(void)
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)
+ GetPosition().z < 0.0f)
if(!bRenderScorched){ // we already know this is true...
CExplosion::AddExplosion(this, nil, EXPLOSION_CAR, GetPosition(), 0);
bRenderScorched = true;
}
}
+
+ // The rest was in PreRender
+
+ bool onlyFrontWheels = false;
+ if(IsRealHeli()){
+ // Looks like LCS actually uses fmodf for the angles but VC has a loop...
+ // top rotor
+ m_aWheelRotation[1] += m_aWheelSpeed[1]*CTimer::GetTimeStep();
+ while(m_aWheelRotation[1] > TWOPI) m_aWheelRotation[1] -= TWOPI;
+ // rear rotor
+ m_aWheelRotation[3] += m_aWheelSpeed[1]*CTimer::GetTimeStep();
+ while(m_aWheelRotation[3] > TWOPI) m_aWheelRotation[3] -= TWOPI;
+ onlyFrontWheels = true;
+ }
+
+ CVehicleModelInfo *mi = GetModelInfo();
+ CVector contactPoints[4]; // relative to model
+ CVector contactSpeeds[4]; // speed at contact points
+ 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 && (!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)
+ m_aWheelSpeed[i] = ProcessWheelRotation(m_aWheelState[i], frontWheelFwd, contactSpeeds[i], 0.5f*mi->m_wheelScale);
+ else
+ m_aWheelSpeed[i] = ProcessWheelRotation(m_aWheelState[i], rearWheelFwd, contactSpeeds[i], 0.5f*mi->m_wheelScale);
+ m_aWheelRotation[i] += m_aWheelSpeed[i];
+ }
+ }
+
+ if(GetModelIndex() == MI_DODO){
+ ProcessSwingingDoor(CAR_DOOR_LF, DOOR_FRONT_LEFT);
+ ProcessSwingingDoor(CAR_DOOR_RF, DOOR_FRONT_RIGHT);
+ }else if(GetModelIndex() == MI_RHINO){
+ }else if(IsRealHeli()){
+ }else{
+ ProcessSwingingDoor(CAR_DOOR_LF, DOOR_FRONT_LEFT);
+ ProcessSwingingDoor(CAR_DOOR_RF, DOOR_FRONT_RIGHT);
+ ProcessSwingingDoor(CAR_DOOR_LR, DOOR_REAR_LEFT);
+ ProcessSwingingDoor(CAR_DOOR_RR, DOOR_REAR_RIGHT);
+ ProcessSwingingDoor(CAR_BONNET, DOOR_BONNET);
+ ProcessSwingingDoor(CAR_BOOT, DOOR_BOOT);
+ }
}
#pragma optimize("", on)
void
+CAutomobile::ProcessCarWheelPair(int leftWheel, int rightWheel, float steerAngle, CVector *contactSpeeds, CVector *contactPoints, float traction, float acceleration, float brake, bool bFront)
+{
+ bool driveWheels;
+ float suspensionBias;
+
+ if(bFront){
+ driveWheels = mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier);
+ suspensionBias = 2.0f*pHandling->fSuspensionBias;
+ }else{
+ driveWheels = mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier);
+ suspensionBias = 2.0f*(1.0f-pHandling->fSuspensionBias);
+
+ float fwdSpeed = DotProduct(m_vecMoveSpeed, GetForward());
+ if(bIsHandbrakeOn && Abs(fwdSpeed) > 0.01f){
+#ifdef FIX_BUGS
+ // Not sure if this is needed, but brake usually has timestep as a factor
+ brake = 20000.0f * CTimer::GetTimeStepFix();
+#else
+ brake = 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(driveWheels && m_doingBurnout){
+ brake = 0.0f;
+ traction = 0.0f;
+ // BUG: missing timestep
+ ApplyTurnForce(contactPoints[leftWheel], -0.003f*m_fTurnMass*Min(3000.0f/m_fTurnMass, 1.0f)*m_fSteerAngle*GetRight());
+ }else if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier)){
+ traction *= m_fTireTemperature;
+ }
+ }
+
+ // Wheels on ground
+ if(m_aWheelTimer[leftWheel] > 0.0f || m_aWheelTimer[rightWheel] > 0.0f){
+ CVector wheelFwd, wheelRight;
+ float s, c;
+ bool canSteer = steerAngle > -100.0f;
+ if(canSteer){
+ s = Sin(steerAngle);
+ c = Cos(steerAngle);
+ }
+
+ bool neutralHandling = GetStatus() != STATUS_PLAYER && GetStatus() != STATUS_PLAYER_REMOTE && (pHandling->Flags & HANDLING_NEUTRALHANDLING);
+ float brakeBias, tractionBias;
+ if(bFront){
+ brakeBias = neutralHandling ? 1.0f : 2.0f*pHandling->fBrakeBias;
+ tractionBias = neutralHandling ? 1.0f : 2.0f*pHandling->fTractionBias;
+ }else{
+ brakeBias = neutralHandling ? 1.0f : 2.0f*(1.0f-pHandling->fBrakeBias);
+ tractionBias = neutralHandling ? 1.0f : 2.0f*(1.0f-pHandling->fTractionBias);
+ }
+
+ if(m_aWheelTimer[leftWheel] > 0.0f){
+ float fThrust = driveWheels ? acceleration : 0.0f;
+
+ wheelFwd = GetForward();
+ wheelFwd -= DotProduct(wheelFwd, m_aWheelColPoints[leftWheel].normal)*m_aWheelColPoints[leftWheel].normal;
+ wheelFwd.Normalise();
+ wheelRight = CrossProduct(wheelFwd, m_aWheelColPoints[leftWheel].normal);
+ wheelRight.Normalise();
+ if(canSteer){
+ CVector tmp = c*wheelFwd - s*wheelRight;
+ wheelRight = s*wheelFwd + c*wheelRight;
+ wheelFwd = tmp;
+ }
+
+ m_aWheelColPoints[leftWheel].surfaceA = SURFACE_WHEELBASE;
+ float adhesion = CSurfaceTable::GetAdhesiveLimit(m_aWheelColPoints[leftWheel])*traction;
+ if(GetStatus() == STATUS_PLAYER){
+ adhesion *= CSurfaceTable::GetWetMultiplier(m_aWheelColPoints[leftWheel].surfaceB);
+ adhesion *= Min(suspensionBias*pHandling->fSuspensionForceLevel*4.0f*(1.0f-m_aSuspensionSpringRatio[leftWheel]), 2.0f);
+ }
+ tWheelState WheelState = m_aWheelState[leftWheel];
+ if(Damage.GetWheelStatus(leftWheel) == WHEEL_STATUS_BURST)
+ ProcessWheel(wheelFwd, wheelRight,
+ contactSpeeds[leftWheel], contactPoints[leftWheel],
+ m_nWheelsOnGround, fThrust,
+ brake*brakeBias,
+ adhesion*tractionBias*Damage.m_fWheelDamageEffect,
+ leftWheel,
+ &m_aWheelRotation[leftWheel],
+ &WheelState,
+ WHEEL_STATUS_BURST);
+ else
+ ProcessWheel(wheelFwd, wheelRight,
+ contactSpeeds[leftWheel], contactPoints[leftWheel],
+ m_nWheelsOnGround, fThrust,
+ brake*brakeBias,
+ adhesion*tractionBias,
+ leftWheel,
+ &m_aWheelRotation[leftWheel],
+ &WheelState,
+ WHEEL_STATUS_OK);
+
+ if(driveWheels && m_fGasPedal < 0.0f && WheelState == WHEEL_STATE_SPINNING)
+ m_aWheelState[leftWheel] = WHEEL_STATE_NORMAL;
+ else
+ m_aWheelState[leftWheel] = WheelState;
+ }
+
+ if(m_aWheelTimer[rightWheel] > 0.0f){
+ float fThrust = driveWheels ? acceleration : 0.0f;
+
+ wheelFwd = GetForward();
+ wheelFwd -= DotProduct(wheelFwd, m_aWheelColPoints[rightWheel].normal)*m_aWheelColPoints[rightWheel].normal;
+ wheelFwd.Normalise();
+ wheelRight = CrossProduct(wheelFwd, m_aWheelColPoints[rightWheel].normal);
+ wheelRight.Normalise();
+ if(canSteer){
+ CVector tmp = c*wheelFwd - s*wheelRight;
+ wheelRight = s*wheelFwd + c*wheelRight;
+ wheelFwd = tmp;
+ }
+
+ m_aWheelColPoints[rightWheel].surfaceA = SURFACE_WHEELBASE;
+ float adhesion = CSurfaceTable::GetAdhesiveLimit(m_aWheelColPoints[rightWheel])*traction;
+ if(GetStatus() == STATUS_PLAYER){
+ adhesion *= CSurfaceTable::GetWetMultiplier(m_aWheelColPoints[rightWheel].surfaceB);
+ adhesion *= Min(suspensionBias*pHandling->fSuspensionForceLevel*4.0f*(1.0f-m_aSuspensionSpringRatio[rightWheel]), 2.0f);
+ }
+ tWheelState WheelState = m_aWheelState[rightWheel];
+ if(Damage.GetWheelStatus(rightWheel) == WHEEL_STATUS_BURST)
+ ProcessWheel(wheelFwd, wheelRight,
+ contactSpeeds[rightWheel], contactPoints[rightWheel],
+ m_nWheelsOnGround, fThrust,
+ brake*brakeBias,
+ adhesion*tractionBias*Damage.m_fWheelDamageEffect,
+ rightWheel,
+ &m_aWheelRotation[rightWheel],
+ &WheelState,
+ WHEEL_STATUS_BURST);
+ else
+ ProcessWheel(wheelFwd, wheelRight,
+ contactSpeeds[rightWheel], contactPoints[rightWheel],
+ m_nWheelsOnGround, fThrust,
+ brake*brakeBias,
+ adhesion*tractionBias,
+ rightWheel,
+ &m_aWheelRotation[rightWheel],
+ &WheelState,
+ WHEEL_STATUS_OK);
+
+ if(driveWheels && m_fGasPedal < 0.0f && WheelState == WHEEL_STATE_SPINNING)
+ m_aWheelState[rightWheel] = WHEEL_STATE_NORMAL;
+ else
+ m_aWheelState[rightWheel] = WheelState;
+ }
+ }
+
+ if(!bFront){
+ if(m_doingBurnout && driveWheels &&
+ (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 wheels off ground
+
+ if(!IsRealHeli()){
+ if(m_aWheelTimer[leftWheel] <= 0.0f){
+ if(driveWheels && acceleration != 0.0f){
+ if(acceleration > 0.0f){
+ if(m_aWheelSpeed[leftWheel] < 1.0f)
+ m_aWheelSpeed[leftWheel] -= 0.1f;
+ }else{
+ if(m_aWheelSpeed[leftWheel] > -1.0f)
+ m_aWheelSpeed[leftWheel] += 0.05f;
+ }
+ }else{
+ m_aWheelSpeed[leftWheel] *= 0.95f;
+ }
+ m_aWheelRotation[leftWheel] += m_aWheelSpeed[leftWheel]*CTimer::GetTimeStep();
+ }
+ if(m_aWheelTimer[rightWheel] <= 0.0f){
+ if(driveWheels && acceleration != 0.0f){
+ if(acceleration > 0.0f){
+ if(m_aWheelSpeed[rightWheel] < 1.0f)
+ m_aWheelSpeed[rightWheel] -= 0.1f;
+ }else{
+ if(m_aWheelSpeed[rightWheel] > -1.0f)
+ m_aWheelSpeed[rightWheel] += 0.05f;
+ }
+ }else{
+ m_aWheelSpeed[rightWheel] *= 0.95f;
+ }
+ m_aWheelRotation[rightWheel] += m_aWheelSpeed[rightWheel]*CTimer::GetTimeStep();
+ }
+ }
+}
+
+void
CAutomobile::Teleport(CVector pos)
{
CWorld::Remove(this);
@@ -1735,25 +1691,24 @@ CAutomobile::Teleport(CVector pos)
CWorld::Add(this);
}
+float gHeadlightRange = 25.0f;
+float gTaxilightRange = 1.1f;
+CVector gHeadlightColour(0.86f, 0.82f, 1.0f);
+CVector gTaxilightColour(1.0, 1.0f, 0.5f);
+
void
CAutomobile::PreRender(void)
{
int i, j, n;
CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex());
- if(GetModelIndex() == MI_RHINO && m_aCarNodes[CAR_WINDSCREEN]){
- // Rotate Rhino turret
- CMatrix m;
- CVector p;
- m.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WINDSCREEN]));
- p = m.GetPosition();
- m.SetRotateZ(m_fCarGunLR);
- m.Translate(p);
- m.UpdateRW();
- }
+ if(GetModelIndex() == MI_FIRETRUCK)
+ FireTruckControl();
+
+ CVehicle::PreRender();
if(GetModelIndex() == MI_RCBANDIT){
- CVector pos = GetMatrix() * CVector(0.218f, -0.444f, 0.391f);
+ CVector pos = GetMatrix() * CVector(0.218f, -0.3f, 0.0f);
CAntennas::RegisterOne((uintptr)this, GetUp(), pos, 1.0f);
}
@@ -1762,7 +1717,7 @@ CAutomobile::PreRender(void)
// Wheel particles
- if(GetModelIndex() == MI_DODO || GetVehicleAppearance() != VEHICLE_APPEARANCE_CAR){
+ if(GetModelIndex() == MI_DODO){
; // nothing
}else if(GetModelIndex() == MI_RCBANDIT){
for(i = 0; i < 4; i++){
@@ -1958,7 +1913,7 @@ CAutomobile::PreRender(void)
// Rain on roof
- if(!CCullZones::CamNoRain() && !CCullZones::PlayerNoRain() &&
+ if(!CCullZones::CamNoRain() && !CCullZones::PlayerNoRain() && // LCS has those checks twice, but let's not be silly
Abs(fwdSpeed) < 20.0f && CWeather::Rain > 0.02f){
CColModel *colModel = GetColModel();
@@ -1973,7 +1928,7 @@ CAutomobile::PreRender(void)
p3 = GetMatrix() * p3;
c = (p1 + p2 + p3)/3.0f;
- n = 6.0f*CWeather::Rain;
+ n = 4.5f*CWeather::Rain;
for(j = 0; j <= n; j++)
CParticle::AddParticle(PARTICLE_RAIN_SPLASHUP,
c + CVector(CGeneral::GetRandomNumberInRange(-0.4f, 0.4f), CGeneral::GetRandomNumberInRange(-0.4f, 0.4f), 0.0f),
@@ -2003,8 +1958,10 @@ CAutomobile::PreRender(void)
dir1.y = m_vecMoveSpeed.y;
}
+ bool dblExhaust = false;
pos1 = GetMatrix() * exhaustPos;
if(pHandling->Flags & HANDLING_DBL_EXHAUST){
+ dblExhaust = true;
pos2 = exhaustPos;
pos2.x = -pos2.x;
pos2 = GetMatrix() * pos2;
@@ -2013,7 +1970,8 @@ CAutomobile::PreRender(void)
static float fumesLimit = 2.0f;
if(CGeneral::GetRandomNumberInRange(1.0f, 3.0f)*(m_fGasPedal+1.1f) > fumesLimit)
- for(i = 0; i < 4;){
+// 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);
@@ -2026,6 +1984,7 @@ CAutomobile::PreRender(void)
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){
@@ -2063,6 +2022,7 @@ CAutomobile::PreRender(void)
dir2 -= 0.05f*GetRight();
}else
i = 99;
+*/
}
}
}
@@ -2082,26 +2042,26 @@ CAutomobile::PreRender(void)
switch(GetModelIndex()){
case MI_FIRETRUCK:
- pos1 = CVector(1.1f, 1.7f, 2.0f);
- pos2 = CVector(-1.1f, 1.7f, 2.0f);
+ pos1 = CVector(0.91f, 1.7f, 1.86f);
+ pos2 = CVector(-0.91f, 1.7f, 1.86f);
r1 = 255; g1 = 0; b1 = 0;
r2 = 255; g2 = 255; b2 = 0;
break;
case MI_AMBULAN:
- pos1 = CVector(1.1f, 0.9f, 1.6f);
- pos2 = CVector(-1.1f, 0.9f, 1.6f);
+ pos1 = CVector(0.95f, 0.64f, 1.6f);
+ pos2 = CVector(-0.95f, 0.64f, 1.6f);
r1 = 255; g1 = 0; b1 = 0;
r2 = 255; g2 = 255; b2 = 255;
break;
case MI_POLICE:
- pos1 = CVector(0.7f, -0.4f, 1.0f);
- pos2 = CVector(-0.7f, -0.4f, 1.0f);
+ pos1 = CVector(0.47f, -0.4f, 1.0f);
+ pos2 = CVector(-0.47f, -0.4f, 1.0f);
r1 = 255; g1 = 0; b1 = 0;
r2 = 0; g2 = 0; b2 = 255;
break;
case MI_ENFORCER:
- pos1 = CVector(1.1f, 0.8f, 1.2f);
- pos2 = CVector(-1.1f, 0.8f, 1.2f);
+ pos1 = CVector(0.7f, 0.98f, 1.55f);
+ pos2 = CVector(-0.7f, 0.98f, 1.55f);
r1 = 255; g1 = 0; b1 = 0;
r2 = 0; g2 = 0; b2 = 255;
break;
@@ -2174,7 +2134,7 @@ CAutomobile::PreRender(void)
}
break;
- case MI_FBIRANCH:
+ //case MI_FBIRANCH:
case MI_VICECHEE:
if(m_bSirenOrAlarm){
CVector pos = GetMatrix() * CVector(0.4f, 0.6f, 0.3f);
@@ -2200,11 +2160,39 @@ CAutomobile::PreRender(void)
break;
case MI_TAXI:
+ if(bTaxiLight){
+ CVector pos = GetPosition() + GetForward()*-0.3f + GetUp()*0.9f;
+ CCoronas::RegisterCorona((uintptr)this + 21,
+ 128, 128, 0, 255,
+ pos, 0.8f, 50.0f,
+ CCoronas::TYPE_NORMAL,
+ CCoronas::FLARE_NONE,
+ CCoronas::REFLECTION_ON, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+ CPointLights::AddLight(CPointLights::LIGHT_POINT,
+ pos, CVector(0.0f, 0.0f, 0.0f), gTaxilightRange,
+ gTaxilightColour.x, gTaxilightColour.y, gTaxilightColour.z, CPointLights::FOG_NONE, true);
+ }
+ break;
+
case MI_CABBIE:
- case MI_ZEBRA:
+ if(bTaxiLight){
+ CVector pos = GetPosition() + GetUp()*0.9f;
+ CCoronas::RegisterCorona((uintptr)this + 21,
+ 128, 128, 0, 255,
+ pos, 0.8f, 50.0f,
+ CCoronas::TYPE_NORMAL,
+ CCoronas::FLARE_NONE,
+ CCoronas::REFLECTION_ON, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
+ CPointLights::AddLight(CPointLights::LIGHT_POINT,
+ pos, CVector(0.0f, 0.0f, 0.0f), gTaxilightRange,
+ gTaxilightColour.x, gTaxilightColour.y, gTaxilightColour.z, CPointLights::FOG_NONE, true);
+ }
+ break;
+
+ case MI_BORGNINE:
case MI_KAUFMAN:
if(bTaxiLight){
- CVector pos = GetPosition() + GetUp()*0.95f;
+ CVector pos = GetPosition() + GetForward()*-0.3f + GetUp()*0.85f;
CCoronas::RegisterCorona((uintptr)this + 21,
128, 128, 0, 255,
pos, 0.8f, 50.0f,
@@ -2212,8 +2200,8 @@ CAutomobile::PreRender(void)
CCoronas::FLARE_NONE,
CCoronas::REFLECTION_ON, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f);
CPointLights::AddLight(CPointLights::LIGHT_POINT,
- pos, CVector(0.0f, 0.0f, 0.0f), 10.0f,
- 1.0f, 1.0f, 0.5f, CPointLights::FOG_NONE, true);
+ pos, CVector(0.0f, 0.0f, 0.0f), gTaxilightRange,
+ gTaxilightColour.x, gTaxilightColour.y, gTaxilightColour.z, CPointLights::FOG_NONE, true);
}
break;
}
@@ -2250,7 +2238,8 @@ CAutomobile::PreRender(void)
else
alarmOff = true;
}
- if(bEngineOn && bLightsOn || alarmOn || alarmOff){
+ bool playerRemote = this == FindPlayerVehicle() && CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle;
+ if((bEngineOn && bLightsOn && !m_bGarageTurnedLightsOff || alarmOn || alarmOff) && !playerRemote){
CVector lookVector = GetPosition() - TheCamera.GetPosition();
float camDist = lookVector.Magnitude();
if(camDist != 0.0f)
@@ -2374,12 +2363,12 @@ CAutomobile::PreRender(void)
intensity += 0.4f;
size += 0.3f;
if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
- CCoronas::RegisterCorona((uintptr)this + 14, 128*intensity, 128*intensity, 128*intensity, 255,
+ CCoronas::RegisterCorona((uintptr)this + 2, 128*intensity, 128*intensity, 128*intensity, 255,
lightL, size, 50.0f*TheCamera.LODDistMultiplier,
CCoronas::TYPE_STREAK, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, angle);
if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
- CCoronas::RegisterCorona((uintptr)this + 15, 128*intensity, 128*intensity, 128*intensity, 255,
+ CCoronas::RegisterCorona((uintptr)this + 3, 128*intensity, 128*intensity, 128*intensity, 255,
lightR, size, 50.0f*TheCamera.LODDistMultiplier,
CCoronas::TYPE_STREAK, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, angle);
@@ -2391,23 +2380,23 @@ CAutomobile::PreRender(void)
if(alarmOff){
if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
- CCoronas::RegisterCorona((uintptr)this + 14, 0, 0, 0, 0,
+ CCoronas::RegisterCorona((uintptr)this + 2, 0, 0, 0, 0,
lightL, size, 0.0f,
CCoronas::TYPE_STREAK, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, angle);
if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
- CCoronas::RegisterCorona((uintptr)this + 15, 0, 0, 0, 0,
+ CCoronas::RegisterCorona((uintptr)this + 3, 0, 0, 0, 0,
lightR, size, 0.0f,
CCoronas::TYPE_STREAK, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, angle);
}else{
if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
- CCoronas::RegisterCorona((uintptr)this + 14, 128*intensity, 0, 0, 255,
+ CCoronas::RegisterCorona((uintptr)this + 2, 128*intensity, 0, 0, 255,
lightL, size, 50.0f*TheCamera.LODDistMultiplier,
CCoronas::TYPE_STREAK, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, angle);
if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
- CCoronas::RegisterCorona((uintptr)this + 15, 128*intensity, 0, 0, 255,
+ CCoronas::RegisterCorona((uintptr)this + 3, 128*intensity, 0, 0, 255,
lightR, size, 50.0f*TheCamera.LODDistMultiplier,
CCoronas::TYPE_STREAK, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, angle);
@@ -2433,27 +2422,52 @@ CAutomobile::PreRender(void)
CVector pos = GetPosition();
CVector2D fwd(GetForward());
fwd.Normalise();
- float f = headLightPos.y + 6.0f;
+ float f = headLightPos.y + 7.0f;
pos += CVector(f*fwd.x, f*fwd.y, 2.0f);
- if(Damage.GetLightStatus(VEHLIGHT_FRONT_LEFT) == LIGHT_STATUS_OK ||
- Damage.GetLightStatus(VEHLIGHT_FRONT_RIGHT) == LIGHT_STATUS_OK)
+ if(Damage.GetLightStatus(VEHLIGHT_FRONT_RIGHT) == LIGHT_STATUS_OK &&
+ Damage.GetLightStatus(VEHLIGHT_FRONT_LEFT) == LIGHT_STATUS_OK)
CShadows::StoreCarLightShadow(this, (uintptr)this + 22, gpShadowHeadLightsTex, &pos,
- 7.0f*fwd.x, 7.0f*fwd.y, 5.5f*fwd.y, -5.5f*fwd.x, 45, 45, 45, 7.0f);
+ 7.0f*fwd.x, 7.0f*fwd.y, -3.5f*fwd.y, 3.5f*fwd.x, 145, 145, 145, 7.0f, true, -0.4f, 1.4f);
+ else if(Damage.GetLightStatus(VEHLIGHT_FRONT_RIGHT) == LIGHT_STATUS_OK)
+ CShadows::StoreCarLightShadow(this, (uintptr)this + 22, gpShadowHeadLightsTex, &pos,
+ 7.0f*fwd.x, 7.0f*fwd.y, -3.5f*fwd.y, 3.5f*fwd.x, 145, 145, 145, 7.0f, false, 9.9f, 1.4f);
+ else if(Damage.GetLightStatus(VEHLIGHT_FRONT_LEFT) == LIGHT_STATUS_OK)
+ CShadows::StoreCarLightShadow(this, (uintptr)this + 22, gpShadowHeadLightsTex, &pos,
+ 7.0f*fwd.x, 7.0f*fwd.y, -3.5f*fwd.y, 3.5f*fwd.x, 145, 145, 145, 7.0f, false, -0.4f, 1.4f);
- f = (tailLightPos.y - 2.5f) - (headLightPos.y + 6.0f);
+ f = (tailLightPos.y - 2.1f) - (headLightPos.y + 7.0f);
pos += CVector(f*fwd.x, f*fwd.y, 0.0f);
- if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK ||
- Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
- CShadows::StoreCarLightShadow(this, (uintptr)this + 25, gpShadowExplosionTex, &pos,
- 3.0f, 0.0f, 0.0f, -3.0f, 35, 0, 0, 4.0f);
+ if(m_fGasPedal < 0.0f){
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK &&
+ Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
+ CShadows::StoreCarLightShadow(this, (uintptr)this + 25, gpShadowHeadLightsTex, &pos,
+ -2.0f*fwd.x, -2.0f*fwd.y, 1.5f*fwd.y, -1.5f*fwd.x, 58, 58, 58, 4.0f, true, -0.5f, 1.5f);
+ else if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
+ CShadows::StoreCarLightShadow(this, (uintptr)this + 25, gpShadowHeadLightsTex, &pos,
+ -2.0f*fwd.x, -2.0f*fwd.y, 1.5f*fwd.y, -1.5f*fwd.x, 58, 58, 58, 4.0f, false, 9.9f, 1.5f);
+ else if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
+ CShadows::StoreCarLightShadow(this, (uintptr)this + 25, gpShadowHeadLightsTex, &pos,
+ -2.0f*fwd.x, -2.0f*fwd.y, 1.5f*fwd.y, -1.5f*fwd.x, 58, 58, 58, 4.0f, false, -0.5f, 1.5f);
+ }else{
+ if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK &&
+ Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
+ CShadows::StoreCarLightShadow(this, (uintptr)this + 25, gpShadowHeadLightsTex, &pos,
+ -2.0f*fwd.x, -2.0f*fwd.y, 1.5f*fwd.y, -1.5f*fwd.x, 56, 0, 0, 4.0f, true, -0.5f, 1.5f);
+ else if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
+ CShadows::StoreCarLightShadow(this, (uintptr)this + 25, gpShadowHeadLightsTex, &pos,
+ -2.0f*fwd.x, -2.0f*fwd.y, 1.5f*fwd.y, -1.5f*fwd.x, 56, 0, 0, 4.0f, false, 9.9f, 1.5f);
+ else if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
+ CShadows::StoreCarLightShadow(this, (uintptr)this + 25, gpShadowHeadLightsTex, &pos,
+ -2.0f*fwd.x, -2.0f*fwd.y, 1.5f*fwd.y, -1.5f*fwd.x, 56, 0, 0, 4.0f, false, -0.5f, 1.5f);
+ }
}
if(this == FindPlayerVehicle() && !alarmOff){
if(Damage.GetLightStatus(VEHLIGHT_FRONT_LEFT) == LIGHT_STATUS_OK ||
Damage.GetLightStatus(VEHLIGHT_FRONT_RIGHT) == LIGHT_STATUS_OK)
CPointLights::AddLight(CPointLights::LIGHT_DIRECTIONAL, GetPosition(), GetForward(),
- 20.0f, 1.0f, 1.0f, 1.0f,
+ gHeadlightRange, gHeadlightColour.x, gHeadlightColour.y, gHeadlightColour.z,
FindPlayerVehicle()->m_vecMoveSpeed.MagnitudeSqr2D() < sq(0.45f) ? CPointLights::FOG_NORMAL : CPointLights::FOG_NONE,
false);
CVector pos = GetPosition() - 4.0f*GetForward();
@@ -2461,15 +2475,15 @@ CAutomobile::PreRender(void)
Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK) {
if(m_fBrakePedal > 0.0f)
CPointLights::AddLight(CPointLights::LIGHT_POINT, pos, CVector(0.0f, 0.0f, 0.0f),
- 10.0f, 1.0f, 0.0f, 0.0f,
+ 8.39f, 1.0f, 0.0f, 0.0f,
CPointLights::FOG_NONE, false);
else
CPointLights::AddLight(CPointLights::LIGHT_POINT, pos, CVector(0.0f, 0.0f, 0.0f),
- 7.0f, 0.6f, 0.0f, 0.0f,
+ 5.13f, 0.64f, 0.0f, 0.0f,
CPointLights::FOG_NONE, false);
}
}
- }else if(GetStatus() != STATUS_ABANDONED && GetStatus() != STATUS_WRECKED){
+ }else if(GetStatus() != STATUS_ABANDONED && GetStatus() != STATUS_WRECKED && !m_bGarageTurnedLightsOff && !playerRemote){
// Lights off
CVector lightPos = mi->m_positions[CAR_POS_TAILLIGHTS];
@@ -2538,7 +2552,7 @@ CAutomobile::PreRender(void)
else
CShadows::StoreShadowForVehicle(this, VEH_SHD_TYPE_CAR);
- DoSunGlare();
+// DoSunGlare();
// Heli dust
if(IsRealHeli() && m_aWheelSpeed[1] > 0.1125f && GetPosition().z < 30.0f){
@@ -2559,31 +2573,13 @@ CAutomobile::PreRender(void)
CMatrix mat;
CVector pos;
- bool onlyFrontWheels = false;
- if(IsRealHeli()){
- // top rotor
- m_aWheelRotation[1] += m_aWheelSpeed[1]*CTimer::GetTimeStep();
- while(m_aWheelRotation[1] > TWOPI) m_aWheelRotation[1] -= TWOPI;
- // rear rotor
- m_aWheelRotation[3] += m_aWheelSpeed[1]*CTimer::GetTimeStep();
- while(m_aWheelRotation[3] > TWOPI) m_aWheelRotation[3] -= TWOPI;
- onlyFrontWheels = true;
- }
-
- CVector contactPoints[4]; // relative to model
- CVector contactSpeeds[4]; // speed at contact points
- 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 && (!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)
- m_aWheelSpeed[i] = ProcessWheelRotation(m_aWheelState[i], frontWheelFwd, contactSpeeds[i], 0.5f*mi->m_wheelScale);
- else
- m_aWheelSpeed[i] = ProcessWheelRotation(m_aWheelState[i], rearWheelFwd, contactSpeeds[i], 0.5f*mi->m_wheelScale);
- m_aWheelRotation[i] += m_aWheelSpeed[i];
- }
+ // what's this supposed to be? Rhino doesn't have this node
+ if(GetModelIndex() == MI_RHINO && m_aCarNodes[CAR_BONNET]){
+ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_BONNET]));
+ pos = mat.GetPosition();
+ mat.SetRotateZ(m_fCarGunLR);
+ mat.Translate(pos);
+ mat.UpdateRW();
}
RwRGBA hoverParticleCol = { 255, 255, 255, 32 };
@@ -2773,9 +2769,6 @@ CAutomobile::PreRender(void)
mat.Translate(pos);
mat.UpdateRW();
}
-
- ProcessSwingingDoor(CAR_DOOR_LF, DOOR_FRONT_LEFT);
- ProcessSwingingDoor(CAR_DOOR_RF, DOOR_FRONT_RIGHT);
}else if(GetModelIndex() == MI_RHINO){
// Front right wheel
mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RF]));
@@ -2849,8 +2842,8 @@ CAutomobile::PreRender(void)
}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);
+ CGeneral::GetRandomNumberInRange(0.0f, 10.0f),
+ CGeneral::GetRandomNumberInRange(0.0f, 90.0f), 1);
}
#ifdef BETTER_ALLCARSAREDODO_CHEAT
} else if (bAllDodosCheat && m_nDriveWheelsOnGround == 0 && m_nDriveWheelsOnGroundPrev == 0) {
@@ -2890,8 +2883,8 @@ CAutomobile::PreRender(void)
}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);
+ CGeneral::GetRandomNumberInRange(0.0f, 10.0f),
+ CGeneral::GetRandomNumberInRange(0.0f, 90.0f), 1);
}
#ifdef BETTER_ALLCARSAREDODO_CHEAT
} else if (bAllDodosCheat && m_nDriveWheelsOnGround == 0 && m_nDriveWheelsOnGroundPrev == 0) {
@@ -2911,13 +2904,6 @@ CAutomobile::PreRender(void)
mat.Scale(mi->m_wheelScale);
mat.Translate(pos);
mat.UpdateRW();
-
- ProcessSwingingDoor(CAR_DOOR_LF, DOOR_FRONT_LEFT);
- ProcessSwingingDoor(CAR_DOOR_RF, DOOR_FRONT_RIGHT);
- ProcessSwingingDoor(CAR_DOOR_LR, DOOR_REAR_LEFT);
- ProcessSwingingDoor(CAR_DOOR_RR, DOOR_REAR_RIGHT);
- ProcessSwingingDoor(CAR_BONNET, DOOR_BONNET);
- ProcessSwingingDoor(CAR_BOOT, DOOR_BOOT);
}
if((GetModelIndex() == MI_PHEONIX || GetModelIndex() == MI_BFINJECT) &&
@@ -2968,6 +2954,7 @@ CAutomobile::Render(void)
{
CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex());
+ m_nSetPieceExtendedRangeTime = CTimer::GetTimeInMilliseconds() + 3000;
mi->SetVehicleColour(m_currentColour1, m_currentColour2);
if(IsRealHeli()){
@@ -3093,6 +3080,9 @@ static float fMouseCentreMult = 0.975f;
void
CAutomobile::ProcessControlInputs(uint8 pad)
{
+ if(this == FindPlayerVehicle() && CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle)
+ return;
+
float speed = DotProduct(m_vecMoveSpeed, GetForward());
if(!CPad::GetPad(pad)->GetExitVehicle() ||
@@ -3103,6 +3093,7 @@ CAutomobile::ProcessControlInputs(uint8 pad)
bIsHandbrakeOn = true;
// Steer left/right
+#if 0 // LCS: removed, need mouse for free cam
if(CCamera::m_bUseMouse3rdPerson && !CVehicle::m_bDisableMouseSteering){
if(CPad::GetPad(pad)->GetMouseX() != 0.0f){
m_fSteerInput += fMouseSteerSens*CPad::GetPad(pad)->GetMouseX();
@@ -3115,7 +3106,9 @@ CAutomobile::ProcessControlInputs(uint8 pad)
0.2f*CTimer::GetTimeStep();
nLastControlInput = 0;
}
- }else{
+ }else
+#endif
+ {
m_fSteerInput += (-CPad::GetPad(pad)->GetSteeringLeftRight()/128.0f - m_fSteerInput)*
0.2f*CTimer::GetTimeStep();
nLastControlInput = 0;
@@ -3209,10 +3202,11 @@ CAutomobile::ProcessControlInputs(uint8 pad)
// Brake if player isn't in control
// BUG: game always uses pad 0 here
#ifdef FIX_BUGS
- if(CPad::GetPad(pad)->ArePlayerControlsDisabled()){
+ if((CPad::GetPad(pad)->ArePlayerControlsDisabled() || CPad::GetPad(pad)->bApplyBrakes || m_bSuperBrake) &&
#else
- if(CPad::GetPad(0)->ArePlayerControlsDisabled()){
+ if((CPad::GetPad(0)->ArePlayerControlsDisabled() || CPad::GetPad(0)->bApplyBrakes || m_bSuperBrake) &&
#endif
+ (gMultiplayerSuperBrakeOnPause || m_bSuperBrake)){
m_fBrakePedal = 1.0f;
bIsHandbrakeOn = true;
m_fGasPedal = 0.0f;
@@ -3226,67 +3220,119 @@ CAutomobile::ProcessControlInputs(uint8 pad)
}
}
+// not sure if global variables
+float FIRETRUCK_LR_SPEED = 0.05f;
+float FIRETRUCK_UD_SPEED = 0.02f;
+
void
CAutomobile::FireTruckControl(void)
{
if(this == FindPlayerVehicle()){
- if(!CPad::GetPad(0)->GetCarGunFired())
- return;
-#ifdef FREE_CAM
- if (!CCamera::bFreeCam)
-#endif
- {
- m_fCarGunLR += CPad::GetPad(0)->GetCarGunLeftRight() * 0.00025f * CTimer::GetTimeStep();
- m_fCarGunUD += CPad::GetPad(0)->GetCarGunUpDown() * 0.0001f * CTimer::GetTimeStep();
- }
- m_fCarGunUD = Clamp(m_fCarGunUD, 0.05f, 0.3f);
-
-
- CVector cannonPos(0.0f, 1.5f, 1.9f);
- cannonPos = GetMatrix() * cannonPos;
- CVector cannonDir(
- Sin(m_fCarGunLR) * Cos(m_fCarGunUD),
- Cos(m_fCarGunLR) * Cos(m_fCarGunUD),
- Sin(m_fCarGunUD));
- cannonDir = Multiply3x3(GetMatrix(), cannonDir);
- cannonDir.z += (CGeneral::GetRandomNumber()&0xF)/1000.0f;
- CWaterCannons::UpdateOne((uintptr)this, &cannonPos, &cannonDir);
- }else if(GetStatus() == STATUS_PHYSICS){
- CFire *fire = gFireManager.FindFurthestFire_NeverMindFireMen(GetPosition(), 10.0f, 35.0f);
- if(fire == nil)
- return;
+ if(CPad::GetPad(0)->GetCarGunFired()){
+ if(TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_CAM_ON_A_STRING){
+ // android code differs
+ CVector localFront = Multiply3x3(TheCamera.Cams[TheCamera.ActiveCam].Front, GetMatrix());
+ float targetDirLR = localFront.Heading();
+ float targetDirUD = Atan2(localFront.z, localFront.Magnitude2D());
+
+ targetDirUD += DEGTORAD(15.0f);
+ if(m_fCarGunLR + PI < targetDirLR)
+ targetDirLR -= TWOPI;
+ else if(m_fCarGunLR - PI > targetDirLR)
+ targetDirLR += TWOPI;
+
+ if(targetDirLR - m_fCarGunLR > CTimer::GetTimeStep()*FIRETRUCK_LR_SPEED)
+ m_fCarGunLR += CTimer::GetTimeStep()*FIRETRUCK_LR_SPEED;
+ else if(targetDirLR - m_fCarGunLR < -CTimer::GetTimeStep()*FIRETRUCK_LR_SPEED)
+ m_fCarGunLR -= CTimer::GetTimeStep()*FIRETRUCK_LR_SPEED;
+ else
+ m_fCarGunLR = targetDirLR;
- // Target cannon onto fire
- float targetAngle = CGeneral::GetATanOfXY(fire->m_vecPos.x-GetPosition().x, fire->m_vecPos.y-GetPosition().y);
- float fwdAngle = CGeneral::GetATanOfXY(GetForward().x, GetForward().y);
- float targetCannonAngle = fwdAngle - targetAngle;
- float angleDelta = CTimer::GetTimeStep()*0.01f;
- float cannonDelta = targetCannonAngle - m_fCarGunLR;
- while(cannonDelta < PI) cannonDelta += TWOPI;
- while(cannonDelta > PI) cannonDelta -= TWOPI;
- if(Abs(cannonDelta) < angleDelta)
- m_fCarGunLR = targetCannonAngle;
- else if(cannonDelta > 0.0f)
- m_fCarGunLR += angleDelta;
- else
- m_fCarGunLR -= angleDelta;
-
- // Go up and down a bit
- float upDown = Sin((float)(CTimer::GetTimeInMilliseconds() & 0xFFF)/0x1000 * TWOPI);
- m_fCarGunUD = 0.2f + 0.2f*upDown;
-
- // Spray water every once in a while
- if((CTimer::GetTimeInMilliseconds()>>10) & 3){
- CVector cannonPos(0.0f, 0.0f, 2.2f); // different position than player's firetruck!
- cannonPos = GetMatrix() * cannonPos;
- CVector cannonDir(
- Sin(m_fCarGunLR) * Cos(m_fCarGunUD),
- Cos(m_fCarGunLR) * Cos(m_fCarGunUD),
- Sin(m_fCarGunUD));
- cannonDir = Multiply3x3(GetMatrix(), cannonDir);
+ if(targetDirUD - m_fCarGunUD > CTimer::GetTimeStep()*FIRETRUCK_UD_SPEED)
+ m_fCarGunUD += CTimer::GetTimeStep()*FIRETRUCK_UD_SPEED;
+ else if(targetDirUD - m_fCarGunUD < -CTimer::GetTimeStep()*FIRETRUCK_UD_SPEED)
+ m_fCarGunUD -= CTimer::GetTimeStep()*FIRETRUCK_UD_SPEED;
+ else
+ m_fCarGunUD = targetDirUD;
+ }else{
+ m_fCarGunLR -= CPad::GetPad(0)->GetCarGunLeftRight()/128.0f * FIRETRUCK_LR_SPEED * CTimer::GetTimeStep();
+ m_fCarGunUD += CPad::GetPad(0)->GetCarGunUpDown()/128.0f * FIRETRUCK_UD_SPEED * CTimer::GetTimeStep();
+ }
+
+ if(m_fCarGunLR < -PI) m_fCarGunLR += TWOPI;
+ else if(m_fCarGunLR > PI) m_fCarGunLR -= TWOPI;
+ m_fCarGunUD = Clamp(m_fCarGunUD, -0.06f, 0.3f);
+
+ CVector cannonPos, cannonDir;
+ CVector localOffset(0.0f, 0.75f, 0.0f);
+ CVector localPos(0.0f, 1.05f, 2.02f);
+ CMatrix rotMat;
+ rotMat.SetUnity();
+ rotMat.SetRotateZ(m_fCarGunLR);
+ localOffset = rotMat * localOffset;
+ localPos += localOffset;
+ cannonPos = GetMatrix() * localPos;
+ cannonDir = Multiply3x3(GetMatrix(), CVector(-Sin(m_fCarGunLR) * Cos(m_fCarGunUD),
+ Cos(m_fCarGunLR) * Cos(m_fCarGunUD),
+ Sin(m_fCarGunUD)));
cannonDir.z += (CGeneral::GetRandomNumber()&0xF)/1000.0f;
CWaterCannons::UpdateOne((uintptr)this, &cannonPos, &cannonDir);
}
+ }else if(GetStatus() == STATUS_PHYSICS){
+ CFire *fire = gFireManager.FindFurthestFire_NeverMindFireMen(GetPosition(), 10.0f, 35.0f);
+ if(fire){
+
+ // Target cannon onto fire
+ float targetAngle = CGeneral::GetATanOfXY(fire->m_vecPos.x-GetPosition().x, fire->m_vecPos.y-GetPosition().y);
+ float fwdAngle = CGeneral::GetATanOfXY(GetForward().x, GetForward().y);
+#ifdef FIX_BUGS
+ // angle direction changed but they didn't notice
+ targetAngle = TWOPI - targetAngle;
+ fwdAngle = TWOPI - fwdAngle;
+#endif
+ float targetCannonAngle = fwdAngle - targetAngle;
+ float angleDelta = CTimer::GetTimeStep()*0.01f;
+ float cannonDelta = CGeneral::LimitRadianAngle(targetCannonAngle - m_fCarGunLR);
+ if(Abs(cannonDelta) < angleDelta)
+ m_fCarGunLR = targetCannonAngle;
+ else if(cannonDelta > 0.0f)
+ m_fCarGunLR += angleDelta;
+ else
+ m_fCarGunLR -= angleDelta;
+
+ // Go up and down a bit
+ float upDown = Sin((float)(CTimer::GetTimeInMilliseconds() & 0xFFF)/0x1000 * TWOPI);
+ m_fCarGunUD = 0.2f + 0.2f*upDown;
+
+ // Spray water every once in a while
+ if((CTimer::GetTimeInMilliseconds()>>10) & 3){
+ CVector cannonPos, cannonDir;
+ CVector localOffset(0.0f, 0.75f, 0.0f);
+ CVector localPos(0.0f, 1.05f, 2.02f);
+ CMatrix rotMat;
+ rotMat.SetUnity();
+ rotMat.SetRotateZ(m_fCarGunLR);
+ localOffset = rotMat * localOffset;
+ localPos += localOffset;
+ cannonPos = GetMatrix() * localPos;
+ cannonDir = Multiply3x3(GetMatrix(), CVector(-Sin(m_fCarGunLR) * Cos(m_fCarGunUD),
+ Cos(m_fCarGunLR) * Cos(m_fCarGunUD),
+ Sin(m_fCarGunUD)));
+ cannonDir.z += (CGeneral::GetRandomNumber()&0xF)/1000.0f;
+#ifdef FIX_BUGS
+ // actual call missing?!?
+ CWaterCannons::UpdateOne((uintptr)this, &cannonPos, &cannonDir);
+#endif
+ }
+ }
+ }
+
+ if(m_aCarNodes[CAR_BUMP_REAR]){
+ CMatrix mat(RwFrameGetMatrix(m_aCarNodes[CAR_BUMP_REAR]));
+ CVector pos = mat.GetPosition();
+ mat.SetRotateZ(m_fCarGunLR);
+ mat.Translate(pos);
+ mat.UpdateRW();
}
}
@@ -3307,10 +3353,7 @@ CAutomobile::TankControl(void)
// Rotate turret
float prevAngle = m_fCarGunLR;
-#ifdef FREE_CAM
- if(!CCamera::bFreeCam)
-#endif
- m_fCarGunLR -= CPad::GetPad(0)->GetCarGunLeftRight() * 0.00015f * CTimer::GetTimeStep();
+ m_fCarGunLR -= CPad::GetPad(0)->GetCarGunLeftRight() * 0.00015f * CTimer::GetTimeStep();
if(m_fCarGunLR < 0.0f)
m_fCarGunLR += TWOPI;
@@ -3387,6 +3430,14 @@ CAutomobile::TankControl(void)
flashPos += 0.1f*shotDir;
CParticle::AddParticle(PARTICLE_GUNFLASH, flashPos, nullDir, nil, 0.15f, black, 0, 0, 0, lifeSpan);
}
+
+ if(m_aCarNodes[CAR_WINDSCREEN]){
+ CMatrix mat(RwFrameGetMatrix(m_aCarNodes[CAR_WINDSCREEN]));
+ CVector pos = mat.GetPosition();
+ mat.SetRotateZ(m_fCarGunLR);
+ mat.Translate(pos);
+ mat.UpdateRW();
+ }
}
#define HYDRAULIC_UPPER_EXT (-0.16f)
@@ -3691,8 +3742,8 @@ CAutomobile::ProcessBuoyancy(void)
if(mod_Buoyancy.ProcessBuoyancy(this, m_fBuoyancy, &point, &impulse)){
bTouchingWater = true;
- float timeStep = Max(CTimer::GetTimeStep(), 0.01f);
- float impulseRatio = impulse.z / (GRAVITY * m_fMass * timeStep);
+ float timeStep = Max(CTimer::GetTimeStep(), 0.5f); // this seems awfully high
+ float impulseRatio = impulse.z / ((bIsHeavy?GRAVITY/3.0f:GRAVITY) * m_fMass * timeStep);
float waterResistance = Pow(1.0f - 0.05f*impulseRatio, CTimer::GetTimeStep());
m_vecMoveSpeed *= waterResistance;
m_vecTurnSpeed *= waterResistance;
@@ -3737,8 +3788,11 @@ CAutomobile::ProcessBuoyancy(void)
if(pDriver){
pDriver->bIsInWater = true;
- if(pDriver->IsPlayer() || !bWaterTight)
+ if(pDriver->IsPlayer() || !bWaterTight){
+ if(pDriver->m_fHealth < 30.0f)
+ SampleManager.SetMusicFadeVolume(Max(0, SampleManager.GetMusicFadeVolume()-4));
pDriver->InflictDamage(nil, WEAPONTYPE_DROWNING, CTimer::GetTimeStep(), PEDPIECE_TORSO, 0);
+ }
}
for(i = 0; i < m_nNumMaxPassengers; i++)
if(pPassengers[i]){
@@ -3907,7 +3961,7 @@ CAutomobile::DoDriveByShootings(void)
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;
+ weapon->m_nTimer = CTimer::GetTimeInMilliseconds() + weapon->GetInfo()->m_nFiringRate;
}
}
}else{
@@ -4158,14 +4212,14 @@ CAutomobile::VehicleDamage(float impulse, uint16 damagedPiece)
case CAR_PIECE_BUMP_FRONT:
GetComponentWorldPosition(CAR_BUMP_FRONT, pos);
dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
- if(Damage.ApplyDamage(COMPONENT_BUMPER_FRONT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
+ if(Damage.ApplyDamage(COMPONENT_BUMPER_FRONT, impulse*impulseMult, pHandling->GetCollisionDamageMultiplier()))
SetBumperDamage(CAR_BUMP_FRONT, VEHBUMPER_FRONT);
if(m_aCarNodes[CAR_BONNET] && Damage.GetPanelStatus(VEHBUMPER_FRONT) == PANEL_STATUS_MISSING){
case CAR_PIECE_BONNET:
GetComponentWorldPosition(CAR_BONNET, pos);
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->GetCollisionDamageMultiplier()))
SetDoorDamage(CAR_BONNET, DOOR_BONNET);
}
break;
@@ -4173,13 +4227,13 @@ CAutomobile::VehicleDamage(float impulse, uint16 damagedPiece)
case CAR_PIECE_BUMP_REAR:
GetComponentWorldPosition(CAR_BUMP_REAR, pos);
dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
- if(Damage.ApplyDamage(COMPONENT_BUMPER_REAR, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
+ if(Damage.ApplyDamage(COMPONENT_BUMPER_REAR, impulse*impulseMult, pHandling->GetCollisionDamageMultiplier()))
SetBumperDamage(CAR_BUMP_REAR, VEHBUMPER_REAR);
if(m_aCarNodes[CAR_BOOT] && Damage.GetPanelStatus(VEHBUMPER_REAR) == PANEL_STATUS_MISSING){
case CAR_PIECE_BOOT:
GetComponentWorldPosition(CAR_BOOT, pos);
dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
- if(Damage.ApplyDamage(COMPONENT_DOOR_BOOT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
+ if(Damage.ApplyDamage(COMPONENT_DOOR_BOOT, impulse*impulseMult, pHandling->GetCollisionDamageMultiplier()))
SetDoorDamage(CAR_BOOT, DOOR_BOOT);
}
break;
@@ -4187,50 +4241,50 @@ CAutomobile::VehicleDamage(float impulse, uint16 damagedPiece)
case CAR_PIECE_DOOR_LF:
GetComponentWorldPosition(CAR_DOOR_LF, pos);
dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
- if(Damage.ApplyDamage(COMPONENT_DOOR_FRONT_LEFT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
+ if(Damage.ApplyDamage(COMPONENT_DOOR_FRONT_LEFT, impulse*impulseMult, pHandling->GetCollisionDamageMultiplier()))
SetDoorDamage(CAR_DOOR_LF, DOOR_FRONT_LEFT);
break;
case CAR_PIECE_DOOR_RF:
GetComponentWorldPosition(CAR_DOOR_RF, pos);
dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
- if(Damage.ApplyDamage(COMPONENT_DOOR_FRONT_RIGHT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
+ if(Damage.ApplyDamage(COMPONENT_DOOR_FRONT_RIGHT, impulse*impulseMult, pHandling->GetCollisionDamageMultiplier()))
SetDoorDamage(CAR_DOOR_RF, DOOR_FRONT_RIGHT);
break;
case CAR_PIECE_DOOR_LR:
GetComponentWorldPosition(CAR_DOOR_LR, pos);
dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
- if(Damage.ApplyDamage(COMPONENT_DOOR_REAR_LEFT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
+ if(Damage.ApplyDamage(COMPONENT_DOOR_REAR_LEFT, impulse*impulseMult, pHandling->GetCollisionDamageMultiplier()))
SetDoorDamage(CAR_DOOR_LR, DOOR_REAR_LEFT);
break;
case CAR_PIECE_DOOR_RR:
GetComponentWorldPosition(CAR_DOOR_RR, pos);
dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
- if(Damage.ApplyDamage(COMPONENT_DOOR_REAR_RIGHT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
+ if(Damage.ApplyDamage(COMPONENT_DOOR_REAR_RIGHT, impulse*impulseMult, pHandling->GetCollisionDamageMultiplier()))
SetDoorDamage(CAR_DOOR_RR, DOOR_REAR_RIGHT);
break;
case CAR_PIECE_WING_LF:
GetComponentWorldPosition(CAR_WING_LF, pos);
dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
- if(Damage.ApplyDamage(COMPONENT_PANEL_FRONT_LEFT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
+ if(Damage.ApplyDamage(COMPONENT_PANEL_FRONT_LEFT, impulse*impulseMult, pHandling->GetCollisionDamageMultiplier()))
SetPanelDamage(CAR_WING_LF, VEHPANEL_FRONT_LEFT);
break;
case CAR_PIECE_WING_RF:
GetComponentWorldPosition(CAR_WING_RF, pos);
dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
- if(Damage.ApplyDamage(COMPONENT_PANEL_FRONT_RIGHT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
+ if(Damage.ApplyDamage(COMPONENT_PANEL_FRONT_RIGHT, impulse*impulseMult, pHandling->GetCollisionDamageMultiplier()))
SetPanelDamage(CAR_WING_RF, VEHPANEL_FRONT_RIGHT);
break;
case CAR_PIECE_WING_LR:
GetComponentWorldPosition(CAR_WING_LR, pos);
dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
- if(Damage.ApplyDamage(COMPONENT_PANEL_REAR_LEFT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
+ if(Damage.ApplyDamage(COMPONENT_PANEL_REAR_LEFT, impulse*impulseMult, pHandling->GetCollisionDamageMultiplier()))
SetPanelDamage(CAR_WING_LR, VEHPANEL_REAR_LEFT);
break;
case CAR_PIECE_WING_RR:
GetComponentWorldPosition(CAR_WING_RR, pos);
dmgDrawCarCollidingParticles(pos, impulse*damageMultiplier);
- if(Damage.ApplyDamage(COMPONENT_PANEL_REAR_RIGHT, impulse*impulseMult, pHandling->fCollisionDamageMultiplier))
+ if(Damage.ApplyDamage(COMPONENT_PANEL_REAR_RIGHT, impulse*impulseMult, pHandling->GetCollisionDamageMultiplier()))
SetPanelDamage(CAR_WING_RR, VEHPANEL_REAR_RIGHT);
break;
@@ -4241,7 +4295,7 @@ CAutomobile::VehicleDamage(float impulse, uint16 damagedPiece)
break;
case CAR_PIECE_WINDSCREEN:
- if(Damage.ApplyDamage(COMPONENT_PANEL_WINDSCREEN, impulse*impulseMult, pHandling->fCollisionDamageMultiplier)){
+ if(Damage.ApplyDamage(COMPONENT_PANEL_WINDSCREEN, impulse*impulseMult, pHandling->GetCollisionDamageMultiplier())){
uint8 oldStatus = Damage.GetPanelStatus(VEHPANEL_WINDSCREEN);
SetPanelDamage(CAR_WINDSCREEN, VEHPANEL_WINDSCREEN);
if(oldStatus != Damage.GetPanelStatus(VEHPANEL_WINDSCREEN)){
@@ -4252,7 +4306,7 @@ CAutomobile::VehicleDamage(float impulse, uint16 damagedPiece)
}
}
- float damage = (impulse-minImpulse)*pHandling->fCollisionDamageMultiplier*0.6f*damageMultiplier;
+ float damage = (impulse-minImpulse)*pHandling->GetCollisionDamageMultiplier()*0.6f*damageMultiplier;
if(GetModelIndex() == MI_SECURICA && m_pDamageEntity && m_pDamageEntity->GetStatus() == STATUS_PLAYER)
damage *= 7.0f;
@@ -4274,6 +4328,7 @@ CAutomobile::VehicleDamage(float impulse, uint16 damagedPiece)
int oldHealth = m_fHealth;
if(this == FindPlayerVehicle())
+ // android has other values here
m_fHealth -= bTakeLessDamage ? damage/6.0f : damage/2.0f;
else if(bTakeLessDamage)
m_fHealth -= damage/12.0f;
@@ -4311,6 +4366,35 @@ CAutomobile::VehicleDamage(float impulse, uint16 damagedPiece)
Damage.SetEngineStatus(100);
}
}
+
+ if(bHitByTrain){
+ for(i = 0; i < PHYSICAL_MAX_COLLISIONRECORDS; i++){
+ CVehicle *train = (CVehicle*)m_aCollisionRecords[i];
+ if(train && train->IsVehicle() &&
+ train->GetModelIndex() == MI_TRAIN &&
+ train->GetSpeed(CVector(0.0f, 0.0, 0.0f)).MagnitudeSqr() > SQR(0.001f)){
+ CPed *ped = KnockPedOutCar(WEAPONTYPE_RAMMEDBYCAR, CAR_DOOR_LF, pDriver);
+ if(ped){
+//TODO(LCS): ped->NailToSubwayTrack();
+ ped->SetDie();
+ }
+ BlowUpCar(train);
+ }
+ }
+ }
+
+ if(pDriver && pDriver->IsPlayer()){
+ for(i = 0; i < PHYSICAL_MAX_COLLISIONRECORDS; i++){
+ CVehicle *airtrain = (CVehicle*)m_aCollisionRecords[i];
+ if(airtrain && airtrain->IsVehicle() &&
+ airtrain->GetModelIndex() == MI_AIRTRAIN){
+ CPed *ped = KnockPedOutCar(WEAPONTYPE_RAMMEDBYCAR, CAR_DOOR_LF, pDriver);
+ if(ped)
+ ped->SetDie();
+ BlowUpCar(airtrain);
+ }
+ }
+ }
}
void
@@ -4339,6 +4423,7 @@ CAutomobile::dmgDrawCarCollidingParticles(const CVector &pos, float amount)
CVector(0.0f, 0.0f, 0.0f), nil, 0.5f);
n = (int)amount/50 + 1;
+ n = Min(n, 10);
for(i = 0; i < n; i++)
CParticle::AddParticle(PARTICLE_CAR_DEBRIS, pos,
CVector(CGeneral::GetRandomNumberInRange(-0.25f, 0.25f),
@@ -4346,7 +4431,7 @@ CAutomobile::dmgDrawCarCollidingParticles(const CVector &pos, float amount)
CGeneral::GetRandomNumberInRange(0.1f, 0.25f)),
nil,
CGeneral::GetRandomNumberInRange(0.02f, 0.08f),
- CVehicleModelInfo::ms_vehicleColourTable[m_currentColour1],
+ CVehicleModelInfo::mspInfo->ms_vehicleColourTable[m_currentColour1],
CGeneral::GetRandomNumberInRange(-40, 40),
0,
CGeneral::GetRandomNumberInRange(0, 4));
@@ -4591,7 +4676,9 @@ CAutomobile::OpenDoor(int32 component, eDoors door, float openRatio)
if(Damage.GetDoorStatus(door) == DOOR_STATUS_SWINGING)
Damage.SetDoorStatus(door, DOOR_STATUS_OK); // huh?
ShowAllComps();
- DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_DOOR_CLOSE_BONNET + door, 0.0f);
+ // TODO(LCS): this makes no sense at all to me
+ if(component != CAR_DOOR_LR || IsDoorReady(DOOR_REAR_RIGHT))
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_DOOR_CLOSE_BONNET + door, 0.0f);
}
axes[Doors[door].m_nAxis] = Doors[door].m_fAngle;
@@ -4644,6 +4731,19 @@ CAutomobile::ProcessOpenDoor(uint32 component, uint32 anim, float time)
{
eDoors door;
+ if(bIsVan){
+ if(component == CAR_DOOR_RR){
+ if(anim == ANIM_STD_VAN_OPEN_DOOR_REAR_RHS || anim == ANIM_STD_VAN_CLOSE_DOOR_REAR_RHS)
+ if(IsDoorReady(DOOR_REAR_LEFT))
+ ProcessOpenDoor(CAR_DOOR_LR, anim, time);
+ }
+ if(component == CAR_DOOR_LR){
+ if(anim == ANIM_STD_VAN_OPEN_DOOR_REAR_LHS || anim == ANIM_STD_VAN_CLOSE_DOOR_REAR_LHS)
+ if(IsDoorReady(DOOR_REAR_RIGHT))
+ ProcessOpenDoor(CAR_DOOR_RR, anim, time);
+ }
+ }
+
switch(component){
case CAR_DOOR_RF: door = DOOR_FRONT_RIGHT; break;
case CAR_DOOR_RR: door = DOOR_REAR_RIGHT; break;
@@ -4665,7 +4765,7 @@ CAutomobile::ProcessOpenDoor(uint32 component, uint32 anim, float time)
case ANIM_STD_CAR_CLOSE_DOOR_LO_LHS:
case ANIM_STD_CAR_CLOSE_DOOR_RHS:
case ANIM_STD_CAR_CLOSE_DOOR_LO_RHS:
- ProcessDoorCloseAnimation(this, component, door, time, 0.2f, 0.45f);
+ ProcessDoorCloseAnimation(this, component, door, time, 0.2f, 0.63f);
break;
case ANIM_STD_CAR_CLOSE_DOOR_ROLLING_LHS:
case ANIM_STD_CAR_CLOSE_DOOR_ROLLING_LO_LHS:
@@ -4679,7 +4779,7 @@ CAutomobile::ProcessOpenDoor(uint32 component, uint32 anim, float time)
break;
case ANIM_STD_CAR_CLOSE_LHS:
case ANIM_STD_CAR_CLOSE_RHS:
- ProcessDoorCloseAnimation(this, component, door, time, 0.1f, 0.23f);
+ ProcessDoorCloseAnimation(this, component, door, time, 0.35f, 0.5f);
break;
case ANIM_STD_CAR_PULL_OUT_PED_RHS:
case ANIM_STD_CAR_PULL_OUT_PED_LO_RHS:
@@ -4996,7 +5096,9 @@ CAutomobile::PlayCarHorn(void)
{
uint32 r;
- if (IsAlarmOn() || m_nCarHornTimer != 0)
+ if (IsAlarmOn() ||
+ this == FindPlayerVehicle() && CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle ||
+ m_nCarHornTimer != 0)
return;
if (m_nCarHornDelay) {
@@ -5047,6 +5149,14 @@ CAutomobile::SetupSuspensionLines(void)
CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex());
CColModel *colModel = mi->GetColModel();
+ bool adjustColModel;
+ if(colModel->lines == nil){
+ adjustColModel = true;
+ colModel->lines = new CColLine[4];
+ colModel->numLines = 4;
+ }else
+ adjustColModel = false;
+
// Each suspension line starts at the uppermost wheel position
// and extends down to the lowermost point on the tyre
for(i = 0; i < 4; i++){
@@ -5086,6 +5196,21 @@ CAutomobile::SetupSuspensionLines(void)
for(i = 0; i < colModel->numSpheres; i++)
colModel->spheres[i].radius = 0.3f;
}
+
+ if(pHandling->Flags & HANDLING_FORCE_GRND_CLR && adjustColModel){
+ // 0.25 is the min distance between ground and col spheres, everything above it is safe
+ float safePos = 0.25f - m_fHeightAboveRoad;
+ for(i = 0; i < colModel->numSpheres; i++){
+ CColSphere *sph = &colModel->spheres[i];
+ if(sph->center.z - sph->radius < safePos){
+ // sphere extends too far down, so move it up
+ // or decrease the radius for bigger spheres
+ if(radius > 0.4f)
+ sph->radius = Max(sph->center.z - safePos, 0.4f);
+ sph->center.z = safePos + sph->radius;
+ }
+ }
+ }
}
// called on police cars
@@ -5108,6 +5233,7 @@ CAutomobile::BlowUpCarsInPath(void)
for(i = 0; i < m_nCollisionRecords; i++)
if(m_aCollisionRecords[i] &&
m_aCollisionRecords[i]->IsVehicle() &&
+ IsVehiclePointerValid((CVehicle*)m_aCollisionRecords[i]) &&
m_aCollisionRecords[i]->GetModelIndex() != MI_RHINO &&
!m_aCollisionRecords[i]->bRenderScorched){
if(this == FindPlayerVehicle())
@@ -5402,6 +5528,7 @@ CAutomobile::Fix(void)
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);
@@ -5411,6 +5538,7 @@ CAutomobile::Fix(void)
RpAtomicSetFlags((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LB]), 0);
RpAtomicSetFlags((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RB]), 0);
}
+*/
}
void
@@ -5472,6 +5600,7 @@ CAutomobile::SpawnFlyingComponent(int32 component, uint32 type)
if(obj == nil)
return nil;
+ phys_lcs_unk1 = false;
if(component == CAR_WINDSCREEN){
obj->SetModelIndexNoCreate(MI_CAR_BONNET);
}else switch(type){
@@ -5510,6 +5639,7 @@ CAutomobile::SpawnFlyingComponent(int32 component, uint32 type)
*RwFrameGetMatrix(frame) = *matrix;
RpAtomicSetFrame(atomic, frame);
CVisibilityPlugins::SetAtomicRenderCallback(atomic, nil);
+ CStreaming::RegisterInstance(atomic, nil);
obj->AttachToRwObject((RwObject*)atomic);
obj->bDontStream = true;
@@ -5554,7 +5684,7 @@ CAutomobile::SpawnFlyingComponent(int32 component, uint32 type)
CVector dist = obj->GetPosition() - GetPosition();
dist.Normalise();
if(component == COMPGROUP_BONNET || component == COMPGROUP_BOOT || component == CAR_WINDSCREEN){
- // push these up some
+ // push these up some
dist += GetUp();
if(GetUp().z > 0.0f){
// simulate fast upward movement if going fast
@@ -5577,9 +5707,9 @@ CAutomobile::SpawnFlyingComponent(int32 component, uint32 type)
ApplyMoveForce(5.0f*dist);
}
- if(CCollision::ProcessColModels(obj->GetMatrix(), *obj->GetColModel(),
- this->GetMatrix(), *this->GetColModel(),
- CWorld::m_aTempColPts, nil, nil) > 0)
+// if(CCollision::ProcessColModels(obj->GetMatrix(), *obj->GetColModel(),
+// this->GetMatrix(), *this->GetColModel(),
+// CWorld::m_aTempColPts, nil, nil) > 0)
obj->m_pCollidingEntity = this;
if(bRenderScorched)
diff --git a/src/vehicles/Automobile.h b/src/vehicles/Automobile.h
index f4046e9e..f3ee803b 100644
--- a/src/vehicles/Automobile.h
+++ b/src/vehicles/Automobile.h
@@ -26,6 +26,8 @@ public:
float m_aSuspensionSpringRatioPrev[4];
float m_aWheelTimer[4]; // set to 4.0 when wheel is touching ground, then decremented
float m_auto_unused1;
+ float m_fEngineInertiaVar1;
+ float m_fEngineInertiaVar2;
eSkidmarkType m_aWheelSkidmarkType[4];
bool m_aWheelSkidmarkBloody[4];
bool m_aWheelSkidmarkUnk[4];
@@ -33,10 +35,9 @@ public:
float m_aWheelPosition[4];
float m_aWheelSpeed[4];
uint8 m_auto_unused2;
-#if (defined GTA_PS2 && !defined FIX_BUGS)
uint8 m_bombType : 3;
-#endif
uint8 bTaxiLight : 1;
+ uint8 bDriverLastFrame : 1;
uint8 bFixedColour : 1;
uint8 bBigWheels : 1;
uint8 bWaterTight : 1; // no damage for non-player peds
@@ -45,9 +46,7 @@ public:
uint8 bTankDetonateCars : 1;
uint8 bStuckInSand : 1;
uint8 bHeliDestroyed : 1;
-#if (defined GTA_PS2 && !defined FIX_BUGS)
CEntity* m_pBombRigger;
-#endif
int16 m_doingBurnout;
uint16 m_hydraulicState;
uint32 m_nBusDoorTimerEnd;
@@ -114,6 +113,7 @@ public:
float GetHeightAboveRoad(void);
void PlayCarHorn(void);
+ void ProcessCarWheelPair(int leftWheel, int rightWheel, float steerAngle, CVector *contactSpeeds, CVector *contactPoints, float traction, float acceleration, float brake, bool bFront);
void FireTruckControl(void);
void TankControl(void);
void HydraulicControl(void);
diff --git a/src/vehicles/Bike.cpp b/src/vehicles/Bike.cpp
index a65b64d2..d8ad71ea 100644
--- a/src/vehicles/Bike.cpp
+++ b/src/vehicles/Bike.cpp
@@ -37,6 +37,7 @@
#include "Bike.h"
#include "Debug.h"
#include "SaveBuf.h"
+#include "Garages.h"
const uint32 CBike::nSaveStructSize =
#ifdef COMPATIBLE_SAVES
@@ -74,15 +75,17 @@ CBike::CBike(int32 id, uint8 CreatedBy)
break;
case MI_PIZZABOY:
case MI_FAGGIO:
+ case MI_NOODLEBOY:
m_bikeAnimType = ASSOCGRP_BIKE_VESPA;
break;
case MI_PCJ600:
m_bikeAnimType = ASSOCGRP_BIKE_STANDARD;
break;
case MI_SANCHEZ:
+ case MI_SANCHEZ2:
m_bikeAnimType = ASSOCGRP_BIKE_DIRT;
break;
- default: assert(0 && "invalid bike model ID");
+ default: m_bikeAnimType = ASSOCGRP_BIKE_STANDARD; //assert(0 && "invalid bike model ID"); // TODO
}
m_vehType = VEHICLE_TYPE_BIKE;
@@ -110,7 +113,7 @@ CBike::CBike(int32 id, uint8 CreatedBy)
m_fTurnMass = pHandling->fTurnMass;
m_vecCentreOfMass = pHandling->CentreOfMass;
m_vecCentreOfMass.z = 0.1f;
- m_fAirResistance = pHandling->Dimension.x*pHandling->Dimension.z/m_fMass;
+ m_fAirResistance = pHandling->fDragMult > 0.01f ? pHandling->fDragMult*0.0005f : pHandling->fDragMult;
m_fElasticity = 0.05f;
m_fBuoyancy = pHandling->fBuoyancy;
@@ -134,6 +137,8 @@ CBike::CBike(int32 id, uint8 CreatedBy)
bIsOnFire = false;
bWheelieCam = false;
+ bFixedColour = false; // <- figure out actual place (TODO)
+
m_fTireTemperature = 1.0f;
m_fBrakeDestabilization = 0.0f;
m_fVelocityChangeForAudio = 0;
@@ -228,7 +233,19 @@ CBike::ProcessControl(void)
ProcessCarAlarm();
- ActivateBombWhenEntered();
+ 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;
+ }
+ else
+ bDriverLastFrame = false;
CRubbish::StirUp(this);
@@ -296,8 +313,23 @@ CBike::ProcessControl(void)
ApplyMoveForce(parallelSpeed * -CTimer::GetTimeStep()*SAND_SLOWDOWN*m_fMass);
}
}
- if(CPad::GetPad(0)->WeaponJustDown())
- ActivateBomb();
+
+#ifdef BOMBS_ON_BIKES
+ 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);
+ }
+ }
+#endif
break;
case STATUS_PLAYER_PLAYBACKFROMBUFFER:
@@ -1723,7 +1755,7 @@ CBike::PreRender(void)
TheCamera.GetLookDirection() == LOOKING_RIGHT)
pos1 -= 0.2f*GetForward();
- CParticle::AddParticle(PARTICLE_HEATHAZE, pos1, CVector(0.0f, 0.0f, 0.0f));
+ //CParticle::AddParticle(PARTICLE_HEATHAZE, pos1, CVector(0.0f, 0.0f, 0.0f));
}
}
}
diff --git a/src/vehicles/Bike.h b/src/vehicles/Bike.h
index 219d8872..ce89e8c7 100644
--- a/src/vehicles/Bike.h
+++ b/src/vehicles/Bike.h
@@ -67,14 +67,18 @@ public:
float m_fPedLeanAmountUD;
uint8 m_bike_unused2;
uint8 unused[3]; // looks like padding..but for what?
+ uint8 m_bombType : 3;
+ uint8 bDriverLastFrame : 1;
uint8 m_bike_flag01 : 1;
uint8 m_bike_flag02 : 1;
- uint8 bWaterTight : 1;
+ uint8 bWaterTight : 1; // 535_40
uint8 bIsBeingPickedUp : 1;
uint8 bIsStanding : 1;
uint8 bExtraSpeed : 1; // leaning forward
uint8 bIsOnFire : 1;
uint8 bWheelieCam : 1;
+ uint8 bFixedColour : 1; // <- figure out its actual place (TODO)
+ CEntity* m_pBombRigger;
int16 m_doingBurnout;
float m_fTireTemperature;
float m_fBrakeDestabilization;
diff --git a/src/vehicles/Boat.cpp b/src/vehicles/Boat.cpp
index 5da8e1cc..cf46f37b 100644
--- a/src/vehicles/Boat.cpp
+++ b/src/vehicles/Boat.cpp
@@ -72,7 +72,7 @@ CBoat::CBoat(int mi, uint8 owner) : CVehicle(owner)
m_fMass = pHandling->fMass;
m_fTurnMass = pHandling->fTurnMass / 2.0f;
m_vecCentreOfMass = pHandling->CentreOfMass;
- m_fAirResistance = pHandling->Dimension.x * pHandling->Dimension.z / m_fMass;
+ m_fAirResistance = pHandling->fDragMult > 0.01f ? pHandling->fDragMult*0.0005f : pHandling->fDragMult;
m_fElasticity = 0.1f;
m_fBuoyancy = pHandling->fBuoyancy;
m_fSteerAngle = 0.0f;
@@ -682,6 +682,7 @@ CBoat::ProcessControl(void)
}
// Spray waterdrops on screen
+ /*
if(TheCamera.GetLookingForwardFirstPerson() && FindPlayerVehicle() && FindPlayerVehicle()->IsBoat() &&
m_nDeltaVolumeUnderWater > 0 && numWaterDropOnScreen < 20){
CVector dropPos;
@@ -712,7 +713,7 @@ CBoat::ProcessControl(void)
if(CParticle::AddParticle(PARTICLE_WATERDROP, dropPos, dropDir, nil,
CGeneral::GetRandomNumberInRange(0.1f, 0.15f), dropColor, 0, 0, frm))
numWaterDropOnScreen++;
- }
+ }*/
if(m_fPrevVolumeUnderWater == 0.0f && m_fVolumeUnderWater > 0.0f && GetModelIndex() == MI_SKIMMER){
CVector splashDir(0.0f, 0.0f, 0.25f*speed);
diff --git a/src/vehicles/Cranes.cpp b/src/vehicles/Cranes.cpp
index 934ccb08..d4b58f05 100644
--- a/src/vehicles/Cranes.cpp
+++ b/src/vehicles/Cranes.cpp
@@ -13,7 +13,7 @@
#include "World.h"
#include "SaveBuf.h"
-#define MAX_DISTANCE_TO_FIND_CRANE (10.0f)
+#define MAX_DISTANCE_TO_FIND_CRANE (100.0f)
#define CRANE_UPDATE_RADIUS (300.0f)
#define CRANE_MOVEMENT_PROCESSING_RADIUS (150.0f)
#define CRUSHER_Z (-0.951f)
@@ -67,7 +67,8 @@ void CCranes::InitCranes(void)
}
}
}
- for (CPtrNode* pNode = CWorld::GetBigBuildingList(LEVEL_MAINLAND).first; pNode; pNode = pNode->next) {
+ // TODO(LCS)
+ for (CPtrNode* pNode = CWorld::GetBigBuildingList(LEVEL_INDUSTRIAL).first; pNode; pNode = pNode->next) {
CEntity* pEntity = (CEntity*)pNode->item;
if (MODELID_CRANE_1 == pEntity->GetModelIndex() ||
MODELID_CRANE_2 == pEntity->GetModelIndex() ||
@@ -77,6 +78,7 @@ void CCranes::InitCranes(void)
MODELID_CRANE_6 == pEntity->GetModelIndex())
AddThisOneCrane(pEntity);
}
+
}
void CCranes::AddThisOneCrane(CEntity* pEntity)
@@ -469,7 +471,7 @@ bool CCranes::DoesMilitaryCraneHaveThisOneAlready(uint32 mi)
case MI_FIRETRUCK: return (CarsCollectedMilitaryCrane & 1);
case MI_AMBULAN: return (CarsCollectedMilitaryCrane & 2);
case MI_ENFORCER: return (CarsCollectedMilitaryCrane & 4);
- case MI_FBIRANCH: return (CarsCollectedMilitaryCrane & 8);
+ case (uint32)MI_FBIRANCH: return (CarsCollectedMilitaryCrane & 8);
case MI_RHINO: return (CarsCollectedMilitaryCrane & 0x10);
case MI_BARRACKS: return (CarsCollectedMilitaryCrane & 0x20);
case MI_POLICE: return (CarsCollectedMilitaryCrane & 0x40);
@@ -484,7 +486,7 @@ void CCranes::RegisterCarForMilitaryCrane(uint32 mi)
case MI_FIRETRUCK: CarsCollectedMilitaryCrane |= 1; break;
case MI_AMBULAN: CarsCollectedMilitaryCrane |= 2; break;
case MI_ENFORCER: CarsCollectedMilitaryCrane |= 4; break;
- case MI_FBIRANCH: CarsCollectedMilitaryCrane |= 8; break;
+ case (uint32)MI_FBIRANCH: CarsCollectedMilitaryCrane |= 8; break;
case MI_RHINO: CarsCollectedMilitaryCrane |= 0x10; break;
case MI_BARRACKS: CarsCollectedMilitaryCrane |= 0x20; break;
case MI_POLICE: CarsCollectedMilitaryCrane |= 0x40; break;
diff --git a/src/vehicles/DamageManager.cpp b/src/vehicles/DamageManager.cpp
index 8ba235b7..b74e7086 100644
--- a/src/vehicles/DamageManager.cpp
+++ b/src/vehicles/DamageManager.cpp
@@ -10,7 +10,8 @@ float G_aComponentDamage[] = { 2.5f, 1.25f, 3.2f, 1.4f, 2.5f, 2.8f, 0.5f };
CDamageManager::CDamageManager(void)
{
ResetDamageStatus();
- m_fWheelDamageEffect = 0.5f;
+ m_fWheelDamageEffect = 0.65f;
+ m_bSmashedDoorDoesntClose = false;
field_18 = 1;
}
@@ -136,6 +137,8 @@ void
CDamageManager::SetDoorStatus(int32 door, uint32 status)
{
m_doorStatus[door] = status;
+ if(m_bSmashedDoorDoesntClose && door != DOOR_BONNET && status == DOOR_STATUS_SMASHED)
+ m_doorStatus[door] = DOOR_STATUS_SWINGING;
}
int32
diff --git a/src/vehicles/DamageManager.h b/src/vehicles/DamageManager.h
index 312006e3..1f836429 100644
--- a/src/vehicles/DamageManager.h
+++ b/src/vehicles/DamageManager.h
@@ -81,6 +81,7 @@ class CDamageManager
public:
float m_fWheelDamageEffect;
+ bool m_bSmashedDoorDoesntClose;
uint8 m_engineStatus;
uint8 m_wheelStatus[4];
uint8 m_doorStatus[6];
diff --git a/src/vehicles/Door.cpp b/src/vehicles/Door.cpp
index 1b3f9e8f..6e35c951 100644
--- a/src/vehicles/Door.cpp
+++ b/src/vehicles/Door.cpp
@@ -168,3 +168,58 @@ CTrainDoor::IsClosed(void)
{
return m_fPosn == RetTranslationWhenClosed();
}
+
+bool
+CFerryDoor::IsInUse(void)
+{
+ float translationDifference = m_fPrevPosn - m_fPosn;
+ m_fPrevPosn = m_fPosn;
+ return Abs(translationDifference) > 0.002f;
+}
+
+float
+CFerryDoor::RetTranslationWhenClosed(void)
+{
+ if(Abs(m_fClosedPosn) < Abs(m_fOpenPosn))
+ return m_fClosedPosn;
+ else
+ return m_fOpenPosn;
+}
+
+bool
+CFerryDoor::IsClosed(void)
+{
+ return m_fPosn == RetTranslationWhenClosed();
+}
+
+float
+CFerryDoor::RetTranslationWhenOpen(void)
+{
+ if(Abs(m_fClosedPosn) < Abs(m_fOpenPosn))
+ return m_fOpenPosn;
+ else
+ return m_fClosedPosn;
+}
+
+bool
+CFerryDoor::IsFullyOpen(void)
+{
+ if(Abs(m_fPosn) < Abs(RetTranslationWhenOpen()) - 0.5f)
+ return false;
+ return true;
+}
+
+void
+CFerryDoor::Open(float ratio)
+{
+ float open;
+
+ m_fPrevPosn = m_fPosn;
+ open = RetTranslationWhenOpen();
+ if(ratio < 1.0f){
+ m_fPosn = open*ratio;
+ }else{
+ m_nDoorState = DOORST_OPEN;
+ m_fPosn = open;
+ }
+} \ No newline at end of file
diff --git a/src/vehicles/Door.h b/src/vehicles/Door.h
index 567d3263..da5a3de0 100644
--- a/src/vehicles/Door.h
+++ b/src/vehicles/Door.h
@@ -67,3 +67,22 @@ public:
float RetTranslationWhenOpen(void);
void Open(float ratio);
};
+
+
+class CFerryDoor {
+private:
+ float m_fClosedPosn;
+ float m_fOpenPosn;
+ int8 m_nDirn;
+ int8 m_nAxis;
+ int8 m_nDoorState;
+ float m_fPosn;
+ float m_fPrevPosn;
+public:
+ bool IsInUse(void);
+ float RetTranslationWhenClosed(void);
+ float RetTranslationWhenOpen(void);
+ bool IsClosed(void);
+ bool IsFullyOpen(void);
+ void Open(float ratio);
+}; \ No newline at end of file
diff --git a/src/vehicles/Ferry.cpp b/src/vehicles/Ferry.cpp
new file mode 100644
index 00000000..339c2819
--- /dev/null
+++ b/src/vehicles/Ferry.cpp
@@ -0,0 +1,833 @@
+#include "common.h"
+#include "main.h"
+#include "Ferry.h"
+
+#include "AudioManager.h"
+#include "Camera.h"
+#include "Coronas.h"
+#include "FileMgr.h"
+#include "General.h"
+#include "Leeds.h"
+#include "Particle.h"
+#include "PlayerPed.h"
+#include "Streaming.h"
+#include "TempColModels.h"
+#include "WaterLevel.h"
+#include "World.h"
+#include "sampman.h"
+
+CFerryInst* CFerry::mspInst;
+
+#define FERRY_SPEED (0.1f)
+#define FERRY_SLOWDOWN_DISTANCE (50.0f)
+#define FERRY_TIME_STOPPED_AT_STATION (10.0f)
+
+CFerry::CFerry(int32 id, uint8 owner) : CVehicle(owner)
+{
+ m_bPlayerArrivedHorn = false;
+ m_nTimeAlongPath = 0;
+ m_vehType = VEHICLE_TYPE_FERRY;
+ CVehicleModelInfo* mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(id);
+ pHandling = mod_HandlingManager.GetHandlingData((tVehicleType)mi->m_handlingId);
+ SetModelIndex(id);
+ m_doors[0].Init(DEGTORAD(90.0f), 0.0f, 1, 0);
+ m_doors[1].Init(DEGTORAD(-95.0f), 0.0f, 1, 0);
+ m_doors[2].Init(DEGTORAD(-90.0f), 0.0f, 1, 0);
+ m_doors[3].Init(DEGTORAD(95.0f), 0.0f, 1, 0);
+ m_fTurnMass = 100000000.0f;
+ m_fAirResistance = 0.9994f;
+ m_fElasticity = 0.05f;
+ m_nNumMaxPassengers = 1;
+ m_fMass = 100000000.0f;
+ bInfiniteMass = true;
+ m_phy_flagA08 = true;
+ m_bFerryDocked = false;
+ SetStatus(STATUS_FERRY_MOVING);
+ bUsesCollision = true;
+ m_nDoorTimer = CTimer::GetTimeInMilliseconds();
+ m_nDoorState = FERRY_DOOR_CLOSED;
+ m_bApproachingDock = false;
+ m_nSkipFerryStatus = 0;
+ m_nCollision = 0;
+ m_pDefaultColModel = mi->GetColModel();
+ m_level = LEVEL_GENERIC;
+}
+
+void CFerry::Init(void* pInstancePtr)
+{
+ mspInst = (CFerryInst*)pInstancePtr;
+ if (mspInst)
+ return;
+ // the following code should be wrapped in a define
+ mspInst = new CFerryInst();
+ memset(mspInst, 0, sizeof(CFerryInst));
+ for (int k = 0; k < NUM_FERRY_PATHS; k++) {
+ mspInst->pPathData[k] = new CFerryPath();
+ mspInst->pPathData[k]->aLineBits = new CFerryInterpolationLine[NUM_FERRY_STATIONS * 4 + 2];
+
+ const char* filename = "Data\\PATHS\\FERRY1.DAT"; // actually base::cStringT<char> filename; filename += k+1; filename += ".DAT"
+
+ bool readingFile = false;
+ int bp, lp;
+ int i, tmp;
+ CFerryPath* pPath = mspInst->pPathData[k];
+
+ if (pPath->aTrackNodes == nil) {
+ readingFile = true;
+
+ CFileMgr::LoadFile(filename, work_buff, sizeof(work_buff), "r");
+ *gString = '\0';
+ for (bp = 0, lp = 0; work_buff[bp] != '\n'; bp++, lp++)
+ gString[lp] = work_buff[bp];
+ bp++;
+#ifdef FIX_BUGS
+ gString[lp] = '\0';
+#endif
+ sscanf(gString, "%d", &tmp);
+ pPath->NumTrackNodes = tmp;
+ pPath->aTrackNodes = new CFerryNode[tmp];
+
+ for (i = 0; i < pPath->NumTrackNodes; i++) {
+ *gString = '\0';
+ for (lp = 0; work_buff[bp] != '\n'; bp++, lp++)
+ gString[lp] = work_buff[bp];
+ bp++;
+#ifdef FIX_BUGS
+ gString[lp] = '\0';
+#endif
+ sscanf(gString, "%f %f %f", &pPath->aTrackNodes[i].x, &pPath->aTrackNodes[i].y, &pPath->aTrackNodes[i].z);
+ pPath->aTrackNodes[i].z = 0.0f;
+ }
+ }
+
+ // Calculate length of segments and track
+ float t = 0.0f;
+ for (i = 0; i < pPath->NumTrackNodes; i++) {
+ pPath->aTrackNodes[i].t = t;
+ t += Sqrt(SQR(pPath->aTrackNodes[(i + 1) % pPath->NumTrackNodes].x - pPath->aTrackNodes[i].x) +
+ (SQR(pPath->aTrackNodes[(i + 1) % pPath->NumTrackNodes].y - pPath->aTrackNodes[i].y)));
+ }
+ pPath->TotalLengthOfTrack = t;
+
+ // Find correct z values
+ if (readingFile) {
+ CColPoint colpoint;
+ CEntity* entity;
+ for (i = 0; i < pPath->NumTrackNodes; i++) {
+ CVector p(pPath->aTrackNodes[i].x, pPath->aTrackNodes[i].y, pPath->aTrackNodes[i].z + 1.0f);
+ if (CWorld::ProcessVerticalLine(p, p.z - 0.5f, colpoint, entity, true, false, false, false, true, false, nil))
+ pPath->aTrackNodes[i].z = colpoint.point.z;
+ pPath->aTrackNodes[i].z += 0.2f;
+ }
+ }
+
+ int nStationIndices[NUM_FERRY_STATIONS];
+ for (int i = 0; i < NUM_FERRY_STATIONS; i++)
+ nStationIndices[i] = 0;
+ int nCurrentStation = 0;
+
+ for (i = 0; i < pPath->NumTrackNodes; i++) {
+ CFerryNode* pCurNode = &pPath->aTrackNodes[i];
+ CFerryNode* pNextNode = (i + 1 < pPath->NumTrackNodes) ? &pPath->aTrackNodes[i + 1] : &pPath->aTrackNodes[0];
+ CFerryNode* pPrevNode = (i - 1 >= 0) ? &pPath->aTrackNodes[i - 1] : &pPath->aTrackNodes[pPath->NumTrackNodes - 1];
+ if (pCurNode->x - pNextNode->x > 0.0f && pPrevNode->x - pCurNode->x < 0.0f)
+ nStationIndices[nCurrentStation++] = i;
+ if (pCurNode->x - pNextNode->x < 0.0f && pPrevNode->x - pCurNode->x > 0.0f)
+ nStationIndices[nCurrentStation++] = i;
+ }
+
+ float stationDists[NUM_FERRY_STATIONS];
+ for (i = 0; i < NUM_FERRY_STATIONS; i++)
+ stationDists[i] = pPath->aTrackNodes[nStationIndices[i]].t;
+
+ // Create animation for stopping at stations
+ float position = 0.0f;
+ float time = 0.0f;
+ int j = 0;
+ for (i = 0; i < NUM_FERRY_STATIONS; i++) {
+ // Start at full speed
+ pPath->aLineBits[j].type = FERRY_CRUISING;
+ pPath->aLineBits[j].time = time;
+ pPath->aLineBits[j].position = position;
+ pPath->aLineBits[j].speed = FERRY_SPEED;
+ pPath->aLineBits[j].acceleration = 0.0f;
+ j++;
+ // distance to next keyframe
+ float dist = (stationDists[i] - FERRY_SLOWDOWN_DISTANCE) - position;
+ time += dist / FERRY_SPEED;
+ position += dist;
+
+ // Now slow down 50 units before stop
+ pPath->aLineBits[j].type = FERRY_SLOWING;
+ pPath->aLineBits[j].time = time;
+ pPath->aLineBits[j].position = position;
+ pPath->aLineBits[j].speed = FERRY_SPEED;
+ pPath->aLineBits[j].acceleration = -(FERRY_SPEED * FERRY_SPEED) / (4 * FERRY_SLOWDOWN_DISTANCE);
+ j++;
+ time += 2 * FERRY_SLOWDOWN_DISTANCE / FERRY_SPEED;
+ position += FERRY_SLOWDOWN_DISTANCE; // at station
+
+ // stopping
+ pPath->aLineBits[j].type = FERRY_STOPPED;
+ pPath->aLineBits[j].time = time;
+ pPath->aLineBits[j].position = position;
+ pPath->aLineBits[j].speed = 0.0f;
+ pPath->aLineBits[j].acceleration = 0.0f;
+ j++;
+ time += FERRY_TIME_STOPPED_AT_STATION;
+
+ // accelerate again
+ pPath->aLineBits[j].type = FERRY_ACCELERATING;
+ pPath->aLineBits[j].time = time;
+ pPath->aLineBits[j].position = position;
+ pPath->aLineBits[j].speed = 0.0f;
+ pPath->aLineBits[j].acceleration = (FERRY_SPEED * FERRY_SPEED) / (4 * FERRY_SLOWDOWN_DISTANCE);
+ j++;
+ time += 2 * FERRY_SLOWDOWN_DISTANCE / FERRY_SPEED;
+ position += FERRY_SLOWDOWN_DISTANCE; // after station
+ }
+ // last keyframe
+ pPath->aLineBits[j].type = FERRY_CRUISING;
+ pPath->aLineBits[j].time = time;
+ pPath->aLineBits[j].position = position;
+ pPath->aLineBits[j].speed = FERRY_SPEED;
+ pPath->aLineBits[j].acceleration = 0.0f;
+ j++;
+ pPath->TotalDurationOfTrack = time + (pPath->TotalLengthOfTrack - position) / FERRY_SPEED;
+
+ // end
+ pPath->aLineBits[j].time = pPath->TotalDurationOfTrack;
+ }
+}
+
+void CFerry::InitFerrys(void)
+{
+ printf("init ferrys\n");
+#ifdef GTA_NETWORK
+ if (gIsMultiplayerGame)
+ SetupForMultiplayer();
+#endif
+ if (!mspInst)
+ Init(nil);
+ for (int i = 0; i < NUM_FERRIES; i++)
+ mspInst->m_apFerries[i] = nil;
+ CStreaming::LoadAllRequestedModels(false);
+ CStreaming::RequestModel(MI_FERRY, 0);
+ CStreaming::LoadAllRequestedModels(false);
+}
+
+void CFerry::SwitchFerryCollision(int type)
+{
+ for (int i = 0; i < NUM_FERRIES; i++) {
+ CFerry* pFerry = GetFerry(i);
+ if (pFerry && pFerry->m_nCollision != type) {
+ pFerry->m_nCollision = type;
+ CVehicleModelInfo* mi = pFerry->GetModelInfo();
+ if (type == 1)
+ mi->SetColModel(&CTempColModels::ms_colModelFerryDocked);
+ else
+ mi->SetColModel(pFerry->m_pDefaultColModel, true);
+ }
+ }
+}
+
+void CFerry::UpdateFerrys(void)
+{
+ int i, j;
+ float t, deltaT;
+ if (mspInst->m_bFerriesDisabled)
+ return;
+ for (i = 0; i < NUM_FERRIES; i++) {
+ CFerry* pFerry = GetFerry(i);
+ if (pFerry) {
+ pFerry->m_nTimeAlongPath += CTimer::GetTimeStepInMilliseconds();
+ t = mspInst->pPathData[i/2]->TotalDurationOfTrack * (float)((pFerry->m_nTimeAlongPath + (i & 1) * 0x20000) & 0x3FFFF) / 0x40000;
+ // find current frame
+ for (j = 0; t > mspInst->pPathData[i / 2]->aLineBits[j + 1].time; j++);
+
+ deltaT = t - mspInst->pPathData[i / 2]->aLineBits[j].time;
+ if (pFerry->m_bFerryDocked) {
+ if (mspInst->pPathData[i / 2]->aLineBits[j].type == FERRY_SLOWING) {
+ pFerry->m_nTimeAlongPath += (mspInst->pPathData[i / 2]->aLineBits[j + 1].time - mspInst->pPathData[i / 2]->aLineBits[j].time);
+ j++;
+ if (j > NUM_FERRY_STATIONS * 4 + 1)
+ j = 0;
+ pFerry->m_bApproachingDock = true;
+ if ((i & 1) == 0) {
+ GetFerry(i + 1)->m_bApproachingDock = true;
+ GetFerry(i + 1)->m_nTimeAlongPath += (mspInst->pPathData[i / 2]->aLineBits[j + 1].time - mspInst->pPathData[i / 2]->aLineBits[j].time);
+ }
+ else {
+ GetFerry(i - 1)->m_bApproachingDock = true;
+ GetFerry(i - 1)->m_nTimeAlongPath += (mspInst->pPathData[i / 2]->aLineBits[j + 1].time - mspInst->pPathData[i / 2]->aLineBits[j].time);
+ }
+ }
+ }
+ if (pFerry->m_nSkipFerryStatus == 1) {
+ float fDelta = 0.0f;
+ pFerry->m_nSkipFerryStatus = 2;
+ while (mspInst->pPathData[i / 2]->aLineBits[j].type != FERRY_STOPPED) {
+ fDelta += (mspInst->pPathData[i / 2]->aLineBits[j + 1].time - mspInst->pPathData[i / 2]->aLineBits[j].time);
+ j++;
+ if (j > NUM_FERRY_STATIONS * 4)
+ j = 0;
+ }
+ pFerry->m_nTimeAlongPath += fDelta;
+ pFerry->m_bApproachingDock = true;
+ if ((i & 1) == 0) {
+ GetFerry(i + 1)->m_bApproachingDock = true;
+ GetFerry(i + 1)->m_nTimeAlongPath += fDelta;
+ }
+ else {
+ GetFerry(i - 1)->m_bApproachingDock = true;
+ GetFerry(i - 1)->m_nTimeAlongPath += fDelta;
+ }
+ }
+ switch (mspInst->pPathData[i / 2]->aLineBits[j].type) {
+ case FERRY_STOPPED:
+ mspInst->m_afPositions[i] = mspInst->pPathData[i / 2]->aLineBits[j].position;
+ mspInst->m_afSpeeds[i] = 0.0f;
+ break;
+ case FERRY_CRUISING:
+ mspInst->m_afPositions[i] = mspInst->pPathData[i / 2]->aLineBits[j].position + mspInst->pPathData[i / 2]->aLineBits[j].speed * deltaT;
+ mspInst->m_afSpeeds[i] = (mspInst->pPathData[i / 2]->TotalDurationOfTrack * 1000.0f / 0x40000) * mspInst->pPathData[i / 2]->aLineBits[j].speed;
+ break;
+ case FERRY_SLOWING:
+ case FERRY_ACCELERATING:
+ pFerry->m_bApproachingDock = (mspInst->pPathData[i / 2]->aLineBits[j].type == FERRY_SLOWING);
+ mspInst->m_afPositions[i] = mspInst->pPathData[i / 2]->aLineBits[j].position + (mspInst->pPathData[i / 2]->aLineBits[j].speed + mspInst->pPathData[i / 2]->aLineBits[j].acceleration * deltaT) * deltaT;
+ mspInst->m_afSpeeds[i] = (mspInst->pPathData[i / 2]->TotalDurationOfTrack * 1000.0f / 0x40000) * (mspInst->pPathData[i / 2]->aLineBits[j].speed + 2 * mspInst->pPathData[i / 2]->aLineBits[j].acceleration * deltaT);
+ break;
+ }
+ }
+ }
+}
+
+void CFerry::SetModelIndex(uint32 mi)
+{
+ CVehicle::SetModelIndex(mi);
+ for (int i = 0; i < NUM_FERRY_NODES; i++)
+ m_aFerryNodes[i] = nil;
+ CClumpModelInfo::FillFrameArray(GetClump(), m_aFerryNodes);
+}
+
+void CFerry::PreRender(void)
+{
+ CVehicleModelInfo* mi = GetModelInfo();
+ if (CGeneral::GetRandomTrueFalse())
+ CParticle::AddParticle(PARTICLE_FERRY_CHIM_SMOKE, GetMatrix() * mi->m_positions[FERRY_POS_CHIM_LEFT], CVector(0.0f, 0.0f, 0.2f));
+ CVector vVectorToCamera = GetPosition() - TheCamera.GetPosition();
+ CVector vDirectionToCamera;
+ float fDistanceToCamera = vVectorToCamera.Magnitude();
+ if (fDistanceToCamera == 0.0f)
+ vVectorToCamera = vDirectionToCamera = CVector(1.0f, 0.0f, 0.0f);
+ else
+ vDirectionToCamera = vVectorToCamera / fDistanceToCamera;
+ float dp = DotProduct(GetForward(), vDirectionToCamera);
+ if (dp < 0.0f) {
+ CVector vFrontLightPosition = GetMatrix() * mi->m_positions[FERRY_POS_LIGHT_FRONT];
+ CVector vFrontLightPosition2 = vFrontLightPosition - 2 * mi->m_positions[FERRY_POS_LIGHT_FRONT].x * GetRight();
+ float size = -dp + 1.0f;
+ float fIntensity = -dp * 0.4f + 0.2f;
+ if (dp < -0.9f && fDistanceToCamera < 35.0f) {
+ uint8 intensity = fIntensity * 255.0f;
+ CCoronas::RegisterCorona((uint32)(uintptr)this + 26, intensity, intensity, intensity, 255, vFrontLightPosition2, size, 80.0f, CCoronas::TYPE_NORMAL, CCoronas::FLARE_HEADLIGHTS, CCoronas::REFLECTION_ON, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f);
+ CCoronas::RegisterCorona((uint32)(uintptr)this + 27, intensity, intensity, intensity, 255, vFrontLightPosition, size, 80.0f, CCoronas::TYPE_NORMAL, CCoronas::FLARE_HEADLIGHTS, CCoronas::REFLECTION_ON, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f);
+ }
+ else {
+ uint8 intensity = fIntensity * 255.0f;
+ CCoronas::RegisterCorona((uint32)(uintptr)this + 26, intensity, intensity, intensity, 255, vFrontLightPosition2, size, 80.0f, CCoronas::TYPE_NORMAL, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f);
+ CCoronas::RegisterCorona((uint32)(uintptr)this + 27, intensity, intensity, intensity, 255, vFrontLightPosition, size, 80.0f, CCoronas::TYPE_NORMAL, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f);
+ }
+ }
+ CVector vRearLightPosition = GetMatrix() * mi->m_positions[FERRY_POS_LIGHT_REAR];
+ CVector vRearLightPosition2 = vRearLightPosition - 2 * mi->m_positions[FERRY_POS_LIGHT_REAR].x * GetRight();
+ CCoronas::RegisterCorona((uint32)(uintptr)this + 28, 255, 0, 0, 255, vRearLightPosition2, 1.0f, 80.0f, CCoronas::TYPE_NORMAL, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f);
+ CCoronas::RegisterCorona((uint32)(uintptr)this + 29, 255, 0, 0, 255, vRearLightPosition, 1.0f, 80.0f, CCoronas::TYPE_NORMAL, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f);
+}
+
+void CFerry::Render(void)
+{
+ m_bAlreadyRendered = true;
+ CEntity::Render();
+}
+
+void CFerry::RenderAllRemaning(void)
+{
+#ifdef GTA_NETWORK
+ if (gIsMultiplayerGame)
+ return;
+#endif
+ for (int i = 0; i < NUM_FERRIES; i++) {
+ CFerry* pFerry = GetFerry(i);
+ if (pFerry) {
+ if (!pFerry->m_bAlreadyRendered)
+ pFerry->Render();
+ pFerry->m_bAlreadyRendered = false;
+ }
+ }
+}
+
+void CFerry::FerryHitStuff(CPtrList& lst)
+{
+ for (CPtrNode* pNode = lst.first; pNode != nil; pNode = pNode->next) {
+ CPhysical* pEntity = (CPhysical*)pNode->item;
+ if (pEntity != this && Abs(GetPosition().x - pEntity->GetPosition().z) < 1.5f)
+ pEntity->bHitByTrain = true;
+ }
+}
+
+void CFerry::ProcessControl(void)
+{
+ if (gbModelViewer)
+ return;
+ PruneWakeTrail();
+ if (m_isFarAway && (m_nFerryId + CTimer::GetFrameCounter() & 0xF) != 0)
+ return;
+ CFerryPath* pPath = mspInst->pPathData[m_nFerryId / 2];
+ float fPosition = mspInst->m_afPositions[m_nFerryId];
+ float fSpeed = mspInst->m_afSpeeds[m_nFerryId];
+ if (fPosition < 0.0f)
+ fPosition += pPath->TotalLengthOfTrack;
+
+ CFerryNode* trackNodes = mspInst->pPathData[m_nFerryId / 2]->aTrackNodes;
+ int16 numTrackNodes = mspInst->pPathData[m_nFerryId / 2]->NumTrackNodes;
+ float totalLengthOfTrack = mspInst->pPathData[m_nFerryId / 2]->TotalLengthOfTrack;
+ float trackPosition = mspInst->m_afPositions[m_nFerryId];
+ float trackSpeed = mspInst->m_afSpeeds[m_nFerryId];
+
+ float trackPositionRear = trackPosition;
+ if (trackPositionRear < 0.0f)
+ trackPositionRear += totalLengthOfTrack;
+
+ // Advance current node to appropriate position
+ float pos1, pos2;
+ int nextTrackNode = m_nCurTrackNode + 1;
+ pos1 = trackNodes[m_nCurTrackNode].t;
+ if (nextTrackNode < numTrackNodes)
+ pos2 = trackNodes[nextTrackNode].t;
+ else {
+ nextTrackNode = 0;
+ pos2 = totalLengthOfTrack;
+ }
+ while (trackPositionRear < pos1 || trackPositionRear > pos2) {
+ m_nCurTrackNode = (m_nCurTrackNode + 1) % numTrackNodes;
+ nextTrackNode = m_nCurTrackNode + 1;
+ pos1 = trackNodes[m_nCurTrackNode].t;
+ if (nextTrackNode < numTrackNodes)
+ pos2 = trackNodes[nextTrackNode].t;
+ else {
+ nextTrackNode = 0;
+ pos2 = totalLengthOfTrack;
+ }
+ }
+ float dist = trackNodes[nextTrackNode].t - trackNodes[m_nCurTrackNode].t;
+ if (dist < 0.0f)
+ dist += totalLengthOfTrack;
+ float f = (trackPositionRear - trackNodes[m_nCurTrackNode].t) / dist;
+ CVector posRear = (1.0f - f) * CVector(trackNodes[m_nCurTrackNode].x, trackNodes[m_nCurTrackNode].y, trackNodes[m_nCurTrackNode].z) +
+ f * CVector(trackNodes[nextTrackNode].x, trackNodes[nextTrackNode].y, trackNodes[nextTrackNode].z);
+
+ // Now same again for the front
+ float trackPositionFront = trackPositionRear + 20.0f;
+ if (trackPositionFront > totalLengthOfTrack)
+ trackPositionFront -= totalLengthOfTrack;
+ int curTrackNodeFront = m_nCurTrackNode;
+ int nextTrackNodeFront = curTrackNodeFront + 1;
+ pos1 = trackNodes[curTrackNodeFront].t;
+ if (nextTrackNodeFront < numTrackNodes)
+ pos2 = trackNodes[nextTrackNodeFront].t;
+ else {
+ nextTrackNodeFront = 0;
+ pos2 = totalLengthOfTrack;
+ }
+ while (trackPositionFront < pos1 || trackPositionFront > pos2) {
+ curTrackNodeFront = (curTrackNodeFront + 1) % numTrackNodes;
+ nextTrackNodeFront = curTrackNodeFront + 1;
+ pos1 = trackNodes[curTrackNodeFront].t;
+ if (nextTrackNodeFront < numTrackNodes)
+ pos2 = trackNodes[nextTrackNodeFront].t;
+ else {
+ nextTrackNodeFront = 0;
+ pos2 = totalLengthOfTrack;
+ }
+ }
+ dist = trackNodes[nextTrackNodeFront].t - trackNodes[curTrackNodeFront].t;
+ if (dist < 0.0f)
+ dist += totalLengthOfTrack;
+ f = (trackPositionFront - trackNodes[curTrackNodeFront].t) / dist;
+ CVector posFront = (1.0f - f) * CVector(trackNodes[curTrackNodeFront].x, trackNodes[curTrackNodeFront].y, trackNodes[curTrackNodeFront].z) +
+ f * CVector(trackNodes[nextTrackNodeFront].x, trackNodes[nextTrackNodeFront].y, trackNodes[nextTrackNodeFront].z);
+
+ // Now set matrix
+ SetPosition((posRear + posFront) / 2.0f);
+ CVector fwd = posFront - posRear;
+ m_vecForwardSpeed = fwd;
+ fwd.Normalise();
+ float dp = DotProduct(fwd, GetForward());
+ if (Abs(dp) > 1.001f || Abs(dp) < 0.999f) {
+ CVector df = CrossProduct(fwd, GetForward());
+ CMatrix tmp;
+ float angle;
+ if (m_nSkipFerryStatus == 2) {
+ m_nSkipFerryStatus = 0;
+ angle = (fwd.x < 0.0f && GetForward().x < 0.0f) ? PI - Acos(dp) : Acos(dp);
+ }
+ else {
+ angle = 0.001f;
+ }
+ if (dp > 0.0f && df.z < 0.0f || dp <= 0.0f && df.z > 0.0f)
+ angle = -angle;
+ tmp.SetRotateZ(angle);
+ fwd = Multiply3x3(GetForward(), tmp);
+ }
+ else
+ fwd = GetForward();
+ CVector right = CrossProduct(fwd, CVector(0.0f, 0.0f, 1.0f));
+ right.Normalise();
+ CVector up = CrossProduct(right, fwd);
+ GetRight() = right;
+ GetUp() = up;
+ GetForward() = fwd;
+
+ // Set speed
+ m_vecMoveSpeed = fwd * trackSpeed / 60.0f;
+ m_fSpeed = trackSpeed / 60.0f;
+ m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f);
+
+ if (m_vecMoveSpeed.MagnitudeSqr() > 0.001f || !m_bApproachingDock) {
+ SetStatus(STATUS_FERRY_MOVING);
+ m_bFerryDocked = false;
+ m_bPlayerArrivedHorn = false;
+ m_nTimeLeftStation = CTimer::GetTimeInMilliseconds();
+ }
+ else {
+ SetStatus(STATUS_FERRY_NOT_MOVING);
+ PlayArrivedHorn();
+ m_bFerryDocked = true;
+ }
+
+ m_isFarAway = !((posFront - TheCamera.GetPosition()).Magnitude2D() < sq(1000.0f));
+
+ switch (m_nDoorState) {
+ case FERRY_DOOR_CLOSED:
+ break;
+ case FERRY_DOOR_OPENING:
+ if (CTimer::GetTimeInMilliseconds() < m_nDoorTimer) {
+ OpenFerryDoor(1.0f - (m_nDoorTimer - CTimer::GetTimeInMilliseconds()) / 1000.0f);
+ }
+ else {
+ OpenFerryDoor(1.0f);
+ m_nDoorState = FERRY_DOOR_OPEN;
+ }
+ break;
+
+ case FERRY_DOOR_OPEN:
+ break;
+
+ case FERRY_DOOR_CLOSING:
+ if (CTimer::GetTimeInMilliseconds() < m_nDoorTimer) {
+ OpenFerryDoor((m_nDoorTimer - CTimer::GetTimeInMilliseconds()) / 1000.0f);
+ }
+ else {
+ OpenFerryDoor(0.0f);
+ m_nDoorState = FERRY_DOOR_CLOSED;
+ }
+ break;
+ }
+
+ CVector wn = CWaterLevel::GetWaterNormal(GetPosition().x, GetPosition().y);
+ float fRollAngle = wn.x - GetUp().x;
+ if (fRollAngle < 0.0f)
+ fRollAngle = Max(-0.05f, fRollAngle);
+ else
+ fRollAngle = Min(0.05f, fRollAngle);
+
+ CVector oldPos = GetPosition();
+ SetPosition(-GetPosition());
+ CMatrix tmp2;
+ tmp2.SetRotateX(fRollAngle);
+ tmp2 = tmp2 * GetMatrix();
+ tmp2.SetTranslateOnly(oldPos);
+ GetMatrix() = tmp2;
+
+ GetMatrix().UpdateRW();
+ UpdateRwFrame();
+ RemoveAndAdd();
+
+ bIsStuck = false;
+ bIsInSafePosition = true;
+ bWasPostponed = false;
+
+ // request/remove model
+ if (m_isFarAway) {
+ if (m_rwObject)
+ DeleteRwObject();
+ }
+ else if (CStreaming::HasModelLoaded(MI_FERRY)) {
+ if (m_rwObject == nil) {
+ m_modelIndex = -1;
+ SetModelIndex(MI_FERRY);
+ }
+ }
+ else {
+ if (FindPlayerCoors().z * GetPosition().z >= 0.0f)
+ CStreaming::RequestModel(MI_FERRY, STREAMFLAGS_DEPENDENCY);
+ }
+
+ // Hit stuff
+ if (GetStatus() == STATUS_TRAIN_MOVING) {
+ CVector nfwd = GetForward() * GetColModel()->boundingBox.max.y;
+ if (m_vecForwardSpeed.x > 0.0f)
+ nfwd = -nfwd;
+ if ((m_nFerryId & 1) == 0)
+ nfwd = -nfwd;
+
+ int x, xmin, xmax;
+ int y, ymin, ymax;
+
+ CVector front = GetPosition() + nfwd + m_vecMoveSpeed * CTimer::GetTimeStep();
+ if (!m_isFarAway && m_vecMoveSpeed.Magnitude2D() > 0.05f)
+ AddWakePoint(nfwd * 0.85f + GetPosition());
+
+ xmin = CWorld::GetSectorIndexX(front.x - 3.0f);
+ if (xmin < 0) xmin = 0;
+ xmax = CWorld::GetSectorIndexX(front.x + 3.0f);
+ if (xmax > NUMSECTORS_X - 1) xmax = NUMSECTORS_X - 1;
+ ymin = CWorld::GetSectorIndexY(front.y - 3.0f);
+ if (ymin < 0) ymin = 0;
+ ymax = CWorld::GetSectorIndexY(front.y + 3.0f);
+ if (ymax > NUMSECTORS_Y - 1) ymax = NUMSECTORS_X - 1;
+
+ CWorld::AdvanceCurrentScanCode();
+
+ for (y = ymin; y <= ymax; y++)
+ for (x = xmin; x <= xmax; x++) {
+ CSector* s = CWorld::GetSector(x, y);
+ FerryHitStuff(s->m_lists[ENTITYLIST_VEHICLES]);
+ FerryHitStuff(s->m_lists[ENTITYLIST_VEHICLES_OVERLAP]);
+ FerryHitStuff(s->m_lists[ENTITYLIST_PEDS]);
+ FerryHitStuff(s->m_lists[ENTITYLIST_PEDS_OVERLAP]);
+ }
+ }
+}
+
+void CFerry::OpenFerryDoor(float ratio)
+{
+ if (!m_rwObject)
+ return;
+
+ int door1 = 0;
+ int door2 = 1;
+ if (!m_bUseFrontDoor) {
+ door1 = 2;
+ door2 = 3;
+ }
+ int node1 = m_bUseFrontDoor ? FERRY_DOOR_FRONT : FERRY_DOOR_BACK;
+ int node2 = m_bUseFrontDoor ? FERRY_RAMP_FRONT : FERRY_RAMP_BACK;
+ CMatrix doorL(RwFrameGetMatrix(m_aFerryNodes[node1]));
+ CMatrix doorR(RwFrameGetMatrix(m_aFerryNodes[node2]));
+ CVector posL = doorL.GetPosition();
+ CVector posR = doorR.GetPosition();
+
+ bool isClosed = m_doors[0].IsClosed(); // useless
+
+ m_doors[door1].Open(ratio);
+ m_doors[door2].Open(ratio);
+
+ doorL.SetRotateXOnly(m_doors[door1].m_fAngle);
+ doorR.SetRotateXOnly(m_doors[door2].m_fAngle);
+
+ doorL.UpdateRW();
+ doorR.UpdateRW();
+}
+
+CVector CFerry::GetBoardingSpace(CFerry::eSpaceUse use, CFerry::eSpaceStyle style, uint8 position)
+{
+ CVehicleModelInfo* pModelInfo = GetModelInfo();
+ CVector space;
+ if (m_nFerryId & 1) {
+ if (style == FERRY_SPACE_STYLE_0)
+ style = FERRY_SPACE_STYLE_1;
+ else
+ style = FERRY_SPACE_STYLE_0;
+ }
+ switch (use) {
+ case FERRY_SPACE_PED:
+ space = pModelInfo->m_positions[FERRY_POS_PED_POINT];
+ break;
+ case FERRY_SPACE_CAR:
+ space = pModelInfo->m_positions[FERRY_POS_CAR1 + position];
+ break;
+ }
+ switch (style) {
+ case FERRY_SPACE_STYLE_0:
+ space = GetMatrix() * space;
+ break;
+ case FERRY_SPACE_STYLE_1:
+ space = GetMatrix() * space - (2 * space.x) * GetRight() - (2 * space.y) * GetForward();
+ break;
+ }
+ return space;
+}
+
+CFerry* CFerry::GetClosestFerry(float x, float y)
+{
+ int closest = -1;
+ float mindist = 9999.9f;
+ for (int i = 0; i < NUM_FERRIES; i++) {
+ CFerry* pFerry = GetFerry(i);
+ if (pFerry) {
+ float dist = ((CVector2D)pFerry->GetPosition() - CVector2D(x, y)).Magnitude();
+ if (dist < 300.0f && dist < mindist) {
+ mindist = dist;
+ closest = i;
+ }
+ }
+ }
+ if (closest == -1)
+ return nil;
+ return GetFerry(closest);
+}
+
+bool CFerry::IsDocked(void)
+{
+ return m_bFerryDocked;
+}
+
+void CFerry::OpenDoor(void)
+{
+ printf("opening the ferry door\n");
+ m_nDoorState = FERRY_DOOR_OPENING;
+ m_nDoorTimer = CTimer::GetTimeInMilliseconds() + 10000;
+ CVehicleModelInfo* pModelInfo = GetModelInfo();
+ CVector2D vPlayerPos = FindPlayerPed()->GetPosition();
+ float fDistToCar4 = (vPlayerPos - GetMatrix() * pModelInfo->m_positions[FERRY_POS_CAR4]).Magnitude();
+ float fDistToCar1 = (vPlayerPos - GetMatrix() * pModelInfo->m_positions[FERRY_POS_CAR1]).Magnitude();
+ m_bUseFrontDoor = true;
+ if (fDistToCar4 < fDistToCar1)
+ m_bUseFrontDoor = false;
+ AudioManager.DirectlyEnqueueSample(SFX_GATE_START_CLU, SFX_BANK_0, 0, 1, 22050, 127, 20);
+}
+
+void CFerry::CloseDoor(void)
+{
+ printf("closing the ferry door\n");
+ m_nDoorState = FERRY_DOOR_CLOSING;
+ m_nDoorTimer = CTimer::GetTimeInMilliseconds() + 10000;
+ AudioManager.DirectlyEnqueueSample(SFX_GATE_START_CLU, SFX_BANK_0, 0, 1, 22050, 127, 20); // shouldn't this be SFX_GATE_STOP_CLU?
+}
+
+bool CFerry::IsDoorOpen(void)
+{
+ return m_nDoorState == FERRY_DOOR_OPEN;
+}
+
+bool CFerry::IsDoorClosed(void)
+{
+ return m_nDoorState == FERRY_DOOR_CLOSED;
+}
+
+void CFerry::CompleteDorrMovement(void)
+{
+ m_nDoorTimer = 0;
+}
+
+void CFerry::DissableFerryPath(int)
+{
+}
+
+void CFerry::EnableFerryPath(int path)
+{
+ CStreaming::LoadAllRequestedModels(false);
+ CStreaming::RequestModel(MI_FERRY, 0);
+ CStreaming::LoadAllRequestedModels(false);
+ for (int i = path * 2; i < path * 2 + 2; i++) {
+ CFerry* pFerry = new CFerry(MI_FERRY, PERMANENT_VEHICLE);
+ bool bDirect = i & 1;
+ mspInst->m_apFerries[i] = pFerry;
+ pFerry->SetPosition(0.0f, 0.0f, 0.0f);
+ pFerry->SetStatus(STATUS_ABANDONED);
+ pFerry->bIsLocked = true;
+ pFerry->SetHeading(bDirect ? HALFPI : 3 * HALFPI);
+ pFerry->m_nFerryId = i;
+ pFerry->m_nCurTrackNode = 0;
+ CWorld::Add(pFerry);
+ }
+}
+
+void CFerry::SkipFerryToNextDock(void)
+{
+ m_nSkipFerryStatus = 1;
+}
+
+void CFerry::PruneWakeTrail(void)
+{
+ int16 num_remaining = 0;
+ for (int i = 0; i < NUM_WAKE_POINTS; i++) {
+ if (mspInst->m_afWakePointTimer[m_nFerryId][i] <= 0.0f)
+ break;
+ if (mspInst->m_afWakePointTimer[m_nFerryId][i] <= CTimer::GetTimeStep()) {
+ mspInst->m_afWakePointTimer[m_nFerryId][i] = 0.0f;
+ break;
+ }
+ mspInst->m_afWakePointTimer[m_nFerryId][i] -= CTimer::GetTimeStep();
+ num_remaining++;
+ }
+ mspInst->m_anNumWakePoints[m_nFerryId] = num_remaining;
+}
+
+void CFerry::AddWakePoint(CVector point)
+{
+ if (mspInst->m_afWakePointTimer[m_nFerryId][0] > 0.0f) {
+ int nNewWakePoints = Min(NUM_WAKE_POINTS - 1, mspInst->m_anNumWakePoints[m_nFerryId]);
+ for (int i = 0; i < nNewWakePoints; i++) {
+ mspInst->m_avWakePoints[m_nFerryId][i + 1] = mspInst->m_avWakePoints[m_nFerryId][i];
+ mspInst->m_afWakePointTimer[m_nFerryId][i + 1] = mspInst->m_afWakePointTimer[m_nFerryId][i];
+ }
+ }
+ mspInst->m_avWakePoints[m_nFerryId][0] = point;
+ mspInst->m_afWakePointTimer[m_nFerryId][0] = 900.0f; // TODO: define
+ mspInst->m_anNumWakePoints[m_nFerryId] += 1;
+}
+
+void CFerry::PlayArrivedHorn(void)
+{
+ if (m_bPlayerArrivedHorn)
+ return;
+ m_bPlayerArrivedHorn = true;
+ float fDistToCamera = (GetPosition() - TheCamera.GetPosition()).Magnitude();
+ if (fDistToCamera < 200.0f) {
+ uint8 volume = (200.0f - fDistToCamera) / 200.0f * 127;
+ AudioManager.DirectlyEnqueueSample(SFX_CAR_HORN_TRUCK, SFX_BANK_0, 0, 1, 18000, volume, 50);
+ }
+}
+
+CVector CFerry::GetNearestDoor(CVector)
+{
+ return CVector(0.0f, 0.0f, 1.0f);
+}
+
+void CFerry::SetupForMultiplayer(void)
+{
+ for (int i = 0; i < NUM_FERRIES; i++)
+ mspInst->m_apFerries[i] = nil;
+ printf("setting up the ferrys for multiplayer\n");
+ CStreaming::SetModelIsDeletable(MI_FERRY);
+}
+
+void CFerry::Write(base::cRelocatableChunkWriter& writer)
+{
+ writer.AllocateRaw(mspInst, sizeof(*mspInst), 4);
+ if (!mspInst)
+ return;
+ for (int i = 0; i < NUM_FERRY_PATHS; i++) {
+ writer.AllocateRaw(mspInst->pPathData[i], sizeof(*mspInst->pPathData[i]), 4);
+ writer.AddPatch(&mspInst->pPathData[i]);
+ writer.AllocateRaw(mspInst->pPathData[i]->aTrackNodes, mspInst->pPathData[i]->NumTrackNodes * sizeof(CFerryNode), 4);
+ writer.AddPatch(&mspInst->pPathData[i]->aTrackNodes);
+ writer.AllocateRaw(mspInst->pPathData[i]->aLineBits, (NUM_FERRY_STATIONS * 4 + 2) * sizeof(CFerryInterpolationLine), 4);
+ writer.AddPatch(&mspInst->pPathData[i]->aTrackNodes);
+ }
+}
+
diff --git a/src/vehicles/Ferry.h b/src/vehicles/Ferry.h
new file mode 100644
index 00000000..f7936da9
--- /dev/null
+++ b/src/vehicles/Ferry.h
@@ -0,0 +1,143 @@
+#pragma once
+
+#include "Vehicle.h"
+#include "Door.h"
+
+enum eFerryNodes
+{
+ FERRY_DOOR_FRONT = 1,
+ FERRY_RAMP_FRONT,
+ FERRY_DOOR_BACK,
+ FERRY_RAMP_BACK,
+ NUM_FERRY_NODES
+};
+
+enum {
+ NUM_FERRY_STATIONS = 2,
+ NUM_FERRIES = NUM_FERRY_PATHS * 2,
+ NUM_WAKE_POINTS = 64
+};
+
+enum {
+ FERRY_STOPPED = 0,
+ FERRY_CRUISING,
+ FERRY_SLOWING,
+ FERRY_ACCELERATING
+};
+
+enum
+{
+ FERRY_DOOR_CLOSED = 0,
+ FERRY_DOOR_OPENING,
+ FERRY_DOOR_OPEN,
+ FERRY_DOOR_CLOSING
+};
+
+struct CFerryNode
+{
+ float x;
+ float y;
+ float z;
+ float t;
+};
+
+struct CFerryInterpolationLine
+{
+ uint8 type;
+ float time; // when does this keyframe start
+ // initial values at start of frame
+ float position;
+ float speed;
+ float acceleration;
+};
+
+struct CFerryPath
+{
+ float TotalLengthOfTrack;
+ float TotalDurationOfTrack;
+ int16 NumTrackNodes;
+ CFerryNode* aTrackNodes;
+ CFerryInterpolationLine* aLineBits;
+};
+
+class CFerry;
+
+class CFerryInst
+{
+public:
+ CFerryPath* pPathData[NUM_FERRY_PATHS];
+ float m_afPositions[NUM_FERRIES];
+ float m_afSpeeds[NUM_FERRIES];
+ CFerry* m_apFerries[NUM_FERRIES];
+ bool m_bFerriesDisabled;
+ uint16 m_anNumWakePoints[NUM_FERRIES];
+ CVector2D m_avWakePoints[NUM_FERRIES][NUM_WAKE_POINTS];
+ float m_afWakePointTimer[NUM_FERRIES][NUM_WAKE_POINTS];
+};
+
+class CFerry : public CVehicle
+{
+public:
+ int16 m_nFerryId;
+ uint16 m_isFarAway;
+ uint16 m_nCurTrackNode;
+ float m_fSpeed;
+ bool m_bFerryDocked;
+ uint32 m_nDoorTimer;
+ uint32 m_nTimeLeftStation;
+ int16 m_nDoorState;
+ bool m_bApproachingDock;
+ uint8 m_nSkipFerryStatus;
+ uint32 m_nTimeAlongPath;
+ bool m_bUseFrontDoor;
+ CVector m_vecForwardSpeed;
+ CColModel* m_pDefaultColModel;
+ uint8 m_nCollision;
+ CDoor m_doors[4];
+ RwFrame* m_aFerryNodes[NUM_FERRY_NODES];
+ bool m_bAlreadyRendered;
+ bool m_bPlayerArrivedHorn;
+
+ static CFerryInst* mspInst;
+
+ enum eSpaceUse {
+ FERRY_SPACE_PED = 0,
+ FERRY_SPACE_CAR
+ };
+ enum eSpaceStyle {
+ FERRY_SPACE_STYLE_0 = 0,
+ FERRY_SPACE_STYLE_1
+ };
+ void Render(void);
+ static void EnableFerryPath(int);
+ CFerry(int32, uint8);
+ void SetModelIndex(uint32);
+ static void InitFerrys(void);
+ static void Init(void*);
+ void ProcessControl(void);
+ void PlayArrivedHorn(void);
+ void AddWakePoint(CVector);
+ void PruneWakeTrail(void);
+ void SkipFerryToNextDock(void);
+ static void DissableFerryPath(int);
+ void CompleteDorrMovement(void);
+ bool IsDoorOpen(void);
+ void CloseDoor(void);
+ bool IsDocked(void);
+ static CFerry* GetClosestFerry(float, float);
+ CVector GetBoardingSpace(CFerry::eSpaceUse, CFerry::eSpaceStyle, uint8);
+ CVector GetNearestDoor(CVector);
+ void OpenFerryDoor(float);
+ void FerryHitStuff(CPtrList&);
+ static void RenderAllRemaning(void);
+ static void UpdateFerrys(void);
+ static void SwitchFerryCollision(int);
+ void SetupForMultiplayer(void);
+ void Write(base::cRelocatableChunkWriter&);
+ virtual void OpenDoor(void);
+ void PreRender(void);
+ virtual bool IsDoorClosed(void);
+
+ static CFerry* GetFerry(int i) { return mspInst ? mspInst->m_apFerries[i] : nil; }
+ static void SetFerriesDisabled(bool disabled) { mspInst->m_bFerriesDisabled = disabled; }
+};
diff --git a/src/vehicles/HandlingMgr.cpp b/src/vehicles/HandlingMgr.cpp
index 8438c5c9..b5dc7658 100644
--- a/src/vehicles/HandlingMgr.cpp
+++ b/src/vehicles/HandlingMgr.cpp
@@ -42,6 +42,7 @@ const char VehicleNames[NUMHANDLINGS][14] = {
"RHINO",
"BARRACKS",
"TRAIN",
+ "FERRY",
"HELI",
"DODO",
"COACH",
@@ -54,66 +55,40 @@ const char VehicleNames[NUMHANDLINGS][14] = {
"DEADDODO",
"FLATBED",
"YANKEE",
- "GOLFCART",
- "VOODOO",
- "WASHING",
- "CUBAN",
- "ROMERO",
- "PACKER",
- "ADMIRAL",
- "GANGBUR",
- "ZEBRA",
- "TOPFUN",
- "GLENDALE",
- "OCEANIC",
- "HERMES",
- "SABRE1",
- "SABRETUR",
- "PHEONIX",
- "WALTON",
- "REGINA",
- "COMET",
- "DELUXO",
- "BURRITO",
- "SPAND",
- "BAGGAGE",
- "KAUFMAN",
- "RANCHER",
- "FBIRANCH",
- "VIRGO",
- "GREENWOO",
- "HOTRING",
- "SANDKING",
- "BLISTAC",
- "BOXVILLE",
- "BENSON",
- "DESPERAD",
- "LOVEFIST",
- "BLOODRA",
- "BLOODRB",
+ "BLISTA",
+ "BELLYUP",
+ "MRWONGS",
+ "YARDIE",
+ "YAKUZA",
+ "DIABLOS",
+ "COLUMB",
+ "HOODS",
+ "PANLANT",
+ "BORGNINE",
+ "CAMPVAN",
+ "BALLOT",
+ "SPIDER",
+ "SHELBY",
+ "PONTIAC",
+ "ESPRIT",
+ "MINI",
+ "HOTROD",
+ "SINDACCO",
+ "FORELLI",
"BIKE",
"MOPED",
"DIRTBIKE",
"ANGEL",
+ "DIRTBIK2",
+ "ANGE2",
"FREEWAY",
"PREDATOR",
"SPEEDER",
"REEFER",
- "RIO",
- "SQUALO",
- "TROPIC",
- "COASTGRD",
- "DINGHY",
- "MARQUIS",
- "CUPBOAT",
- "SEAPLANE",
- "SPARROW",
- "SEASPAR",
"MAVERICK",
"COASTMAV",
"POLMAV",
"HUNTER",
- "RCBARON",
"RCGOBLIN",
"RCCOPTER"
};
@@ -138,18 +113,17 @@ void
cHandlingDataMgr::LoadHandlingData(void)
{
char *start, *end;
- char line[201]; // weird value
+ char line[300];
char delim[4]; // not sure
char *word;
int field, handlingId;
- int keepGoing;
tHandlingData *handling;
tFlyingHandlingData *flyingHandling;
tBoatHandlingData *boatHandling;
tBikeHandlingData *bikeHandling;
CFileMgr::SetDir("DATA");
- CFileMgr::LoadFile(HandlingFilename, work_buff, sizeof(work_buff), "r");
+ ssize_t filesz = CFileMgr::LoadFile(HandlingFilename, work_buff, sizeof(work_buff), "r");
CFileMgr::SetDir("");
start = (char*)work_buff;
@@ -158,21 +132,18 @@ cHandlingDataMgr::LoadHandlingData(void)
flyingHandling = nil;
boatHandling = nil;
bikeHandling = nil;
- keepGoing = 1;
- while(keepGoing){
+ while(start < (char*)&work_buff[filesz]){
// find end of line
while(*end != '\n') end++;
// get line
strncpy(line, start, end - start);
line[end - start] = '\0';
- start = end+1;
- end = start+1;
// yeah, this is kinda crappy
if(strcmp(line, ";the end") == 0)
- keepGoing = 0;
+ break;
else if(line[0] != ';'){
if(line[0] == '!'){
// Bike data
@@ -286,19 +257,19 @@ cHandlingDataMgr::LoadHandlingData(void)
handling->nIdentifier = (tVehicleType)handlingId;
break;
case 1: handling->fMass = atof(word); break;
- case 2: handling->Dimension.x = atof(word); break;
- case 3: handling->Dimension.y = atof(word); break;
- case 4: handling->Dimension.z = atof(word); break;
- case 5: handling->CentreOfMass.x = atof(word); break;
- case 6: handling->CentreOfMass.y = atof(word); break;
- case 7: handling->CentreOfMass.z = atof(word); break;
- case 8: handling->nPercentSubmerged = atoi(word); break;
- case 9: handling->fTractionMultiplier = atof(word); break;
- case 10: handling->fTractionLoss = atof(word); break;
- case 11: handling->fTractionBias = atof(word); break;
- case 12: handling->Transmission.nNumberOfGears = atoi(word); break;
- case 13: handling->Transmission.fMaxVelocity = atof(word); break;
- case 14: handling->Transmission.fEngineAcceleration = atof(word) * 0.4; break;
+ case 2: handling->fTurnMass = atof(word); break;
+ case 3: handling->fDragMult = atof(word); break;
+ case 4: handling->CentreOfMass.x = atof(word); break;
+ case 5: handling->CentreOfMass.y = atof(word); break;
+ case 6: handling->CentreOfMass.z = atof(word); break;
+ case 7: handling->nPercentSubmerged = atoi(word); break;
+ case 8: handling->fTractionMultiplier = atof(word); break;
+ case 9: handling->fTractionLoss = atof(word); break;
+ case 10: handling->fTractionBias = atof(word); break;
+ case 11: handling->Transmission.nNumberOfGears = atoi(word); break;
+ case 12: handling->Transmission.fMaxVelocity = atof(word); break;
+ case 13: handling->Transmission.fEngineAcceleration = atof(word) * 0.4; break;
+ case 14: handling->Transmission.fEngineInertia = atof(word); break;
case 15: handling->Transmission.nDriveType = word[0]; break;
case 16: handling->Transmission.nEngineType = word[0]; break;
case 17: handling->fBrakeDeceleration = atof(word); break;
@@ -307,25 +278,28 @@ cHandlingDataMgr::LoadHandlingData(void)
case 20: handling->fSteeringLock = atof(word); break;
case 21: handling->fSuspensionForceLevel = atof(word); break;
case 22: handling->fSuspensionDampingLevel = atof(word); break;
- case 23: handling->fSeatOffsetDistance = atof(word); break;
- case 24: handling->fCollisionDamageMultiplier = atof(word); break;
- case 25: handling->nMonetaryValue = atoi(word); break;
- case 26: handling->fSuspensionUpperLimit = atof(word); break;
- case 27: handling->fSuspensionLowerLimit = atof(word); break;
- case 28: handling->fSuspensionBias = atof(word); break;
- case 29: handling->fSuspensionAntidiveMultiplier = atof(word); break;
- case 30:
+ // case 23: // fSuspensionHighSpdComDamp unused
+ case 24: handling->fSuspensionUpperLimit = atof(word); break;
+ case 25: handling->fSuspensionLowerLimit = atof(word); break;
+ case 26: handling->fSuspensionBias = atof(word); break;
+ case 27: handling->fSuspensionAntidiveMultiplier = atof(word); break;
+ case 28: handling->fSeatOffsetDistance = atof(word); break;
+ case 29: handling->fCollisionDamageMultiplier = atof(word); break;
+ case 30: handling->nMonetaryValue = atoi(word); break;
+ case 31:
sscanf(word, "%x", &handling->Flags);
- handling->Transmission.Flags = handling->Flags;
+ // handling->Transmission.Flags = handling->Flags;
break;
- case 31: handling->FrontLights = atoi(word); break;
- case 32: handling->RearLights = atoi(word); break;
+ case 32: handling->FrontLights = atoi(word); break;
+ case 33: handling->RearLights = atoi(word); break;
}
field++;
}
ConvertDataToGameUnits(handling);
}
}
+ start = end+1;
+ end = start+1;
}
}
@@ -353,12 +327,9 @@ cHandlingDataMgr::ConvertDataToGameUnits(tHandlingData *handling)
handling->Transmission.fEngineAcceleration *= 1.0f/(50.0f*50.0f);
handling->Transmission.fMaxVelocity *= 1000.0f/(60.0f*60.0f * 50.0f);
handling->fBrakeDeceleration *= 1.0f/(50.0f*50.0f);
- handling->fTurnMass = (sq(handling->Dimension.x) + sq(handling->Dimension.y)) * handling->fMass / 12.0f;
- if(handling->fTurnMass < 10.0f)
- handling->fTurnMass *= 5.0f;
- handling->fInvMass = 1.0f/handling->fMass;
- handling->fCollisionDamageMultiplier *= 2000.0f/handling->fMass;
- handling->fBuoyancy = 100.0f/handling->nPercentSubmerged * GRAVITY*handling->fMass;
+ handling->fInvMass = 1.0f/handling->GetMass();
+ handling->fCollisionDamageMultiplier = handling->GetCollisionDamageMultiplier() * 2000.0f/handling->GetMass();
+ handling->fBuoyancy = 100.0f/handling->nPercentSubmerged * GRAVITY*handling->GetMass();
// Don't quite understand this. What seems to be going on is that
// we calculate a drag (air resistance) deceleration for a given velocity and
@@ -371,10 +342,13 @@ cHandlingDataMgr::ConvertDataToGameUnits(tHandlingData *handling)
velocity -= 0.01f;
// what's the 1/6?
a = handling->Transmission.fEngineAcceleration/6.0f;
- // no density or drag coefficient here...
- float a_drag = 0.5f*SQR(velocity) * handling->Dimension.x*handling->Dimension.z / handling->fMass;
- // can't make sense of this... maybe v - v/(drag + 1) ? but that doesn't make so much sense either
- b = -velocity * (1.0f/(a_drag + 1.0f) - 1.0f);
+ // no idea what's happening here
+ float drag;
+ if(handling->fDragMult < 0.01f)
+ drag = 1.0f - 1.0f/(SQR(velocity)*handling->fDragMult + 1.0f);
+ else
+ drag = 0.0005f*handling->fDragMult * velocity;
+ b = velocity * drag;
}
if(handling->nIdentifier == HANDLING_RCBANDIT){
@@ -420,15 +394,15 @@ cHandlingDataMgr::GetHandlingId(const char *name)
tFlyingHandlingData*
cHandlingDataMgr::GetFlyingPointer(uint8 id)
{
- if(id >= HANDLING_SEAPLANE && id <= HANDLING_RCCOPTER)
- return &FlyingHandlingData[id-HANDLING_SEAPLANE];
+ if(id >= HANDLING_MAVERICK && id <= HANDLING_RCCOPTER)
+ return &FlyingHandlingData[id-HANDLING_MAVERICK];
return &FlyingHandlingData[0];
}
tBoatHandlingData*
cHandlingDataMgr::GetBoatPointer(uint8 id)
{
- if(id >= HANDLING_PREDATOR && id <= HANDLING_SEAPLANE)
+ if(id >= HANDLING_PREDATOR && id <= HANDLING_MAVERICK)
return &BoatHandlingData[id-HANDLING_PREDATOR];
return &BoatHandlingData[0];
}
diff --git a/src/vehicles/HandlingMgr.h b/src/vehicles/HandlingMgr.h
index 8d290f7d..2d49761c 100644
--- a/src/vehicles/HandlingMgr.h
+++ b/src/vehicles/HandlingMgr.h
@@ -36,6 +36,7 @@ enum tVehicleType
HANDLING_RHINO,
HANDLING_BARRACKS,
HANDLING_TRAIN,
+ HANDLING_FERRY,
HANDLING_HELI,
HANDLING_DODO,
HANDLING_COACH,
@@ -48,76 +49,51 @@ enum tVehicleType
HANDLING_DEADDODO,
HANDLING_FLATBED,
HANDLING_YANKEE,
- HANDLING_GOLFCART,
- HANDLING_VOODOO,
- HANDLING_WASHING,
- HANDLING_CUBAN,
- HANDLING_ROMERO,
- HANDLING_PACKER,
- HANDLING_ADMIRAL,
- HANDLING_GANGBUR,
- HANDLING_ZEBRA,
- HANDLING_TOPFUN,
- HANDLING_GLENDALE,
- HANDLING_OCEANIC,
- HANDLING_HERMES,
- HANDLING_SABRE1,
- HANDLING_SABRETUR,
- HANDLING_PHEONIX,
- HANDLING_WALTON,
- HANDLING_REGINA,
- HANDLING_COMET,
- HANDLING_DELUXO,
- HANDLING_BURRITO,
- HANDLING_SPAND,
- HANDLING_BAGGAGE,
- HANDLING_KAUFMAN,
- HANDLING_RANCHER,
- HANDLING_FBIRANCH,
- HANDLING_VIRGO,
- HANDLING_GREENWOO,
- HANDLING_HOTRING,
- HANDLING_SANDKING,
- HANDLING_BLISTAC,
- HANDLING_BOXVILLE,
- HANDLING_BENSON,
- HANDLING_DESPERAD,
- HANDLING_LOVEFIST,
- HANDLING_BLOODRA,
- HANDLING_BLOODRB,
+ HANDLING_BLISTA,
+ HANDLING_BELLYUP,
+ HANDLING_MRWONGS,
+ HANDLING_YARDIE,
+ HANDLING_YAKUZA,
+ HANDLING_DIABLOS,
+ HANDLING_COLUMB,
+ HANDLING_HOODS,
+ HANDLING_PANLANT,
+ HANDLING_BORGNINE,
+ HANDLING_CAMPVAN,
+ HANDLING_BALLOT,
+ HANDLING_SPIDER,
+ HANDLING_SHELBY,
+ HANDLING_PONTIAC,
+ HANDLING_ESPRIT,
+ HANDLING_MINI,
+ HANDLING_HOTROD,
+ HANDLING_SINDACCO,
+ HANDLING_FORELLI,
HANDLING_BIKE,
HANDLING_MOPED,
HANDLING_DIRTBIKE,
HANDLING_ANGEL,
+ HANDLING_DIRTBIK2,
+ HANDLING_ANGE2,
HANDLING_FREEWAY,
HANDLING_PREDATOR,
HANDLING_SPEEDER,
HANDLING_REEFER,
- HANDLING_RIO,
- HANDLING_SQUALO,
- HANDLING_TROPIC,
- HANDLING_COASTGRD,
- HANDLING_DINGHY,
- HANDLING_MARQUIS,
- HANDLING_CUPBOAT,
- HANDLING_SEAPLANE, // both boat and plane!
- HANDLING_SPARROW,
- HANDLING_SEASPAR,
+
HANDLING_MAVERICK,
HANDLING_COASTMAV,
HANDLING_POLMAV,
HANDLING_HUNTER,
- HANDLING_RCBARON,
HANDLING_RCGOBLIN,
HANDLING_RCCOPTER,
NUMHANDLINGS,
NUMBIKEHANDLINGS = HANDLING_FREEWAY+1 - HANDLING_BIKE,
- NUMFLYINGHANDLINGS = HANDLING_RCCOPTER+1 - HANDLING_SEAPLANE,
- NUMBOATHANDLINGS = HANDLING_SEAPLANE+1 - HANDLING_PREDATOR,
+ NUMFLYINGHANDLINGS = HANDLING_RCCOPTER+1 - HANDLING_MAVERICK,
+ NUMBOATHANDLINGS = HANDLING_REEFER+1 - HANDLING_PREDATOR,
};
enum tField // most likely a handling field enum, never used so :shrug:
@@ -155,19 +131,21 @@ enum
HANDLING_NARROW_FRONTW = 0x2000000,
HANDLING_GOOD_INSAND = 0x4000000,
HANDLING_UNKNOWN = 0x8000000, // something for helis and planes
+ HANDLING_FORCE_GRND_CLR = 0x10000000
};
struct tHandlingData
{
- tVehicleType nIdentifier;
float fMass;
- float fInvMass;
float fTurnMass;
- CVector Dimension;
+ float fTractionMultiplier;
+ float fCollisionDamageMultiplier;
+ tVehicleType nIdentifier;
+ float fInvMass;
+ float fDragMult;
CVector CentreOfMass;
int8 nPercentSubmerged;
float fBuoyancy;
- float fTractionMultiplier;
cTransmission Transmission;
float fBrakeDeceleration;
float fBrakeBias;
@@ -182,12 +160,17 @@ struct tHandlingData
float fSuspensionLowerLimit;
float fSuspensionBias;
float fSuspensionAntidiveMultiplier;
- float fCollisionDamageMultiplier;
uint32 Flags;
float fSeatOffsetDistance;
int32 nMonetaryValue;
int8 FrontLights;
int8 RearLights;
+ int unk[4];
+
+ float GetMass(void) const { return fMass; }
+ float GetTurnMass(void) const { return fTurnMass; }
+ float GetTractionMultiplier(void) const { return fTractionMultiplier; }
+ float GetCollisionDamageMultiplier(void) const { return fCollisionDamageMultiplier; }
};
struct tBikeHandlingData
diff --git a/src/vehicles/Heli.cpp b/src/vehicles/Heli.cpp
index f51c8481..a8423855 100644
--- a/src/vehicles/Heli.cpp
+++ b/src/vehicles/Heli.cpp
@@ -756,7 +756,7 @@ CHeli::InitHelis(void)
for(i = 0; i < NUM_HELIS; i++)
pHelis[i] = nil;
- ((CVehicleModelInfo*)CModelInfo::GetModelInfo(MI_CHOPPER))->SetColModel(&CTempColModels::ms_colModelPed1);
+ ((CVehicleModelInfo*)CModelInfo::GetModelInfo(MI_CHOPPER))->SetColModel(&gpTempColModels->ms_colModelPed1);
}
CHeli*
diff --git a/src/vehicles/Plane.cpp b/src/vehicles/Plane.cpp
index 0b40ca7e..7684d7dd 100644
--- a/src/vehicles/Plane.cpp
+++ b/src/vehicles/Plane.cpp
@@ -681,6 +681,12 @@ CPlane::Render(void)
CEntity::Render();
}
+void
+CPlane::RenderAllRemaning(void)
+{
+ // TODO(LCS)
+}
+
#define CRUISE_SPEED (50.0f)
#define TAXI_SPEED (5.0f)
diff --git a/src/vehicles/Plane.h b/src/vehicles/Plane.h
index c8f02048..ee65913b 100644
--- a/src/vehicles/Plane.h
+++ b/src/vehicles/Plane.h
@@ -59,6 +59,7 @@ public:
void Render(void);
void FlagToDestroyWhenNextProcessed() { bRemoveFromWorld = true; }
+ static void RenderAllRemaning(void);
static void InitPlanes(void);
static void Shutdown(void);
static CPlaneNode *LoadPath(char const *filename, int32 &numNodes, float &totalLength, bool loop);
diff --git a/src/vehicles/Train.cpp b/src/vehicles/Train.cpp
index 3a04b614..57337459 100644
--- a/src/vehicles/Train.cpp
+++ b/src/vehicles/Train.cpp
@@ -15,6 +15,10 @@
#include "Train.h"
#include "AudioScriptObject.h"
+#define TRAIN_SPEED (15.0f)
+#define TRAIN_SLOWDOWN_DISTANCE (40.0f)
+#define TRAIN_TIME_STOPPED_AT_STATION (25.0f)
+
static CTrainNode* pTrackNodes;
static int16 NumTrackNodes;
static float StationDist[3] = { 873.0f, 1522.0f, 2481.0f };
@@ -459,11 +463,11 @@ CTrain::InitTrains(void)
CStreaming::LoadAllRequestedModels(false);
// El-Train wagons
- float wagonPositions[] = { 0.0f, 20.0f, 40.0f, 0.0f, 20.0f };
- int8 firstWagon[] = { 1, 0, 0, 1, 0 };
- int8 lastWagon[] = { 0, 0, 1, 0, 1 };
- int16 wagonGroup[] = { 0, 0, 0, 1, 1 };
- for(i = 0; i < 5; i++){
+ float wagonPositions[] = { 0.0f, 20.0f, 0.0f, 20.0f };
+ int8 firstWagon[] = { 1, 0, 1, 0 };
+ int8 lastWagon[] = { 0, 1, 0, 1 };
+ int16 wagonGroup[] = { 0, 0, 1, 1 };
+ for(i = 0; i < 4; i++){
train = new CTrain(MI_TRAIN, PERMANENT_VEHICLE);
train->GetMatrix().SetTranslate(0.0f, 0.0f, 0.0f);
train->SetStatus(STATUS_ABANDONED);
@@ -598,23 +602,23 @@ CTrain::ReadAndInterpretTrackFile(Const char *filename, CTrainNode **nodes, int1
interpLines[j].type = 1;
interpLines[j].time = time;
interpLines[j].position = position;
- interpLines[j].speed = 15.0f;
+ interpLines[j].speed = TRAIN_SPEED;
interpLines[j].acceleration = 0.0f;
j++;
// distance to next keyframe
- float dist = (stationDists[i]-40.0f) - position;
- time += dist/15.0f;
+ float dist = (stationDists[i]-TRAIN_SLOWDOWN_DISTANCE) - position;
+ time += dist/TRAIN_SPEED;
position += dist;
// Now slow down 40 units before stop
interpLines[j].type = 2;
interpLines[j].time = time;
interpLines[j].position = position;
- interpLines[j].speed = 15.0f;
- interpLines[j].acceleration = -45.0f/32.0f;
+ interpLines[j].speed = TRAIN_SPEED;
+ interpLines[j].acceleration = -(TRAIN_SPEED * TRAIN_SPEED) / (4 * TRAIN_SLOWDOWN_DISTANCE);
j++;
- time += 80.0f/15.0f;
- position += 40.0f; // at station
+ time += 2*TRAIN_SLOWDOWN_DISTANCE/TRAIN_SPEED;
+ position += TRAIN_SLOWDOWN_DISTANCE; // at station
// stopping
interpLines[j].type = 0;
@@ -623,26 +627,26 @@ CTrain::ReadAndInterpretTrackFile(Const char *filename, CTrainNode **nodes, int1
interpLines[j].speed = 0.0f;
interpLines[j].acceleration = 0.0f;
j++;
- time += 25.0f;
+ time += TRAIN_TIME_STOPPED_AT_STATION;
// accelerate again
interpLines[j].type = 2;
interpLines[j].time = time;
interpLines[j].position = position;
interpLines[j].speed = 0.0f;
- interpLines[j].acceleration = 45.0f/32.0f;
+ interpLines[j].acceleration = (TRAIN_SPEED * TRAIN_SPEED) / (4 * TRAIN_SLOWDOWN_DISTANCE);
j++;
- time += 80.0f/15.0f;
- position += 40.0f; // after station
+ time += 2*TRAIN_SLOWDOWN_DISTANCE /TRAIN_SPEED;
+ position += TRAIN_SLOWDOWN_DISTANCE; // after station
}
// last keyframe
interpLines[j].type = 1;
interpLines[j].time = time;
interpLines[j].position = position;
- interpLines[j].speed = 15.0f;
+ interpLines[j].speed = TRAIN_SPEED;
interpLines[j].acceleration = 0.0f;
j++;
- *totalDuration = time + (*totalLength - position)/15.0f;
+ *totalDuration = time + (*totalLength - position)/ TRAIN_SPEED;
// end
interpLines[j].time = *totalDuration;
@@ -650,52 +654,6 @@ CTrain::ReadAndInterpretTrackFile(Const char *filename, CTrainNode **nodes, int1
}
void
-PlayAnnouncement(uint8 sound, uint8 station)
-{
- // this was gone in a PC version but inlined on PS2
- cAudioScriptObject *obj = new cAudioScriptObject;
- obj->AudioId = sound;
- obj->Posn = CTrain::aStationCoors[station];
- obj->AudioEntity = AEHANDLE_NONE;
- DMAudio.CreateOneShotScriptObject(obj);
-}
-
-void
-ProcessTrainAnnouncements(void)
-{
-#ifdef GTA_TRAIN
- for (int i = 0; i < ARRAY_SIZE(StationDist); i++) {
- for (int j = 0; j < ARRAY_SIZE(EngineTrackPosition); j++) {
- if (!bTrainArrivalAnnounced[i]) {
- float preDist = StationDist[i] - 100.0f;
- if (preDist < 0.0f)
- preDist += TotalLengthOfTrack;
- if (EngineTrackPosition[j] > preDist && EngineTrackPosition[j] < StationDist[i]) {
- bTrainArrivalAnnounced[i] = true;
- PlayAnnouncement(SCRIPT_SOUND_TRAIN_ANNOUNCEMENT_1, i);
- break;
- }
- } else {
- float postDist = StationDist[i] + 10.0f;
-#ifdef FIX_BUGS
- if (postDist > TotalLengthOfTrack)
- postDist -= TotalLengthOfTrack;
-#else
- if (postDist < 0.0f) // does this even make sense here?
- postDist += TotalLengthOfTrack;
-#endif
- if (EngineTrackPosition[j] > StationDist[i] && EngineTrackPosition[j] < postDist) {
- bTrainArrivalAnnounced[i] = false;
- PlayAnnouncement(SCRIPT_SOUND_TRAIN_ANNOUNCEMENT_2, i);
- break;
- }
- }
- }
- }
-#endif
-}
-
-void
CTrain::UpdateTrains(void)
{
#ifdef GTA_TRAIN
@@ -732,8 +690,6 @@ CTrain::UpdateTrains(void)
// time offset for each train
time += 0x20000/2;
}
-
- ProcessTrainAnnouncements();
}
// Update Subway
diff --git a/src/vehicles/Transmission.cpp b/src/vehicles/Transmission.cpp
index 1aeabfe0..18e5fa98 100644
--- a/src/vehicles/Transmission.cpp
+++ b/src/vehicles/Transmission.cpp
@@ -4,6 +4,7 @@
#include "HandlingMgr.h"
#include "Transmission.h"
+//--LCS: file done
void
cTransmission::InitGearRatios(void)
{
@@ -14,11 +15,14 @@ cTransmission::InitGearRatios(void)
memset(Gears, 0, sizeof(Gears));
+ float baseVelocity = 0.5f*fMaxVelocity / nNumberOfGears;
+ float step = (fMaxVelocity - baseVelocity) / nNumberOfGears;
+
for(i = 1; i <= nNumberOfGears; i++){
pGearRatio0 = &Gears[i-1];
pGearRatio1 = &Gears[i];
- pGearRatio1->fMaxVelocity = (float)i / nNumberOfGears * fMaxVelocity;
+ pGearRatio1->fMaxVelocity = baseVelocity + i*step;
velocityDiff = pGearRatio1->fMaxVelocity - pGearRatio0->fMaxVelocity;
@@ -45,9 +49,12 @@ cTransmission::CalculateGearForSimpleCar(float speed, uint8 &gear)
pGearRatio = &Gears[gear];
fCurVelocity = speed;
- if(speed > pGearRatio->fShiftUpVelocity)
- gear++;
- else if(speed < pGearRatio->fShiftDownVelocity){
+ if(speed > pGearRatio->fShiftUpVelocity){
+ if(gear + 1 > nNumberOfGears)
+ gear = nNumberOfGears;
+ else
+ gear++;
+ }else if(speed < pGearRatio->fShiftDownVelocity){
if(gear - 1 < 0)
gear = 0;
else
@@ -55,6 +62,109 @@ cTransmission::CalculateGearForSimpleCar(float speed, uint8 &gear)
}
}
+float TRANSMISSION_NITROS_INERTIA_MULT = 0.5f;
+float TRANSMISSION_AI_CHEAT_INERTIA_MULT = 0.75f;
+float TRANSMISSION_NITROS_MULT = 2.0f;
+float TRANSMISSION_AI_CHEAT_MULT = 1.2f;
+float TRANSMISSION_SMOOTHER_FRAC = 0.85f;
+float TRANSMISSION_FREE_ACCELERATION = 0.1f;
+
+float
+cTransmission::CalculateDriveAcceleration(const float &gasPedal, uint8 &gear, float &time, const float &velocity, float *inertiaVar1, float *inertiaVar2, uint8 nDriveWheels, uint8 cheat)
+{
+ static float fAcceleration = 0.0f;
+ static float fVelocity;
+ static float fCheat;
+ static tGear *pGearRatio;
+
+ fVelocity = velocity;
+ if(fVelocity < fMaxReverseVelocity)
+ return 0.0f;
+ if(fVelocity > fMaxVelocity)
+ return 0.0f;
+ fCurVelocity = fVelocity;
+
+ assert(gear <= nNumberOfGears);
+
+ pGearRatio = &Gears[gear];
+ if(fVelocity > pGearRatio->fShiftUpVelocity){
+ if(gear != 0 || gasPedal > 0.0f){
+ gear++;
+ return CalculateDriveAcceleration(gasPedal, gear, time, fVelocity, nil, nil, 0, false);
+ }
+ }else if(fVelocity < pGearRatio->fShiftDownVelocity && gear != 0){
+ if(gear != 1 || gasPedal < 0.0f){
+ gear--;
+ return CalculateDriveAcceleration(gasPedal, gear, time, fVelocity, nil, nil, 0, false);
+ }
+ }
+
+ float accelMul;
+
+ if(nNumberOfGears == 1){
+ accelMul = 1.0f;
+ }else if(gear == 0){
+ accelMul = 4.5f;
+ }else{
+ float f = 1.0f - (gear-1.0f)/(nNumberOfGears-1.0f);
+ if(Flags & HANDLING_1G_BOOST)
+ accelMul = SQR(f)*5.0f + 1.0f;
+ else if(Flags & HANDLING_2G_BOOST)
+ accelMul = SQR(f)*4.0f + 1.0f;
+ else
+ accelMul = SQR(f)*3.0f + 1.0f;
+ }
+
+ fCheat = 1.0f;
+ float nitroMult = 1.0f;
+ if(cheat == 1)
+ fCheat = TRANSMISSION_AI_CHEAT_MULT;
+ else if(cheat == 2)
+ nitroMult = TRANSMISSION_NITROS_MULT;
+
+ fAcceleration = fEngineAcceleration*CTimer::GetTimeStep()*0.4f*accelMul*gasPedal*fCheat*nitroMult;
+
+ if(inertiaVar1 != nil && inertiaVar2 != nil){
+ if(nDriveWheels == 0){
+ float f = TRANSMISSION_FREE_ACCELERATION*CTimer::GetTimeStep()*Abs(gasPedal)/fEngineInertia;
+ *inertiaVar1 = Min(*inertiaVar1 + f, 1.0f);
+ *inertiaVar2 = 0.1f;
+ }else{
+ float var1;
+ // What is being calculated here?
+ // TODO: find better names for the inertia vars
+ if(gear == 0){
+ var1 = ((fMaxVelocity/nNumberOfGears)*(1.0f-0.6667f) - fVelocity) /
+ ((fMaxVelocity/nNumberOfGears)*(1.0f-0.6667f) - Gears[gear].fShiftDownVelocity);
+ }else if(gear == 1){
+ var1 = ((fMaxVelocity/nNumberOfGears)*(1.0f-0.6667f) + fVelocity) /
+ ((fMaxVelocity/nNumberOfGears)*(1.0f-0.6667f) + Gears[gear].fShiftUpVelocity);
+ }else{
+ var1 = (fVelocity - Gears[gear].fShiftDownVelocity) /
+ (Gears[gear].fShiftUpVelocity - Gears[gear].fShiftDownVelocity);
+ }
+ float inertiaMult = var1 - *inertiaVar1;
+ if(cheat == 1)
+ inertiaMult *= TRANSMISSION_AI_CHEAT_INERTIA_MULT;
+ else if(cheat == 2)
+ inertiaMult *= TRANSMISSION_NITROS_INERTIA_MULT;
+ float var2target = 1.0f - inertiaMult*fEngineInertia;
+ var2target = Clamp(var2target, 0.1f, 1.0f);
+ *inertiaVar2 = (1.0f-TRANSMISSION_SMOOTHER_FRAC)*var2target + TRANSMISSION_SMOOTHER_FRAC*(*inertiaVar2);
+ *inertiaVar1 = var1;
+ fAcceleration *= *inertiaVar2;
+ }
+ }
+
+ float targetVelocity = Gears[gear].fMaxVelocity*fCheat;
+ if(Gears[gear].fMaxVelocity < 0.0f && targetVelocity > fVelocity)
+ fAcceleration *= 1.0f - Min((targetVelocity - fVelocity)/0.05f, 1.0f);
+ else if(Gears[gear].fMaxVelocity > 0.0f && targetVelocity < fVelocity)
+ fAcceleration *= 1.0f - Min((fVelocity - targetVelocity)/0.05f, 1.0f);
+ return fAcceleration;
+}
+
+// TEMP old VC code until we have bikes
float
cTransmission::CalculateDriveAcceleration(const float &gasPedal, uint8 &gear, float &time, const float &velocity, bool cheat)
{
diff --git a/src/vehicles/Transmission.h b/src/vehicles/Transmission.h
index a3d15513..8aea7b02 100644
--- a/src/vehicles/Transmission.h
+++ b/src/vehicles/Transmission.h
@@ -17,6 +17,7 @@ public:
int8 nNumberOfGears;
uint8 Flags;
float fEngineAcceleration;
+ float fEngineInertia;
float fMaxVelocity;
float fMaxCruiseVelocity;
float fMaxReverseVelocity;
@@ -24,5 +25,6 @@ public:
void InitGearRatios(void);
void CalculateGearForSimpleCar(float speed, uint8 &gear);
+ float CalculateDriveAcceleration(const float &gasPedal, uint8 &gear, float &time, const float &velocity, float *inertiaVar1, float *inertiaVar2, uint8 nDriveWheels, uint8 cheat);
float CalculateDriveAcceleration(const float &gasPedal, uint8 &gear, float &time, const float &velocity, bool cheat);
};
diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp
index d1054191..308a517e 100644
--- a/src/vehicles/Vehicle.cpp
+++ b/src/vehicles/Vehicle.cpp
@@ -34,6 +34,8 @@
#include "Coronas.h"
#include "SaveBuf.h"
+// LCS: done except trivial stuff
+
bool CVehicle::bWheelsOnlyCheat;
bool CVehicle::bAllDodosCheat;
bool CVehicle::bCheat3;
@@ -50,6 +52,12 @@ bool CVehicle::bDisableRemoteDetonationOnContact;
#ifndef MASTER
bool CVehicle::m_bDisplayHandlingInfo;
#endif
+float CVehicle::rcHeliHeightLimit = 60.0f;
+float CVehicle::WHEELSPIN_FALL_RATE = 0.7f;
+float CVehicle::WHEELSPIN_RISE_RATE = 0.95f;
+float CVehicle::WHEELSPIN_INAIR_TARGET_RATE = 10.0f;
+float CVehicle::WHEELSPIN_TARGET_RATE = 1.0f;
+
void *CVehicle::operator new(size_t sz) throw() { return CPools::GetVehiclePool()->New(); }
void *CVehicle::operator new(size_t sz, int handle) throw() { return CPools::GetVehiclePool()->New(handle); }
@@ -72,6 +80,17 @@ CVehicle::CVehicle(uint8 CreatedBy)
{
int i;
+ m_fGasPedal = 0.0f;
+ m_fBrakePedal = 0.0f;
+ m_fWheelSpin = 0.0f;
+#if defined FIX_BUGS || !defined GTA_PSP
+ bRewardVehicle = false;
+#endif
+ m_vehLCS_29E = 0;
+ m_vehLCS_29C = 0;
+ m_vehLCS_2A3 = -1;
+ m_bSuperBrake = false; // probably for multiplayer
+
m_nCurrentGear = 1;
m_fChangeGearTime = 0.0f;
m_fSteerInput = 0.0f;
@@ -82,9 +101,7 @@ CVehicle::CVehicle(uint8 CreatedBy)
bIsLawEnforcer = false;
bIsAmbulanceOnDuty = false;
bIsFireTruckOnDuty = false;
-#ifdef FIX_BUGS
bIsHandbrakeOn = false;
-#endif
CCarCtrl::UpdateCarCount(this, false);
m_fHealth = 1000.0f;
bEngineOn = true;
@@ -134,16 +151,14 @@ CVehicle::CVehicle(uint8 CreatedBy)
bCreatedAsPoliceVehicle = false;
bRestingOnPhysical = false;
bParking = false;
+ m_bGarageTurnedLightsOff = false;
+ m_vehLCS_259 = -1;
bCanPark = CGeneral::GetRandomNumberInRange(0.0f, 1.0f) < 0.0f; // never true. probably doesn't work very well
bIsVan = false;
bIsBus = false;
bIsBig = false;
bLowVehicle = false;
- m_bombType = CARBOMB_NONE;
- bDriverLastFrame = false;
- m_pBombRigger = nil;
-
m_nSetPieceExtendedRangeTime = 0;
m_nAlarmState = 0;
m_nDoorLock = CARLOCK_UNLOCKED;
@@ -157,6 +172,7 @@ CVehicle::CVehicle(uint8 CreatedBy)
switch(GetModelIndex()){
case MI_HUNTER:
case MI_ANGEL:
+ case MI_ANGEL2:
case MI_FREEWAY:
m_nRadioStation = V_ROCK;
break;
@@ -189,6 +205,8 @@ CVehicle::CVehicle(uint8 CreatedBy)
CVehicle::~CVehicle()
{
+ //TODO(LCS): clear something in music manager (?)
+
m_nAlarmState = 0;
if (m_audioEntityId >= 0){
DMAudio.DestroyEntity(m_audioEntityId);
@@ -218,8 +236,8 @@ void
CVehicle::SetModelIndex(uint32 id)
{
CEntity::SetModelIndex(id);
- m_aExtras[0] = CVehicleModelInfo::ms_compsUsed[0];
- m_aExtras[1] = CVehicleModelInfo::ms_compsUsed[1];
+ m_aExtras[0] = CVehicleModelInfo::mspInfo->ms_compsUsed[0];
+ m_aExtras[1] = CVehicleModelInfo::mspInfo->ms_compsUsed[1];
m_nNumMaxPassengers = CVehicleModelInfo::GetMaximumNumberOfPassengersFromNumberOfDoors(id);
}
@@ -247,6 +265,8 @@ void
CVehicle::RemoveLighting(bool reset)
{
CRenderer::RemoveVehiclePedLights(this, reset);
+ SetAmbientColours();
+ DeActivateDirectional();
}
bool
@@ -332,14 +352,16 @@ CVehicle::FlyingControl(eFlightModel flightModel)
{
float fSteerLR = CPad::GetPad(0)->GetSteeringLeftRight() / 128.0f;
float fSteerUD = CPad::GetPad(0)->GetSteeringUpDown() / 128.0f;
+/*
float fGunUD = Abs(CPad::GetPad(0)->GetCarGunUpDown());
#ifdef FREE_CAM
if(!CCamera::bFreeCam || (CCamera::bFreeCam && !CPad::IsAffectedByController))
#endif
if(fGunUD > 1.0f)
fSteerUD = -CPad::GetPad(0)->GetCarGunUpDown() / 128.0f;
+*/
- float fSteerAngle = Atan2(fSteerUD, fSteerLR);
+ float fSteerAngle = fSteerUD != 0.0f && fSteerLR != 0.0f ? Atan2(fSteerUD, fSteerLR) : 0.0f;
float fSteerMult = 1.0f;
if(fSteerAngle > -PI/4.0f && fSteerAngle <= PI/4.0f)
fSteerMult = 1.0f/Cos(fSteerAngle);
@@ -440,7 +462,7 @@ CVehicle::FlyingControl(eFlightModel flightModel)
m_vecTurnSpeed = Multiply3x3(GetMatrix(), vecTurnSpeed);
ApplyTurnForce(-GetUp() * fResistance * m_fTurnMass, GetRight() + Multiply3x3(GetMatrix(), m_vecCentreOfMass));
-
+/*
float fMoveSpeed = m_vecMoveSpeed.MagnitudeSqr();
if(fMoveSpeed > SQR(1.5f))
m_vecMoveSpeed *= 1.5f/Sqrt(fMoveSpeed);
@@ -448,6 +470,7 @@ CVehicle::FlyingControl(eFlightModel flightModel)
float fTurnSpeed = m_vecTurnSpeed.MagnitudeSqr();
if(fTurnSpeed > SQR(0.2f))
m_vecTurnSpeed *= 0.2f/Sqrt(fTurnSpeed);
+*/
break;
}
case FLIGHT_MODEL_RCHELI:
@@ -464,6 +487,11 @@ CVehicle::FlyingControl(eFlightModel flightModel)
return;
float fUpSpeed = DotProduct(m_vecMoveSpeed, GetUp());
float fThrust = (CPad::GetPad(0)->GetAccelerate() - CPad::GetPad(0)->GetBrake()) / 255.0f;
+#ifdef FREE_CAM
+ if(!CCamera::bFreeCam || (CCamera::bFreeCam && !CPad::IsAffectedByController))
+#endif
+ if(Abs(CPad::GetPad(0)->GetCarGunUpDown()) > 1.0f)
+ fThrust = CPad::GetPad(0)->GetCarGunUpDown() / 128.0f;
if(fThrust < 0.0f)
fThrust *= 2.0f;
if(flightModel == FLIGHT_MODEL_RCHELI){
@@ -472,7 +500,7 @@ CVehicle::FlyingControl(eFlightModel flightModel)
}else
fThrust = flyingHandling->fThrust * fThrust + 0.95f;
fThrust -= flyingHandling->fThrustFallOff * fUpSpeed;
- if(flightModel == FLIGHT_MODEL_RCHELI && GetPosition().z > 40.0f)
+ if(flightModel == FLIGHT_MODEL_RCHELI && GetPosition().z > rcHeliHeightLimit)
fThrust *= 10.0f/(GetPosition().z - 30.0f);
else if(GetPosition().z > 80.0f)
fThrust *= 10.0f/(GetPosition().z - 70.0f);
@@ -515,11 +543,13 @@ CVehicle::FlyingControl(eFlightModel flightModel)
if(Abs(CPad::GetPad(0)->GetCarGunLeftRight()) > 1.0f)
fYaw = CPad::GetPad(0)->GetCarGunLeftRight() / 128.0f;
}
+/*
#ifdef FREE_CAM
if(!CCamera::bFreeCam || (CCamera::bFreeCam && !CPad::IsAffectedByController))
#endif
if(Abs(CPad::GetPad(0)->GetCarGunUpDown()) > 1.0f)
fPitch = -CPad::GetPad(0)->GetCarGunUpDown() / 128.0f;
+*/
if (CPad::GetPad(0)->GetHorn()) {
fYaw = 0.0f;
fPitch = Clamp(flyingHandling->fPitchStab * DotProduct(m_vecMoveSpeed, GetForward()), -200.0f, 1.3f);
@@ -713,7 +743,7 @@ CVehicle::BladeColSectorList(CPtrList &list, CColModel &rotorColModel, CMatrix &
}
ped->InflictDamage(this, WEAPONTYPE_RUNOVERBYCAR, 1000.0f, PEDPIECE_TORSO, localDir);
- if(CGame::nastyGame && ped->GetIsOnScreen()){
+ if(ped->GetIsOnScreen()){
for(i = 0; i < 16; i++)
CParticle::AddParticle(PARTICLE_BLOOD_SMALL, ped->GetPosition(), CVector(dirToRotor.x, dirToRotor.y, 1.0f) * 0.01f);
CParticle::AddParticle(PARTICLE_TEST, ped->GetPosition(), CVector(0.0f, 0.0f, 0.02f), nil, 0.1f);
@@ -772,7 +802,9 @@ CVehicle::BladeColSectorList(CPtrList &list, CColModel &rotorColModel, CMatrix &
}
-float fBurstSpeedMax = 0.3f;
+float WS_ALREADY_SPINNING_LOSS = 0.2f;
+float WS_TRAC_FRAC_LIMIT = 0.3f;
+float fBurstSpeedMax = 0.2f;
float fBurstTyreMod = 0.13f;
void
@@ -800,13 +832,15 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon
float contactSpeedFwd = DotProduct(wheelContactSpeed, wheelFwd);
float contactSpeedRight = DotProduct(wheelContactSpeed, wheelRight);
- if(*wheelState != WHEEL_STATE_NORMAL)
+ adhesion *= CTimer::GetTimeStep();
+ if(*wheelState != WHEEL_STATE_NORMAL){
bAlreadySkidding = true;
+ adhesion *= pHandling->fTractionLoss;
+ if(*wheelState == WHEEL_STATE_SPINNING && (GetStatus() == STATUS_PLAYER || GetStatus() == STATUS_PLAYER_REMOTE))
+ adhesion *= 1.0f - Abs(m_fGasPedal) * WS_ALREADY_SPINNING_LOSS;
+ }
*wheelState = WHEEL_STATE_NORMAL;
- adhesion *= CTimer::GetTimeStep();
- if(bAlreadySkidding)
- adhesion *= pHandling->fTractionLoss;
// moving sideways
if(contactSpeedRight != 0.0f){
@@ -848,13 +882,15 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon
if(!bBraking){
if(m_fGasPedal < 0.01f){
if(IsBike())
- brake = 0.6f * mod_HandlingManager.fWheelFriction / (pHandling->fMass + 200.0f);
- else if(pHandling->fMass < 500.0f)
- brake = 0.2f * mod_HandlingManager.fWheelFriction / pHandling->fMass;
+ brake = 0.6f * mod_HandlingManager.fWheelFriction / (pHandling->GetMass() + 200.0f);
+ else if(IsPlane())
+ brake = 0.0f;
+ else if(pHandling->GetMass() < 500.0f)
+ brake = 0.1f * mod_HandlingManager.fWheelFriction / pHandling->GetMass();
else if(GetModelIndex() == MI_RCBANDIT)
- brake = 0.2f * mod_HandlingManager.fWheelFriction / pHandling->fMass;
+ brake = 0.2f * mod_HandlingManager.fWheelFriction / pHandling->GetMass();
else
- brake = mod_HandlingManager.fWheelFriction / pHandling->fMass;
+ brake = mod_HandlingManager.fWheelFriction / pHandling->GetMass();
#ifdef FIX_BUGS
brake *= CTimer::GetTimeStepFix();
#endif
@@ -878,7 +914,10 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon
float speedSq = sq(right) + sq(fwd);
if(sq(adhesion) < speedSq){
if(*wheelState != WHEEL_STATE_FIXED){
- if(bDriving && contactSpeedFwd < 0.2f)
+ float tractionLimit = WS_TRAC_FRAC_LIMIT;
+ if(contactSpeedFwd > 0.15f && (wheelId == CARWHEEL_FRONT_LEFT || wheelId == CARWHEEL_FRONT_RIGHT))
+ tractionLimit *= 2.0f;
+ if(bDriving && tractionLimit*adhesion < Abs(fwd))
*wheelState = WHEEL_STATE_SPINNING;
else
*wheelState = WHEEL_STATE_SKIDDING;
@@ -886,6 +925,8 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon
float l = Sqrt(speedSq);
float tractionLoss = bAlreadySkidding ? 1.0f : pHandling->fTractionLoss;
+ if(*wheelState == WHEEL_STATE_SPINNING && (GetStatus() == STATUS_PLAYER || GetStatus() == STATUS_PLAYER_REMOTE))
+ tractionLoss *= 1.0f - Abs(m_fGasPedal) * WS_ALREADY_SPINNING_LOSS;
right *= adhesion * tractionLoss / l;
fwd *= adhesion * tractionLoss / l;
}
@@ -894,7 +935,7 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon
CVector totalSpeed = fwd*wheelFwd + right*wheelRight;
CVector turnDirection = totalSpeed;
- bool separateTurnForce = false; // BUG: not initialized on PC
+ bool separateTurnForce = false;
if(pHandling->fSuspensionAntidiveMultiplier > 0.0f){
if(bBraking){
separateTurnForce = true;
@@ -920,14 +961,14 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon
turnDirection = direction;
float impulse = speed*m_fMass;
- float turnImpulse = turnSpeed*GetMass(wheelContactPoint, turnDirection);
+ float turnImpulse = turnSpeed*GetMass(wheelContactPoint - Multiply3x3(GetMatrix(), m_vecCentreOfMass), turnDirection);
ApplyMoveForce(impulse * direction);
ApplyTurnForce(turnImpulse * turnDirection, wheelContactPoint);
}
}
-float fBurstBikeSpeedMax = 0.12f;
+float fBurstBikeSpeedMax = 0.08f;
float fBurstBikeTyreMod = 0.05f;
float fTweakBikeWheelTurnForce = 2.0f;
@@ -1122,6 +1163,84 @@ CVehicle::FindTyreNearestPoint(float x, float y)
return piece - CAR_PIECE_WHEEL_LF;
}
+bool
+CVehicle::PedsShouldScreamOnDisembarking(void)
+{
+ switch(GetModelIndex()){
+ case MI_AMBULAN:
+ case MI_TAXI:
+ case MI_CABBIE:
+ return false;
+ default:
+ return true;
+ }
+}
+
+void
+CVehicle::OccupantsReactToDamage(CEntity *damagedBy)
+{
+ if (VehicleCreatedBy == RANDOM_VEHICLE && !IsBoat()){
+ switch (GetStatus()) {
+ case STATUS_SIMPLE:
+ case STATUS_PHYSICS:
+ if(bIsLawEnforcer &&
+ (GetModelIndex() == MI_POLICE || GetModelIndex() == MI_ENFORCER ||
+ GetModelIndex() == MI_CHOPPER || GetModelIndex() == MI_PREDATOR) &&
+ damagedBy == FindPlayerPed()){
+ // Police gets angry
+ FindPlayerPed()->SetWantedLevelNoDrop(1);
+ }else if(pDriver && pDriver->CharCreatedBy != MISSION_CHAR &&
+ pDriver->m_nPedType >= PEDTYPE_GANG1 && pDriver->m_nPedType <= PEDTYPE_GANG9 &&
+ damagedBy == FindPlayerPed()){
+ // Gang gets angry
+ SetStatus(STATUS_ABANDONED);
+ pDriver->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, damagedBy);
+ int time = 200;
+ for (int i = 0; i < m_nNumMaxPassengers; i++) {
+ if (pPassengers[i] &&
+ pPassengers[i]->m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT &&
+ pPassengers[i]->CharCreatedBy != MISSION_CHAR) {
+ pPassengers[i]->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, damagedBy);
+ pPassengers[i]->m_objectiveTimer = CTimer::GetTimeInMilliseconds() + time;
+ time += 200;
+ }
+ }
+ }else if(AutoPilot.m_nDrivingStyle == DRIVINGSTYLE_PLOUGH_THROUGH ||
+ CGeneral::GetRandomNumberInRange(0.0f, 1.0f) > 0.5f && AutoPilot.m_nCarMission == MISSION_CRUISE){
+ // Drive away like a maniac
+ if(pDriver && pDriver->m_objective != OBJECTIVE_LEAVE_CAR){
+ if(AutoPilot.m_nDrivingStyle != DRIVINGSTYLE_PLOUGH_THROUGH)
+ AutoPilot.m_nCruiseSpeed *= 1.5f;
+ AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_PLOUGH_THROUGH;
+ }
+ }else{
+ // Leave vehicle
+ if (pDriver && pDriver->CharCreatedBy != MISSION_CHAR) {
+ SetStatus(STATUS_ABANDONED);
+ pDriver->bFleeAfterExitingCar = true;
+ pDriver->SetObjective(OBJECTIVE_LEAVE_CAR, this);
+ pDriver->Say(SOUND_PED_FLEE_SPRINT);
+ }
+ int time = 200;
+ for (int i = 0; i < m_nNumMaxPassengers; i++) {
+ if (pPassengers[i] &&
+ pPassengers[i]->m_objective != OBJECTIVE_LEAVE_CAR &&
+ pPassengers[i]->CharCreatedBy != MISSION_CHAR) {
+ pPassengers[i]->bFleeAfterExitingCar = true;
+ pPassengers[i]->SetObjective(OBJECTIVE_LEAVE_CAR, this);
+ pPassengers[i]->m_objectiveTimer = CTimer::GetTimeInMilliseconds() + time;
+ pPassengers[i]->Say(SOUND_PED_FLEE_SPRINT);
+ time += 200;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
void
CVehicle::InflictDamage(CEntity *damagedBy, eWeaponType weaponType, float damage, CVector pos)
{
@@ -1207,7 +1326,7 @@ CVehicle::InflictDamage(CEntity *damagedBy, eWeaponType weaponType, float damage
accuracy = 10;
break;
case WEAPONTYPE_PYTHON:
- if(!((CPed*)damagedBy)->IsPlayer())
+// if(!((CPed*)damagedBy)->IsPlayer())
accuracy = 64;
break;
case WEAPONTYPE_SHOTGUN:
@@ -1230,14 +1349,16 @@ CVehicle::InflictDamage(CEntity *damagedBy, eWeaponType weaponType, float damage
break;
}
+ // not in LCS (ifdef?)
if(((CPed*)damagedBy)->IsPlayer() && (CCamera::m_bUseMouse3rdPerson || TheCamera.Using1stPersonWeaponMode()))
accuracy = 0;
- if(accuracy != 0 && !bTyresDontBurst && (CGeneral::GetRandomNumber()&0x7F) < accuracy){
+ int difficulty = damagedBy == FindPlayerPed() ? 0x7F : 0xFF;
+ if(accuracy != 0 && !bTyresDontBurst && (CGeneral::GetRandomNumber()&difficulty) < accuracy){
if(IsBike())
BurstTyre(FindTyreNearestPoint(pos.x, pos.y) + CAR_PIECE_WHEEL_LF, false);
- else if(GetVehicleAppearance() == VEHICLE_APPEARANCE_CAR)
- BurstTyre(FindTyreNearestPoint(pos.x, pos.y) + CAR_PIECE_WHEEL_LF, true);
+ else// if(GetVehicleAppearance() == VEHICLE_APPEARANCE_CAR)
+ BurstTyre(FindTyreNearestPoint(pos.x, pos.y) + CAR_PIECE_WHEEL_LF, false); //true);
}
}
@@ -1257,44 +1378,7 @@ CVehicle::InflictDamage(CEntity *damagedBy, eWeaponType weaponType, float damage
float oldHealth = m_fHealth;
if (m_fHealth > damage) {
m_fHealth -= damage;
- if (VehicleCreatedBy == RANDOM_VEHICLE && !IsBoat()){
- switch (GetStatus()) {
- case STATUS_SIMPLE:
- case STATUS_PHYSICS:
- if(AutoPilot.m_nDrivingStyle == DRIVINGSTYLE_PLOUGH_THROUGH ||
- CGeneral::GetRandomNumberInRange(0.0f, 1.0f) > 0.5f && AutoPilot.m_nCarMission == MISSION_CRUISE){
- // Drive away like a maniac
- if(pDriver && pDriver->m_objective != OBJECTIVE_LEAVE_CAR){
- if(AutoPilot.m_nDrivingStyle != DRIVINGSTYLE_PLOUGH_THROUGH)
- AutoPilot.m_nCruiseSpeed *= 1.5f;
- AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_PLOUGH_THROUGH;
- }
- }else{
- // Leave vehicle
- if (pDriver && pDriver->CharCreatedBy != MISSION_CHAR) {
- SetStatus(STATUS_ABANDONED);
- pDriver->bFleeAfterExitingCar = true;
- pDriver->SetObjective(OBJECTIVE_LEAVE_CAR, this);
- pDriver->Say(SOUND_PED_FLEE_SPRINT);
- }
- int time = 200;
- for (int i = 0; i < m_nNumMaxPassengers; i++) {
- if (pPassengers[i] &&
- pPassengers[i]->m_objective != OBJECTIVE_LEAVE_CAR &&
- pPassengers[i]->CharCreatedBy != MISSION_CHAR) {
- pPassengers[i]->bFleeAfterExitingCar = true;
- pPassengers[i]->SetObjective(OBJECTIVE_LEAVE_CAR, this);
- pPassengers[i]->m_objectiveTimer = CTimer::GetTimeInMilliseconds() + time;
- pPassengers[i]->Say(SOUND_PED_FLEE_SPRINT);
- time += 200;
- }
- }
- }
- break;
- default:
- break;
- }
- }
+ OccupantsReactToDamage(damagedBy);
if (oldHealth >= DAMAGE_HEALTH_TO_CATCH_FIRE && m_fHealth < DAMAGE_HEALTH_TO_CATCH_FIRE) {
if (IsCar()) {
CAutomobile* pThisCar = (CAutomobile*)this;
@@ -1318,12 +1402,6 @@ CVehicle::InflictDamage(CEntity *damagedBy, eWeaponType weaponType, float damage
BlowUpCar(damagedBy);
}
}
-#ifdef FIX_BUGS // removing dumb case when shooting police car in player's own garage gives wanted level
- if (GetModelIndex() == MI_POLICE && damagedBy == FindPlayerPed() && damagedBy != nil && !bHasBeenOwnedByPlayer)
-#else
- if (GetModelIndex() == MI_POLICE && damagedBy == FindPlayerPed())
-#endif
- FindPlayerPed()->SetWantedLevelNoDrop(1);
}
void
@@ -1356,7 +1434,7 @@ CVehicle::FireFixedMachineGuns(void)
m_nGunFiringTime = CTimer::GetTimeInMilliseconds();
- source = GetMatrix() * CVector(2.0f, 2.5f, 1.0f);
+ source = GetMatrix() * CVector(0.95f, 9.3f, 0.85f);
target = source + CVector(dx, dy, 0.0f) * 60.0f;
target += CVector(
((CGeneral::GetRandomNumber() & 0xFF) - 128) * 0.015f,
@@ -1365,7 +1443,7 @@ CVehicle::FireFixedMachineGuns(void)
CWeapon::DoTankDoomAiming(this, pDriver, &source, &target);
FireOneInstantHitRound(&source, &target, 15);
- source = GetMatrix() * CVector(-2.0f, 2.5f, 1.0f);
+ source = GetMatrix() * CVector(-0.95f, 9.3f, 0.85f);
target = source + CVector(dx, dy, 0.0f) * 60.0f;
target += CVector(
((CGeneral::GetRandomNumber() & 0xFF) - 128) * 0.015f,
@@ -1384,42 +1462,10 @@ CVehicle::FireFixedMachineGuns(void)
}
void
-CVehicle::ActivateBomb(void)
-{
- 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);
- }
-}
-
-void
-CVehicle::ActivateBombWhenEntered(void)
-{
- 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;
- }else
- bDriverLastFrame = false;
-}
-
-void
CVehicle::ExtinguishCarFire(void)
{
- if(GetStatus() != STATUS_WRECKED)
+//TODO(LCS): check if this line was added in PC VC
+// if(GetStatus() != STATUS_WRECKED)
m_fHealth = Max(m_fHealth, 300.0f);
if(m_pCarFire)
m_pCarFire->Extinguish();
@@ -1438,6 +1484,7 @@ CVehicle::ShufflePassengersToMakeSpace(void)
return false;
if (pPassengers[1] &&
!(m_nGettingInFlags & CAR_DOOR_FLAG_LR) &&
+ !(m_nGettingOutFlags & CAR_DOOR_FLAG_LR) &&
IsRoomForPedToLeaveCar(CAR_DOOR_LR, nil)) {
if (!pPassengers[2] && !(m_nGettingInFlags & CAR_DOOR_FLAG_RR)) {
pPassengers[2] = pPassengers[1];
@@ -1445,7 +1492,7 @@ CVehicle::ShufflePassengersToMakeSpace(void)
pPassengers[2]->m_vehDoor = CAR_DOOR_RR;
return true;
}
- if (!pPassengers[0] && !(m_nGettingInFlags & CAR_DOOR_FLAG_RF)) {
+ if (!pPassengers[0] && !pPassengers[1]->bOnlyAllowedToSitBehind && !(m_nGettingInFlags & CAR_DOOR_FLAG_RF)) {
pPassengers[0] = pPassengers[1];
pPassengers[1] = nil;
pPassengers[0]->m_vehDoor = CAR_DOOR_RF;
@@ -1455,6 +1502,7 @@ CVehicle::ShufflePassengersToMakeSpace(void)
}
if (pPassengers[2] &&
!(m_nGettingInFlags & CAR_DOOR_FLAG_RR) &&
+ !(m_nGettingOutFlags & CAR_DOOR_FLAG_RR) &&
IsRoomForPedToLeaveCar(CAR_DOOR_RR, nil)) {
if (!pPassengers[1] && !(m_nGettingInFlags & CAR_DOOR_FLAG_LR)) {
pPassengers[1] = pPassengers[2];
@@ -1462,7 +1510,7 @@ CVehicle::ShufflePassengersToMakeSpace(void)
pPassengers[1]->m_vehDoor = CAR_DOOR_LR;
return true;
}
- if (!pPassengers[0] && !(m_nGettingInFlags & CAR_DOOR_FLAG_RF)) {
+ if (!pPassengers[0] && !pPassengers[2]->bOnlyAllowedToSitBehind && !(m_nGettingInFlags & CAR_DOOR_FLAG_RF)) {
pPassengers[0] = pPassengers[2];
pPassengers[2] = nil;
pPassengers[0]->m_vehDoor = CAR_DOOR_RF;
@@ -1472,8 +1520,9 @@ CVehicle::ShufflePassengersToMakeSpace(void)
}
if (pPassengers[0] &&
!(m_nGettingInFlags & CAR_DOOR_FLAG_RF) &&
+ !(m_nGettingOutFlags & CAR_DOOR_FLAG_RF) &&
IsRoomForPedToLeaveCar(CAR_DOOR_RF, nil)) {
- if (!pPassengers[1] && !(m_nGettingInFlags & CAR_DOOR_FLAG_LR)) {
+ if (!pPassengers[1] && !pPassengers[0]->bOnlyAllowedToSitInFront && !(m_nGettingInFlags & CAR_DOOR_FLAG_LR)) {
pPassengers[1] = pPassengers[0];
pPassengers[0] = nil;
pPassengers[1]->m_vehDoor = CAR_DOOR_LR;
@@ -1547,7 +1596,8 @@ CVehicle::MakeNonDraggedPedsLeaveVehicle(CPed *ped1, CPed *ped2, CPlayerPed *&pl
for(i = 0; i < numPeds2; i++)
if(peds2[i]->IsFemale() || CGeneral::GetRandomTrueFalse()){
peds2[i]->m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 10000;
- peds2[i]->bHeldHostageInCar = true;
+ if(peds2[i]->b1A4_2)
+ peds2[i]->bHeldHostageInCar = true;
peds2[i]->bFleeAfterExitingCar = true;
}
}
@@ -1576,12 +1626,13 @@ bool
CVehicle::IsLawEnforcementVehicle(void)
{
switch(GetModelIndex()){
+ case MI_FBICAR:
case MI_POLICE:
case MI_ENFORCER:
case MI_PREDATOR:
case MI_RHINO:
case MI_BARRACKS:
- case MI_FBIRANCH:
+// case MI_FBIRANCH:
case MI_VICECHEE:
return true;
default:
@@ -1692,8 +1743,8 @@ CVehicle::CanPedOpenLocks(CPed *ped)
m_nDoorLock == CARLOCK_LOCKED_PLAYER_INSIDE ||
m_nDoorLock == CARLOCK_LOCKED_BUT_CAN_BE_DAMAGED)
return false;
- if(ped->IsPlayer() && m_nDoorLock == CARLOCK_LOCKOUT_PLAYER_ONLY)
- return false;
+// if(ped->IsPlayer() && m_nDoorLock == CARLOCK_LOCKOUT_PLAYER_ONLY)
+// return false;
return true;
}
@@ -1838,6 +1889,9 @@ CVehicle::SetupPassenger(int n)
void
CVehicle::SetDriver(CPed *driver)
{
+ m_vehLCS_258 = false;
+ bCraneMessageDone = false;
+
pDriver = driver;
pDriver->RegisterReference((CEntity**)&pDriver);
@@ -1850,8 +1904,7 @@ CVehicle::SetDriver(CPed *driver)
case MI_TAXI:
case MI_CABBIE:
- case MI_ZEBRA:
- case MI_KAUFMAN:
+ case MI_BORGNINE:
CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 12;
break;
@@ -1927,6 +1980,7 @@ CVehicle::AddPassenger(CPed *passenger, uint8 n)
void
CVehicle::RemoveDriver(void)
{
+ m_vehLCS_259 = -1;
#ifdef FIX_BUGS
if (GetStatus() != STATUS_WRECKED)
#endif
@@ -2021,6 +2075,16 @@ CVehicle::UpdatePassengerList(void)
m_nNumPassengers = 0;
}
+bool
+CVehicle::AreThereAnyPassengers(void)
+{
+ int i;
+ for(i = 0; i < m_nNumMaxPassengers; i++)
+ if(pPassengers[i])
+ return true;
+ return false;
+}
+
void
CVehicle::ProcessCarAlarm(void)
{
@@ -2213,6 +2277,7 @@ CVehicle::HeliDustGenerate(CEntity *heli, float radius, float ground, int rnd)
}
}
+/*
#define GLARE_MIN_DIST (13.0f)
#define GLARE_FULL_DIST (30.0f)
#define GLARE_MIN_ANGLE (0.99f)
@@ -2315,6 +2380,7 @@ CVehicle::DoSunGlare(void)
}
}
}
+*/
void
CVehicle::KillPedsInVehicle(void)
@@ -2390,10 +2456,10 @@ CVehicle::Save(uint8*& buf)
ZeroSaveBuf(buf, 42);
WriteSaveBuf(buf, m_nNumMaxPassengers);
ZeroSaveBuf(buf, 3);
- WriteSaveBuf(buf, field_1D0[0]);
- WriteSaveBuf(buf, field_1D0[1]);
- WriteSaveBuf(buf, field_1D0[2]);
- WriteSaveBuf(buf, field_1D0[3]);
+ WriteSaveBuf(buf, m_vehLCS_230.x);
+ WriteSaveBuf(buf, m_vehLCS_230.y);
+ WriteSaveBuf(buf, m_vehLCS_230.z);
+ WriteSaveBuf(buf, m_vehLCS_230.w);
ZeroSaveBuf(buf, 8);
WriteSaveBuf(buf, m_fSteerAngle);
WriteSaveBuf(buf, m_fGasPedal);
@@ -2453,10 +2519,10 @@ CVehicle::Load(uint8*& buf)
SkipSaveBuf(buf, 42);
ReadSaveBuf(&m_nNumMaxPassengers, buf);
SkipSaveBuf(buf, 3);
- ReadSaveBuf(&field_1D0[0], buf);
- ReadSaveBuf(&field_1D0[1], buf);
- ReadSaveBuf(&field_1D0[2], buf);
- ReadSaveBuf(&field_1D0[3], buf);
+ ReadSaveBuf(&m_vehLCS_230.x, buf);
+ ReadSaveBuf(&m_vehLCS_230.y, buf);
+ ReadSaveBuf(&m_vehLCS_230.z, buf);
+ ReadSaveBuf(&m_vehLCS_230.w, buf);
SkipSaveBuf(buf, 8);
ReadSaveBuf(&m_fSteerAngle, buf);
ReadSaveBuf(&m_fGasPedal, buf);
diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h
index f83e1bb0..7be4e563 100644
--- a/src/vehicles/Vehicle.h
+++ b/src/vehicles/Vehicle.h
@@ -60,6 +60,8 @@ enum eCarLock {
CARLOCK_LOCKED_PLAYER_INSIDE,
CARLOCK_LOCKED_INITIALLY,
CARLOCK_FORCE_SHUT_DOORS,
+ CARLOCK_7,
+ CARLOCK_8,
CARLOCK_LOCKED_BUT_CAN_BE_DAMAGED
};
@@ -189,7 +191,7 @@ public:
int8 m_nGettingInFlags;
int8 m_nGettingOutFlags;
uint8 m_nNumMaxPassengers;
- float field_1D0[4];
+ CVector m_vehLCS_230;
CEntity *m_pCurGroundEntity;
CFire *m_pCarFire;
float m_fSteerAngle;
@@ -225,6 +227,9 @@ public:
uint8 bCanBeDamaged : 1; // Set to FALSE during cut scenes to avoid explosions
uint8 bUsingSpecialColModel : 1;// Is player vehicle using special collision model, stored in player strucure
+ uint8 m_vehLCS_258 : 1;
+ int8 m_vehLCS_259;
+
uint8 bOccupantsHaveBeenGenerated : 1; // Is true if the occupants have already been generated. (Shouldn't happen again)
uint8 bGunSwitchedOff : 1; // Level designers can use this to switch off guns on boats
uint8 bVehicleColProcessed : 1;// Has ProcessEntityCollision been processed for this car?
@@ -240,21 +245,18 @@ public:
uint8 bRestingOnPhysical : 1; // Dont go static cause car is sitting on a physical object that might get removed
uint8 bParking : 1;
uint8 bCanPark : 1;
-#if (!defined GTA_PS2 || defined FIX_BUGS)
- uint8 m_bombType : 3;
-#endif
- uint8 bDriverLastFrame : 1;
+ uint8 bRewardVehicle : 1; // 25B_40
int8 m_numPedsUseItAsCover;
uint8 m_nAmmoInClip; // Used to make the guns on boat do a reload (20 by default)
int8 m_nPacManPickupsCarried;
uint8 m_nRoadblockType;
+ uint8 m_bGarageTurnedLightsOff;
+ float m_fWheelSpin;
float m_fHealth; // 1000.0f = full health. 250.0f = fire. 0 -> explode
+ float m_fEngineEnergy; // TODO(LCS): better name. it adds up acceleration force, so possibly kinetic energy??
uint8 m_nCurrentGear;
float m_fChangeGearTime;
-#if (!defined GTA_PS2 || defined FIX_BUGS)
- CEntity* m_pBombRigger;
-#endif
uint32 m_nSetPieceExtendedRangeTime;
uint32 m_nGunFiringTime; // last time when gun on vehicle was fired (used on boats)
uint32 m_nTimeOfDeath;
@@ -264,19 +266,26 @@ public:
float m_fMapObjectHeightAhead; // front Z?
float m_fMapObjectHeightBehind; // rear Z?
eCarLock m_nDoorLock;
- int8 m_nLastWeaponDamage; // see eWeaponType, -1 if no damage
CEntity *m_pLastDamageEntity;
+ int16 m_vehLCS_29C;
+ int8 m_vehLCS_29E;
+ int8 m_nLastWeaponDamage; // see eWeaponType, -1 if no damage
uint8 m_nRadioStation;
uint8 m_bRainAudioCounter;
uint8 m_bRainSamplesCounter;
+ int8 m_vehLCS_2A3; // enables 2A4
+ uint8 m_vehLCS_2A4; // some timer
uint32 m_nCarHornTimer;
uint8 m_nCarHornPattern;
bool m_bSirenOrAlarm;
uint8 m_nCarHornDelay;
int8 m_comedyControlState;
+ int32 m_vehLCS_2B0;
+ int32 m_vehLCS_2B4;
CStoredCollPoly m_aCollPolys[2]; // poly which is under front/rear part of car
float m_fSteerInput;
eVehicleType m_vehType;
+ bool m_bSuperBrake;
static void *operator new(size_t) throw();
static void *operator new(size_t sz, int slot) throw();
@@ -288,6 +297,7 @@ public:
~CVehicle(void);
// from CEntity
void SetModelIndex(uint32 id);
+ void PreRender(void) {}
bool SetupLighting(void);
void RemoveLighting(bool);
void FlagToDestroyWhenNextProcessed(void) {}
@@ -330,6 +340,9 @@ public:
bool DoBladeCollision(CVector pos, CMatrix &matrix, int16 rotorType, float radius, float damageMult);
bool BladeColSectorList(CPtrList &list, CColModel &rotorColModel, CMatrix &matrix, int16 rotorType, float damageMult);
+ // TODO(LCS)?
+ // CVehicle::ApplyCollisionMultiplayer
+
void ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelContactSpeed, CVector &wheelContactPoint,
int32 wheelsOnGround, float thrust, float brake, float adhesion, int8 wheelId, float *wheelSpeed, tWheelState *wheelState, uint16 wheelStatus);
void ProcessBikeWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelContactSpeed, CVector &wheelContactPoint,
@@ -365,15 +378,16 @@ public:
bool IsPassenger(CPed *ped);
bool IsPassenger(int32 model);
void UpdatePassengerList(void);
+ bool AreThereAnyPassengers(void);
void ProcessCarAlarm(void);
bool IsSphereTouchingVehicle(float sx, float sy, float sz, float radius);
bool ShufflePassengersToMakeSpace(void);
void MakeNonDraggedPedsLeaveVehicle(CPed *ped1, CPed *ped2, CPlayerPed *&player, CCopPed *&cop);
+ bool PedsShouldScreamOnDisembarking(void);
+ void OccupantsReactToDamage(CEntity *damagedBy);
void InflictDamage(CEntity *damagedBy, eWeaponType weaponType, float damage, CVector pos = CVector(0.0f, 0.0f, 0.0f));
void DoFixedMachineGuns(void);
void FireFixedMachineGuns(void);
- void ActivateBomb(void);
- void ActivateBombWhenEntered(void);
void KillPedsInVehicle(void);
void SetComponentAtomicAlpha(RpAtomic *atomic, int32 alpha);
@@ -384,8 +398,8 @@ public:
bool IsAlarmOn(void) { return m_nAlarmState != 0 && m_nAlarmState != -1 && GetStatus() != STATUS_WRECKED; }
CVehicleModelInfo* GetModelInfo() { return (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex()); }
- bool IsTaxi(void) { return GetModelIndex() == MI_TAXI || GetModelIndex() == MI_CABBIE || GetModelIndex() == MI_ZEBRA || GetModelIndex() == MI_KAUFMAN; }
- bool IsLimo(void) { return GetModelIndex() == MI_STRETCH || GetModelIndex() == MI_LOVEFIST; }
+ bool IsTaxi(void) { return GetModelIndex() == MI_TAXI || GetModelIndex() == MI_CABBIE || GetModelIndex() == MI_BORGNINE || GetModelIndex() == MI_KAUFMAN; }
+ bool IsLimo(void) { return GetModelIndex() == MI_STRETCH; }
bool IsRealHeli(void) { return !!(pHandling->Flags & HANDLING_IS_HELI); }
bool IsRealPlane(void) { return !!(pHandling->Flags & HANDLING_IS_PLANE); }
@@ -405,6 +419,11 @@ public:
#ifndef MASTER
static bool m_bDisplayHandlingInfo;
#endif
+ static float rcHeliHeightLimit;
+ static float WHEELSPIN_FALL_RATE;
+ static float WHEELSPIN_RISE_RATE;
+ static float WHEELSPIN_INAIR_TARGET_RATE;
+ static float WHEELSPIN_TARGET_RATE;
};
void DestroyVehicleAndDriverAndPassengers(CVehicle* pVehicle);