diff options
Diffstat (limited to '')
-rw-r--r-- | src/vehicles/Automobile.cpp | 1488 | ||||
-rw-r--r-- | src/vehicles/Automobile.h | 8 | ||||
-rw-r--r-- | src/vehicles/Bike.cpp | 44 | ||||
-rw-r--r-- | src/vehicles/Bike.h | 6 | ||||
-rw-r--r-- | src/vehicles/Boat.cpp | 5 | ||||
-rw-r--r-- | src/vehicles/Cranes.cpp | 10 | ||||
-rw-r--r-- | src/vehicles/DamageManager.cpp | 5 | ||||
-rw-r--r-- | src/vehicles/DamageManager.h | 1 | ||||
-rw-r--r-- | src/vehicles/Door.cpp | 55 | ||||
-rw-r--r-- | src/vehicles/Door.h | 19 | ||||
-rw-r--r-- | src/vehicles/Ferry.cpp | 833 | ||||
-rw-r--r-- | src/vehicles/Ferry.h | 143 | ||||
-rw-r--r-- | src/vehicles/HandlingMgr.cpp | 160 | ||||
-rw-r--r-- | src/vehicles/HandlingMgr.h | 93 | ||||
-rw-r--r-- | src/vehicles/Heli.cpp | 2 | ||||
-rw-r--r-- | src/vehicles/Plane.cpp | 6 | ||||
-rw-r--r-- | src/vehicles/Plane.h | 1 | ||||
-rw-r--r-- | src/vehicles/Train.cpp | 88 | ||||
-rw-r--r-- | src/vehicles/Transmission.cpp | 118 | ||||
-rw-r--r-- | src/vehicles/Transmission.h | 2 | ||||
-rw-r--r-- | src/vehicles/Vehicle.cpp | 320 | ||||
-rw-r--r-- | src/vehicles/Vehicle.h | 45 |
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); |