#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--; }