From 21ce0a4b28a1842dad91433362d250089ec491b8 Mon Sep 17 00:00:00 2001 From: aap Date: Sun, 31 May 2020 17:05:49 +0200 Subject: [PATCH] CAutomobile done --- src/core/Cam.cpp | 5 +- src/core/Camera.h | 1 + src/core/PlayerInfo.h | 1 + src/core/re3.cpp | 4 +- src/entities/Physical.cpp | 4 +- src/math/Matrix.h | 14 +- src/math/math.cpp | 6 + src/peds/Ped.cpp | 3 + src/render/Skidmarks.cpp | 54 +- src/render/Skidmarks.h | 27 +- src/render/WindModifiers.cpp | 5 + src/render/WindModifiers.h | 1 + src/vehicles/Automobile.cpp | 1608 ++++++++++++++++++++++++++-------- src/vehicles/Automobile.h | 17 +- src/vehicles/Vehicle.cpp | 29 +- src/vehicles/Vehicle.h | 5 +- src/weapons/Explosion.cpp | 2 +- src/weapons/Explosion.h | 3 +- src/weapons/Weapon.cpp | 12 + src/weapons/Weapon.h | 1 + 20 files changed, 1365 insertions(+), 437 deletions(-) diff --git a/src/core/Cam.cpp b/src/core/Cam.cpp index 1c74598c..fe2c250f 100644 --- a/src/core/Cam.cpp +++ b/src/core/Cam.cpp @@ -3778,7 +3778,7 @@ CCam::Process_Debug(const CVector&, float, float, float) if(FindPlayerVehicle()) FindPlayerVehicle()->Teleport(Source); else - CWorld::Players[CWorld::PlayerInFocus].m_pPed->SetPosition(Source); + CWorld::Players[CWorld::PlayerInFocus].m_pPed->SetPosition(Source); } // stay inside sectors @@ -3845,8 +3845,7 @@ CCam::Process_Debug(const CVector&, float, float, float) if(FindPlayerVehicle()) FindPlayerVehicle()->Teleport(Source); else - CWorld::Players[CWorld::PlayerInFocus].m_pPed->GetPosition() = Source; - + CWorld::Players[CWorld::PlayerInFocus].m_pPed->SetPosition(Source); } // stay inside sectors diff --git a/src/core/Camera.h b/src/core/Camera.h index 18144ef5..669ac740 100644 --- a/src/core/Camera.h +++ b/src/core/Camera.h @@ -382,6 +382,7 @@ public: bool m_WideScreenOn; bool m_1rstPersonRunCloseToAWall; bool m_bHeadBob; + bool m_bVehicleSuspenHigh; bool m_bFailedCullZoneTestPreviously; bool m_FadeTargetIsSplashScreen; diff --git a/src/core/PlayerInfo.h b/src/core/PlayerInfo.h index e2e874e6..ba8dc8fe 100644 --- a/src/core/PlayerInfo.h +++ b/src/core/PlayerInfo.h @@ -42,6 +42,7 @@ public: uint32 m_nTimeLastHealthLoss; uint32 m_nTimeLastArmourLoss; uint32 m_nTimeTankShotGun; + int32 m_nTimeNotFullyOnGround; int32 m_nUpsideDownCounter; int32 field_248; int16 m_nTrafficMultiplier; diff --git a/src/core/re3.cpp b/src/core/re3.cpp index 61de2e08..d02bd9b0 100644 --- a/src/core/re3.cpp +++ b/src/core/re3.cpp @@ -335,6 +335,8 @@ DebugMenuPopulate(void) DebugMenuAddCmd("Spawn", "Spawn Stinger", [](){ SpawnCar(MI_STINGER); }); DebugMenuAddCmd("Spawn", "Spawn Infernus", [](){ SpawnCar(MI_INFERNUS); }); DebugMenuAddCmd("Spawn", "Spawn Cheetah", [](){ SpawnCar(MI_CHEETAH); }); + DebugMenuAddCmd("Spawn", "Spawn Phoenix", [](){ SpawnCar(MI_PHEONIX); }); + DebugMenuAddCmd("Spawn", "Spawn Banshee", [](){ SpawnCar(MI_BANSHEE); }); DebugMenuAddCmd("Spawn", "Spawn Esperanto", [](){ SpawnCar(MI_ESPERANT); }); DebugMenuAddCmd("Spawn", "Spawn Stallion", [](){ SpawnCar(MI_STALLION); }); DebugMenuAddCmd("Spawn", "Spawn Admiral", [](){ SpawnCar(MI_ADMIRAL); }); @@ -342,9 +344,9 @@ DebugMenuPopulate(void) DebugMenuAddCmd("Spawn", "Spawn Taxi", [](){ SpawnCar(MI_TAXI); }); DebugMenuAddCmd("Spawn", "Spawn Police", [](){ SpawnCar(MI_POLICE); }); DebugMenuAddCmd("Spawn", "Spawn Enforcer", [](){ SpawnCar(MI_ENFORCER); }); - DebugMenuAddCmd("Spawn", "Spawn Banshee", [](){ SpawnCar(MI_BANSHEE); }); DebugMenuAddCmd("Spawn", "Spawn Cuban", [](){ SpawnCar(MI_CUBAN); }); DebugMenuAddCmd("Spawn", "Spawn Voodoo", [](){ SpawnCar(MI_VOODOO); }); + DebugMenuAddCmd("Spawn", "Spawn BF injection", [](){ SpawnCar(MI_BFINJECT); }); DebugMenuAddCmd("Spawn", "Spawn Maverick", [](){ SpawnCar(MI_MAVERICK); }); DebugMenuAddCmd("Spawn", "Spawn VCN Maverick", [](){ SpawnCar(MI_VCNMAV); }); DebugMenuAddCmd("Spawn", "Spawn Sparrow", [](){ SpawnCar(MI_SPARROW); }); diff --git a/src/entities/Physical.cpp b/src/entities/Physical.cpp index 02feb5cb..f97194d0 100644 --- a/src/entities/Physical.cpp +++ b/src/entities/Physical.cpp @@ -478,7 +478,9 @@ CPhysical::ApplySpringCollisionAlt(float springConst, CVector &springDir, CVecto if(DotProduct(springDir, forceDir) > 0.0f) forceDir *= -1.0f; float step = Min(CTimer::GetTimeStep(), 3.0f); - float impulse = -GRAVITY*m_fMass*step * springConst * compression * bias*2.0f; + float impulse = GRAVITY*m_fMass*step * springConst * compression * bias*2.0f; + if(bIsHeavy) + impulse *= 0.75f; ApplyMoveForce(forceDir*impulse); ApplyTurnForce(forceDir*impulse, point); } diff --git a/src/math/Matrix.h b/src/math/Matrix.h index 1d26cc20..90f66d7a 100644 --- a/src/math/Matrix.h +++ b/src/math/Matrix.h @@ -130,13 +130,18 @@ public: { float *pFloatMatrix = (float*)&m_matrix; for (int i = 0; i < 3; i++) -#ifdef FIX_BUGS // BUGFIX from VC for (int j = 0; j < 3; j++) -#else - for (int j = 0; j < 4; j++) -#endif pFloatMatrix[i * 4 + j] *= scale; } + void Scale(float sx, float sy, float sz) + { + float *pFloatMatrix = (float*)&m_matrix; + for (int i = 0; i < 3; i++){ + pFloatMatrix[i * 4 + 0] *= sx; + pFloatMatrix[i * 4 + 1] *= sy; + pFloatMatrix[i * 4 + 2] *= sz; + } + } void SetRotateXOnly(float angle){ @@ -224,6 +229,7 @@ public: void SetRotate(float xAngle, float yAngle, float zAngle); void Rotate(float x, float y, float z); void RotateX(float x); + void RotateY(float y); void RotateZ(float z); void Reorthogonalise(void); diff --git a/src/math/math.cpp b/src/math/math.cpp index e11d048c..e8b459ae 100644 --- a/src/math/math.cpp +++ b/src/math/math.cpp @@ -46,6 +46,12 @@ CMatrix::RotateX(float x) Rotate(x, 0.0f, 0.0f); } +void +CMatrix::RotateY(float y) +{ + Rotate(0.0f, y, 0.0f); +} + void CMatrix::RotateZ(float z) { diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp index 687f9da1..47d72ed6 100644 --- a/src/peds/Ped.cpp +++ b/src/peds/Ped.cpp @@ -16623,6 +16623,8 @@ CPed::ScanForThreats(void) CPed *shooter = nil; if ((fearFlags & PED_FLAG_GUN) && (shooter = CheckForGunShots()) && (m_nPedType != shooter->m_nPedType || m_nPedType == PEDTYPE_CIVMALE || m_nPedType == PEDTYPE_CIVFEMALE)) { +//TODO(MIAMI): just a quick fix for heli weapons +if(shooter->IsPed()){ if (!IsGangMember()) { m_threatEntity = shooter; m_threatEntity->RegisterReference((CEntity **) &m_threatEntity); @@ -16634,6 +16636,7 @@ CPed::ScanForThreats(void) m_threatEntity->RegisterReference((CEntity **) &m_threatEntity); return CPedType::GetFlag(shooter->m_nPedType); } +} } CPed *deadPed = nil; diff --git a/src/render/Skidmarks.cpp b/src/render/Skidmarks.cpp index 961c38a6..efd88387 100644 --- a/src/render/Skidmarks.cpp +++ b/src/render/Skidmarks.cpp @@ -114,11 +114,12 @@ CSkidmarks::Render(void) continue; CRGBA color(0, 0, 0, 255); - // TODO(MIAMI): we have a type field here actually (0-3) - if(aSkidmarks[i].m_isBloody) // TODO: type 3 - color = CRGBA(132, 34, 11, 255); - else if(aSkidmarks[i].m_isMuddy) // TODO: type 1 - color = CRGBA(90, 62, 9, 255); + switch(aSkidmarks[i].m_type){ + case SKIDMARK_NORMAL: color = CRGBA(0, 0, 0, 255); break; + case SKIDMARK_MUDDY: color = CRGBA(90, 62, 9, 255); break; + case SKIDMARK_SANDY: color = CRGBA(108, 108, 96, 255); break; + case SKIDMARK_BLOODY: color = CRGBA(132, 34, 11, 255); break; + } uint32 fade, alpha; if(aSkidmarks[i].m_state == 1 || CTimer::GetTimeInMilliseconds() < aSkidmarks[i].m_fadeStart) @@ -132,8 +133,12 @@ CSkidmarks::Render(void) alpha = 0; alpha = alpha*fade/256; - CVector p1 = aSkidmarks[i].m_pos[j] + aSkidmarks[i].m_side[j]; - CVector p2 = aSkidmarks[i].m_pos[j] - aSkidmarks[i].m_side[j]; + CVector p1 = aSkidmarks[i].m_pos[j]; + p1.x += aSkidmarks[i].m_sideX[j]; + p1.y += aSkidmarks[i].m_sideY[j]; + CVector p2 = aSkidmarks[i].m_pos[j]; + p2.x -= aSkidmarks[i].m_sideX[j]; + p2.y -= aSkidmarks[i].m_sideY[j]; RwIm3DVertexSetRGBA(&SkidmarkVertices[j*2+0], color.red, color.green, color.blue, alpha); RwIm3DVertexSetPos(&SkidmarkVertices[j*2+0], p1.x, p1.y, p1.z+0.1f); RwIm3DVertexSetRGBA(&SkidmarkVertices[j*2+1], color.red, color.green, color.blue, alpha); @@ -153,7 +158,20 @@ CSkidmarks::Render(void) } void -CSkidmarks::RegisterOne(uintptr id, CVector pos, float fwdX, float fwdY, bool *isMuddy, bool *isBloody) +CSkidmarks::RegisterOne(uintptr id, const CVector &pos, float fwdX, float fwdY, bool *isMuddy, bool *isBloody) +{ + eSkidmarkType type; + if(*isBloody) + type = SKIDMARK_BLOODY; + else if(*isMuddy) + type = SKIDMARK_MUDDY; + else + type = SKIDMARK_NORMAL; + RegisterOne(id, pos, fwdX, fwdY, type, isBloody); +} + +void +CSkidmarks::RegisterOne(uintptr id, const CVector &pos, float fwdX, float fwdY, eSkidmarkType type, bool *isBloody) { int i; CVector2D fwd(fwdX, fwdY); @@ -169,7 +187,7 @@ CSkidmarks::RegisterOne(uintptr id, CVector pos, float fwdX, float fwdY, bool *i if(i < NUMSKIDMARKS){ // Continue this one - if(aSkidmarks[i].m_isBloody != *isBloody){ + if((aSkidmarks[i].m_type==SKIDMARK_BLOODY) != *isBloody){ // Blood-status changed, end this one aSkidmarks[i].m_state = 2; aSkidmarks[i].m_fadeStart = CTimer::GetTimeInMilliseconds() + 10000; @@ -204,9 +222,12 @@ CSkidmarks::RegisterOne(uintptr id, CVector pos, float fwdX, float fwdY, bool *i CVector2D right(dist.y, -dist.x); float turn = DotProduct2D(fwd, right); turn = Abs(turn) + 1.0f; - aSkidmarks[i].m_side[aSkidmarks[i].m_last] = CVector(right.x, right.y, 0.0f) * turn * 0.125f; - if(aSkidmarks[i].m_last == 1) - aSkidmarks[i].m_side[0] = aSkidmarks[i].m_side[1]; + aSkidmarks[i].m_sideX[aSkidmarks[i].m_last] = right.x * turn * 0.125f; + aSkidmarks[i].m_sideY[aSkidmarks[i].m_last] = right.y * turn * 0.125f; + if(aSkidmarks[i].m_last == 1){ + aSkidmarks[i].m_sideX[0] = aSkidmarks[i].m_sideX[1]; + aSkidmarks[i].m_sideY[0] = aSkidmarks[i].m_sideY[1]; + } if(aSkidmarks[i].m_last > 8) *isBloody = false; // stop blood marks after 8 @@ -222,12 +243,15 @@ CSkidmarks::RegisterOne(uintptr id, CVector pos, float fwdX, float fwdY, bool *i aSkidmarks[i].m_state = 1; aSkidmarks[i].m_id = id; aSkidmarks[i].m_pos[0] = pos; - aSkidmarks[i].m_side[0] = CVector(0.0f, 0.0f, 0.0f); + aSkidmarks[i].m_sideX[0] = 0.0f; + aSkidmarks[i].m_sideY[0] = 0.0f; aSkidmarks[i].m_wasUpdated = true; aSkidmarks[i].m_last = 0; aSkidmarks[i].m_lastUpdate = CTimer::GetTimeInMilliseconds() - 1000; - aSkidmarks[i].m_isBloody = *isBloody; - aSkidmarks[i].m_isMuddy = *isMuddy; + if(*isBloody) + aSkidmarks[i].m_type = SKIDMARK_BLOODY; + else + aSkidmarks[i].m_type = type; }else *isBloody = false; // stop blood marks if no space } diff --git a/src/render/Skidmarks.h b/src/render/Skidmarks.h index 085b4c6d..28082f08 100644 --- a/src/render/Skidmarks.h +++ b/src/render/Skidmarks.h @@ -2,20 +2,28 @@ enum { SKIDMARK_LENGTH = 16 }; +enum eSkidmarkType +{ + SKIDMARK_NORMAL, + SKIDMARK_MUDDY, + SKIDMARK_SANDY, + SKIDMARK_BLOODY +}; + class CSkidmark { public: - uint8 m_state; - bool m_wasUpdated; - bool m_isBloody; - bool m_isMuddy; + CVector m_pos[SKIDMARK_LENGTH]; + float m_sideX[SKIDMARK_LENGTH]; + float m_sideY[SKIDMARK_LENGTH]; uintptr m_id; - int16 m_last; - uint32 m_lastUpdate;; + uint32 m_lastUpdate; uint32 m_fadeStart; uint32 m_fadeEnd; - CVector m_pos[SKIDMARK_LENGTH]; - CVector m_side[SKIDMARK_LENGTH]; + uint32 m_type; + int16 m_last; + uint8 m_state; + bool m_wasUpdated; }; class CSkidmarks @@ -28,5 +36,6 @@ public: static void Clear(void); static void Update(void); static void Render(void); - static void RegisterOne(uintptr id, CVector pos, float fwdX, float fwdY, bool *isMuddy, bool *isBloody); + static void RegisterOne(uintptr id, const CVector &pos, float fwdX, float fwdY, eSkidmarkType type, bool *isBloody); + static void RegisterOne(uintptr id, const CVector &pos, float fwdX, float fwdY, bool *isMuddy, bool *isBloody); }; diff --git a/src/render/WindModifiers.cpp b/src/render/WindModifiers.cpp index d7405c7a..49e7c96a 100644 --- a/src/render/WindModifiers.cpp +++ b/src/render/WindModifiers.cpp @@ -1,6 +1,11 @@ #include "common.h" #include "WindModifiers.h" +void +CWindModifiers::RegisterOne(CVector pos, int32 unk) +{ +} + int32 CWindModifiers::FindWindModifier(CVector pos, float *x, float *y) { diff --git a/src/render/WindModifiers.h b/src/render/WindModifiers.h index b4024343..c42e185d 100644 --- a/src/render/WindModifiers.h +++ b/src/render/WindModifiers.h @@ -3,5 +3,6 @@ class CWindModifiers { public: + static void RegisterOne(CVector pos, int32 unk); static int32 FindWindModifier(CVector pos, float *x, float *y); }; diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp index 538797d3..bb5a58ec 100644 --- a/src/vehicles/Automobile.cpp +++ b/src/vehicles/Automobile.cpp @@ -20,6 +20,7 @@ #include "Glass.h" #include "Antennas.h" #include "Skidmarks.h" +#include "WindModifiers.h" #include "Shadows.h" #include "PointLights.h" #include "Coronas.h" @@ -39,6 +40,7 @@ #include "Stats.h" #include "Garages.h" #include "PathFind.h" +#include "Replay.h" #include "AnimManager.h" #include "RpAnimBlend.h" #include "AnimBlendAssociation.h" @@ -47,7 +49,9 @@ #include "Object.h" #include "Automobile.h" -bool bAllCarCheat; // unused +//--MIAMI: file done except TODOs + +bool bAllCarCheat; RwObject *GetCurrentAtomicObjectCB(RwObject *object, void *data); @@ -69,20 +73,37 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy) CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(id); m_fFireBlowUpTimer = 0.0f; - field_4E0 = 0; + m_doingBurnout = 0; bTaxiLight = m_sAllTaxiLights; bFixedColour = false; bBigWheels = false; bWaterTight = false; - bTankDetonateCars = true; SetModelIndex(id); + // Already done in CVehicle... + switch(GetModelIndex()){ + case MI_HUNTER: + case MI_ANGEL: + case MI_FREEWAY: + m_nRadioStation = V_ROCK; + break; + case MI_RCBARON: + case MI_RCBANDIT: + case MI_RCRAIDER: + case MI_RCGOBLIN: + case MI_TOPFUN: + case MI_CADDY: + case MI_BAGGAGE: + m_nRadioStation = RADIO_OFF; + break; + } + pHandling = mod_HandlingManager.GetHandlingData((eHandlingId)mi->m_handlingId); pFlyingHandling = mod_HandlingManager.GetFlyingPointer((eHandlingId)mi->m_handlingId); - field_49C = 20.0f; - field_4D8 = 0; + m_auto_unused1 = 20.0f; + m_auto_unused2 = 0; mi->ChooseVehicleColour(m_currentColour1, m_currentColour2); @@ -133,6 +154,8 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy) m_fElasticity = 0.05f; m_fBuoyancy = pHandling->fBuoyancy; + m_fOrientation = m_auto_unk4 = 0.0f; + m_nBusDoorTimerEnd = 0; m_nBusDoorTimerStart = 0; @@ -143,6 +166,9 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy) m_fGasPedalAudio = 0.0f; bNotDamagedUpsideDown = false; bMoreResistantToDamage = false; + bTankDetonateCars = true; + bStuckInSand = false; + bHeliDestroyed = false; m_fVelocityChangeForAudio = 0.0f; m_hydraulicState = 0; @@ -155,7 +181,7 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy) m_aWheelRotation[i] = 0.0f; m_aWheelSpeed[i] = 0.0f; m_aWheelState[i] = WHEEL_STATE_NORMAL; - m_aWheelSkidmarkMuddy[i] = false; + m_aWheelSkidmarkType[i] = SKIDMARK_NORMAL; m_aWheelSkidmarkBloody[i] = false; } @@ -164,6 +190,7 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy) m_nDriveWheelsOnGroundPrev = 0; m_fHeightAboveRoad = 0.0f; m_fTraction = 1.0f; + m_fTireTemperature = 1.0f; CColModel *colModel = mi->GetColModel(); if(colModel->lines == nil){ @@ -178,10 +205,6 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy) m_nNumPassengers = 0; - m_bombType = CARBOMB_NONE; - bDriverLastFrame = false; - m_pBombRigger = nil; - if(m_nDoorLock == CARLOCK_UNLOCKED && (id == MI_POLICE || id == MI_ENFORCER || id == MI_RHINO)) m_nDoorLock = CARLOCK_LOCKED_INITIALLY; @@ -189,6 +212,7 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy) m_fCarGunLR = 0.0f; m_fCarGunUD = 0.05f; m_fPropellerRotation = 0.0f; + m_fHeliOrientation = -1.0f; m_weaponDoorTimerLeft = 0.0f; m_weaponDoorTimerRight = m_weaponDoorTimerLeft; @@ -199,6 +223,9 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy) CMatrix mat2(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_LF])); mat1.GetPosition() += CVector(mat2.GetPosition().x + 0.1f, 0.0f, mat2.GetPosition().z); mat1.UpdateRW(); + }else if(GetModelIndex() == MI_HUNTER){ + RpAtomicSetFlags((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LB]), 0); + RpAtomicSetFlags((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RB]), 0); }else if(IsRealHeli()){ RpAtomicSetFlags((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LF]), 0); RpAtomicSetFlags((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RF]), 0); @@ -210,7 +237,6 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy) } } -//--MIAMI: done void CAutomobile::SetModelIndex(uint32 id) { @@ -218,6 +244,11 @@ CAutomobile::SetModelIndex(uint32 id) SetupModelNodes(); } +#define SAND_SLOWDOWN (0.01f) +float CAR_BALANCE_MULT = 0.3f; +CVector vecSeaSparrowGunPos(-0.5f, 2.4f, -0.785f); +CVector vecHunterGunPos(0.0f, 4.8f, -1.3f); +CVector vecHunterRocketPos(2.5f, 1.0f, -0.5f); CVector vecDAMAGE_ENGINE_POS_SMALL(-0.1f, -0.1f, 0.0f); CVector vecDAMAGE_ENGINE_POS_BIG(-0.5f, -0.3f, 0.0f); @@ -231,30 +262,41 @@ CAutomobile::ProcessControl(void) colModel = &CWorld::Players[CWorld::PlayerInFocus].m_ColModel; else colModel = GetColModel(); + bool drivingInSand = false; bWarnedPeds = false; + m_doingBurnout = 0; + bStuckInSand = false; + bRestingOnPhysical = false; + + bool carHasNitro = bAllTaxisHaveNitro && GetStatus() == STATUS_PLAYER && IsTaxi(); + + if(CReplay::IsPlayingBack()) + return; + + UpdatePassengerList(); + + // Heli wind + if(IsRealHeli()) + if((GetStatus() == STATUS_PLAYER || GetStatus() == STATUS_PHYSICS) && m_aWheelSpeed[1] > 0.075f || + GetStatus() == STATUS_SIMPLE) + CWindModifiers::RegisterOne(GetPosition(), 1); // Improve grip of vehicles in certain cases bool strongGrip1 = false; bool strongGrip2 = false; - if(FindPlayerVehicle() && this != FindPlayerVehicle()){ - switch(AutoPilot.m_nCarMission){ - case MISSION_RAMPLAYER_FARAWAY: - case MISSION_RAMPLAYER_CLOSE: - case MISSION_BLOCKPLAYER_FARAWAY: - case MISSION_BLOCKPLAYER_CLOSE: - if(FindPlayerSpeed().Magnitude() > 0.3f){ - strongGrip1 = true; - if(FindPlayerSpeed().Magnitude() > 0.4f){ - if(m_vecMoveSpeed.Magnitude() < 0.3f) - strongGrip2 = true; - }else{ - if((GetPosition() - FindPlayerCoors()).Magnitude() > 50.0f) - strongGrip2 = true; - } - } - default: break; + if(FindPlayerVehicle() && this != FindPlayerVehicle() && + (AutoPilot.m_nCarMission == MISSION_RAMPLAYER_FARAWAY || AutoPilot.m_nCarMission == MISSION_RAMPLAYER_CLOSE || + AutoPilot.m_nCarMission == MISSION_BLOCKPLAYER_FARAWAY || AutoPilot.m_nCarMission == MISSION_BLOCKPLAYER_CLOSE)){ + if(FindPlayerSpeed().Magnitude() > 0.3f){ + strongGrip1 = true; + if(FindPlayerSpeed().Magnitude() > 0.4f && + m_vecMoveSpeed.Magnitude() < 0.3f) + strongGrip2 = true; + else if((GetPosition() - FindPlayerCoors()).Magnitude() > 50.0f) + strongGrip2 = true; } - } + }else if(GetModelIndex() == MI_RCBANDIT && GetStatus() != STATUS_PLAYER_REMOTE) + strongGrip1 = true; if(bIsBus) ProcessAutoBusDoors(); @@ -263,9 +305,9 @@ CAutomobile::ProcessControl(void) // Scan if this car sees the player committing any crimes if(GetStatus() != STATUS_ABANDONED && GetStatus() != STATUS_WRECKED && - GetStatus() != STATUS_PLAYER && GetStatus() != STATUS_PLAYER_REMOTE && GetStatus() != STATUS_PLAYER_DISABLED){ + GetStatus() != STATUS_PLAYER && GetStatus() != STATUS_PLAYER_REMOTE && GetStatus() != STATUS_PLAYER_DISABLED){ switch(GetModelIndex()) - case MI_FBICAR: + case MI_FBIRANCH: case MI_POLICE: case MI_ENFORCER: case MI_SECURICA: @@ -308,7 +350,18 @@ CAutomobile::ProcessControl(void) else if(pHandling->Flags & HANDLING_NONPLAYER_STABILISER && GetStatus() == STATUS_PHYSICS) m_vecCentreOfMass.z = pHandling->CentreOfMass.z - 0.2f*pHandling->Dimension.z; else - m_vecCentreOfMass.z = pHandling->CentreOfMass.z; + m_vecCentreOfMass = pHandling->CentreOfMass; + + // Park car + if(bCanPark && !bParking && VehicleCreatedBy != MISSION_VEHICLE && AutoPilot.m_nCarMission == MISSION_CRUISE && + ((CTimer::GetFrameCounter() + m_randomSeed)&0xF) == 0 && !IsTaxi()){ + CVector parkPosition = GetPosition() + 3.0f*GetRight() + 10.0f*GetForward(); + CEntity *ent = nil; + CColPoint colpoint; + if(!CWorld::ProcessLineOfSight(GetPosition(), parkPosition, colpoint, ent, true, true, true, false, false, false) || + ent == this) + CCarAI::GetCarToParkAtCoors(this, &parkPosition); + } // Process depending on status @@ -320,12 +373,10 @@ CAutomobile::ProcessControl(void) CRemote::TakeRemoteControlledCarFromPlayer(); } - if(GetModelIndex() == MI_RCBANDIT){ - CVector pos = GetPosition(); + if(GetModelIndex() == MI_RCBANDIT && !bDisableRemoteDetonationOnContact){ + //CVector pos = GetPosition(); // FindPlayerCoors unused - if(RcbanditCheckHitWheels() || bIsInWater || CPopulation::IsPointInSafeZone(&pos)){ - if(CPopulation::IsPointInSafeZone(&pos)) - CGarages::TriggerMessage("HM2_5", -1, 5000, -1); + if(RcbanditCheckHitWheels() || bIsInWater){ CRemote::TakeRemoteControlledCarFromPlayer(); BlowUpCar(FindPlayerPed()); } @@ -336,7 +387,7 @@ CAutomobile::ProcessControl(void) // fall through case STATUS_PLAYER: if(playerRemote || - pDriver && pDriver->GetPedState() != PED_EXIT_CAR && pDriver->GetPedState() != PED_DRAG_FROM_CAR){ + pDriver && pDriver->GetPedState() != PED_EXIT_CAR && pDriver->GetPedState() != PED_DRAG_FROM_CAR && pDriver->GetPedState() != PED_ARRESTED){ // process control input if controlled by player if(playerRemote || pDriver->m_nPedType == PEDTYPE_PLAYER1) ProcessControlInputs(0); @@ -345,7 +396,59 @@ CAutomobile::ProcessControl(void) if(GetStatus() == STATUS_PLAYER && !CRecordDataForChase::IsRecording()) DoDriveByShootings(); + + // Tweak center on mass when driving on two wheels + int twoWheelTime = CWorld::Players[CWorld::PlayerInFocus].m_nTimeNotFullyOnGround; + if(twoWheelTime > 500 && !IsRealHeli() && !IsRealPlane()){ + float tweak = Min(twoWheelTime-500, 1000)/500.0f; + if(GetUp().z > 0.0f){ + // positive when on left wheels, negative on right wheels + if(GetRight().z <= 0.0f) + tweak *= -1.0f; + m_vecCentreOfMass.z = pHandling->CentreOfMass.z + + CPad::GetPad(0)->GetSteeringLeftRight()/128.0f * + CAR_BALANCE_MULT * tweak * colModel->boundingBox.max.z; + } + }else + m_vecCentreOfMass.z = pHandling->CentreOfMass.z; + + if(bHoverCheat) + DoHoverSuspensionRatios(); + + if(m_aSuspensionSpringRatio[0] < 1.0f && CSurfaceTable::GetAdhesionGroup(m_aWheelColPoints[0].surfaceB) == ADHESIVE_SAND || + m_aSuspensionSpringRatio[1] < 1.0f && CSurfaceTable::GetAdhesionGroup(m_aWheelColPoints[1].surfaceB) == ADHESIVE_SAND || + m_aSuspensionSpringRatio[2] < 1.0f && CSurfaceTable::GetAdhesionGroup(m_aWheelColPoints[2].surfaceB) == ADHESIVE_SAND || + m_aSuspensionSpringRatio[3] < 1.0f && CSurfaceTable::GetAdhesionGroup(m_aWheelColPoints[3].surfaceB) == ADHESIVE_SAND){ + if(GetModelIndex() != MI_RCBANDIT && GetModelIndex() != MI_RHINO){ + float slowdown; + CVector parallelSpeed = m_vecMoveSpeed - DotProduct(m_vecMoveSpeed, GetUp())*m_vecMoveSpeed; + float fSpeed = parallelSpeed.MagnitudeSqr(); + if(fSpeed > 0.09f){ + fSpeed = Sqrt(fSpeed); + parallelSpeed *= 0.3f / fSpeed; + slowdown = SAND_SLOWDOWN * Max(1.0f - 2.0f*fSpeed, 0.2f); + }else{ + bStuckInSand = true; + slowdown = SAND_SLOWDOWN; + } + if(pHandling->Flags & HANDLING_GOOD_INSAND) + slowdown *= 0.5f; + if(CWeather::WetRoads > 0.2f) + slowdown *= (1.2f - CWeather::WetRoads); + ApplyMoveForce(parallelSpeed * -CTimer::GetTimeStep()*slowdown*m_fMass); + drivingInSand = true; + } + } + }else if(pDriver && pDriver->IsPlayer() && + (pDriver->GetPedState() == PED_ARRESTED || + pDriver->GetPedState() == PED_DRAG_FROM_CAR || + (pDriver->GetPedState() == PED_EXIT_CAR || pDriver->m_objective == OBJECTIVE_LEAVE_VEHICLE) && !CanPedJumpOutCar())){ + bIsHandbrakeOn = true; + m_fBrakePedal = 1.0f; + m_fGasPedal = 0.0f; } + if(CPad::GetPad(0)->WeaponJustDown()) + ActivateBomb(); break; case STATUS_SIMPLE: @@ -368,6 +471,7 @@ CAutomobile::ProcessControl(void) PlayHornIfNecessary(); ReduceHornCounter(); bVehicleColProcessed = false; + bAudioChangingGear = false; // that's all we do for simple vehicles return; @@ -375,15 +479,44 @@ CAutomobile::ProcessControl(void) CCarAI::UpdateCarAI(this); CCarCtrl::SteerAICarWithPhysics(this); PlayHornIfNecessary(); + + if(bIsBeingCarJacked){ + m_fGasPedal = 0.0f; + m_fBrakePedal = 1.0f; + bIsHandbrakeOn = true; + } + + if(m_aSuspensionSpringRatio[0] < 1.0f && CSurfaceTable::GetAdhesionGroup(m_aWheelColPoints[0].surfaceB) == ADHESIVE_SAND || + m_aSuspensionSpringRatio[1] < 1.0f && CSurfaceTable::GetAdhesionGroup(m_aWheelColPoints[1].surfaceB) == ADHESIVE_SAND || + m_aSuspensionSpringRatio[2] < 1.0f && CSurfaceTable::GetAdhesionGroup(m_aWheelColPoints[2].surfaceB) == ADHESIVE_SAND || + m_aSuspensionSpringRatio[3] < 1.0f && CSurfaceTable::GetAdhesionGroup(m_aWheelColPoints[3].surfaceB) == ADHESIVE_SAND){ + if(GetModelIndex() != MI_RCBANDIT && GetModelIndex() != MI_SANDKING && GetModelIndex() != MI_BFINJECT){ + bStuckInSand = true; + if(CWeather::WetRoads > 0.0f) + ApplyMoveForce(m_vecMoveSpeed * -CTimer::GetTimeStep()*SAND_SLOWDOWN*m_fMass * (1.0f-CWeather::WetRoads)); + else + ApplyMoveForce(m_vecMoveSpeed * -CTimer::GetTimeStep()*SAND_SLOWDOWN*m_fMass); + } + } break; case STATUS_ABANDONED: - m_fBrakePedal = 0.2f; + if(m_vecMoveSpeed.MagnitudeSqr() < 0.01f) + m_fBrakePedal = 0.2f; + else + m_fBrakePedal = 0.0f; bIsHandbrakeOn = false; m_fSteerAngle = 0.0f; m_fGasPedal = 0.0f; - m_nCarHornTimer = 0; + if(!IsAlarmOn()) + m_nCarHornTimer = 0; + + if(bIsBeingCarJacked){ + m_fGasPedal = 0.0f; + m_fBrakePedal = 1.0f; + bIsHandbrakeOn = true; + } break; case STATUS_WRECKED: @@ -392,26 +525,32 @@ CAutomobile::ProcessControl(void) m_fSteerAngle = 0.0f; m_fGasPedal = 0.0f; - m_nCarHornTimer = 0; + if(!IsAlarmOn()) + m_nCarHornTimer = 0; break; case STATUS_PLAYER_DISABLED: - m_fBrakePedal = 1.0f; - bIsHandbrakeOn = true; + if(m_vecMoveSpeed.MagnitudeSqr() < 0.01f || + (pDriver && pDriver->IsPlayer() && + (pDriver->GetPedState() == PED_ARRESTED || + pDriver->GetPedState() == PED_DRAG_FROM_CAR || + (pDriver->GetPedState() == PED_EXIT_CAR || pDriver->m_objective == OBJECTIVE_LEAVE_VEHICLE) && !CanPedJumpOutCar()))){ + bIsHandbrakeOn = true; + m_fBrakePedal = 1.0f; + m_fGasPedal = 0.0f; + }else{ + m_fBrakePedal = 0.0f; + bIsHandbrakeOn = false; + } m_fSteerAngle = 0.0f; m_fGasPedal = 0.0f; - m_nCarHornTimer = 0; + if(!IsAlarmOn()) + m_nCarHornTimer = 0; break; default: break; } - // what's going on here? - if(GetPosition().z < -0.6f && - Abs(m_vecMoveSpeed.x) < 0.05f && - Abs(m_vecMoveSpeed.y) < 0.05f) - m_vecTurnSpeed *= Pow(0.95f, CTimer::GetTimeStep()); - // Skip physics if object is found to have been static recently bool skipPhysics = false; if(!bIsStuck && (GetStatus() == STATUS_ABANDONED || GetStatus() == STATUS_WRECKED)){ @@ -439,7 +578,8 @@ CAutomobile::ProcessControl(void) if(m_vecMoveSpeedAvg.MagnitudeSqr() <= sq(moveSpeedLimit*CTimer::GetTimeStep()) && m_vecTurnSpeedAvg.MagnitudeSqr() <= sq(turnSpeedLimit*CTimer::GetTimeStep()) && - m_fDistanceTravelled < distanceLimit || + m_fDistanceTravelled < distanceLimit && + !(m_fDamageImpulse > 0.0f && m_pDamageEntity && m_pDamageEntity->IsPed()) || makeStatic){ m_nStaticFrames++; @@ -455,15 +595,27 @@ CAutomobile::ProcessControl(void) } }else m_nStaticFrames = 0; + if(IsRealHeli() && m_aWheelSpeed[1] > 0.0f){ + skipPhysics = false; + m_nStaticFrames = 0; + } } // Postpone for(i = 0; i < 4; i++) - if(m_aGroundPhysical[i] && !CWorld::bForceProcessControl && m_aGroundPhysical[i]->bIsInSafePosition){ - bWasPostponed = true; - return; + if(m_aGroundPhysical[i]){ + bRestingOnPhysical = true; + if(!CWorld::bForceProcessControl && m_aGroundPhysical[i]->bIsInSafePosition){ + bWasPostponed = true; + return; + } } + if(bRestingOnPhysical){ + skipPhysics = false; + m_nStaticFrames = 0; + } + VehicleDamage(0.0f, 0); // special control @@ -479,7 +631,7 @@ CAutomobile::ProcessControl(void) HydraulicControl(); break; default: - if(CVehicle::bCheat3){ + if(CVehicle::bCheat3 || carHasNitro){ // Make vehicle jump when horn is sounded if(GetStatus() == STATUS_PLAYER && m_vecMoveSpeed.MagnitudeSqr() > sq(0.2f) && // BUG: game checks [0] four times, instead of all wheels @@ -518,12 +670,17 @@ CAutomobile::ProcessControl(void) 1.2f*m_vecMoveSpeed, nil, 2.0f); ApplyMoveForce(CVector(0.0f, 0.0f, 1.0f)*m_fMass*0.4f); - ApplyTurnForce(GetUp()*m_fMass*0.035f, GetForward()*1.0f); + ApplyTurnForce(GetUp()*m_fTurnMass*0.01f, GetForward()*1.0f); } } break; } + if(GetStatus() == STATUS_PHYSICS || GetStatus() == STATUS_SIMPLE) + if(AutoPilot.m_nCarMission == MISSION_HELI_FLYTOCOORS || + AutoPilot.m_nCarMission == MISSION_PLANE_FLYTOCOORS) + skipPhysics = true; + float brake; if(skipPhysics){ bHasContacted = false; @@ -533,11 +690,13 @@ CAutomobile::ProcessControl(void) m_nCollisionRecords = 0; bHasCollided = false; bVehicleColProcessed = false; + bAudioChangingGear = false; m_nDamagePieceType = 0; m_fDamageImpulse = 0.0f; m_pDamageEntity = nil; m_vecTurnFriction = CVector(0.0f, 0.0f, 0.0f); m_vecMoveFriction = CVector(0.0f, 0.0f, 0.0f); + m_fTireTemperature = 1.0f; }else{ // This has to be done if ProcessEntityCollision wasn't called @@ -574,7 +733,7 @@ CAutomobile::ProcessControl(void) m_aSuspensionSpringRatio[i] = (m_aSuspensionSpringRatio[i]-wheelRadius)/(1.0f-wheelRadius); } - float fwdSpeed = DotProduct(m_vecMoveSpeed, GetForward()); + float fwdSpeed = Abs(DotProduct(m_vecMoveSpeed, GetForward())); CVector contactPoints[4]; // relative to model CVector contactSpeeds[4]; // speed at contact points CVector springDirections[4]; // normalized, in model space @@ -590,6 +749,14 @@ CAutomobile::ProcessControl(void) if(m_aSuspensionSpringRatio[i] > 1.0f) m_aSuspensionSpringRatio[i] = 1.0f; } + }else if(CSurfaceTable::GetAdhesionGroup(m_aWheelColPoints[i].surfaceB) == ADHESIVE_SAND && + GetModelIndex() != MI_RHINO){ + fwdSpeed *= 0.7f; + float f = 1.0f - fwdSpeed/0.3f - 0.7f*CWeather::WetRoads; + f = Max(f, 0.4f); + m_aSuspensionSpringRatio[i] += f*(m_aSuspensionLineLength[i]-m_aSuspensionSpringLength[i])/m_aSuspensionSpringLength[i]; + if(m_aSuspensionSpringRatio[i] > 1.0f) + m_aSuspensionSpringRatio[i] = 1.0f; } // get points and directions if spring is compressed @@ -607,13 +774,20 @@ CAutomobile::ProcessControl(void) if(i == 1 || i == 3) // rear bias = 1.0f - bias; - ApplySpringCollision(pHandling->fSuspensionForceLevel, + ApplySpringCollisionAlt(pHandling->fSuspensionForceLevel, springDirections[i], contactPoints[i], - m_aSuspensionSpringRatio[i], bias); - m_aWheelSkidmarkMuddy[i] = - m_aWheelColPoints[i].surfaceB == SURFACE_GRASS || - m_aWheelColPoints[i].surfaceB == SURFACE_MUD_DRY || - m_aWheelColPoints[i].surfaceB == SURFACE_SAND; + m_aSuspensionSpringRatio[i], bias, m_aWheelColPoints[i].normal); + + m_aWheelSkidmarkUnk[i] = false; + if(m_aWheelColPoints[i].surfaceB == SURFACE_GRASS || + m_aWheelColPoints[i].surfaceB == SURFACE_MUD_DRY) + m_aWheelSkidmarkType[i] = SKIDMARK_MUDDY; + else if(m_aWheelColPoints[i].surfaceB == SURFACE_SAND || + m_aWheelColPoints[i].surfaceB == SURFACE_SAND_BEACH){ + m_aWheelSkidmarkType[i] = SKIDMARK_SANDY; + m_aWheelSkidmarkUnk[i] = true; + }else + m_aWheelSkidmarkType[i] = SKIDMARK_NORMAL; }else{ contactPoints[i] = Multiply3x3(GetMatrix(), colModel->lines[i].p1); } @@ -630,6 +804,8 @@ CAutomobile::ProcessControl(void) m_aGroundPhysical[i] = nil; #endif } + if(m_aSuspensionSpringRatio[i] < 1.0f && m_aWheelColPoints[i].normal.z > 0.35f) + springDirections[i] = -m_aWheelColPoints[i].normal; } // dampen springs @@ -656,16 +832,29 @@ CAutomobile::ProcessControl(void) float acceleration = pHandling->Transmission.CalculateDriveAcceleration(m_fGasPedal, m_nCurrentGear, m_fChangeGearTime, fwdSpeed, gripCheat); acceleration /= m_fForceMultiplier; - // unused - if(GetModelIndex() == MI_RCBARON || IsRealHeli()) + 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 if(m_nBusDoorTimerEnd > (uint32)CTimer::GetTimeStepInMilliseconds()) + m_nBusDoorTimerEnd -= CTimer::GetTimeStepInMilliseconds(); + } + + if(m_aSuspensionSpringRatio[0] < 1.0f || m_aSuspensionSpringRatio[1] < 1.0f || + m_aSuspensionSpringRatio[2] < 1.0f || m_aSuspensionSpringRatio[3] < 1.0f) + ApplyTurnForce(-0.008*Min(m_fTurnMass, 2500.0f)*GetUp(), -1.0f*GetForward()); + } + brake = m_fBrakePedal * pHandling->fBrakeDeceleration * CTimer::GetTimeStep(); - bool neutralHandling = !!(pHandling->Flags & HANDLING_NEUTRALHANDLING); + 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*(1.0f-pHandling->fBrakeBias); float tractionBiasFront = neutralHandling ? 1.0f : 2.0f*pHandling->fTractionBias; - float tractionBiasRear = neutralHandling ? 1.0f : 2.0f*(1.0f-pHandling->fTractionBias); + float tractionBiasRear = neutralHandling ? 1.0f : 2.0f-tractionBiasFront; // Count how many wheels are touching the ground @@ -707,10 +896,7 @@ CAutomobile::ProcessControl(void) if(CVehicle::bCheat3) traction *= 4.0f; - if(FindPlayerVehicle() && FindPlayerVehicle() == this){ - if(CPad::GetPad(0)->WeaponJustDown()) - ActivateBomb(); - }else if(strongGrip1 || CVehicle::bCheat3){ + if(FindPlayerVehicle() != this && (strongGrip1 || CVehicle::bCheat3)){ traction *= 1.2f; acceleration *= 1.4f; if(strongGrip2 || CVehicle::bCheat3){ @@ -722,13 +908,16 @@ CAutomobile::ProcessControl(void) static float fThrust; static tWheelState WheelState[4]; - // Process front wheels on ground + 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 = Multiply3x3(GetMatrix(), CVector(-s, c, 0.0f)); - CVector wheelRight = Multiply3x3(GetMatrix(), CVector(c, s, 0.0f)); + + CVector wheelFwd, wheelRight, tmp; if(m_aWheelTimer[CARWHEEL_FRONT_LEFT] > 0.0f){ if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier)) @@ -736,6 +925,15 @@ CAutomobile::ProcessControl(void) else fThrust = acceleration; + 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) @@ -770,6 +968,15 @@ CAutomobile::ProcessControl(void) else fThrust = acceleration; + 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) @@ -801,33 +1008,36 @@ CAutomobile::ProcessControl(void) // Process front wheels off ground - if(m_aWheelTimer[CARWHEEL_FRONT_LEFT] <= 0.0f){ - if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f) - m_aWheelSpeed[CARWHEEL_FRONT_LEFT] *= 0.95f; - else{ - 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; + if(!IsRealHeli()){ + if(m_aWheelTimer[CARWHEEL_FRONT_LEFT] <= 0.0f){ + if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f) + m_aWheelSpeed[CARWHEEL_FRONT_LEFT] *= 0.95f; + else{ + 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; + } } + m_aWheelRotation[CARWHEEL_FRONT_LEFT] += m_aWheelSpeed[CARWHEEL_FRONT_LEFT]; + } + if(m_aWheelTimer[CARWHEEL_FRONT_RIGHT] <= 0.0f){ + if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f) + m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] *= 0.95f; + else{ + 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; + } + } + m_aWheelRotation[CARWHEEL_FRONT_RIGHT] += m_aWheelSpeed[CARWHEEL_FRONT_RIGHT]; } - m_aWheelRotation[CARWHEEL_FRONT_LEFT] += m_aWheelSpeed[CARWHEEL_FRONT_LEFT]; } - if(m_aWheelTimer[CARWHEEL_FRONT_RIGHT] <= 0.0f){ - if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f) - m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] *= 0.95f; - else{ - 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; - } - } - m_aWheelRotation[CARWHEEL_FRONT_RIGHT] += m_aWheelSpeed[CARWHEEL_FRONT_RIGHT]; } // Process rear wheels @@ -836,14 +1046,27 @@ CAutomobile::ProcessControl(void) CVector wheelFwd = GetForward(); CVector wheelRight = GetRight(); + 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 - if(bIsHandbrakeOn) - brake = 20000.0f * CTimer::GetTimeStepFix(); + // Not sure if this is needed, but brake usually has timestep as a factor + rearBrake = 20000.0f * CTimer::GetTimeStepFix(); #else - if(bIsHandbrakeOn) - brake = 20000.0f; + 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; + } + }else if(m_doingBurnout && !mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier)){ + rearBrake = 0.0f; + rearTraction = 0.0f; + 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.HasFrontWheelDrive(pHandling->nIdentifier)) @@ -851,8 +1074,14 @@ CAutomobile::ProcessControl(void) else fThrust = acceleration; + wheelFwd = GetForward(); + 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])*traction; + 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]; @@ -861,7 +1090,7 @@ CAutomobile::ProcessControl(void) ProcessWheel(wheelFwd, wheelRight, contactSpeeds[CARWHEEL_REAR_LEFT], contactPoints[CARWHEEL_REAR_LEFT], m_nWheelsOnGround, fThrust, - brake*brakeBiasRear, + rearBrake*brakeBiasRear, adhesion*tractionBiasRear*Damage.m_fWheelDamageEffect, CARWHEEL_REAR_LEFT, &m_aWheelSpeed[CARWHEEL_REAR_LEFT], @@ -871,7 +1100,7 @@ CAutomobile::ProcessControl(void) ProcessWheel(wheelFwd, wheelRight, contactSpeeds[CARWHEEL_REAR_LEFT], contactPoints[CARWHEEL_REAR_LEFT], m_nWheelsOnGround, fThrust, - brake*brakeBiasRear, + rearBrake*brakeBiasRear, adhesion*tractionBiasRear, CARWHEEL_REAR_LEFT, &m_aWheelSpeed[CARWHEEL_REAR_LEFT], @@ -879,14 +1108,26 @@ CAutomobile::ProcessControl(void) WHEEL_STATUS_OK); } +#ifdef FIX_BUGS + // Shouldn't we reset these after the left wheel? + wheelFwd = GetForward(); + wheelRight = GetRight(); +#endif + if(m_aWheelTimer[CARWHEEL_REAR_RIGHT] > 0.0f){ if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier)) fThrust = 0.0f; else fThrust = acceleration; + wheelFwd = GetForward(); + 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])*traction; + 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]; @@ -895,7 +1136,7 @@ CAutomobile::ProcessControl(void) ProcessWheel(wheelFwd, wheelRight, contactSpeeds[CARWHEEL_REAR_RIGHT], contactPoints[CARWHEEL_REAR_RIGHT], m_nWheelsOnGround, fThrust, - brake*brakeBiasRear, + rearBrake*brakeBiasRear, adhesion*tractionBiasRear*Damage.m_fWheelDamageEffect, CARWHEEL_REAR_RIGHT, &m_aWheelSpeed[CARWHEEL_REAR_RIGHT], @@ -905,7 +1146,7 @@ CAutomobile::ProcessControl(void) ProcessWheel(wheelFwd, wheelRight, contactSpeeds[CARWHEEL_REAR_RIGHT], contactPoints[CARWHEEL_REAR_RIGHT], m_nWheelsOnGround, fThrust, - brake*brakeBiasRear, + rearBrake*brakeBiasRear, adhesion*tractionBiasRear, CARWHEEL_REAR_RIGHT, &m_aWheelSpeed[CARWHEEL_REAR_RIGHT], @@ -914,58 +1155,203 @@ CAutomobile::ProcessControl(void) } } + if(m_doingBurnout && !mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier) && + (m_aWheelState[CARWHEEL_REAR_LEFT] == WHEEL_STATE_SPINNING || m_aWheelState[CARWHEEL_REAR_RIGHT])){ + 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(m_aWheelTimer[CARWHEEL_REAR_LEFT] <= 0.0f){ - if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f) - m_aWheelSpeed[CARWHEEL_REAR_LEFT] *= 0.95f; - else{ - 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; + if(!IsRealHeli()){ + if(m_aWheelTimer[CARWHEEL_REAR_LEFT] <= 0.0f){ + if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f) + m_aWheelSpeed[CARWHEEL_REAR_LEFT] *= 0.95f; + else{ + 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; + } } + m_aWheelRotation[CARWHEEL_REAR_LEFT] += m_aWheelSpeed[CARWHEEL_REAR_LEFT]; + } + if(m_aWheelTimer[CARWHEEL_REAR_RIGHT] <= 0.0f){ + if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f) + m_aWheelSpeed[CARWHEEL_REAR_RIGHT] *= 0.95f; + else{ + 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; + } + } + m_aWheelRotation[CARWHEEL_REAR_RIGHT] += m_aWheelSpeed[CARWHEEL_REAR_RIGHT]; } - m_aWheelRotation[CARWHEEL_REAR_LEFT] += m_aWheelSpeed[CARWHEEL_REAR_LEFT]; } - if(m_aWheelTimer[CARWHEEL_REAR_RIGHT] <= 0.0f){ - if(mod_HandlingManager.HasFrontWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f) - m_aWheelSpeed[CARWHEEL_REAR_RIGHT] *= 0.95f; - else{ - 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; - } + + // 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.HasRearWheelDrive(pHandling->nIdentifier)) + fThrust = 0.0f; + else + fThrust = acceleration; + + 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(VEHWHEEL_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); } - m_aWheelRotation[CARWHEEL_REAR_RIGHT] += m_aWheelSpeed[CARWHEEL_REAR_RIGHT]; + + if(m_aWheelTimer[CARWHEEL_FRONT_RIGHT] > 0.0f){ + if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier)) + fThrust = 0.0f; + else + fThrust = acceleration; + + 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(VEHWHEEL_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.HasRearWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f) + m_aWheelSpeed[CARWHEEL_FRONT_LEFT] *= 0.95f; + else{ + 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; + } + } + m_aWheelRotation[CARWHEEL_FRONT_LEFT] += m_aWheelSpeed[CARWHEEL_FRONT_LEFT]; + } + if(m_aWheelTimer[CARWHEEL_FRONT_RIGHT] <= 0.0f){ + if(mod_HandlingManager.HasRearWheelDrive(pHandling->nIdentifier) || acceleration == 0.0f) + m_aWheelSpeed[CARWHEEL_FRONT_RIGHT] *= 0.95f; + else{ + 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; + } + } + m_aWheelRotation[CARWHEEL_FRONT_RIGHT] += m_aWheelSpeed[CARWHEEL_FRONT_RIGHT]; + } + } } for(i = 0; i < 4; i++){ float wheelPos = colModel->lines[i].p0.z; if(m_aSuspensionSpringRatio[i] > 0.0f) wheelPos -= m_aSuspensionSpringRatio[i]*m_aSuspensionSpringLength[i]; - m_aWheelPosition[i] += (wheelPos - m_aWheelPosition[i])*0.75f; + if(GetModelIndex() == MI_VOODOO && bUsingSpecialColModel) + m_aWheelPosition[i] = wheelPos; + 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 if(GetStatus() != STATUS_PLAYER){ - ReduceHornCounter(); + if(!IsAlarmOn()) + ReduceHornCounter(); }else{ - if(GetModelIndex() == MI_MRWHOOP){ - if(Pads[0].bHornHistory[Pads[0].iCurrHornHistory] && - !Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+4) % 5]){ - m_bSirenOrAlarm = !m_bSirenOrAlarm; - printf("m_bSirenOrAlarm toggled to %d\n", m_bSirenOrAlarm); - } - }else if(UsesSiren(GetModelIndex())){ + if(UsesSiren(GetModelIndex())){ if(Pads[0].bHornHistory[Pads[0].iCurrHornHistory]){ if(Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+4) % 5] && Pads[0].bHornHistory[(Pads[0].iCurrHornHistory+3) % 5]) @@ -978,44 +1364,126 @@ CAutomobile::ProcessControl(void) m_bSirenOrAlarm = !m_bSirenOrAlarm; }else m_nCarHornTimer = 0; - }else if(GetModelIndex() != MI_VOODOO && !CVehicle::bCheat3){ - if(Pads[0].GetHorn()) - m_nCarHornTimer = 1; - else - m_nCarHornTimer = 0; + }else if(GetModelIndex() != MI_VOODOO && !CVehicle::bCheat3 && !carHasNitro){ + if(!IsAlarmOn()){ + if(Pads[0].GetHorn()) + m_nCarHornTimer = 1; + else + m_nCarHornTimer = 0; + } } } // Flying + bool foo = false; if(GetStatus() != STATUS_PLAYER && GetStatus() != STATUS_PLAYER_REMOTE && GetStatus() != STATUS_PHYSICS){ - if(GetModelIndex() == MI_RCRAIDER || GetModelIndex() == MI_SPARROW) - m_aWheelSpeed[0] = Max(m_aWheelSpeed[0]-0.0005f, 0.0f); + 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) + foo = true; + } }else if((GetModelIndex() == MI_DODO || CVehicle::bAllDodosCheat) && m_vecMoveSpeed.Magnitude() > 0.0f && CTimer::GetTimeStep() > 0.0f){ #ifdef ALT_DODO_CHEAT if (bAltDodoCheat) - FlyingControl(FLIGHT_MODEL_SEAPLANE); + FlyingControl(FLIGHT_MODEL_PLANE); else #endif + if(GetModelIndex() == MI_DODO) FlyingControl(FLIGHT_MODEL_DODO); + else + FlyingControl(FLIGHT_MODEL_PLANE); }else if(GetModelIndex() == MI_RCBARON){ FlyingControl(FLIGHT_MODEL_RCPLANE); }else if(IsRealHeli() || bAllCarCheat){ -#ifdef ALLCARSHELI_CHEAT - if (bAllCarCheat) - FlyingControl(FLIGHT_MODEL_HELI); - else -#endif - { - // if (CPad::GetPad(0)->GetCircleJustDown()) - // m_aWheelSpeed[0] = Max(m_aWheelSpeed[0] - 0.03f, 0.0f); - // if (m_aWheelSpeed[0] < 0.22f) - // m_aWheelSpeed[0] += 0.0001f; - // if (m_aWheelSpeed[0] > 0.15f) + // Speed up rotor + if(m_aWheelSpeed[1] < 0.22f && !bIsInWater){ + if(GetModelIndex() == MI_RCRAIDER || GetModelIndex() == MI_RCGOBLIN) + m_aWheelSpeed[1] += 0.003f; + else + m_aWheelSpeed[1] += 0.001f; + } + + // Fly + if(m_aWheelSpeed[1] > 0.15f){ + if(GetModelIndex() == MI_RCRAIDER || GetModelIndex() == MI_RCGOBLIN) + FlyingControl(FLIGHT_MODEL_RCHELI); + else if(m_nWheelsOnGround < 4 && !(GetModelIndex() == MI_SEASPAR && bTouchingWater) || + CPad::GetPad(0)->GetAccelerate() != 0 || CPad::GetPad(0)->GetCarGunUpDown() > 1.0f || + Abs(m_vecMoveSpeed.x) > 0.02f || + Abs(m_vecMoveSpeed.y) > 0.02f || + Abs(m_vecMoveSpeed.z) > 0.02f) FlyingControl(FLIGHT_MODEL_HELI); } + + // Blade collision + if(m_aWheelSpeed[1] > 0.015f && m_aCarNodes[CAR_BONNET]){ + CMatrix mat; + mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_BONNET])); + if(GetModelIndex() == MI_RCRAIDER || GetModelIndex() == MI_RCGOBLIN) + DoBladeCollision(mat.GetPosition(), GetMatrix(), ROTOR_TOP, 0.72f, 0.9f); + else if(GetModelIndex() == MI_SPARROW || GetModelIndex() == MI_SEASPAR) + DoBladeCollision(mat.GetPosition(), GetMatrix(), ROTOR_TOP, 5.15f, 0.8f); + else if(GetModelIndex() == MI_HUNTER) + DoBladeCollision(mat.GetPosition(), GetMatrix(), ROTOR_TOP, 6.15f, 0.5f); + else + DoBladeCollision(mat.GetPosition(), GetMatrix(), ROTOR_TOP, 6.15f, 1.0f); + } + + // Heli weapons + if(GetModelIndex() == MI_HUNTER && GetStatus() == STATUS_PLAYER){ + // Hunter rockets + if(CPad::GetPad(0)->CarGunJustDown() && CTimer::GetTimeInMilliseconds() > m_nGunFiringTime+350){ + CWeapon gun(WEAPONTYPE_ROCKETLAUNCHER, 100); + CVector source = vecHunterRocketPos; + source = GetMatrix()*source + Max(DotProduct(m_vecMoveSpeed, GetForward()), 0.0f)*GetForward()*CTimer::GetTimeStep(); + gun.FireProjectile(this, &source, 0.0f); + + source = vecHunterRocketPos; + source.x = -source.x; + source = GetMatrix()*source + Max(DotProduct(m_vecMoveSpeed, GetForward()), 0.0f)*GetForward()*CTimer::GetTimeStep(); + gun.FireProjectile(this, &source, 0.0f); + + CStats::RoundsFiredByPlayer++; +//TODO(MIAMI): +// DMAudio.PlayOneShot(m_audioEntityId, 55, 0.0f); + m_nGunFiringTime = CTimer::GetTimeInMilliseconds(); + // Hunter gun + }else if(CPad::GetPad(0)->GetHandBrake() && CTimer::GetTimeInMilliseconds() > m_nGunFiringTime+60){ + CWeapon gun(WEAPONTYPE_HELICANNON, 5000); + CVector source = vecHunterGunPos; + source = GetMatrix()*source + m_vecMoveSpeed*CTimer::GetTimeStep(); + gun.FireInstantHit(this, &source); + gun.AddGunshell(this, source, CVector2D(0.0f, 0.1f), 0.025f); + CStats::RoundsFiredByPlayer++; +//TODO(MIAMI): +// DMAudio.PlayOneShot(m_audioEntityId, 55, 0.0f); + m_nGunFiringTime = CTimer::GetTimeInMilliseconds(); + } + }else if(GetModelIndex() == MI_SEASPAR && GetStatus() == STATUS_PLAYER){ + // Sea sparrow gun + if(CPad::GetPad(0)->GetHandBrake() && CTimer::GetTimeInMilliseconds() > m_nGunFiringTime+40){ + CWeapon gun(WEAPONTYPE_M4, 5000); + CVector source = vecSeaSparrowGunPos; + source = GetMatrix()*source + m_vecMoveSpeed*CTimer::GetTimeStep(); + gun.FireInstantHit(this, &source); + gun.AddGunshell(this, source, CVector2D(0.0f, 0.1f), 0.025f); + CStats::RoundsFiredByPlayer++; +//TODO(MIAMI): +// DMAudio.PlayOneShot(m_audioEntityId, 55, 0.0f); + m_nGunFiringTime = CTimer::GetTimeInMilliseconds(); + } + } + + if(GetModelIndex() != MI_RCRAIDER && GetModelIndex() != MI_RCGOBLIN) + if(m_aWheelSpeed[1] < 0.154f && m_aWheelSpeed[1] > 0.0044f) + foo = true; } + +//TODO(MIAMI): propeller stuff } @@ -1056,7 +1524,7 @@ CAutomobile::ProcessControl(void) CParticle::AddParticle(PARTICLE_CARFLAME, damagePos, CVector(0.0f, 0.0f, CGeneral::GetRandomNumberInRange(0.01125f, 0.09f)), - nil, 0.9f); + nil, 0.63f); CVector coors = damagePos; coors.x += CGeneral::GetRandomNumberInRange(-0.5625f, 0.5625f), @@ -1091,9 +1559,11 @@ CAutomobile::ProcessControl(void) float suspShake = 0.0f; float surfShake = 0.0f; + float speedsq = m_vecMoveSpeed.MagnitudeSqr(); for(i = 0; i < 4; i++){ float suspChange = m_aSuspensionSpringRatioPrev[i] - m_aSuspensionSpringRatio[i]; - if(suspChange > 0.3f){ + if(suspChange > 0.3f && !drivingInSand && speedsq > 0.04f){ +//TODO(MIAMI): depends on wheel status DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_JUMP, suspChange); if(suspChange > suspShake) suspShake = suspChange; @@ -1103,7 +1573,7 @@ CAutomobile::ProcessControl(void) if(surf == SURFACE_GRAVEL || surf == SURFACE_WATER || surf == SURFACE_HEDGE){ if(surfShake < 0.2f) surfShake = 0.3f; - }else if(surf == SURFACE_MUD_DRY || surf == SURFACE_SAND){ + }else if(surf == SURFACE_MUD_DRY){ if(surfShake < 0.1f) surfShake = 0.2f; }else if(surf == SURFACE_GRASS){ @@ -1111,13 +1581,17 @@ CAutomobile::ProcessControl(void) surfShake = 0.1f; } + if(this == FindPlayerVehicle()) +// BUG: this only observes one of the wheels + TheCamera.m_bVehicleSuspenHigh = suspChange > 0.05f; + m_aSuspensionSpringRatioPrev[i] = m_aSuspensionSpringRatio[i]; m_aSuspensionSpringRatio[i] = 1.0f; } // Shake pad - if((suspShake > 0.0f || surfShake > 0.0f) && GetStatus() == STATUS_PLAYER){ + if(!drivingInSand && (suspShake > 0.0f || surfShake > 0.0f) && GetStatus() == STATUS_PLAYER){ float speed = m_vecMoveSpeed.MagnitudeSqr(); if(speed > sq(0.1f)){ speed = Sqrt(speed); @@ -1125,15 +1599,16 @@ CAutomobile::ProcessControl(void) uint8 freq = Min(200.0f*suspShake*speed*2000.0f/m_fMass + 100.0f, 250.0f); CPad::GetPad(0)->StartShake(20000.0f*CTimer::GetTimeStep()/freq, freq); }else{ - uint8 freq = Min(200.0f*surfShake*speed*2000.0f/m_fMass + 40.0f, 145.0f); + uint8 freq = Min(200.0f*surfShake*speed*2000.0f/m_fMass + 40.0f, 150.0f); CPad::GetPad(0)->StartShake(5000.0f*CTimer::GetTimeStep()/freq, freq); } } } bVehicleColProcessed = false; + bAudioChangingGear = false; - if(!bWarnedPeds) + if(!bWarnedPeds && GetVehicleAppearance() != VEHICLE_APPEARANCE_HELI && GetVehicleAppearance() != VEHICLE_APPEARANCE_PLANE) CCarCtrl::ScanForPedDanger(this); @@ -1141,20 +1616,20 @@ CAutomobile::ProcessControl(void) // TODO: make the numbers defines float heading; - if(GetPosition().x > 1900.0f){ + if(GetPosition().x > 1950.0f-400.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 < -1900.0f){ + }else if(GetPosition().x < -1950.0f-400.0f){ if(m_vecMoveSpeed.x < 0.0f) m_vecMoveSpeed.x *= -1.0f; heading = GetForward().Heading(); if(heading < 0.0f) // going east SetHeading(-heading); } - if(GetPosition().y > 1900.0f){ + if(GetPosition().y > 1950.0f){ if(m_vecMoveSpeed.y > 0.0f) m_vecMoveSpeed.y *= -1.0f; heading = GetForward().Heading(); @@ -1162,7 +1637,7 @@ CAutomobile::ProcessControl(void) SetHeading(PI-heading); else if(heading > -HALFPI && heading < 0.0f) SetHeading(-PI-heading); - }else if(GetPosition().y < -1900.0f){ + }else if(GetPosition().y < -1950.0f){ if(m_vecMoveSpeed.y < 0.0f) m_vecMoveSpeed.y *= -1.0f; heading = GetForward().Heading(); @@ -1181,14 +1656,33 @@ CAutomobile::ProcessControl(void) (m_fGasPedal == 0.0f && brake == 0.0f || GetStatus() == STATUS_WRECKED)){ if(Abs(m_vecMoveSpeed.x) < 0.005f && Abs(m_vecMoveSpeed.y) < 0.005f && - Abs(m_vecMoveSpeed.z) < 0.005f){ + Abs(m_vecMoveSpeed.z) < 0.005f && + !(m_fDamageImpulse > 0.0f && m_pDamageEntity == FindPlayerPed()) && + (m_aSuspensionSpringRatioPrev[0] < 1.0f && m_aSuspensionSpringRatioPrev[1] < 1.0f && + m_aSuspensionSpringRatioPrev[2] < 1.0f && m_aSuspensionSpringRatioPrev[3] < 1.0f)){ m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); m_vecTurnSpeed.z = 0.0f; } } + + if(IsRealHeli() && bHeliDestroyed && !bRenderScorched){ + ApplyMoveForce(0.0f, 0.0f, -2.0f*CTimer::GetTimeStep()); + m_vecTurnSpeed.z += -0.002f*CTimer::GetTimeStep(); + m_vecTurnSpeed.x += -0.0002f*CTimer::GetTimeStep(); + + RwRGBA col = { 84, 84, 84, 255 }; + CParticle::AddParticle(PARTICLE_ENGINE_SMOKE, GetMatrix()*CVector(0.0f, 0.0f, -10.0f), + 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) + if(!bRenderScorched){ // we already know this is true... + CExplosion::AddExplosion(this, nil, EXPLOSION_CAR, GetPosition(), 0); + bRenderScorched = true; + } + } } -//--MIAMI: done void CAutomobile::Teleport(CVector pos) { @@ -1210,6 +1704,17 @@ CAutomobile::PreRender(void) int i, j, n; CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex()); + if(GetModelIndex() == MI_RHINO && m_aCarNodes[CAR_BONNET]){ + // Rotate Rhino turret + CMatrix m; + CVector p; + m.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_BONNET])); + p = m.GetPosition(); + m.SetRotateZ(m_fCarGunLR); + m.Translate(p); + m.UpdateRW(); + } + if(GetModelIndex() == MI_RCBANDIT){ CVector pos = GetMatrix() * CVector(0.218f, -0.444f, 0.391f); CAntennas::RegisterOne((uintptr)this, GetUp(), pos, 1.0f); @@ -1220,7 +1725,7 @@ CAutomobile::PreRender(void) // Wheel particles - if(GetModelIndex() == MI_DODO){ + if(GetModelIndex() == MI_DODO || GetVehicleAppearance() != VEHICLE_APPEARANCE_CAR){ ; // nothing }else if(GetModelIndex() == MI_RCBANDIT){ for(i = 0; i < 4; i++){ @@ -1268,13 +1773,14 @@ CAutomobile::PreRender(void) int drawParticles = Abs(fwdSpeed) < 90.0f; if(GetStatus() == STATUS_SIMPLE || GetStatus() == STATUS_PHYSICS || - GetStatus() == STATUS_PLAYER || GetStatus() == STATUS_PLAYER_PLAYBACKFROMBUFFER){ + GetStatus() == STATUS_PLAYER || GetStatus() == STATUS_PLAYER_PLAYBACKFROMBUFFER){ bool rearSkidding = false; if(m_aWheelState[CARWHEEL_REAR_LEFT] == WHEEL_STATE_SKIDDING || m_aWheelState[CARWHEEL_REAR_RIGHT] == WHEEL_STATE_SKIDDING) rearSkidding = true; for(i = 0; i < 4; i++){ + if(m_aSuspensionSpringRatioPrev[i] < 1.0f && m_aWheelColPoints[i].surfaceB != SURFACE_WATER) switch(m_aWheelState[i]){ case WHEEL_STATE_SPINNING: if(AddWheelDirtAndWater(&m_aWheelColPoints[i], drawParticles)){ @@ -1294,46 +1800,79 @@ CAutomobile::PreRender(void) if(m_aWheelTimer[i] > 0.0f) CSkidmarks::RegisterOne((uintptr)this + i, m_aWheelColPoints[i].point, GetForward().x, GetForward().y, - &m_aWheelSkidmarkMuddy[i], &m_aWheelSkidmarkBloody[i]); + m_aWheelSkidmarkType[i], &m_aWheelSkidmarkBloody[i]); break; case WHEEL_STATE_SKIDDING: if(i == CARWHEEL_REAR_LEFT || i == CARWHEEL_REAR_RIGHT || rearSkidding){ // same as below + if(Abs(fwdSpeed) > 5.0f){ + AddWheelDirtAndWater(&m_aWheelColPoints[i], drawParticles); + + CParticle::AddParticle(PARTICLE_RUBBER_SMOKE, + m_aWheelColPoints[i].point + CVector(0.0f, 0.0f, 0.25f), + CVector(0.0f, 0.0f, 0.0f)); + } + + if(m_aWheelTimer[i] > 0.0f) + CSkidmarks::RegisterOne((uintptr)this + i, m_aWheelColPoints[i].point, + GetForward().x, GetForward().y, + m_aWheelSkidmarkType[i], &m_aWheelSkidmarkBloody[i]); + } + break; + + case WHEEL_STATE_FIXED: + if(Abs(fwdSpeed) > 5.0f){ AddWheelDirtAndWater(&m_aWheelColPoints[i], drawParticles); CParticle::AddParticle(PARTICLE_RUBBER_SMOKE, m_aWheelColPoints[i].point + CVector(0.0f, 0.0f, 0.25f), CVector(0.0f, 0.0f, 0.0f)); - - if(m_aWheelTimer[i] > 0.0f) - CSkidmarks::RegisterOne((uintptr)this + i, m_aWheelColPoints[i].point, - GetForward().x, GetForward().y, - &m_aWheelSkidmarkMuddy[i], &m_aWheelSkidmarkBloody[i]); } - break; - - case WHEEL_STATE_FIXED: - AddWheelDirtAndWater(&m_aWheelColPoints[i], drawParticles); - - CParticle::AddParticle(PARTICLE_RUBBER_SMOKE, - m_aWheelColPoints[i].point + CVector(0.0f, 0.0f, 0.25f), - CVector(0.0f, 0.0f, 0.0f)); if(m_aWheelTimer[i] > 0.0f) CSkidmarks::RegisterOne((uintptr)this + i, m_aWheelColPoints[i].point, GetForward().x, GetForward().y, - &m_aWheelSkidmarkMuddy[i], &m_aWheelSkidmarkBloody[i]); + m_aWheelSkidmarkType[i], &m_aWheelSkidmarkBloody[i]); break; default: if(Abs(fwdSpeed) > 0.5f) AddWheelDirtAndWater(&m_aWheelColPoints[i], drawParticles); - if(m_aWheelSkidmarkBloody[i] && m_aWheelTimer[i] > 0.0f) + if((m_aWheelSkidmarkBloody[i] || m_aWheelSkidmarkUnk[i]) && m_aWheelTimer[i] > 0.0f) CSkidmarks::RegisterOne((uintptr)this + i, m_aWheelColPoints[i].point, GetForward().x, GetForward().y, - &m_aWheelSkidmarkMuddy[i], &m_aWheelSkidmarkBloody[i]); + m_aWheelSkidmarkType[i], &m_aWheelSkidmarkBloody[i]); + } + + // Sparks for friction of burst wheels + if(Damage.GetWheelStatus(i) == WHEEL_STATUS_BURST && m_aSuspensionSpringRatioPrev[i] < 1.0f){ + static float speedSq; + speedSq = m_vecMoveSpeed.MagnitudeSqr(); + if(speedSq > 0.01f && + m_aWheelColPoints[i].surfaceB != SURFACE_GRASS && + m_aWheelColPoints[i].surfaceB != SURFACE_MUD_DRY && + m_aWheelColPoints[i].surfaceB != SURFACE_SAND && + m_aWheelColPoints[i].surfaceB != SURFACE_SAND_BEACH && + m_aWheelColPoints[i].surfaceB != SURFACE_WATER){ + CVector normalSpeed = m_aWheelColPoints[i].normal * DotProduct(m_aWheelColPoints[i].normal, m_vecMoveSpeed); + CVector frictionSpeed = m_vecMoveSpeed - normalSpeed; + if(i == CARWHEEL_FRONT_LEFT || i == CARWHEEL_REAR_LEFT) + frictionSpeed -= 0.05f*GetRight(); + else + frictionSpeed += 0.05f*GetRight(); + CVector unusedRight = 0.15f*GetRight(); + CVector sparkDir = 0.25f*frictionSpeed; + CParticle::AddParticle(PARTICLE_SPARK_SMALL, m_aWheelColPoints[i].point, sparkDir); + + if(speedSq > 0.04f) + CParticle::AddParticle(PARTICLE_SPARK_SMALL, m_aWheelColPoints[i].point, sparkDir); + if(speedSq > 0.16f){ + CParticle::AddParticle(PARTICLE_SPARK_SMALL, m_aWheelColPoints[i].point, sparkDir); + CParticle::AddParticle(PARTICLE_SPARK_SMALL, m_aWheelColPoints[i].point, sparkDir); + } + } } } } @@ -1356,7 +1895,7 @@ CAutomobile::PreRender(void) CSkidmarks::RegisterOne((uintptr)this + CARWHEEL_REAR_LEFT, m_aWheelColPoints[CARWHEEL_REAR_LEFT].point + offset, GetForward().x, GetForward().y, - &m_aWheelSkidmarkMuddy[CARWHEEL_REAR_LEFT], &m_aWheelSkidmarkBloody[CARWHEEL_REAR_LEFT]); + m_aWheelSkidmarkType[CARWHEEL_REAR_LEFT], &m_aWheelSkidmarkBloody[CARWHEEL_REAR_LEFT]); break; default: break; } @@ -1374,7 +1913,7 @@ CAutomobile::PreRender(void) CSkidmarks::RegisterOne((uintptr)this + CARWHEEL_REAR_RIGHT, m_aWheelColPoints[CARWHEEL_REAR_RIGHT].point + offset, GetForward().x, GetForward().y, - &m_aWheelSkidmarkMuddy[CARWHEEL_REAR_RIGHT], &m_aWheelSkidmarkBloody[CARWHEEL_REAR_RIGHT]); + m_aWheelSkidmarkType[CARWHEEL_REAR_RIGHT], &m_aWheelSkidmarkBloody[CARWHEEL_REAR_RIGHT]); break; default: break; } @@ -1400,7 +1939,7 @@ CAutomobile::PreRender(void) n = 6.0f*CWeather::Rain; for(j = 0; j <= n; j++) CParticle::AddParticle(PARTICLE_RAIN_SPLASHUP, - c + CVector(CGeneral::GetRandomNumberInRange(-.04f, 0.4f), CGeneral::GetRandomNumberInRange(-.04f, 0.4f), 0.0f), + c + CVector(CGeneral::GetRandomNumberInRange(-0.4f, 0.4f), CGeneral::GetRandomNumberInRange(-0.4f, 0.4f), 0.0f), CVector(0.0f, 0.0f, 0.0f), nil, 0.0f, 0, 0, CGeneral::GetRandomNumber() & 1); } @@ -1409,21 +1948,22 @@ CAutomobile::PreRender(void) AddDamagedVehicleParticles(); // Exhaust smoke - if(bEngineOn && fwdSpeed < 90.0f){ + if(bEngineOn && !(pHandling->Flags & HANDLING_NO_EXHAUST) && fwdSpeed < 130.0f){ CVector exhaustPos = mi->m_positions[CAR_POS_EXHAUST]; - CVector pos1, pos2, dir; + CVector pos1, pos2, dir1, dir2; if(exhaustPos != CVector(0.0f, 0.0f, 0.0f)){ - dir.z = 0.0f; + dir1.z = 0.0f; + dir2.z = 0.0f; if(fwdSpeed < 10.0f){ CVector steerFwd(-Sin(m_fSteerAngle), Cos(m_fSteerAngle), 0.0f); steerFwd = Multiply3x3(GetMatrix(), steerFwd); float r = CGeneral::GetRandomNumberInRange(-0.06f, -0.03f); - dir.x = steerFwd.x * r; - dir.y = steerFwd.y * r; + dir1.x = steerFwd.x * r; + dir1.y = steerFwd.y * r; }else{ - dir.x = m_vecMoveSpeed.x; - dir.y = m_vecMoveSpeed.y; + dir1.x = m_vecMoveSpeed.x; + dir1.y = m_vecMoveSpeed.y; } bool dblExhaust = false; @@ -1433,17 +1973,62 @@ CAutomobile::PreRender(void) pos2 = exhaustPos; pos2.x = -pos2.x; pos2 = GetMatrix() * pos2; + dir2 = dir1; } - n = 4.0f*m_fGasPedal; - if(dblExhaust) - for(i = 0; i <= n; i++){ - CParticle::AddParticle(PARTICLE_EXHAUST_FUMES, pos1, dir); - CParticle::AddParticle(PARTICLE_EXHAUST_FUMES, pos2, dir); + static float fumesLimit = 2.0f; + if(CGeneral::GetRandomNumberInRange(1.0f, 3.0f)*(m_fGasPedal+1.1f) > fumesLimit) + 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); + + static float extraFumesLimit = 0.5f; + if(m_fGasPedal > extraFumesLimit && m_nCurrentGear < 3){ + if(CGeneral::GetRandomNumber() & 1) + CParticle::AddParticle(PARTICLE_EXHAUST_FUMES, pos1, dir1); + else if(pHandling->Flags & HANDLING_DBL_EXHAUST) + 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){ + if(CGeneral::GetRandomNumber() & 1){ + CParticle::AddParticle(PARTICLE_FIREBALL, pos1, dir1, nil, 0.05f, 0, 0, 2, 200); + CParticle::AddParticle(PARTICLE_FIREBALL, pos1, dir1, nil, 0.05f, 0, 0, 2, 200); + }else{ + CParticle::AddParticle(PARTICLE_FIREBALL, pos2, dir2, nil, 0.05f, 0, 0, 2, 200); + CParticle::AddParticle(PARTICLE_FIREBALL, pos2, dir2, nil, 0.05f, 0, 0, 2, 200); + } + } + } + + if(GetStatus() == STATUS_PLAYER && (CTimer::GetFrameCounter()&3) == 0 && + CWeather::Rain == 0.0f && i == 0){ + CVector camDist = GetPosition() - TheCamera.GetPosition(); + if(DotProduct(GetForward(), camDist) > 0.0f || + TheCamera.GetLookDirection() == LOOKING_LEFT || + TheCamera.GetLookDirection() == LOOKING_RIGHT){ + CParticle::AddParticle(PARTICLE_HEATHAZE, pos1, CVector(0.0f, 0.0f, 0.0f)); + if(pHandling->Flags & HANDLING_DBL_EXHAUST) + CParticle::AddParticle(PARTICLE_HEATHAZE, pos2, CVector(0.0f, 0.0f, 0.0f)); + + CParticle::AddParticle(PARTICLE_HEATHAZE, pos1, CVector(0.0f, 0.0f, 0.0f)); + if(pHandling->Flags & HANDLING_DBL_EXHAUST) + CParticle::AddParticle(PARTICLE_HEATHAZE, pos2, CVector(0.0f, 0.0f, 0.0f)); + } + } + + if(GetModelIndex() == MI_CUBAN && i < 1){ + i = 1; + pos1 = GetMatrix() * CVector(1.134f, -1.276f, -0.56f); + pos2 = GetMatrix() * CVector(-1.134f, -1.276f, -0.56f); + dir1 += 0.05f*GetRight(); + dir2 -= 0.05f*GetRight(); + }else + i = 99; } - else - for(i = 0; i <= n; i++) - CParticle::AddParticle(PARTICLE_EXHAUST_FUMES, pos1, dir); } } @@ -1515,8 +2100,8 @@ CAutomobile::PreRender(void) float angle = (CTimer::GetTimeInMilliseconds() & 0x3FF)*TWOPI/0x3FF; float s = 8.0f*Sin(angle); float c = 8.0f*Cos(angle); - CShadows::StoreCarLightShadow(this, (uintptr)this + 21, gpShadowHeadLightsTex, - &pos, c, s, s, -c, r, g, b, 8.0f); + //CShadows::StoreCarLightShadow(this, (uintptr)this + 21, gpShadowHeadLightsTex, + // &pos, c, s, s, -c, r, g, b, 8.0f); CPointLights::AddLight(CPointLights::LIGHT_POINT, pos + GetUp()*2.0f, CVector(0.0f, 0.0f, 0.0f), 12.0f, @@ -1554,17 +2139,26 @@ CAutomobile::PreRender(void) } break; - case MI_FBICAR: + case MI_FBIRANCH: + case MI_VICECHEE: if(m_bSirenOrAlarm){ CVector pos = GetMatrix() * CVector(0.4f, 0.6f, 0.3f); if(CTimer::GetTimeInMilliseconds() & 0x100 && DotProduct(GetForward(), GetPosition() - TheCamera.GetPosition()) < 0.0f) - CCoronas::RegisterCorona((uintptr)this + 21, - 0, 0, 255, 255, - pos, 0.4f, 50.0f, - CCoronas::TYPE_STAR, - CCoronas::FLARE_NONE, - CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f); + if(GetModelIndex() == MI_VICECHEE) + CCoronas::RegisterCorona((uintptr)this + 21, + 255, 70, 70, 255, + pos, 0.4f, 50.0f, + CCoronas::TYPE_STAR, + CCoronas::FLARE_NONE, + CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f); + else + CCoronas::RegisterCorona((uintptr)this + 21, + 0, 0, 255, 255, + pos, 0.4f, 50.0f, + CCoronas::TYPE_STAR, + CCoronas::FLARE_NONE, + CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f); else CCoronas::UpdateCoronaCoors((uintptr)this + 21, pos, 50.0f, 0.0f); } @@ -1589,11 +2183,10 @@ CAutomobile::PreRender(void) break; } - if(GetModelIndex() == MI_RCBANDIT || GetModelIndex() == MI_DODO || - GetModelIndex() == MI_RHINO) { - CShadows::StoreShadowForCar(this); - return; - } + if(GetModelIndex() != MI_RCBANDIT && GetModelIndex() != MI_DODO && + GetModelIndex() != MI_RHINO && GetModelIndex() != MI_RCBARON && + GetVehicleAppearance() != VEHICLE_APPEARANCE_HELI) { + // Process lights // Turn lights on/off bool shouldLightsBeOn = @@ -1631,7 +2224,6 @@ CAutomobile::PreRender(void) lookVector = CVector(1.0f, 0.0f, 0.0f); // 1.0 if directly behind car, -1.0 if in front - // BUG on PC: Abs of DotProduct is taken float behindness = DotProduct(lookVector, GetForward()); behindness = clamp(behindness, -1.0f, 1.0f); // shouldn't be necessary // 0.0 if behind car, PI if in front @@ -1646,7 +2238,8 @@ CAutomobile::PreRender(void) lightL -= GetRight()*2.0f*headLightPos.x; // Headlight coronas - if(behindness < 0.0f){ + if(DotProduct(lightR-TheCamera.GetPosition(), GetForward()) < 0.0f && + (TheCamera.Cams[TheCamera.ActiveCam].Mode != CCam::MODE_1STPERSON || this != FindPlayerVehicle())){ // In front of car float intensity = -0.5f*behindness + 0.3f; float size = 1.0f - behindness; @@ -1736,7 +2329,7 @@ CAutomobile::PreRender(void) lightL -= GetRight()*2.0f*tailLightPos.x; // Taillight coronas - if(behindness > 0.0f){ + if(DotProduct(lightR-TheCamera.GetPosition(), GetForward()) > 0.0f){ // Behind car float intensity = 0.4f*behindness + 0.4f; float size = (behindness + 1.0f)/2.0f; @@ -1810,7 +2403,7 @@ CAutomobile::PreRender(void) if(Damage.GetLightStatus(VEHLIGHT_FRONT_LEFT) == LIGHT_STATUS_OK || Damage.GetLightStatus(VEHLIGHT_FRONT_RIGHT) == LIGHT_STATUS_OK) CShadows::StoreCarLightShadow(this, (uintptr)this + 22, gpShadowHeadLightsTex, &pos, - 7.0f*fwd.x, 7.0f*fwd.y, 7.0f*fwd.y, -7.0f*fwd.x, 45, 45, 45, 7.0f); + 7.0f*fwd.x, 7.0f*fwd.y, 5.5f*fwd.y, -5.5f*fwd.x, 45, 45, 45, 7.0f); f = (tailLightPos.y - 2.5f) - (headLightPos.y + 6.0f); pos += CVector(f*fwd.x, f*fwd.y, 0.0f); @@ -1840,14 +2433,9 @@ CAutomobile::PreRender(void) CPointLights::FOG_NONE, false); } } - }else{ + }else if(GetStatus() != STATUS_ABANDONED && GetStatus() != STATUS_WRECKED){ // Lights off - if(GetStatus() == STATUS_ABANDONED || GetStatus() == STATUS_WRECKED) { - CShadows::StoreShadowForCar(this); - return; - } - CVector lightPos = mi->m_positions[CAR_POS_TAILLIGHTS]; CVector lightR = GetMatrix() * lightPos; CVector lightL = lightR; @@ -1904,29 +2492,42 @@ CAutomobile::PreRender(void) CCoronas::UpdateCoronaCoors((uintptr)this + 3, lightR, 50.0f*TheCamera.LODDistMultiplier, 0.0f); } } + // end of lights + } +//TODO(MIAMI): StoreShadowForVehicle once we have it CShadows::StoreShadowForCar(this); DoSunGlare(); -} -void -CAutomobile::Render(void) -{ - int i; + // Heli dust + if(IsRealHeli() && m_aWheelSpeed[1] > 0.1125f && GetPosition().z < 30.0f){ + bool foundGround = false; + float waterZ = -1000.0f; + float groundZ = CWorld::FindGroundZFor3DCoord(GetPosition().x, GetPosition().y, GetPosition().z, &foundGround); + if(!CWaterLevel::GetWaterLevel(GetPosition(), &waterZ, false)) + waterZ = 0.0f; + groundZ = Max(groundZ, waterZ); + float rnd = (m_aWheelSpeed[1]-0.1125f)*((int)Max(16.0f-4.0f*CTimer::GetTimeStep(),2.0f))*400.0f/43.0f; + float radius = 10.0f; + if(GetModelIndex() == MI_RCGOBLIN || GetModelIndex() == MI_RCRAIDER) + radius = 3.0f; + if(GetPosition().z - groundZ < radius) + HeliDustGenerate(this, radius-(GetPosition().z - groundZ), groundZ, ceilf(rnd)); + } + CMatrix mat; CVector pos; - CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex()); - if(GetModelIndex() == MI_RHINO && m_aCarNodes[CAR_BONNET]){ - // Rotate Rhino turret - CMatrix m; - CVector p; - m.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_BONNET])); - p = m.GetPosition(); - m.SetRotateZ(m_fCarGunLR); - m.Translate(p); - m.UpdateRW(); + bool onlyFrontWheels = false; + if(IsRealHeli()){ + // top rotor + m_aWheelRotation[1] += m_aWheelSpeed[1]*CTimer::GetTimeStep(); + if(m_aWheelRotation[1] > TWOPI) m_aWheelRotation[1] -= TWOPI; + // rear rotor + m_aWheelRotation[3] += m_aWheelSpeed[1]*CTimer::GetTimeStep(); + if(m_aWheelRotation[3] > TWOPI) m_aWheelRotation[3] -= TWOPI; + onlyFrontWheels = true; } CVector contactPoints[4]; // relative to model @@ -1934,7 +2535,7 @@ CAutomobile::Render(void) 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) { + 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) @@ -1945,75 +2546,146 @@ CAutomobile::Render(void) } } + RwRGBA hoverParticleCol = { 255, 255, 255, 32 }; + // Rear right wheel mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RB])); - pos.x = mat.GetPosition().x; - pos.y = mat.GetPosition().y; + pos = mat.GetPosition(); pos.z = m_aWheelPosition[CARWHEEL_REAR_RIGHT]; if(Damage.GetWheelStatus(CARWHEEL_REAR_RIGHT) == WHEEL_STATUS_BURST) mat.SetRotate(m_aWheelRotation[CARWHEEL_REAR_RIGHT], 0.0f, 0.3f*Sin(m_aWheelRotation[CARWHEEL_REAR_RIGHT])); else mat.SetRotateX(m_aWheelRotation[CARWHEEL_REAR_RIGHT]); - mat.Scale(mi->m_wheelScale); + if(GetStatus() == STATUS_PLAYER){ + if(bHoverCheat && m_aSuspensionSpringRatioPrev[CARWHEEL_REAR_RIGHT] < 1.0f && + m_aWheelColPoints[CARWHEEL_REAR_RIGHT].surfaceB == SURFACE_WATER){ + // hovering on water + mat.RotateY(-HALFPI); + if((CTimer::GetFrameCounter()+CARWHEEL_REAR_RIGHT) & 1){ + CParticle::AddParticle(PARTICLE_STEAM_NY_SLOWMOTION, m_aWheelColPoints[CARWHEEL_REAR_RIGHT].point, + 0.5f*m_vecMoveSpeed+0.1f*GetRight(), nil, 0.4f, hoverParticleCol); + }else{ + CParticle::AddParticle(PARTICLE_CAR_SPLASH, m_aWheelColPoints[CARWHEEL_REAR_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); + } + }else{ + // tilt wheel depending oh how much it presses on ground + float groundOffset = pos.z + m_fHeightAboveRoad - 0.5f*mi->m_wheelScale; + if(GetModelIndex() == MI_VOODOO) + groundOffset *= 0.6f; + mat.RotateY(Asin(clamp(-groundOffset, -1.0f, 1.0f))); + } + } + if(pHandling->Flags & HANDLING_FAT_REARW) + mat.Scale(1.15f*mi->m_wheelScale, mi->m_wheelScale, mi->m_wheelScale); + else + mat.Scale(mi->m_wheelScale); mat.Translate(pos); mat.UpdateRW(); - if(CVehicle::bWheelsOnlyCheat) - RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RB])); // Rear left wheel mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_LB])); - pos.x = mat.GetPosition().x; - pos.y = mat.GetPosition().y; + pos = mat.GetPosition(); pos.z = m_aWheelPosition[CARWHEEL_REAR_LEFT]; if(Damage.GetWheelStatus(CARWHEEL_REAR_LEFT) == WHEEL_STATUS_BURST) - mat.SetRotate(-m_aWheelRotation[CARWHEEL_REAR_LEFT], 0.0f, PI+0.3f*Sin(-m_aWheelRotation[CARWHEEL_REAR_LEFT])); + mat.SetRotate(-m_aWheelRotation[CARWHEEL_REAR_LEFT], 0.0f, PI+0.3f*Sin(m_aWheelRotation[CARWHEEL_REAR_LEFT])); else mat.SetRotate(-m_aWheelRotation[CARWHEEL_REAR_LEFT], 0.0f, PI); - mat.Scale(mi->m_wheelScale); + if(GetStatus() == STATUS_PLAYER){ + if(bHoverCheat && m_aSuspensionSpringRatioPrev[CARWHEEL_REAR_LEFT] < 1.0f && + m_aWheelColPoints[CARWHEEL_REAR_LEFT].surfaceB == SURFACE_WATER){ + // hovering on water + mat.RotateY(HALFPI); + if((CTimer::GetFrameCounter()+CARWHEEL_REAR_LEFT) & 1){ + CParticle::AddParticle(PARTICLE_STEAM_NY_SLOWMOTION, m_aWheelColPoints[CARWHEEL_REAR_LEFT].point, + 0.5f*m_vecMoveSpeed-0.1f*GetRight(), nil, 0.4f, hoverParticleCol); + }else{ + CParticle::AddParticle(PARTICLE_CAR_SPLASH, m_aWheelColPoints[CARWHEEL_REAR_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); + } + }else{ + // tilt wheel depending oh how much it presses on ground + float groundOffset = pos.z + m_fHeightAboveRoad - 0.5f*mi->m_wheelScale; + if(GetModelIndex() == MI_VOODOO) + groundOffset *= 0.6f; + mat.RotateY(Asin(clamp(groundOffset, -1.0f, 1.0f))); + } + } + if(pHandling->Flags & HANDLING_FAT_REARW) + mat.Scale(1.15f*mi->m_wheelScale, mi->m_wheelScale, mi->m_wheelScale); + else + mat.Scale(mi->m_wheelScale); mat.Translate(pos); mat.UpdateRW(); - if(CVehicle::bWheelsOnlyCheat) - RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LB])); // Mid right wheel if(m_aCarNodes[CAR_WHEEL_RM]){ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RM])); - pos.x = mat.GetPosition().x; - pos.y = mat.GetPosition().y; + pos = mat.GetPosition(); pos.z = m_aWheelPosition[CARWHEEL_REAR_RIGHT]; if(Damage.GetWheelStatus(CARWHEEL_REAR_RIGHT) == WHEEL_STATUS_BURST) mat.SetRotate(m_aWheelRotation[CARWHEEL_REAR_RIGHT], 0.0f, 0.3f*Sin(m_aWheelRotation[CARWHEEL_REAR_RIGHT])); else mat.SetRotateX(m_aWheelRotation[CARWHEEL_REAR_RIGHT]); - mat.Scale(mi->m_wheelScale); + if(GetStatus() == STATUS_PLAYER){ + if(bHoverCheat && m_aSuspensionSpringRatioPrev[CARWHEEL_REAR_RIGHT] < 1.0f && + m_aWheelColPoints[CARWHEEL_REAR_RIGHT].surfaceB == SURFACE_WATER){ + // hovering on water + mat.RotateY(-HALFPI); + }else{ + // tilt wheel depending oh how much it presses on ground + float groundOffset = pos.z + m_fHeightAboveRoad - 0.5f*mi->m_wheelScale; + if(GetModelIndex() == MI_VOODOO) + groundOffset *= 0.6f; + mat.RotateY(Asin(clamp(-groundOffset, -1.0f, 1.0f))); + } + } + if(pHandling->Flags & HANDLING_FAT_REARW) + mat.Scale(1.15f*mi->m_wheelScale, mi->m_wheelScale, mi->m_wheelScale); + else + mat.Scale(mi->m_wheelScale); mat.Translate(pos); mat.UpdateRW(); - if(CVehicle::bWheelsOnlyCheat) - RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RM])); } // Mid left wheel if(m_aCarNodes[CAR_WHEEL_LM]){ mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_LM])); - pos.x = mat.GetPosition().x; - pos.y = mat.GetPosition().y; + pos = mat.GetPosition(); pos.z = m_aWheelPosition[CARWHEEL_REAR_LEFT]; if(Damage.GetWheelStatus(CARWHEEL_REAR_LEFT) == WHEEL_STATUS_BURST) - mat.SetRotate(-m_aWheelRotation[CARWHEEL_REAR_LEFT], 0.0f, PI+0.3f*Sin(-m_aWheelRotation[CARWHEEL_REAR_LEFT])); + mat.SetRotate(-m_aWheelRotation[CARWHEEL_REAR_LEFT], 0.0f, PI+0.3f*Sin(m_aWheelRotation[CARWHEEL_REAR_LEFT])); else mat.SetRotate(-m_aWheelRotation[CARWHEEL_REAR_LEFT], 0.0f, PI); - mat.Scale(mi->m_wheelScale); + if(GetStatus() == STATUS_PLAYER){ + if(bHoverCheat && m_aSuspensionSpringRatioPrev[CARWHEEL_REAR_LEFT] < 1.0f && + m_aWheelColPoints[CARWHEEL_REAR_LEFT].surfaceB == SURFACE_WATER){ + // hovering on water + mat.RotateY(HALFPI); + }else{ + // tilt wheel depending oh how much it presses on ground + float groundOffset = pos.z + m_fHeightAboveRoad - 0.5f*mi->m_wheelScale; + if(GetModelIndex() == MI_VOODOO) + groundOffset *= 0.6f; + mat.RotateY(Asin(clamp(groundOffset, -1.0f, 1.0f))); + } + } + if(pHandling->Flags & HANDLING_FAT_REARW) + mat.Scale(1.15f*mi->m_wheelScale, mi->m_wheelScale, mi->m_wheelScale); + else + mat.Scale(mi->m_wheelScale); mat.Translate(pos); mat.UpdateRW(); - if(CVehicle::bWheelsOnlyCheat) - RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LM])); } if(GetModelIndex() == MI_DODO){ // Front wheel mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RF])); - pos.x = mat.GetPosition().x; - pos.y = mat.GetPosition().y; + pos = mat.GetPosition(); pos.z = m_aWheelPosition[CARWHEEL_FRONT_RIGHT]; if(Damage.GetWheelStatus(CARWHEEL_FRONT_RIGHT) == WHEEL_STATUS_BURST) mat.SetRotate(m_aWheelRotation[CARWHEEL_FRONT_RIGHT], 0.0f, m_fSteerAngle+0.3f*Sin(m_aWheelRotation[CARWHEEL_FRONT_RIGHT])); @@ -2022,8 +2694,6 @@ CAutomobile::Render(void) mat.Scale(mi->m_wheelScale); mat.Translate(pos); mat.UpdateRW(); - if(CVehicle::bWheelsOnlyCheat) - RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RF])); // Rotate propeller if(m_aCarNodes[CAR_WINDSCREEN]){ @@ -2053,59 +2723,130 @@ CAutomobile::Render(void) }else if(GetModelIndex() == MI_RHINO){ // Front right wheel mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RF])); - pos.x = mat.GetPosition().x; - pos.y = mat.GetPosition().y; + pos = mat.GetPosition(); pos.z = m_aWheelPosition[CARWHEEL_FRONT_RIGHT]; // no damaged wheels or steering mat.SetRotate(m_aWheelRotation[CARWHEEL_FRONT_RIGHT], 0.0f, 0.0f); mat.Scale(mi->m_wheelScale); mat.Translate(pos); mat.UpdateRW(); - if(CVehicle::bWheelsOnlyCheat) - RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RF])); // Front left wheel mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_LF])); - pos.x = mat.GetPosition().x; - pos.y = mat.GetPosition().y; + pos = mat.GetPosition(); pos.z = m_aWheelPosition[CARWHEEL_FRONT_LEFT]; // no damaged wheels or steering mat.SetRotate(-m_aWheelRotation[CARWHEEL_FRONT_LEFT], 0.0f, PI); mat.Scale(mi->m_wheelScale); mat.Translate(pos); mat.UpdateRW(); - if(CVehicle::bWheelsOnlyCheat) - RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LF])); + }else if(IsRealHeli()){ + // Top rotor + if(m_aCarNodes[CAR_BONNET]){ + mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_BONNET])); + pos = mat.GetPosition(); + mat.SetRotateZ(m_aWheelRotation[1]); + mat.Translate(pos); + mat.UpdateRW(); + } + // Blurred top rotor + if(m_aCarNodes[CAR_WINDSCREEN]){ + mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WINDSCREEN])); + pos = mat.GetPosition(); + mat.SetRotateZ(-m_aWheelRotation[1]); + mat.Translate(pos); + mat.UpdateRW(); + } + // Rear rotor + if(m_aCarNodes[CAR_BOOT]){ + mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_BOOT])); + pos = mat.GetPosition(); + mat.SetRotateX(m_aWheelRotation[3]); + mat.Translate(pos); + mat.UpdateRW(); + } + // Blurred rear rotor + if(m_aCarNodes[CAR_BUMP_REAR]){ + mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_BUMP_REAR])); + pos = mat.GetPosition(); + mat.SetRotateX(-m_aWheelRotation[3]); + mat.Translate(pos); + mat.UpdateRW(); + } }else{ // Front right wheel mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_RF])); - pos.x = mat.GetPosition().x; - pos.y = mat.GetPosition().y; + pos = mat.GetPosition(); pos.z = m_aWheelPosition[CARWHEEL_FRONT_RIGHT]; if(Damage.GetWheelStatus(CARWHEEL_FRONT_RIGHT) == WHEEL_STATUS_BURST) mat.SetRotate(m_aWheelRotation[CARWHEEL_FRONT_RIGHT], 0.0f, m_fSteerAngle+0.3f*Sin(m_aWheelRotation[CARWHEEL_FRONT_RIGHT])); else mat.SetRotate(m_aWheelRotation[CARWHEEL_FRONT_RIGHT], 0.0f, m_fSteerAngle); - mat.Scale(mi->m_wheelScale); + if(GetStatus() == STATUS_PLAYER){ + if(bHoverCheat && m_aSuspensionSpringRatioPrev[CARWHEEL_FRONT_RIGHT] < 1.0f && + m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].surfaceB == SURFACE_WATER){ + // hovering on water + mat.RotateY(-HALFPI); + if((CTimer::GetFrameCounter()+CARWHEEL_FRONT_RIGHT) & 1){ + CParticle::AddParticle(PARTICLE_STEAM_NY_SLOWMOTION, m_aWheelColPoints[CARWHEEL_FRONT_RIGHT].point, + 0.5f*m_vecMoveSpeed+0.1f*GetRight(), nil, 0.4f, hoverParticleCol); + }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); + } + }else{ + // tilt wheel depending oh how much it presses on ground + float groundOffset = pos.z + m_fHeightAboveRoad - 0.5f*mi->m_wheelScale; + if(GetModelIndex() == MI_VOODOO) + groundOffset *= 0.6f; + mat.RotateY(Asin(clamp(-groundOffset, -1.0f, 1.0f))); + } + } + if(pHandling->Flags & HANDLING_NARROW_FRONTW) + mat.Scale(0.7f*mi->m_wheelScale, mi->m_wheelScale, mi->m_wheelScale); + else + mat.Scale(mi->m_wheelScale); mat.Translate(pos); mat.UpdateRW(); - if(CVehicle::bWheelsOnlyCheat) - RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RF])); // Front left wheel mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WHEEL_LF])); - pos.x = mat.GetPosition().x; - pos.y = mat.GetPosition().y; + pos = mat.GetPosition(); pos.z = m_aWheelPosition[CARWHEEL_FRONT_LEFT]; if(Damage.GetWheelStatus(CARWHEEL_FRONT_LEFT) == WHEEL_STATUS_BURST) - mat.SetRotate(-m_aWheelRotation[CARWHEEL_FRONT_LEFT], 0.0f, PI+m_fSteerAngle+0.3f*Sin(-m_aWheelRotation[CARWHEEL_FRONT_LEFT])); + mat.SetRotate(-m_aWheelRotation[CARWHEEL_FRONT_LEFT], 0.0f, PI+m_fSteerAngle+0.3f*Sin(m_aWheelRotation[CARWHEEL_FRONT_LEFT])); else mat.SetRotate(-m_aWheelRotation[CARWHEEL_FRONT_LEFT], 0.0f, PI+m_fSteerAngle); - mat.Scale(mi->m_wheelScale); + if(GetStatus() == STATUS_PLAYER){ + if(bHoverCheat && m_aSuspensionSpringRatioPrev[CARWHEEL_FRONT_LEFT] < 1.0f && + m_aWheelColPoints[CARWHEEL_FRONT_LEFT].surfaceB == SURFACE_WATER){ + // hovering on water + mat.RotateY(HALFPI); + if((CTimer::GetFrameCounter()+CARWHEEL_FRONT_LEFT) & 1){ + CParticle::AddParticle(PARTICLE_STEAM_NY_SLOWMOTION, m_aWheelColPoints[CARWHEEL_FRONT_LEFT].point, + 0.5f*m_vecMoveSpeed-0.1f*GetRight(), nil, 0.4f, hoverParticleCol); + }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); + } + }else{ + // tilt wheel depending oh how much it presses on ground + float groundOffset = pos.z + m_fHeightAboveRoad - 0.5f*mi->m_wheelScale; + if(GetModelIndex() == MI_VOODOO) + groundOffset *= 0.6f; + mat.RotateY(Asin(clamp(groundOffset, -1.0f, 1.0f))); + } + } + if(pHandling->Flags & HANDLING_NARROW_FRONTW) + mat.Scale(0.7f*mi->m_wheelScale, mi->m_wheelScale, mi->m_wheelScale); + else + mat.Scale(mi->m_wheelScale); mat.Translate(pos); mat.UpdateRW(); - if(CVehicle::bWheelsOnlyCheat) - RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LF])); ProcessSwingingDoor(CAR_DOOR_LF, DOOR_FRONT_LEFT); ProcessSwingingDoor(CAR_DOOR_RF, DOOR_FRONT_RIGHT); @@ -2113,15 +2854,107 @@ CAutomobile::Render(void) ProcessSwingingDoor(CAR_DOOR_RR, DOOR_REAR_RIGHT); ProcessSwingingDoor(CAR_BONNET, DOOR_BONNET); ProcessSwingingDoor(CAR_BOOT, DOOR_BOOT); - - mi->SetVehicleColour(m_currentColour1, m_currentColour2); } - if(!CVehicle::bWheelsOnlyCheat) + if((GetModelIndex() == MI_PHEONIX || GetModelIndex() == MI_BFINJECT) && + GetStatus() == STATUS_PLAYER && m_aCarNodes[CAR_WING_LR]){ + float rotation = 0.0f; + + if(GetModelIndex() == MI_BFINJECT) + if(m_fPropellerRotation > TWOPI) m_fPropellerRotation -= TWOPI; + + if(Abs(m_fGasPedal) > 0.0f){ + if(GetModelIndex() == MI_BFINJECT){ + m_fPropellerRotation += 0.2f*CTimer::GetTimeStep(); + rotation = m_fPropellerRotation; + }else{ + if(m_fPropellerRotation < 1.3f){ + m_fPropellerRotation = Min(m_fPropellerRotation+0.1f*CTimer::GetTimeStep(), 1.3f); + rotation = m_fPropellerRotation; + }else{ + float wave = Sin((CTimer::GetTimeInMilliseconds()%10000)/70.0f); + rotation = m_fPropellerRotation + 0.13*wave; + } + } + }else{ + if(GetModelIndex() == MI_BFINJECT){ + m_fPropellerRotation += 0.1f*CTimer::GetTimeStep(); + rotation = m_fPropellerRotation; + }else{ + if(m_fPropellerRotation > 0.0f){ + m_fPropellerRotation = Max(m_fPropellerRotation-0.05f*CTimer::GetTimeStep(), 0.0f); + rotation = m_fPropellerRotation; + } + } + } + + mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WING_LR])); + pos = mat.GetPosition(); + if(GetModelIndex() == MI_BFINJECT) + mat.SetRotateY(rotation); + else + mat.SetRotateX(rotation); + mat.Translate(pos); + mat.UpdateRW(); + } +} + +void +CAutomobile::Render(void) +{ + CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex()); + + mi->SetVehicleColour(m_currentColour1, m_currentColour2); + + if(IsRealHeli()){ + RpAtomic *atomic = nil; + int rotorAlpha = (1.5f - Min(1.7f*Max(m_aWheelSpeed[1],0.0f)/0.22f, 1.5f))*255.0f; + rotorAlpha = Min(rotorAlpha, 255); + int blurAlpha = Max(1.5f*m_aWheelSpeed[1]/0.22f - 0.4f, 0.0f)*150.0f; + blurAlpha = Min(blurAlpha, 150); + + // Top rotor + if(m_aCarNodes[CAR_BONNET]){ + RwFrameForAllObjects(m_aCarNodes[CAR_BONNET], GetCurrentAtomicObjectCB, &atomic); + if(atomic) + SetComponentAtomicAlpha(atomic, rotorAlpha); + } + atomic = nil; + // Rear rotor + if(m_aCarNodes[CAR_BOOT]){ + RwFrameForAllObjects(m_aCarNodes[CAR_BOOT], GetCurrentAtomicObjectCB, &atomic); + if(atomic) + SetComponentAtomicAlpha(atomic, rotorAlpha); + } + atomic = nil; + // Blurred top rotor + if(m_aCarNodes[CAR_WINDSCREEN]){ + RwFrameForAllObjects(m_aCarNodes[CAR_WINDSCREEN], GetCurrentAtomicObjectCB, &atomic); + if(atomic) + SetComponentAtomicAlpha(atomic, blurAlpha); + } + atomic = nil; + // Blurred rear rotor + if(m_aCarNodes[CAR_BUMP_REAR]){ + RwFrameForAllObjects(m_aCarNodes[CAR_BUMP_REAR], GetCurrentAtomicObjectCB, &atomic); + if(atomic) + SetComponentAtomicAlpha(atomic, blurAlpha); + } + } + + if(CVehicle::bWheelsOnlyCheat){ + RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RB])); + RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LB])); + RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RF])); + RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LF])); + if(m_aCarNodes[CAR_WHEEL_RM]) + RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_RM])); + if(m_aCarNodes[CAR_WHEEL_LM]) + RpAtomicRender((RpAtomic*)GetFirstObject(m_aCarNodes[CAR_WHEEL_LM])); + }else CEntity::Render(); } -//--MIAMI: done int32 CAutomobile::ProcessEntityCollision(CEntity *ent, CColPoint *colpoints) { @@ -2198,10 +3031,12 @@ CAutomobile::ProcessControlInputs(uint8 pad) { float speed = DotProduct(m_vecMoveSpeed, GetForward()); - if(CPad::GetPad(pad)->GetExitVehicle()) - bIsHandbrakeOn = true; - else + if(!CPad::GetPad(pad)->GetExitVehicle() || + pDriver && pDriver->m_pVehicleAnim && (pDriver->m_pVehicleAnim->animId == ANIM_CAR_ROLLOUT_LHS || + pDriver->m_pVehicleAnim->animId == ANIM_CAR_ROLLOUT_LHS2)) bIsHandbrakeOn = !!CPad::GetPad(pad)->GetHandBrake(); + else + bIsHandbrakeOn = true; // Steer left/right if(CCamera::m_bUseMouse3rdPerson && !CVehicle::m_bDisableMouseSteering){ @@ -2229,8 +3064,14 @@ CAutomobile::ProcessControlInputs(uint8 pad) acceleration *= 0.3f; if(Abs(speed) < 0.01f){ // standing still, go into direction we want - m_fGasPedal = acceleration; - m_fBrakePedal = 0.0f; + 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 @@ -2460,7 +3301,7 @@ CAutomobile::TankControl(void) float f = i/15.0f; CParticle::AddParticle(PARTICLE_GUNSMOKE2, point1, shotDir*CGeneral::GetRandomNumberInRange(0.3f, 1.0f)*f, - nil, CGeneral::GetRandomNumberInRange(0.5f, 1.0f)*f, black); + nil, CGeneral::GetRandomNumberInRange(0.5f, 1.5f)*f, black); } // And some gun flashes near the gun @@ -2478,20 +3319,11 @@ CAutomobile::TankControl(void) flashPos += 0.1f*shotDir; CParticle::AddParticle(PARTICLE_GUNFLASH, flashPos, nullDir, nil, 0.15f, black, 0, 0, 0, lifeSpan); } - - // Actually update turret node - if(m_aCarNodes[CAR_WINDSCREEN]){ - CMatrix mat; - CVector pos; - - mat.Attach(RwFrameGetMatrix(m_aCarNodes[CAR_WINDSCREEN])); - pos = mat.GetPosition(); - mat.SetRotateZ(m_fCarGunLR); - mat.Translate(pos); - mat.UpdateRW(); - } } +#define HYDRAULIC_UPPER_EXT (-0.16f) +#define HYDRAULIC_LOWER_EXT (0.16f) + void CAutomobile::HydraulicControl(void) { @@ -2554,8 +3386,8 @@ CAutomobile::HydraulicControl(void) m_hydraulicState = 20; else{ m_hydraulicState = 0; - normalUpperLimit += -0.12f; - normalSpringLength = normalUpperLimit - (normalLowerLimit+0.14f); + normalUpperLimit += HYDRAULIC_UPPER_EXT; + normalSpringLength = normalUpperLimit - (normalLowerLimit+HYDRAULIC_LOWER_EXT); DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_2, 0.0f); } @@ -2588,7 +3420,7 @@ CAutomobile::HydraulicControl(void) float radius = Max(specialColModel->boundingBox.min.Magnitude(), specialColModel->boundingBox.max.Magnitude()); if(specialColModel->boundingSphere.radius < radius) specialColModel->boundingSphere.radius = radius; - + return; } if(playerInfo->m_WBState != WBSTATE_PLAYING) @@ -2627,8 +3459,8 @@ CAutomobile::HydraulicControl(void) if(m_hydraulicState < 100){ if(m_hydraulicState == 0){ - normalUpperLimit += -0.12f; - normalLowerLimit += 0.14f; + normalUpperLimit += HYDRAULIC_UPPER_EXT; + normalLowerLimit += HYDRAULIC_LOWER_EXT; normalSpringLength = normalUpperLimit - normalLowerLimit; } @@ -2673,7 +3505,6 @@ CAutomobile::HydraulicControl(void) } setPrevRatio = true; - m_aWheelPosition[i] -= 0.05f; } DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_2, 0.0f); } @@ -2693,8 +3524,8 @@ CAutomobile::HydraulicControl(void) // Lowered, move wheels up if(m_hydraulicState == 0){ - normalUpperLimit += -0.12f; - normalLowerLimit += 0.14f; + normalUpperLimit += HYDRAULIC_UPPER_EXT; + normalLowerLimit += HYDRAULIC_LOWER_EXT; normalSpringLength = normalUpperLimit - normalLowerLimit; } @@ -2704,7 +3535,6 @@ CAutomobile::HydraulicControl(void) if(suspChange[i] > 1.0f) suspChange[i] = 1.0f; - float oldZ = specialColModel->lines[i].p1.z; float upperLimit = suspChange[i]*(extendedUpperLimit-normalUpperLimit) + normalUpperLimit; float springLength = suspChange[i]*(extendedSpringLength-normalSpringLength) + normalSpringLength; float lineLength = springLength + wheelRadius; @@ -2724,19 +3554,15 @@ CAutomobile::HydraulicControl(void) m_aSuspensionSpringRatio[i] = (specialColModel->lines[i].p0.z - wheelPositions[i])/m_aSuspensionLineLength[i]; if(m_aSuspensionSpringRatio[i] > 1.0f) m_aSuspensionSpringRatio[i] = 1.0f; - m_aWheelPosition[i] -= (oldZ - specialColModel->lines[i].p1.z)*0.3f; } } }else{ - if(m_hydraulicState < 104){ + if(m_hydraulicState < 104) m_hydraulicState++; - for(i = 0; i < 4; i++) - m_aWheelPosition[i] -= 0.1f; - } if(m_fVelocityChangeForAudio < 0.1f){ - normalUpperLimit += -0.12f; - normalLowerLimit += 0.14f; + normalUpperLimit += HYDRAULIC_UPPER_EXT; + normalLowerLimit += HYDRAULIC_LOWER_EXT; normalSpringLength = normalUpperLimit - normalLowerLimit; } @@ -2958,7 +3784,6 @@ CAutomobile::ProcessBuoyancy(void) } } -//--MIAMI: done void CAutomobile::DoDriveByShootings(void) { @@ -3039,7 +3864,6 @@ CAutomobile::DoDriveByShootings(void) } } -//--MIAMI: done void CAutomobile::DoHoverSuspensionRatios(void) { @@ -3078,7 +3902,6 @@ CAutomobile::DoHoverSuspensionRatios(void) } } -//--MIAMI: done int32 CAutomobile::RcbanditCheckHitWheels(void) { @@ -3106,7 +3929,6 @@ CAutomobile::RcbanditCheckHitWheels(void) return 0; } -//--MIAMI: done int32 CAutomobile::RcbanditCheck1CarWheels(CPtrList &list) { @@ -3145,7 +3967,6 @@ CAutomobile::RcbanditCheck1CarWheels(CPtrList &list) return 0; } -//--MIAMI: done void CAutomobile::PlaceOnRoadProperly(void) { @@ -3191,7 +4012,6 @@ CAutomobile::PlaceOnRoadProperly(void) GetMatrix().GetPosition() = CVector((front.x + rear.x) / 2.0f, (front.y + rear.y) / 2.0f, (frontZ + rearZ) / 2.0f + GetHeightAboveRoad()); } -//--MIAMI: done void CAutomobile::VehicleDamage(float impulse, uint16 damagedPiece) { @@ -3427,7 +4247,6 @@ CAutomobile::VehicleDamage(float impulse, uint16 damagedPiece) } } -//--MIAMI: done void CAutomobile::dmgDrawCarCollidingParticles(const CVector &pos, float amount) { @@ -3467,7 +4286,6 @@ CAutomobile::dmgDrawCarCollidingParticles(const CVector &pos, float amount) CGeneral::GetRandomNumberInRange(0.0f, 4.0f)); } -//--MIAMI: done void CAutomobile::AddDamagedVehicleParticles(void) { @@ -3567,7 +4385,6 @@ CAutomobile::AddDamagedVehicleParticles(void) } } -//--MIAMI: done int32 CAutomobile::AddWheelDirtAndWater(CColPoint *colpoint, uint32 belowEffectSpeed) { @@ -3648,7 +4465,6 @@ CAutomobile::AddWheelDirtAndWater(CColPoint *colpoint, uint32 belowEffectSpeed) } } -//--MIAMI: done void CAutomobile::GetComponentWorldPosition(int32 component, CVector &pos) { @@ -3660,14 +4476,12 @@ CAutomobile::GetComponentWorldPosition(int32 component, CVector &pos) pos = *RwMatrixGetPos(ltm); } -//--MIAMI: done bool CAutomobile::IsComponentPresent(int32 comp) { return m_aCarNodes[comp] != nil; } -//--MIAMI: done void CAutomobile::SetComponentRotation(int32 component, CVector rotation) { @@ -3681,7 +4495,6 @@ CAutomobile::SetComponentRotation(int32 component, CVector rotation) mat.UpdateRW(); } -//--MIAMI: done void CAutomobile::OpenDoor(int32 component, eDoors door, float openRatio) { @@ -3759,7 +4572,6 @@ inline void ProcessDoorOpenCloseAnimation(CAutomobile *car, uint32 component, eD } } -//--MIAMI: done void CAutomobile::ProcessOpenDoor(uint32 component, uint32 anim, float time) { @@ -3831,7 +4643,6 @@ CAutomobile::ProcessOpenDoor(uint32 component, uint32 anim, float time) } } -//--MIAMI: done bool CAutomobile::IsDoorReady(eDoors door) { @@ -3848,28 +4659,24 @@ CAutomobile::IsDoorReady(eDoors door) return (doorflag & m_nGettingInFlags) == 0; } -//--MIAMI: done bool CAutomobile::IsDoorFullyOpen(eDoors door) { return Doors[door].IsFullyOpen() || IsDoorMissing(door); } -//--MIAMI: done bool CAutomobile::IsDoorClosed(eDoors door) { return !!Doors[door].IsClosed(); } -//--MIAMI: done bool CAutomobile::IsDoorMissing(eDoors door) { return Damage.GetDoorStatus(door) == DOOR_STATUS_MISSING; } -//--MIAMI: done bool CAutomobile::IsDoorReady(uint32 door) { @@ -3883,7 +4690,6 @@ CAutomobile::IsDoorReady(uint32 door) } } -//--MIAMI: done bool CAutomobile::IsDoorMissing(uint32 door) { @@ -3897,7 +4703,6 @@ CAutomobile::IsDoorMissing(uint32 door) } } -//--MIAMI: done bool CAutomobile::IsOpenTopCar(void) { @@ -3907,7 +4712,6 @@ CAutomobile::IsOpenTopCar(void) GetModelIndex() == MI_STALLION && m_aExtras[0] != 0 && m_aExtras[1] != 0; } -//--MIAMI: done void CAutomobile::RemoveRefsToVehicle(CEntity *ent) { @@ -3917,7 +4721,6 @@ CAutomobile::RemoveRefsToVehicle(CEntity *ent) m_aGroundPhysical[i] = nil; } -//--MIAMI void CAutomobile::BlowUpCar(CEntity *culprit) { @@ -3985,7 +4788,6 @@ CAutomobile::BlowUpCar(CEntity *culprit) CExplosion::AddExplosion(this, culprit, EXPLOSION_CAR, GetPosition(), 0); } -//--MIAMI: done bool CAutomobile::SetUpWheelColModel(CColModel *colModel) { @@ -4021,7 +4823,6 @@ CAutomobile::SetUpWheelColModel(CColModel *colModel) return true; } -//--MIAMI: done void CAutomobile::BurstTyre(uint8 wheel, bool applyForces) { @@ -4055,7 +4856,6 @@ CAutomobile::BurstTyre(uint8 wheel, bool applyForces) } } -//--MIAMI: done bool CAutomobile::IsRoomForPedToLeaveCar(uint32 component, CVector *doorOffset) { @@ -4118,20 +4918,18 @@ CAutomobile::IsRoomForPedToLeaveCar(uint32 component, CVector *doorOffset) return true; } -//-MIAMI: done float CAutomobile::GetHeightAboveRoad(void) { return m_fHeightAboveRoad; } -//-MIAMI: done void CAutomobile::PlayCarHorn(void) { int r; - if (IsAlarmOn() || GetStatus() == STATUS_WRECKED || m_nCarHornTimer != 0) + if (IsAlarmOn() || m_nCarHornTimer != 0) return; if (m_nCarHornDelay) { @@ -4153,7 +4951,6 @@ CAutomobile::PlayCarHorn(void) } } -//--MIAMI: done void CAutomobile::PlayHornIfNecessary(void) { @@ -4163,7 +4960,6 @@ CAutomobile::PlayHornIfNecessary(void) PlayCarHorn(); } -//--MIAMI: done void CAutomobile::ResetSuspension(void) { @@ -4176,7 +4972,6 @@ CAutomobile::ResetSuspension(void) } } -//--MIAMI: done void CAutomobile::SetupSuspensionLines(void) { @@ -4226,7 +5021,6 @@ CAutomobile::SetupSuspensionLines(void) } } -//--MIAMI: done // called on police cars void CAutomobile::ScanForCrimes(void) @@ -4238,7 +5032,6 @@ CAutomobile::ScanForCrimes(void) CWorld::Players[CWorld::PlayerInFocus].m_pPed->SetWantedLevelNoDrop(1); } -//--MIAMI: done void CAutomobile::BlowUpCarsInPath(void) { @@ -4256,7 +5049,6 @@ CAutomobile::BlowUpCarsInPath(void) } } -//--MIAMI: done bool CAutomobile::HasCarStoppedBecauseOfLight(void) { @@ -4288,7 +5080,6 @@ CAutomobile::HasCarStoppedBecauseOfLight(void) return false; } -//--MIAMI: done void CAutomobile::SetBusDoorTimer(uint32 timer, uint8 type) { @@ -4303,7 +5094,6 @@ CAutomobile::SetBusDoorTimer(uint32 timer, uint8 type) m_nBusDoorTimerEnd = m_nBusDoorTimerStart + timer; } -//--MIAMI: done void CAutomobile::ProcessAutoBusDoors(void) { @@ -4343,7 +5133,6 @@ CAutomobile::ProcessAutoBusDoors(void) } } -//--MIAMI: done void CAutomobile::ProcessSwingingDoor(int32 component, eDoors door) { @@ -4382,7 +5171,6 @@ CAutomobile::ProcessSwingingDoor(int32 component, eDoors door) } } -//--MIAMI: done void CAutomobile::Fix(void) { @@ -4422,7 +5210,6 @@ CAutomobile::Fix(void) } } -//--MIAMI: done void CAutomobile::SetupDamageAfterLoad(void) { @@ -4452,7 +5239,6 @@ CAutomobile::SetupDamageAfterLoad(void) SetPanelDamage(CAR_WING_RR, VEHPANEL_REAR_RIGHT); } -//--MIAMI: done RwObject* GetCurrentAtomicObjectCB(RwObject *object, void *data) { @@ -4463,7 +5249,6 @@ GetCurrentAtomicObjectCB(RwObject *object, void *data) return object; } -//--MIAMI: done CObject* CAutomobile::SpawnFlyingComponent(int32 component, uint32 type) { @@ -4602,7 +5387,6 @@ CAutomobile::SpawnFlyingComponent(int32 component, uint32 type) return obj; } -//--MIAMI: done CObject* CAutomobile::RemoveBonnetInPedCollision(void) { @@ -4623,7 +5407,6 @@ CAutomobile::RemoveBonnetInPedCollision(void) return nil; } -//--MIAMI:: done void CAutomobile::SetPanelDamage(int32 component, ePanels panel, bool noFlyingComponents) { @@ -4645,7 +5428,6 @@ CAutomobile::SetPanelDamage(int32 component, ePanels panel, bool noFlyingCompone } } -//--MIAMI: done void CAutomobile::SetBumperDamage(int32 component, ePanels panel, bool noFlyingComponents) { @@ -4666,7 +5448,6 @@ CAutomobile::SetBumperDamage(int32 component, ePanels panel, bool noFlyingCompon } } -//--MIAMI: done void CAutomobile::SetDoorDamage(int32 component, eDoors door, bool noFlyingComponents) { @@ -4712,7 +5493,6 @@ CAutomobile::SetDoorDamage(int32 component, eDoors door, bool noFlyingComponents } -//--MIAMI: done static RwObject* SetVehicleAtomicVisibilityCB(RwObject *object, void *data) { @@ -4725,7 +5505,6 @@ SetVehicleAtomicVisibilityCB(RwObject *object, void *data) return object; } -//--MIAMI: done void CAutomobile::SetComponentVisibility(RwFrame *frame, uint32 flags) { @@ -4734,7 +5513,6 @@ CAutomobile::SetComponentVisibility(RwFrame *frame, uint32 flags) RwFrameForAllObjects(frame, SetVehicleAtomicVisibilityCB, (void*)flags); } -//--MIAMI: done void CAutomobile::SetupModelNodes(void) { @@ -4744,14 +5522,12 @@ CAutomobile::SetupModelNodes(void) CClumpModelInfo::FillFrameArray((RpClump*)m_rwObject, m_aCarNodes); } -//--MIAMI: done void CAutomobile::SetTaxiLight(bool light) { bTaxiLight = light; } -//--MIAMI: done bool CAutomobile::GetAllWheelsOffGround(void) { @@ -4770,7 +5546,6 @@ CAutomobile::ShowAllComps(void) // empty } -//--MIAMI: done void CAutomobile::ReduceHornCounter(void) { @@ -4793,10 +5568,27 @@ CAutomobile::TellHeliToGoToCoors(float x, float y, float z, uint8 speed) AutoPilot.m_vecDestinationCoors.z = z; AutoPilot.m_nCruiseSpeed = speed; SetStatus(STATUS_PHYSICS); - //TODO(MIAMI) + + if(m_fOrientation == 0.0f){ + m_fOrientation = CGeneral::GetATanOfXY(GetForward().x, GetForward().y) + TWOPI; + while(m_fOrientation > TWOPI) m_fOrientation -= TWOPI; + } +} + +void +CAutomobile::TellPlaneToGoToCoors(float x, float y, float z, uint8 speed) +{ + AutoPilot.m_nCarMission = MISSION_HELI_FLYTOCOORS; + AutoPilot.m_vecDestinationCoors.x = x; + AutoPilot.m_vecDestinationCoors.y = y; + AutoPilot.m_vecDestinationCoors.z = z; + AutoPilot.m_nCruiseSpeed = speed; + SetStatus(STATUS_PHYSICS); + + if(m_fOrientation == 0.0f) + m_fOrientation = CGeneral::GetATanOfXY(GetForward().x, GetForward().y); } -//--MIAMI: done void CAutomobile::PopBoot(void) { @@ -4814,7 +5606,6 @@ CAutomobile::PopBoot(void) } } -//--MIAMI: done void CAutomobile::PopBootUsingPhysics(void) { @@ -4825,7 +5616,6 @@ CAutomobile::PopBootUsingPhysics(void) Doors[DOOR_BOOT].m_fAngle = -2.0f; } -//--MIAMI: done void CAutomobile::CloseAllDoors(void) { @@ -4844,6 +5634,48 @@ CAutomobile::CloseAllDoors(void) } } +void +CAutomobile::KnockPedOutCar(eWeaponType weapon, uint16 door, CPed *ped) +{ + AnimationId anim = ANIM_KO_SHOT_FRONT1; + if(ped == nil) + return; + + ped->m_vehEnterType = door; + ped->SetPedState(PED_IDLE); + CAnimManager::BlendAnimation(ped->GetClump(), ped->m_animGroup, ANIM_IDLE_STANCE, 100.0f); + CPed::PedSetOutCarCB(nil, ped); + ped->SetMoveState(PEDMOVE_STILL); + if(GetUp().z < 0.0f) + ped->SetHeading(CGeneral::LimitRadianAngle(GetForward().Heading() + PI)); + else + ped->SetHeading(GetForward().Heading()); + + switch(weapon){ + case WEAPONTYPE_UNARMED: + case WEAPONTYPE_UNIDENTIFIED: + ped->m_vecMoveSpeed = m_vecMoveSpeed; + ped->m_pCollidingEntity = this; + anim = NUM_STD_ANIMS; + break; + + case WEAPONTYPE_BASEBALLBAT: + case WEAPONTYPE_RAMMEDBYCAR: + case WEAPONTYPE_FALL: + ped->m_vecMoveSpeed = m_vecMoveSpeed; + anim = ANIM_KD_LEFT; + ApplyMoveForce(4.0f*GetUp() + 8.0f*GetRight()); + break; + } + + if(weapon != WEAPONTYPE_UNARMED){ + ped->SetFall(1000, anim, 0); + ped->bIsStanding = false; + ped->m_headingRate = 0.0f; + } + ped->m_pMyVehicle = nil; +} + #ifdef COMPATIBLE_SAVES void CAutomobile::Save(uint8*& buf) diff --git a/src/vehicles/Automobile.h b/src/vehicles/Automobile.h index e9837a3b..9d24d237 100644 --- a/src/vehicles/Automobile.h +++ b/src/vehicles/Automobile.h @@ -3,6 +3,7 @@ #include "Vehicle.h" #include "DamageManager.h" #include "Door.h" +#include "Skidmarks.h" class CObject; @@ -76,13 +77,14 @@ public: float m_aSuspensionSpringRatio[4]; float m_aSuspensionSpringRatioPrev[4]; float m_aWheelTimer[4]; // set to 4.0 when wheel is touching ground, then decremented - float field_49C; - bool m_aWheelSkidmarkMuddy[4]; + float m_auto_unused1; + eSkidmarkType m_aWheelSkidmarkType[4]; bool m_aWheelSkidmarkBloody[4]; + bool m_aWheelSkidmarkUnk[4]; float m_aWheelRotation[4]; float m_aWheelPosition[4]; float m_aWheelSpeed[4]; - uint8 field_4D8; + uint8 m_auto_unused2; uint8 bTaxiLight : 1; uint8 bFixedColour : 1; uint8 bBigWheels : 1; @@ -90,7 +92,9 @@ public: uint8 bNotDamagedUpsideDown : 1; uint8 bMoreResistantToDamage : 1; uint8 bTankDetonateCars : 1; - int16 field_4E0; + uint8 bStuckInSand : 1; + uint8 bHeliDestroyed : 1; + int16 m_doingBurnout; uint16 m_hydraulicState; uint32 m_nBusDoorTimerEnd; uint32 m_nBusDoorTimerStart; @@ -98,6 +102,9 @@ public: float m_aSuspensionLineLength[4]; float m_fHeightAboveRoad; float m_fTraction; + float m_fTireTemperature; + float m_fOrientation; // for heli and plane go-to + float m_auto_unk4; // related to the above float m_fVelocityChangeForAudio; float m_randomValues[6]; // used for what? float m_fFireBlowUpTimer; @@ -183,6 +190,7 @@ public: void SetDoorDamage(int32 component, eDoors door, bool noFlyingComponents = false); void TellHeliToGoToCoors(float x, float y, float z, uint8 speed); + void TellPlaneToGoToCoors(float x, float y, float z, uint8 speed); void SetHeliOrientation(float orient) { m_fHeliOrientation = orient; } void ClearHeliOrientation(void) { m_fHeliOrientation = -1.0f; } @@ -198,6 +206,7 @@ public: void PopBoot(void); void PopBootUsingPhysics(void); void CloseAllDoors(void); + void KnockPedOutCar(eWeaponType weapon, uint16 door, CPed *ped); #ifdef COMPATIBLE_SAVES virtual void Save(uint8*& buf); diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp index 17364013..88f15ffd 100644 --- a/src/vehicles/Vehicle.cpp +++ b/src/vehicles/Vehicle.cpp @@ -42,6 +42,7 @@ bool CVehicle::bCheat5; bool CVehicle::bAltDodoCheat; #endif bool CVehicle::bHoverCheat; +bool CVehicle::bAllTaxisHaveNitro; bool CVehicle::m_bDisableMouseSteering = true; bool CVehicle::bDisableRemoteDetonation; bool CVehicle::bDisableRemoteDetonationOnContact; @@ -126,7 +127,7 @@ CVehicle::CVehicle(uint8 CreatedBy) bCreatedAsPoliceVehicle = false; bRestingOnPhysical = false; bParking = false; - bCanPark = CGeneral::GetRandomNumberInRange(0.0f, 1.0f) < 0.0f; // BUG? this makes no sense + bCanPark = CGeneral::GetRandomNumberInRange(0.0f, 1.0f) < 0.0f; // never true. probably doesn't work very well bIsVan = false; bIsBus = false; bIsBig = false; @@ -345,7 +346,7 @@ CVehicle::FlyingControl(eFlightModel flightModel) // thrust float fForwSpeed = DotProduct(GetMoveSpeed(), GetForward()); - CVector vecWidthForward = GetColModel()->boundingBox.min.y * GetForward(); + CVector vecTail = GetColModel()->boundingBox.min.y * GetForward(); float fThrust = (CPad::GetPad(0)->GetAccelerate() - CPad::GetPad(0)->GetBrake()) / 255.0f; float fThrustAccel; if(fForwSpeed > 0.0f || fThrust > 0.0f) @@ -363,9 +364,9 @@ CVehicle::FlyingControl(eFlightModel flightModel) float fSideSlipAccel = pFlyingHandling->fSideSlip * fSideSpeed * Abs(fSideSpeed); ApplyMoveForce(m_fMass * GetRight() * fSideSlipAccel * CTimer::GetTimeStep()); - float fYaw = -DotProduct(GetSpeed(vecWidthForward), GetRight()); + float fYaw = -DotProduct(GetSpeed(vecTail), GetRight()); float fYawAccel = pFlyingHandling->fYawStab * fYaw * Abs(fYaw) + pFlyingHandling->fYaw * fSteerLR * fForwSpeed; - ApplyTurnForce(fYawAccel * GetRight() * m_fTurnMass * CTimer::GetTimeStep(), vecWidthForward); + ApplyTurnForce(fYawAccel * GetRight() * m_fTurnMass * CTimer::GetTimeStep(), vecTail); float fRollAccel; if (flightModel == FLIGHT_MODEL_RCPLANE) { @@ -385,9 +386,9 @@ CVehicle::FlyingControl(eFlightModel flightModel) ApplyTurnForce(fStabiliseSpeed * m_fTurnMass * GetRight(), GetUp()); // no CTimer::GetTimeStep(), is it right? // up/down - float fTail = -DotProduct(GetSpeed(vecWidthForward), GetUp()); + float fTail = -DotProduct(GetSpeed(vecTail), GetUp()); float fPitchAccel = pFlyingHandling->fPitchStab * fTail * Abs(fTail) + pFlyingHandling->fPitch * fSteerUD * fForwSpeed; - ApplyTurnForce(fPitchAccel * m_fTurnMass * GetUp() * CTimer::GetTimeStep(), vecWidthForward); + ApplyTurnForce(fPitchAccel * m_fTurnMass * GetUp() * CTimer::GetTimeStep(), vecTail); float fLift = -DotProduct(GetMoveSpeed(), GetUp()) / Max(0.01f, GetMoveSpeed().Magnitude()); float fLiftAccel = (pFlyingHandling->fAttackLift * fLift + pFlyingHandling->fFormLift) * fForwSpeed * fForwSpeed; @@ -555,7 +556,7 @@ CVehicle::DoBladeCollision(CVector pos, CMatrix &matrix, int16 rotorType, float rotorColModel.numSpheres = 1; pos = matrix * pos; - bool hadCollision; + bool hadCollision = false; int minX = CWorld::GetSectorIndexX(pos.x - radius); if(minX <= 0) minX = 0; @@ -656,7 +657,7 @@ CVehicle::BladeColSectorList(CPtrList &list, CColModel &rotorColModel, CMatrix & if(entity->IsPed()) entityCol = ((CPedModelInfo*)CModelInfo::GetModelInfo(entity->GetModelIndex()))->AnimatePedColModelSkinned(entity->GetClump()); else - entityCol = CModelInfo::GetModelInfo(entity->GetModelIndex())->GetColModel(); + entityCol = entity->GetColModel(); if(entityCol) numCollisions = CCollision::ProcessColModels(matrix, rotorColModel, entity->GetMatrix(), *entityCol, CWorld::m_aTempColPts, nil, nil); @@ -691,10 +692,12 @@ CVehicle::BladeColSectorList(CPtrList &list, CColModel &rotorColModel, CMatrix & CVector localColpos = colpos - center; float axisDir = DotProduct(axis, localColpos); float colDir = DotProduct(CWorld::m_aTempColPts[i].normal, localColpos); + if(2.0f*ROTOR_SEMI_THICKNESS < Abs(axisDir) && ROTOR_DISGUARD_MULT*Abs(colDir) < Abs(axisDir)) continue; + hadCollision = true; colpos -= axisDir*axis; // get rid of axis component CVector tangentSpeed = CrossProduct(turnSpeed, colpos - center); @@ -720,7 +723,6 @@ CVehicle::BladeColSectorList(CPtrList &list, CColModel &rotorColModel, CMatrix & if(damageImpulse > m_fDamageImpulse) SetDamagedPieceRecord(0, damageImpulse, entity, CWorld::m_aTempColPts[i].normal); - hadCollision = true; } if(hadCollision && !entity->IsPed()) @@ -1712,6 +1714,15 @@ CVehicle::CanPedExitCar(bool jumpExit) } } +bool +CVehicle::CanPedJumpOutCar(void) +{ + if(GetUp().z < 0.3f) + return false; + float speed = m_vecMoveSpeed.MagnitudeSqr(); + return speed < 0.1f || speed > 0.5f ? false : true; +} + bool CVehicle::CanPedJumpOffBike(void) { diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h index 29058b1e..87ee928c 100644 --- a/src/vehicles/Vehicle.h +++ b/src/vehicles/Vehicle.h @@ -317,6 +317,7 @@ public: bool CanDoorsBeDamaged(void); bool CanPedEnterCar(void); bool CanPedExitCar(bool jumpExit); + bool CanPedJumpOutCar(void); bool CanPedJumpOffBike(void); // do these two actually return something? CPed *SetUpDriver(void); @@ -348,11 +349,12 @@ public: static void HeliDustGenerate(CEntity *heli, float radius, float ground, int rnd); void DoSunGlare(void); - bool IsAlarmOn(void) { return m_nAlarmState != 0 && m_nAlarmState != -1; } + 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 IsRealHeli(void) { return !!(pHandling->Flags & HANDLING_IS_HELI); } + bool IsRealPlane(void) { return !!(pHandling->Flags & HANDLING_IS_PLANE); } static bool bWheelsOnlyCheat; static bool bAllDodosCheat; @@ -363,6 +365,7 @@ public: static bool bAltDodoCheat; #endif static bool bHoverCheat; + static bool bAllTaxisHaveNitro; static bool m_bDisableMouseSteering; static bool bDisableRemoteDetonation; static bool bDisableRemoteDetonationOnContact; diff --git a/src/weapons/Explosion.cpp b/src/weapons/Explosion.cpp index d0a68279..f4ad346d 100644 --- a/src/weapons/Explosion.cpp +++ b/src/weapons/Explosion.cpp @@ -86,7 +86,7 @@ CExplosion::GetExplosionPosition(uint8 id) } bool -CExplosion::AddExplosion(CEntity *explodingEntity, CEntity *culprit, eExplosionType type, const CVector &pos, uint32 lifetime) +CExplosion::AddExplosion(CEntity *explodingEntity, CEntity *culprit, eExplosionType type, const CVector &pos, uint32 lifetime, bool unk) { CVector pPosn; CVector posGround; diff --git a/src/weapons/Explosion.h b/src/weapons/Explosion.h index bf54328c..c8539cca 100644 --- a/src/weapons/Explosion.h +++ b/src/weapons/Explosion.h @@ -40,7 +40,8 @@ public: static void ResetExplosionActiveCounter(uint8 id); static uint8 GetExplosionType(uint8 id); static CVector *GetExplosionPosition(uint8 id); - static bool AddExplosion(CEntity *explodingEntity, CEntity *culprit, eExplosionType type, const CVector &pos, uint32 lifetime); +// TODO(MIAMI): that new parameter + static bool AddExplosion(CEntity *explodingEntity, CEntity *culprit, eExplosionType type, const CVector &pos, uint32 lifetime, bool unk = true); static void Update(); static bool TestForExplosionInArea(eExplosionType type, float x1, float x2, float y1, float y2, float z1, float z2); static void RemoveAllExplosionsInArea(CVector pos, float radius); diff --git a/src/weapons/Weapon.cpp b/src/weapons/Weapon.cpp index 0ac37e31..b2ac2ad2 100644 --- a/src/weapons/Weapon.cpp +++ b/src/weapons/Weapon.cpp @@ -113,6 +113,18 @@ CWeapon::UpdateWeapons(void) CBulletInfo::Update(); } +//--MIAMI: done +CWeapon::CWeapon(eWeaponType type, int32 ammo) +{ + m_eWeaponType = type; + m_eWeaponState = WEAPONSTATE_READY; + m_nAmmoTotal = Min(ammo, 99999); + m_nAmmoInClip = 0; + Reload(); + m_nTimer = 0; + m_bAddRotOffset = false; +} + // --MIAMI: Done void CWeapon::Initialise(eWeaponType type, int32 ammo) diff --git a/src/weapons/Weapon.h b/src/weapons/Weapon.h index b4ed93c3..8680fdcf 100644 --- a/src/weapons/Weapon.h +++ b/src/weapons/Weapon.h @@ -25,6 +25,7 @@ public: CWeapon() { m_bAddRotOffset = false; } + CWeapon(eWeaponType type, int32 ammo); CWeaponInfo *GetInfo();