summaryrefslogtreecommitdiffstats
path: root/src/vehicles/Bike.cpp
diff options
context:
space:
mode:
authoraap <aap@papnet.eu>2020-06-03 08:26:24 +0200
committeraap <aap@papnet.eu>2020-06-03 08:26:24 +0200
commitb73e42346e007f07cdf62412d4b13fb0389f1f2a (patch)
treeea44ee90c1af57293c72181c1202b37c561655bf /src/vehicles/Bike.cpp
parentsome CBike code; vehicle cleanup (diff)
downloadre3-b73e42346e007f07cdf62412d4b13fb0389f1f2a.tar
re3-b73e42346e007f07cdf62412d4b13fb0389f1f2a.tar.gz
re3-b73e42346e007f07cdf62412d4b13fb0389f1f2a.tar.bz2
re3-b73e42346e007f07cdf62412d4b13fb0389f1f2a.tar.lz
re3-b73e42346e007f07cdf62412d4b13fb0389f1f2a.tar.xz
re3-b73e42346e007f07cdf62412d4b13fb0389f1f2a.tar.zst
re3-b73e42346e007f07cdf62412d4b13fb0389f1f2a.zip
Diffstat (limited to 'src/vehicles/Bike.cpp')
-rw-r--r--src/vehicles/Bike.cpp782
1 files changed, 782 insertions, 0 deletions
diff --git a/src/vehicles/Bike.cpp b/src/vehicles/Bike.cpp
new file mode 100644
index 00000000..b4f6452e
--- /dev/null
+++ b/src/vehicles/Bike.cpp
@@ -0,0 +1,782 @@
+#include "common.h"
+#include "General.h"
+#include "Pad.h"
+#include "DMAudio.h"
+#include "Camera.h"
+#include "Darkel.h"
+#include "Explosion.h"
+#include "World.h"
+#include "CarCtrl.h"
+#include "Stats.h"
+#include "AnimManager.h"
+#include "AnimBlendAssociation.h"
+#include "Ped.h"
+#include "PlayerPed.h"
+#include "DamageManager.h"
+#include "Vehicle.h"
+#include "Automobile.h"
+#include "Bike.h"
+
+#define FAKESUSPENSION (99999.992f)
+
+CBike::CBike(int32 id, uint8 CreatedBy)
+ : CVehicle(CreatedBy)
+{
+ int i;
+ CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(id);
+ switch(GetModelIndex()){
+ case MI_ANGEL:
+ case MI_FREEWAY:
+ m_bikeAnimType = ASSOCGRP_BIKE_HARLEY;
+ break;
+ case MI_PIZZABOY:
+ case MI_FAGGIO:
+ m_bikeAnimType = ASSOCGRP_BIKE_VESPA;
+ break;
+ case MI_PCJ600:
+ m_bikeAnimType = ASSOCGRP_BIKE_STANDARD;
+ break;
+ case MI_SANCHEZ:
+ m_bikeAnimType = ASSOCGRP_BIKE_DIRT;
+ break;
+ }
+ m_vehType = VEHICLE_TYPE_BIKE;
+
+ m_fFireBlowUpTimer = 0.0f;
+ m_doingBurnout = 0;
+ m_bike_flag01 = false;
+
+ SetModelIndex(id);
+
+ pHandling = mod_HandlingManager.GetHandlingData((eHandlingId)mi->m_handlingId);
+ pBikeHandling = mod_HandlingManager.GetBikePointer((eHandlingId)mi->m_handlingId);
+ pFlyingHandling = mod_HandlingManager.GetFlyingPointer((eHandlingId)mi->m_handlingId);
+
+ m_bike_unused1 = 20.0f;
+ m_bike_unused2 = 0;
+
+ mi->ChooseVehicleColour(m_currentColour1, m_currentColour2);
+
+ m_fRearForkLength = 0.0f;
+ m_fFrontForkY = 0.0;
+ m_fFrontForkZ = 0.0;
+ m_fFrontForkSlope = Tan(DEGTORAD(mi->m_bikeSteerAngle));
+
+ m_fMass = pHandling->fMass;
+ m_fTurnMass = pHandling->fTurnMass;
+ m_vecCentreOfMass = pHandling->CentreOfMass;
+ m_vecCentreOfMass.z = 0.1f;
+ m_fAirResistance = pHandling->Dimension.x*pHandling->Dimension.z/m_fMass;
+ m_fElasticity = 0.05f;
+ m_fBuoyancy = pHandling->fBuoyancy;
+
+ m_fSteerAngle = 0.0f;
+ m_fBikeSteerAngle = 0.0f;
+ m_fLeanLRAngle = 0.0f;
+ m_fLeanLRAngle2 = 0.0f;
+ m_fGasPedal = 0.0f;
+ m_fBrakePedal = 0.0f;
+ m_fLeanInput = 0.0f;
+ field_478 = 0;
+ field_47C = 0;
+ m_pSetOnFireEntity = nil;
+ m_pBombRigger = nil;
+ m_fGasPedalAudio = 0.0f;
+ m_bike_flag02 = false;
+ m_bike_flag04 = false;
+ m_bike_flag08 = false;
+ m_bike_flag10 = false;
+ m_bike_flag20 = false;
+ m_bike_flag40 = false;
+ m_bike_flag80 = false;
+
+ m_fTireTemperature = 0.0f;
+ someAngle = 0.0f;
+ field_490 = 0;
+
+ for(i = 0; i < 2; i++){
+ m_aWheelRotation[i] = 0.0f;
+ m_aWheelSpeed[i] = 0.0f;
+ m_aWheelState[i] = WHEEL_STATE_NORMAL;
+ m_aWheelSkidmarkType[i] = SKIDMARK_NORMAL;
+ m_aWheelSkidmarkBloody[i] = false;
+ m_aWheelSkidmarkUnk[0] = false;
+ m_wheelStatus[i] = WHEEL_STATUS_OK;
+ }
+
+ for(i = 0; i < 4; i++){
+ m_aGroundPhysical[i] = nil;
+ m_aGroundOffset[i] = CVector(0.0f, 0.0f, 0.0f);
+ m_aSuspensionSpringRatioPrev[i] = m_aSuspensionSpringRatio[i] = 1.0f;
+ m_aWheelTimer[i] = 0.0f;
+ }
+
+ m_nWheelsOnGround = 0;
+ m_nDriveWheelsOnGround = 0;
+ m_nDriveWheelsOnGroundPrev = 0;
+ m_fHeightAboveRoad = 0.0f;
+ m_fTraction = 1.0f;
+
+ CColModel *colModel = mi->GetColModel();
+ if(colModel->lines == nil){
+ colModel->lines = (CColLine*)RwMalloc(4*sizeof(CColLine));
+ colModel->numLines = 4;
+ }
+ // BUG? this would make more sense in the if above
+ colModel->lines[0].p0.z = FAKESUSPENSION;
+
+ SetupSuspensionLines();
+
+ AutoPilot.m_nCarMission = MISSION_NONE;
+ AutoPilot.m_nTempAction = TEMPACT_NONE;
+ AutoPilot.m_nTimeToStartMission = CTimer::GetTimeInMilliseconds();
+ AutoPilot.m_bStayInCurrentLevel = false;
+
+ SetStatus(STATUS_SIMPLE);
+ bUseCollisionRecords = true;
+ m_nNumPassengers = 0;
+ bIsVan = false;
+ bIsBus = false;
+ bIsBig = false;
+ bLowVehicle = false;
+ bPedPhysics = false;
+
+ bLeanMatrixClean = false;
+ m_leanMatrix = GetMatrix();
+}
+
+void
+CBike::SetModelIndex(uint32 id)
+{
+ CVehicle::SetModelIndex(id);
+ SetupModelNodes();
+}
+
+void
+CBike::ProcessControl(void)
+{
+}
+
+void
+CBike::Teleport(CVector pos)
+{
+ CWorld::Remove(this);
+
+ SetPosition(pos);
+ SetOrientation(0.0f, 0.0f, 0.0f);
+ SetMoveSpeed(0.0f, 0.0f, 0.0f);
+ SetTurnSpeed(0.0f, 0.0f, 0.0f);
+
+ ResetSuspension();
+
+ CWorld::Add(this);
+}
+
+void
+CBike::PreRender(void)
+{
+}
+
+void
+CBike::Render(void)
+{
+ CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex());
+
+ m_nSetPieceExtendedRangeTime = CTimer::GetTimeInMilliseconds() + 3000;
+ mi->SetVehicleColour(m_currentColour1, m_currentColour2);
+ CEntity::Render();
+}
+
+int32
+CBike::ProcessEntityCollision(CEntity *ent, CColPoint *colpoints)
+{
+ int i;
+ CColModel *colModel;
+
+ if(GetStatus() != STATUS_SIMPLE)
+ bVehicleColProcessed = true;
+
+ colModel = GetColModel();
+
+ int numWheelCollisions = 0;
+ float prevRatios[4] = { 0.0f, 0.0f, 0.0f, 0.0f};
+ for(i = 0; i < 4; i++)
+ prevRatios[i] = m_aSuspensionSpringRatio[i];
+
+ if(m_bIsVehicleBeingShifted || bSkipLineCol || ent->IsPed() ||
+ GetModelIndex() == MI_DODO && ent->IsVehicle())
+ colModel->numLines = 0;
+
+ int numCollisions = CCollision::ProcessColModels(GetMatrix(), *colModel,
+ ent->GetMatrix(), *ent->GetColModel(),
+ colpoints,
+ m_aWheelColPoints, m_aSuspensionSpringRatio);
+
+ // m_aSuspensionSpringRatio are now set to the point where the tyre touches ground.
+ // In ProcessControl these will be re-normalized to ignore the tyre radius.
+
+ if(colModel->numLines){
+ for(i = 0; i < 4; i++)
+ if(m_aSuspensionSpringRatio[i] < 1.0f && m_aSuspensionSpringRatio[i] < prevRatios[i]){
+ numWheelCollisions++;
+
+ // wheel is touching a physical
+ if(ent->IsVehicle() || ent->IsObject()){
+ CPhysical *phys = (CPhysical*)ent;
+
+ m_aGroundPhysical[i] = phys;
+ phys->RegisterReference((CEntity**)&m_aGroundPhysical[i]);
+ m_aGroundOffset[i] = m_aWheelColPoints[i].point - phys->GetPosition();
+ }
+
+ m_nSurfaceTouched = m_aWheelColPoints[i].surfaceB;
+ if(ent->IsBuilding())
+ m_pCurGroundEntity = ent;
+ }
+ }else
+ colModel->numLines = 4;
+
+ if(numCollisions > 0 || numWheelCollisions > 0){
+ AddCollisionRecord(ent);
+ if(!ent->IsBuilding())
+ ((CPhysical*)ent)->AddCollisionRecord(this);
+
+ if(numCollisions > 0)
+ if(ent->IsBuilding() ||
+ ent->IsObject() && ((CPhysical*)ent)->bInfiniteMass)
+ bHasHitWall = true;
+ }
+
+ return numCollisions;
+}
+
+static int16 nLastControlInput;
+static float fMouseCentreRange = 0.35f;
+static float fMouseSteerSens = -0.0035f;
+static float fMouseCentreMult = 0.975f;
+
+void
+CBike::ProcessControlInputs(uint8 pad)
+{
+ float speed = DotProduct(m_vecMoveSpeed, GetForward());
+
+ if(CPad::GetPad(pad)->GetExitVehicle())
+ bIsHandbrakeOn = true;
+ else
+ bIsHandbrakeOn = !!CPad::GetPad(pad)->GetHandBrake();
+
+ // Steer left/right
+#ifdef FIX_BUGS
+ if(CCamera::m_bUseMouse3rdPerson && !CVehicle::m_bDisableMouseSteering){
+ if(CPad::GetPad(pad)->GetMouseX() != 0.0f){
+ m_fSteerInput += fMouseSteerSens*CPad::GetPad(pad)->GetMouseX();
+ nLastControlInput = 2;
+ if(Abs(m_fSteerInput) < fMouseCentreRange)
+ m_fSteerInput *= Pow(fMouseCentreMult, CTimer::GetTimeStep());
+ }else if(CPad::GetPad(pad)->GetSteeringLeftRight() || nLastControlInput != 2){
+ // mouse hasn't move, steer with pad like below
+ m_fSteerInput += (-CPad::GetPad(pad)->GetSteeringLeftRight()/128.0f - m_fSteerInput)*
+ 0.2f*CTimer::GetTimeStep();
+ nLastControlInput = 0;
+ }
+ }else
+#endif
+ {
+ m_fSteerInput += (-CPad::GetPad(pad)->GetSteeringLeftRight()/128.0f - m_fSteerInput)*
+ 0.2f*CTimer::GetTimeStep();
+ nLastControlInput = 0;
+ }
+ m_fSteerInput = clamp(m_fSteerInput, -1.0f, 1.0f);
+
+ // Lean forward/backward
+ float updown = -CPad::GetPad(pad)->GetSteeringUpDown()/128.0f + CPad::GetPad(pad)->GetCarGunUpDown()/128.0f;
+ m_fLeanInput += (updown - m_fLeanInput)*0.2f*CTimer::GetTimeStep();
+ m_fLeanInput = clamp(m_fLeanInput, -1.0f, 1.0f);
+
+ // Accelerate/Brake
+ float acceleration = (CPad::GetPad(pad)->GetAccelerate() - CPad::GetPad(pad)->GetBrake())/255.0f;
+ if(GetModelIndex() == MI_DODO && acceleration < 0.0f)
+ acceleration *= 0.3f;
+ if(Abs(speed) < 0.01f){
+ // standing still, go into direction we want
+ if(CPad::GetPad(pad)->GetAccelerate() > 150.0f && CPad::GetPad(pad)->GetBrake() > 150.0f){
+ m_fGasPedal = CPad::GetPad(pad)->GetAccelerate()/255.0f;
+ m_fBrakePedal = CPad::GetPad(pad)->GetBrake()/255.0f;
+ m_doingBurnout = 1;
+ }else{
+ m_fGasPedal = acceleration;
+ m_fBrakePedal = 0.0f;
+ }
+ }else{
+#if 1
+ // simpler than the code below
+ if(speed * acceleration < 0.0f){
+ // if opposite directions, have to brake first
+ m_fGasPedal = 0.0f;
+ m_fBrakePedal = Abs(acceleration);
+ }else{
+ // accelerating in same direction we were already going
+ m_fGasPedal = acceleration;
+ m_fBrakePedal = 0.0f;
+ }
+#else
+ if(speed < 0.0f){
+ // moving backwards currently
+ if(acceleration < 0.0f){
+ // still go backwards
+ m_fGasPedal = acceleration;
+ m_fBrakePedal = 0.0f;
+ }else{
+ // want to go forwards, so brake
+ m_fGasPedal = 0.0f;
+ m_fBrakePedal = acceleration;
+ }
+ }else{
+ // moving forwards currently
+ if(acceleration < 0.0f){
+ // want to go backwards, so brake
+ m_fGasPedal = 0.0f;
+ m_fBrakePedal = -acceleration;
+ }else{
+ // still go forwards
+ m_fGasPedal = acceleration;
+ m_fBrakePedal = 0.0f;
+ }
+ }
+#endif
+ }
+
+ // Actually turn wheels
+ static float fValue; // why static?
+ if(m_fSteerInput < 0.0f)
+ fValue = -sq(m_fSteerInput);
+ else
+ fValue = sq(m_fSteerInput);
+ m_fSteerAngle = DEGTORAD(pHandling->fSteeringLock) * fValue;
+
+ if(bComedyControls){
+ if(((CTimer::GetTimeInMilliseconds() >> 10) & 0xF) < 12)
+ m_fGasPedal = 1.0f;
+ if((((CTimer::GetTimeInMilliseconds() >> 10)+6) & 0xF) < 12)
+ m_fBrakePedal = 0.0f;
+ bIsHandbrakeOn = false;
+ if(CTimer::GetTimeInMilliseconds() & 0x800)
+ m_fSteerAngle += 0.08f;
+ else
+ m_fSteerAngle -= 0.03f;
+ }
+
+ // Brake if player isn't in control
+ // BUG: game always uses pad 0 here
+ if(CPad::GetPad(pad)->ArePlayerControlsDisabled()){
+ m_fBrakePedal = 1.0f;
+ bIsHandbrakeOn = true;
+ m_fGasPedal = 0.0f;
+
+ FindPlayerPed()->KeepAreaAroundPlayerClear();
+
+ // slow down car immediately
+ speed = m_vecMoveSpeed.Magnitude();
+ if(speed > 0.28f)
+ m_vecMoveSpeed *= 0.28f/speed;
+ }
+}
+
+void
+CBike::GetComponentWorldPosition(int32 component, CVector &pos)
+{
+ if(m_aBikeNodes[component] == nil){
+ printf("BikeNode missing: %d %d\n", GetModelIndex(), component);
+ return;
+ }
+ RwMatrix *ltm = RwFrameGetLTM(m_aBikeNodes[component]);
+ pos = *RwMatrixGetPos(ltm);
+}
+
+bool
+CBike::IsComponentPresent(int32 component)
+{
+ return m_aBikeNodes[component] != nil;
+}
+
+void
+CBike::SetComponentRotation(int32 component, CVector rotation)
+{
+ CMatrix mat(RwFrameGetMatrix(m_aBikeNodes[component]));
+ CVector pos = mat.GetPosition();
+ // BUG: all these set the whole matrix
+ mat.SetRotateX(DEGTORAD(rotation.x));
+ mat.SetRotateY(DEGTORAD(rotation.y));
+ mat.SetRotateZ(DEGTORAD(rotation.z));
+ mat.Translate(pos);
+ mat.UpdateRW();
+}
+
+bool
+CBike::IsDoorReady(eDoors door)
+{
+ return true;
+}
+
+bool
+CBike::IsDoorFullyOpen(eDoors door)
+{
+ return false;
+}
+
+bool
+CBike::IsDoorClosed(eDoors door)
+{
+ return false;
+}
+
+bool
+CBike::IsDoorMissing(eDoors door)
+{
+ return true;
+}
+
+void
+CBike::RemoveRefsToVehicle(CEntity *ent)
+{
+ int i;
+ for(i = 0; i < 4; i++)
+ if(m_aGroundPhysical[i] == ent)
+ m_aGroundPhysical[i] = nil;
+}
+
+void
+CBike::BlowUpCar(CEntity *culprit)
+{
+ if(!bCanBeDamaged)
+ return;
+
+ // explosion pushes vehicle up
+ m_vecMoveSpeed.z += 0.13f;
+ SetStatus(STATUS_WRECKED);
+ bRenderScorched = true;
+
+ m_fHealth = 0.0f;
+ m_nBombTimer = 0;
+
+ TheCamera.CamShake(0.7f, GetPosition().x, GetPosition().y, GetPosition().z);
+
+ KillPedsInVehicle();
+
+ bEngineOn = false;
+ bLightsOn = false;
+ ChangeLawEnforcerState(false);
+
+ CExplosion::AddExplosion(this, culprit, EXPLOSION_CAR, GetPosition(), 0);
+ CDarkel::RegisterCarBlownUpByPlayer(this);
+}
+
+bool
+CBike::SetUpWheelColModel(CColModel *colModel)
+{
+ // TODO, but unused
+ return true;
+}
+
+void
+CBike::BurstTyre(uint8 wheel, bool applyForces)
+{
+ if(bTyresDontBurst)
+ return;
+
+ switch(wheel){
+ case CAR_PIECE_WHEEL_LF: wheel = BIKEWHEEL_FRONT; break;
+ case CAR_PIECE_WHEEL_LR: wheel = BIKEWHEEL_REAR; break;
+ default: assert(0 && "invalid wheel");
+ }
+
+ if(m_wheelStatus[wheel] == WHEEL_STATUS_OK){
+ m_wheelStatus[wheel] = WHEEL_STATUS_BURST;
+#ifdef FIX_BUGS
+ CStats::TyresPopped++;
+#endif
+// TODO(MIAMI)
+// DMAudio.PlayOneShot(m_audioEntityId, SOUND_15, 0.0f);
+
+ if(GetStatus() == STATUS_SIMPLE){
+ SetStatus(STATUS_PHYSICS);
+ CCarCtrl::SwitchVehicleToRealPhysics(this);
+ }
+
+ if(applyForces){
+ ApplyMoveForce(GetRight() * m_fMass * CGeneral::GetRandomNumberInRange(-0.02f, 0.02f));
+ ApplyTurnForce(GetRight() * m_fTurnMass * CGeneral::GetRandomNumberInRange(-0.02f, 0.02f), GetForward());
+ }
+// TODO: knock off driver
+ }
+}
+
+bool
+CBike::IsRoomForPedToLeaveCar(uint32 component, CVector *doorOffset)
+{
+ CColPoint colpoint;
+ CEntity *ent;
+ colpoint.point = CVector(0.0f, 0.0f, 0.0f);
+ CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex());
+
+ CVector seatPos = mi->GetFrontSeatPosn();
+ if(component == CAR_DOOR_RR || component == CAR_DOOR_LR)
+ seatPos = mi->m_positions[CAR_POS_BACKSEAT];
+ if(component == CAR_DOOR_LF || component == CAR_DOOR_LR)
+ seatPos.x = -seatPos.x;
+ seatPos = GetMatrix() * seatPos;
+
+ CVector doorPos = CPed::GetPositionToOpenCarDoor(this, component);
+ if(doorOffset){
+ CVector off = *doorOffset;
+ if(component == CAR_DOOR_RF || component == CAR_DOOR_RR)
+ off.x = -off.x;
+ doorPos += Multiply3x3(GetMatrix(), off);
+ }
+
+ if(GetUp().z < 0.0f){
+ seatPos.z += 0.5f;
+ doorPos.z += 0.5f;
+ }
+
+ CVector dist = doorPos - seatPos;
+
+ // Removing that makes thiProcessEntityCollisions func. return false for van doors.
+ doorPos.z += 0.5f;
+ float length = dist.Magnitude();
+ CVector pedPos = seatPos + dist*((length+0.6f)/length);
+
+ if(!CWorld::GetIsLineOfSightClear(seatPos, pedPos, true, false, false, true, false, false))
+ return false;
+ if(CWorld::TestSphereAgainstWorld(doorPos, 0.6f, this, true, true, false, true, false, false))
+ return false;
+ if(CWorld::ProcessVerticalLine(doorPos, 1000.0f, colpoint, ent, true, false, false, true, false, false, nil))
+ if(colpoint.point.z > doorPos.z && colpoint.point.z < doorPos.z + 0.6f)
+ return false;
+ float upperZ = colpoint.point.z;
+ if(!CWorld::ProcessVerticalLine(doorPos, -1000.0f, colpoint, ent, true, false, false, true, false, false, nil))
+ return false;
+ if(upperZ != 0.0f && upperZ < colpoint.point.z)
+ return false;
+ return true;
+}
+
+float
+CBike::GetHeightAboveRoad(void)
+{
+ return m_fHeightAboveRoad;
+}
+
+void
+CBike::PlayCarHorn(void)
+{
+ int r;
+
+ if (IsAlarmOn() || m_nCarHornTimer != 0)
+ return;
+
+ if (m_nCarHornDelay) {
+ m_nCarHornDelay--;
+ return;
+ }
+
+ m_nCarHornDelay = (CGeneral::GetRandomNumber() & 0x7F) + 150;
+ r = m_nCarHornDelay & 7;
+ if(r < 2){
+ m_nCarHornTimer = 45;
+ }else if(r < 4){
+ if(pDriver)
+ pDriver->Say(SOUND_PED_CAR_COLLISION);
+ m_nCarHornTimer = 45;
+ }else{
+ if(pDriver)
+ pDriver->Say(SOUND_PED_CAR_COLLISION);
+ }
+}
+
+void
+CBike::PlayHornIfNecessary(void)
+{
+ if(AutoPilot.m_bSlowedDownBecauseOfPeds ||
+ AutoPilot.m_bSlowedDownBecauseOfCars)
+ PlayCarHorn();
+}
+
+void
+CBike::ResetSuspension(void)
+{
+ int i;
+ for(i = 0; i < 2; i++){
+ m_aWheelRotation[i] = 0.0f;
+ m_aWheelState[i] = WHEEL_STATE_NORMAL;
+ }
+ for(i = 0; i < 4; i++){
+ m_aSuspensionSpringRatio[i] = 1.0f;
+ m_aWheelTimer[i] = 0.0f;
+ }
+}
+
+// TODO: maybe put this somewhere else
+inline void
+GetRelativeMatrix(RwMatrix *mat, RwFrame *frm, RwFrame *end)
+{
+ *mat = *RwFrameGetMatrix(frm);
+ frm = RwFrameGetParent(frm);
+ while(frm){
+ RwMatrixTransform(mat, RwFrameGetMatrix(frm), rwCOMBINEPOSTCONCAT);
+ frm = RwFrameGetParent(frm);
+ if(frm == end)
+ frm = nil;
+ }
+}
+
+void
+CBike::SetupSuspensionLines(void)
+{
+ int i;
+ CVector posn;
+ float suspOffset = 0.0f;
+ RwFrame *node = nil;
+ CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex());
+ CColModel *colModel = mi->GetColModel();
+ RwMatrix *mat = RwMatrixCreate();
+
+ bool initialized = colModel->lines[0].p0.z != FAKESUSPENSION;
+
+ for(i = 0; i < 4; i++){
+ if(initialized){
+ posn = colModel->lines[i].p0;
+ if(i < 2)
+ posn.z = m_aWheelBasePosition[0];
+ else
+ posn.z = m_aWheelBasePosition[1];
+ }else{
+ switch(i){
+ case BIKESUSP_FRONT_1:
+ node = m_aBikeNodes[BIKE_WHEEL_FRONT];
+ suspOffset = 0.25f*mi->m_wheelScale;
+ break;
+ case BIKESUSP_FRONT_2:
+ node = m_aBikeNodes[BIKE_WHEEL_FRONT];
+ suspOffset = -0.25f*mi->m_wheelScale;
+ break;
+ case BIKESUSP_REAR_1:
+ node = m_aBikeNodes[BIKE_WHEEL_REAR];
+ suspOffset = 0.25f*mi->m_wheelScale;
+ break;
+ case BIKESUSP_REAR_2:
+ node = m_aBikeNodes[BIKE_WHEEL_REAR];
+ suspOffset = -0.25f*mi->m_wheelScale;
+ break;
+ }
+
+ GetRelativeMatrix(mat, node, node);
+ posn = *RwMatrixGetPos(mat);
+ if(i == BIKESUSP_FRONT_1)
+ m_aWheelBasePosition[BIKEWHEEL_FRONT] = posn.z;
+ else if(i == BIKESUSP_REAR_1){
+ m_aWheelBasePosition[BIKEWHEEL_REAR] = posn.z;
+
+ GetRelativeMatrix(mat, node, m_aBikeNodes[BIKE_FORKS_REAR]);
+ float dz = posn.z - RwMatrixGetPos(mat)->z;
+ float dy = posn.y - RwMatrixGetPos(mat)->y;
+ m_fRearForkLength = Sqrt(SQR(dy) + SQR(dz));
+ }
+ posn.y += suspOffset;
+ }
+
+ // uppermost wheel position
+ posn.z += pHandling->fSuspensionUpperLimit;
+ colModel->lines[i].p0 = posn;
+
+ // lowermost wheel position
+ posn.z += pHandling->fSuspensionLowerLimit - pHandling->fSuspensionUpperLimit;
+ // lowest point on tyre
+ posn.z -= mi->m_wheelScale*0.5f;
+ colModel->lines[i].p1 = posn;
+
+ // this is length of the spring at rest
+ m_aSuspensionSpringLength[i] = pHandling->fSuspensionUpperLimit - pHandling->fSuspensionLowerLimit;
+ m_aSuspensionLineLength[i] = colModel->lines[i].p0.z - colModel->lines[i].p1.z;
+ }
+
+ if(!initialized){
+ GetRelativeMatrix(mat, m_aBikeNodes[BIKE_FORKS_REAR], m_aBikeNodes[BIKE_FORKS_REAR]);
+ m_fFrontForkY = RwMatrixGetPos(mat)->y;
+ m_fFrontForkZ = RwMatrixGetPos(mat)->z;
+ }
+
+ // Compress spring somewhat to get normal height on road
+ m_fHeightAboveRoad = m_aSuspensionSpringLength[0]*(1.0f - 1.0f/(4.0f*pHandling->fSuspensionForceLevel))
+ - colModel->lines[0].p0.z + mi->m_wheelScale*0.5f;
+ for(i = 0; i < 2; i++)
+ m_aWheelPosition[i] = mi->m_wheelScale*0.5f - m_fHeightAboveRoad;
+
+ // adjust col model to include suspension lines
+ if(colModel->boundingBox.min.z > colModel->lines[0].p1.z)
+ colModel->boundingBox.min.z = colModel->lines[0].p1.z;
+ float radius = Max(colModel->boundingBox.min.Magnitude(), colModel->boundingBox.max.Magnitude());
+ if(colModel->boundingSphere.radius < radius)
+ colModel->boundingSphere.radius = radius;
+
+#ifdef FIX_BUGS
+ RwMatrixDestroy(mat);
+#endif
+}
+
+void
+CBike::CalculateLeanMatrix(void)
+{
+ if(bLeanMatrixClean)
+ return;
+
+ CMatrix mat;
+ mat.SetRotateX(-0.05f*Abs(m_fLeanLRAngle));
+ mat.RotateY(m_fLeanLRAngle);
+ m_leanMatrix = GetMatrix();
+ m_leanMatrix = m_leanMatrix * mat;
+ // place wheel back on ground
+ m_leanMatrix.GetPosition() += GetUp()*(1.0f-Cos(m_fLeanLRAngle))*GetColModel()->boundingBox.min.z;
+ bLeanMatrixClean = true;
+}
+
+void
+CBike::GetCorrectedWorldDoorPosition(CVector &pos, CVector p1, CVector p2)
+{
+ CVector &fwd = GetForward();
+ CVector rightWorld = CrossProduct(fwd, CVector(0.0f, 0.0f, 1.0f));
+ CVector upWorld = CrossProduct(rightWorld, fwd);
+ CColModel *colModel = GetColModel();
+ float onSide = DotProduct(GetUp(), rightWorld);
+ float diff = Max(colModel->boundingBox.max.z-colModel->boundingBox.max.x, 0.0f);
+ pos = CVector(0.0f, 0.0f, 0.0f);
+ float y = p2.y - p1.y;
+ float x = onSide*diff + p2.x + p1.x;
+ float z = p2.z - p1.z;
+ pos = x*rightWorld + y*fwd + z*upWorld + GetPosition();
+}
+
+void
+CBike::Fix(void)
+{
+ bIsDamaged = false;
+ m_bike_flag40 = false;
+ m_wheelStatus[0] = WHEEL_STATUS_OK;
+ m_wheelStatus[1] = WHEEL_STATUS_OK;
+}
+
+void
+CBike::SetupModelNodes(void)
+{
+ int i;
+ for(i = 0; i < BIKE_NUM_NODES; i++)
+ m_aBikeNodes[i] = nil;
+ CClumpModelInfo::FillFrameArray(GetClump(), m_aBikeNodes);
+}
+
+void
+CBike::ReduceHornCounter(void)
+{
+ if(m_nCarHornTimer != 0)
+ m_nCarHornTimer--;
+}