diff options
Diffstat (limited to 'src/vehicles/Vehicle.cpp')
-rw-r--r-- | src/vehicles/Vehicle.cpp | 336 |
1 files changed, 323 insertions, 13 deletions
diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp index dccd9195..d8ed1a15 100644 --- a/src/vehicles/Vehicle.cpp +++ b/src/vehicles/Vehicle.cpp @@ -1,7 +1,9 @@ #include "common.h" #include "main.h" #include "patcher.h" +#include "General.h" #include "Timer.h" +#include "Pad.h" #include "Vehicle.h" #include "Pools.h" #include "HandlingMgr.h" @@ -13,6 +15,7 @@ #include "PointLights.h" #include "Renderer.h" #include "DMAudio.h" +#include "MusicManager.h" #include "Radar.h" bool &CVehicle::bWheelsOnlyCheat = *(bool *)0x95CD78; @@ -27,6 +30,79 @@ void *CVehicle::operator new(size_t sz, int handle) { return CPools::GetVehicleP void CVehicle::operator delete(void *p, size_t sz) { CPools::GetVehiclePool()->Delete((CVehicle*)p); } void CVehicle::operator delete(void *p, int handle) { CPools::GetVehiclePool()->Delete((CVehicle*)p); } +CVehicle::CVehicle(uint8 CreatedBy) +{ + int i; + + m_nCurrentGear = 0; + field_208 = 0; + m_fSteerRatio = 0.0f; + m_type = ENTITY_TYPE_VEHICLE; + VehicleCreatedBy = CreatedBy; + bIsLocked = false; + bIsLawEnforcer = false; + bIsAmbulanceOnDuty = false; + bIsFireTruckOnDuty = false; + CCarCtrl::UpdateCarCount(this, false); + m_fHealth = 1000.0f; + bEngineOn = true; + bFreebies = true; + pDriver = nil; + m_nNumPassengers = 0; + m_nNumGettingIn = 0; + m_nGettingInFlags = 0; + m_nGettingOutFlags = 0; + m_nNumMaxPassengers = 8; + for(i = 0; i < m_nNumMaxPassengers; i++) + pPassengers[i] = nil; + m_nBombTimer = 0; + m_pWhoSetMeOnFire = nil; + field_1FB = 0; + m_veh_flagB10 = false; + m_veh_flagB40 = false; + m_veh_flagB80 = false; + m_veh_flagC1 = false; + bIsDamaged = false; + m_veh_flagC8 = false; + m_veh_flagC10 = false; + m_veh_flagC4 = false; + m_veh_flagC20 = false; + bCanBeDamaged = true; + m_veh_flagC80 = false; + m_veh_flagD1 = false; + m_veh_flagD2 = false; + m_nGunFiringTime = 0; + field_214 = 0; + bLightsOn = false; + bVehicleColProcessed = false; + field_1F9 = 0; + bIsCarParkVehicle = false; + bHasAlreadyBeenRecorded = false; + m_bSirenOrAlarm = 0; + m_nCarHornTimer = 0; + field_22D = 0; + m_nAlarmState = 0; + m_nDoorLock = CARLOCK_UNLOCKED; + m_nLastWeaponDamage = -1; + field_220 = 0.0; + field_21C = field_220; + m_audioEntityId = DMAudio.CreateEntity(0, this); + if(m_audioEntityId) + DMAudio.SetEntityStatus(m_audioEntityId, true); + m_nRadioStation = CGeneral::GetRandomNumber() % USERTRACK; + m_pCurGroundEntity = nil; + field_22A = 0; + field_22B = 0; + field_22F = 0; + m_aCollPolys[0].valid = false; + m_aCollPolys[1].valid = false; + m_autoPilot.m_nCarMission = MISSION_NONE; + m_autoPilot.m_nAnimationId = TEMPACT_NONE; + m_autoPilot.m_nTimeToStartMission = CTimer::GetTimeInMilliseconds(); + m_autoPilot.m_flag4 = false; + m_autoPilot.m_flag10 = false; +} + CVehicle::~CVehicle() { m_nAlarmState = 0; @@ -92,9 +168,227 @@ CVehicle::RemoveLighting(bool reset) float CVehicle::GetHeightAboveRoad(void) { - return -1.0f * CModelInfo::GetModelInfo(GetModelIndex())->GetColModel()->boundingBox.min.z; + return -1.0f * GetColModel()->boundingBox.min.z; +} + +void +CVehicle::FlyingControl(eFlightModel flightModel) +{ + switch(flightModel){ + case FLIGHT_MODEL_DODO: + { + // This seems pretty magic + + // Move Left/Right + float moveSpeed = m_vecMoveSpeed.Magnitude(); + float sideSpeed = DotProduct(m_vecMoveSpeed, GetRight()); + float sideImpulse = -1.0f * sideSpeed / moveSpeed; + float fwdSpeed = DotProduct(m_vecMoveSpeed, GetForward()); + float magic = m_vecMoveSpeed.MagnitudeSqr() * sq(fwdSpeed); + float turnImpulse = (sideImpulse*0.003f + m_fSteerAngle*0.001f) * + magic*m_fTurnMass*CTimer::GetTimeStep(); + ApplyTurnForce(turnImpulse*GetRight(), -4.0f*GetForward()); + + float impulse = sideImpulse*0.2f * + magic*m_fMass*CTimer::GetTimeStep(); + ApplyMoveForce(impulse*GetRight()); + ApplyTurnForce(impulse*GetRight(), 2.0f*GetUp()); + + + // Move Up/Down + moveSpeed = m_vecMoveSpeed.Magnitude(); + float upSpeed = DotProduct(m_vecMoveSpeed, GetUp()); + float upImpulse = -1.0f * upSpeed / moveSpeed; + turnImpulse = (upImpulse*0.002f + -CPad::GetPad(0)->GetSteeringUpDown()/128.0f*0.001f) * + magic*m_fTurnMass*CTimer::GetTimeStep(); + ApplyTurnForce(turnImpulse*GetUp(), -4.0f*GetForward()); + + impulse = (upImpulse*3.5f + 0.5f)*0.05f * + magic*m_fMass*CTimer::GetTimeStep(); + if(GRAVITY*m_fMass*CTimer::GetTimeStep() < impulse && + GetPosition().z > 100.0f) + impulse = 0.9f*GRAVITY*m_fMass*CTimer::GetTimeStep(); + CVector com = Multiply3x3(GetMatrix(), m_vecCentreOfMass); + ApplyMoveForce(impulse*GetUp()); + ApplyTurnForce(impulse*GetUp(), 2.0f*GetUp() + com); + + + m_vecTurnSpeed.y *= Pow(0.9f, CTimer::GetTimeStep()); + moveSpeed = m_vecMoveSpeed.MagnitudeSqr(); + if(moveSpeed > 2.25f) + m_vecMoveSpeed *= 1.5f/Sqrt(moveSpeed); + + float turnSpeed = m_vecTurnSpeed.MagnitudeSqr(); + if(turnSpeed > 0.04f) + m_vecTurnSpeed *= 0.2f/Sqrt(turnSpeed); + } + break; + + case FLIGHT_MODEL_RCPLANE: + case FLIGHT_MODEL_SEAPLANE: + assert(0 && "Plane flight model not implemented"); + case FLIGHT_MODEL_HELI: + assert(0 && "Heli flight model not implemented"); + } +} + +void +CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelContactSpeed, CVector &wheelContactPoint, + int32 wheelsOnGround, float thrust, float brake, float adhesion, int8 wheelId, float *wheelSpeed, tWheelState *wheelState, uint16 wheelStatus) +{ + // BUG: using statics here is probably a bad idea + static bool bAlreadySkidding = false; // this is never reset + static bool bBraking; + static bool bDriving; + + // how much force we want to apply in these axes + float fwd = 0.0f; + float right = 0.0f; + + bBraking = brake != 0.0f; + if(bBraking) + thrust = 0.0f; + bDriving = thrust != 0.0f; + + float contactSpeedFwd = DotProduct(wheelContactSpeed, wheelFwd); + float contactSpeedRight = DotProduct(wheelContactSpeed, wheelRight); + + if(*wheelState != WHEEL_STATE_0) + bAlreadySkidding = true; + *wheelState = WHEEL_STATE_0; + + adhesion *= CTimer::GetTimeStep(); + if(bAlreadySkidding) + adhesion *= m_handling->fTractionLoss; + + // moving sideways + if(contactSpeedRight != 0.0f){ + // exert opposing force + right = -contactSpeedRight/wheelsOnGround; + + if(wheelStatus == WHEEL_STATUS_BURST){ + float fwdspeed = min(contactSpeedFwd, 0.3f); + right += fwdspeed * CGeneral::GetRandomNumberInRange(-0.1f, 0.1f); + } + } + + if(bDriving){ + fwd = thrust; + + // limit sideways force (why?) + if(right > 0.0f){ + if(right > adhesion) + right = adhesion; + }else{ + if(right < -adhesion) + right = -adhesion; + } + }else if(contactSpeedFwd != 0.0f){ + fwd = -contactSpeedFwd/wheelsOnGround; + + if(!bBraking){ + if(m_fGasPedal < 0.01f){ + if(GetModelIndex() == MI_RCBANDIT) + brake = 0.2f * mod_HandlingManager.field_4 / m_fMass; + else + brake = mod_HandlingManager.field_4 / m_fMass; + } + } + + if(brake > adhesion){ + if(Abs(contactSpeedFwd) > 0.005f) + *wheelState = WHEEL_STATE_STATIC; + }else { + if(fwd > 0.0f){ + if(fwd > brake) + fwd = brake; + }else{ + if(fwd < -brake) + fwd = -brake; + } + } + } + + if(sq(adhesion) < sq(right) + sq(fwd)){ + if(*wheelState != WHEEL_STATE_STATIC){ + if(bDriving && contactSpeedFwd < 0.2f) + *wheelState = WHEEL_STATE_1; + else + *wheelState = WHEEL_STATE_2; + } + + float l = Sqrt(sq(right) + sq(fwd)); + float tractionLoss = bAlreadySkidding ? 1.0f : m_handling->fTractionLoss; + right *= adhesion * tractionLoss / l; + fwd *= adhesion * tractionLoss / l; + } + + if(fwd != 0.0f || right != 0.0f){ + CVector direction = fwd*wheelFwd + right*wheelRight; + float speed = direction.Magnitude(); + direction.Normalise(); + + float impulse = speed*m_fMass; + float turnImpulse = speed*GetMass(wheelContactPoint, direction); + + ApplyMoveForce(impulse * direction); + ApplyTurnForce(turnImpulse * direction, wheelContactPoint); + } +} + +float +CVehicle::ProcessWheelRotation(tWheelState state, const CVector &fwd, const CVector &speed, float radius) +{ + float angularVelocity; + switch(state){ + case WHEEL_STATE_1: + angularVelocity = -1.1f; // constant speed forward + break; + case WHEEL_STATE_STATIC: + angularVelocity = 0.0f; // not moving + break; + default: + angularVelocity = -DotProduct(fwd, speed) / radius; // forward speed + break; + } + return angularVelocity * CTimer::GetTimeStep(); } +void +CVehicle::ExtinguishCarFire(void) +{ + m_fHealth = max(m_fHealth, 300.0f); + if(m_pCarFire) + m_pCarFire->Extinguish(); + if(IsCar()){ + CAutomobile *car = (CAutomobile*)this; + if(car->Damage.GetEngineStatus() >= 225) + car->Damage.SetEngineStatus(215); + car->field_530 = 0.0f; + } +} + +void +CVehicle::ProcessDelayedExplosion(void) +{ + if(m_nBombTimer == 0) + return; + + if(m_nBombTimer == 0){ + int tick = CTimer::GetTimeStep()/60.0f*1000.0f; + if(tick > m_nBombTimer) + m_nBombTimer = 0; + else + m_nBombTimer -= tick; + + if(IsCar() && ((CAutomobile*)this)->m_auto_flagA7 == 4 && (m_nBombTimer & 0xFE00) != 0xFE00) + DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_BOMB_TICK, 0.0f); + + if(FindPlayerVehicle() != this && m_pWhoSetMeOnFire == FindPlayerPed()) + CWorld::Players[CWorld::PlayerInFocus].AwardMoneyForExplosion(this); + BlowUpCar(m_pWhoSetMeOnFire); + } +} bool CVehicle::IsLawEnforcementVehicle(void) @@ -258,9 +552,9 @@ CVehicle::CanPedExitCar(void) if(m_vecMoveSpeed.MagnitudeSqr() > 0.005f) return false; // if car is slow enough, check turn speed - if(fabs(m_vecTurnSpeed.x) > 0.01f || - fabs(m_vecTurnSpeed.y) > 0.01f || - fabs(m_vecTurnSpeed.z) > 0.01f) + if(Abs(m_vecTurnSpeed.x) > 0.01f || + Abs(m_vecTurnSpeed.y) > 0.01f || + Abs(m_vecTurnSpeed.z) > 0.01f) return false; return true; }else{ @@ -270,9 +564,9 @@ CVehicle::CanPedExitCar(void) if(m_vecMoveSpeed.MagnitudeSqr() >= 0.005f) return false; // if car is slow enough, check turn speed - if(fabs(m_vecTurnSpeed.x) >= 0.01f || - fabs(m_vecTurnSpeed.y) >= 0.01f || - fabs(m_vecTurnSpeed.z) >= 0.01f) + if(Abs(m_vecTurnSpeed.x) >= 0.01f || + Abs(m_vecTurnSpeed.y) >= 0.01f || + Abs(m_vecTurnSpeed.z) >= 0.01f) return false; return true; } @@ -442,7 +736,7 @@ CVehicle::IsSphereTouchingVehicle(float sx, float sy, float sz, float radius) float x, y, z; // sphere relative to vehicle CVector sph = CVector(sx, sy, sz) - GetPosition(); - CColModel *colmodel = CModelInfo::GetModelInfo(GetModelIndex())->GetColModel(); + CColModel *colmodel = GetColModel(); x = DotProduct(sph, GetRight()); if(colmodel->boundingBox.min.x - radius > x || @@ -460,12 +754,28 @@ CVehicle::IsSphereTouchingVehicle(float sx, float sy, float sz, float radius) return true; } -STARTPATCHES - InjectHook(0x551170, &CVehicle::SetModelIndex_, PATCH_JUMP); - InjectHook(0x4A7DD0, &CVehicle::SetupLighting_, PATCH_JUMP); - InjectHook(0x4A7E60, &CVehicle::RemoveLighting_, PATCH_JUMP); - InjectHook(0x417E60, &CVehicle::GetHeightAboveRoad_, PATCH_JUMP); +class CVehicle_ : public CVehicle +{ +public: + void dtor(void) { CVehicle::~CVehicle(); } + void SetModelIndex_(uint32 id) { CVehicle::SetModelIndex(id); } + bool SetupLighting_(void) { return CVehicle::SetupLighting(); } + void RemoveLighting_(bool reset) { CVehicle::RemoveLighting(reset); } + float GetHeightAboveRoad_(void) { return CVehicle::GetHeightAboveRoad(); } +}; + +STARTPATCHES + InjectHook(0x551170, &CVehicle_::SetModelIndex_, PATCH_JUMP); + InjectHook(0x4A7DD0, &CVehicle_::SetupLighting_, PATCH_JUMP); + InjectHook(0x4A7E60, &CVehicle_::RemoveLighting_, PATCH_JUMP); + InjectHook(0x417E60, &CVehicle_::GetHeightAboveRoad_, PATCH_JUMP); + + InjectHook(0x552BB0, &CVehicle::FlyingControl, PATCH_JUMP); + InjectHook(0x5512E0, &CVehicle::ProcessWheel, PATCH_JUMP); + InjectHook(0x551280, &CVehicle::ProcessWheelRotation, PATCH_JUMP); + InjectHook(0x552AF0, &CVehicle::ExtinguishCarFire, PATCH_JUMP); + InjectHook(0x551C90, &CVehicle::ProcessDelayedExplosion, PATCH_JUMP); InjectHook(0x552880, &CVehicle::IsLawEnforcementVehicle, PATCH_JUMP); InjectHook(0x552820, &CVehicle::ChangeLawEnforcerState, PATCH_JUMP); InjectHook(0x552200, &CVehicle::UsesSiren, PATCH_JUMP); |